Imported Upstream version 5.10 upstream/5.10
authorWu zheng <wu.zheng@intel.com>
Wed, 23 Oct 2013 02:59:15 +0000 (10:59 +0800)
committerWu zheng <wu.zheng@intel.com>
Wed, 23 Oct 2013 02:59:15 +0000 (10:59 +0800)
621 files changed:
AUTHORS
ChangeLog
Makefile.am
Makefile.android [new file with mode: 0644]
Makefile.in
Makefile.obexd [new file with mode: 0644]
Makefile.plugins [new file with mode: 0644]
Makefile.tools
README
TODO
acinclude.m4
aclocal.m4
android/Android.mk [new file with mode: 0644]
android/hal-ipc-api.txt [new file with mode: 0644]
android/log.c [moved from alert/main.c with 54% similarity]
android/main.c [new file with mode: 0644]
attrib/att-database.h
attrib/att.c
attrib/att.h
attrib/client.c [deleted file]
attrib/client.h [deleted file]
attrib/gatt-service.c
attrib/gatt-service.h
attrib/gatt.c
attrib/gatt.h
attrib/gattrib.c
attrib/gattrib.h
attrib/gatttool.c
attrib/gatttool.h
attrib/interactive.c
attrib/utils.c
audio/audio.conf [deleted file]
audio/avctp.c [deleted file]
audio/avctp.h [deleted file]
audio/avrcp.c [deleted file]
audio/bluetooth.conf [deleted file]
audio/control.c [deleted file]
audio/ctl_bluetooth.c [deleted file]
audio/device.c [deleted file]
audio/device.h [deleted file]
audio/gateway.c [deleted file]
audio/gateway.h [deleted file]
audio/gsta2dpsink.c [deleted file]
audio/gsta2dpsink.h [deleted file]
audio/gstavdtpsink.c [deleted file]
audio/gstavdtpsink.h [deleted file]
audio/gstbluetooth.c [deleted file]
audio/gstrtpsbcpay.c [deleted file]
audio/gstrtpsbcpay.h [deleted file]
audio/gstsbcdec.c [deleted file]
audio/gstsbcdec.h [deleted file]
audio/gstsbcenc.c [deleted file]
audio/gstsbcenc.h [deleted file]
audio/gstsbcparse.c [deleted file]
audio/gstsbcparse.h [deleted file]
audio/gstsbcutil.c [deleted file]
audio/gstsbcutil.h [deleted file]
audio/headset.c [deleted file]
audio/headset.h [deleted file]
audio/ipc.c [deleted file]
audio/ipc.h [deleted file]
audio/main.c [deleted file]
audio/manager.c [deleted file]
audio/manager.h [deleted file]
audio/pcm_bluetooth.c [deleted file]
audio/rtp.h [deleted file]
audio/sink.c [deleted file]
audio/source.c [deleted file]
audio/telephony-dummy.c [deleted file]
audio/telephony-maemo5.c [deleted file]
audio/telephony-maemo6.c [deleted file]
audio/telephony-ofono.c [deleted file]
audio/telephony.h [deleted file]
audio/transport.c [deleted file]
audio/unix.c [deleted file]
btio/btio.c
btio/btio.h
client/agent.c [new file with mode: 0644]
client/agent.h [moved from plugins/storage.c with 67% similarity]
client/display.c [moved from network/main.c with 55% similarity]
client/display.h [moved from src/oob.h with 68% similarity]
client/main.c [new file with mode: 0644]
compat/bnep.c [deleted file]
compat/dun.c [deleted file]
compat/dund.1 [deleted file]
compat/dund.c [deleted file]
compat/fakehid.c [deleted file]
compat/hidd.1 [deleted file]
compat/hidd.c [deleted file]
compat/hidd.h [deleted file]
compat/lib.h [deleted file]
compat/msdun.c [deleted file]
compat/pand.1 [deleted file]
compat/pand.c [deleted file]
compat/sdp.c [deleted file]
compat/sdp.h [deleted file]
compile
config.h.in
config.sub
configure
configure.ac
depcomp
deviceinfo/deviceinfo.h [deleted file]
deviceinfo/manager.c [deleted file]
doc/adapter-api.txt
doc/agent-api.txt
doc/alert-api.txt [new file with mode: 0644]
doc/assigned-numbers.txt
doc/attribute-api.txt [deleted file]
doc/audio-api.txt [deleted file]
doc/control-api.txt [deleted file]
doc/cyclingspeed-api.txt [new file with mode: 0644]
doc/device-api.txt
doc/health-api.txt
doc/heartrate-api.txt [new file with mode: 0644]
doc/hfp-api.txt [deleted file]
doc/input-api.txt [deleted file]
doc/manager-api.txt [deleted file]
doc/media-api.txt
doc/mgmt-api.txt [new file with mode: 0644]
doc/network-api.txt
doc/obex-agent-api.txt [new file with mode: 0644]
doc/obex-api.txt [new file with mode: 0644]
doc/profile-api.txt [new file with mode: 0644]
doc/proximity-api.txt [new file with mode: 0644]
doc/sap-api.txt
doc/serial-api.txt [deleted file]
doc/service-api.txt [deleted file]
doc/supported-features.txt [new file with mode: 0644]
doc/thermometer-api.txt [new file with mode: 0644]
doc/version.xml.in [deleted file]
emulator/amp.c [new file with mode: 0644]
emulator/amp.h [moved from audio/gstpragma.h with 81% similarity]
emulator/b1ee.c [new file with mode: 0644]
emulator/btdev.c
emulator/btdev.h
emulator/bthost.c [new file with mode: 0644]
emulator/bthost.h [new file with mode: 0644]
emulator/main.c
emulator/server.c
emulator/server.h
emulator/vhci.c
emulator/vhci.h
gdbus/client.c [new file with mode: 0644]
gdbus/gdbus.h
gdbus/mainloop.c
gdbus/object.c
gdbus/watch.c
gobex/gobex-apparam.c [new file with mode: 0644]
gobex/gobex-apparam.h [new file with mode: 0644]
gobex/gobex-debug.h [new file with mode: 0644]
gobex/gobex-defs.c [moved from alert/server.c with 76% similarity]
gobex/gobex-defs.h [new file with mode: 0644]
gobex/gobex-header.c [new file with mode: 0644]
gobex/gobex-header.h [new file with mode: 0644]
gobex/gobex-packet.c [new file with mode: 0644]
gobex/gobex-packet.h [new file with mode: 0644]
gobex/gobex-transfer.c [new file with mode: 0644]
gobex/gobex.c [new file with mode: 0644]
gobex/gobex.h [new file with mode: 0644]
input/device.c [deleted file]
input/fakehid.c [deleted file]
input/manager.c [deleted file]
lib/a2mp.h
lib/amp.h [new file with mode: 0644]
lib/bluetooth.c
lib/bluetooth.h
lib/bluez.pc.in [moved from bluez.pc.in with 100% similarity]
lib/hci.c
lib/hci.h
lib/hci_lib.h
lib/mgmt.h
lib/sdp.c
lib/sdp.h
lib/uuid.c
lib/uuid.h
ltmain.sh
monitor/bt.h
monitor/btsnoop.c
monitor/btsnoop.h
monitor/control.c
monitor/control.h
monitor/crc.c [new file with mode: 0644]
monitor/crc.h [moved from sbc/sbc_primitives_neon.h with 59% similarity]
monitor/display.c [new file with mode: 0644]
monitor/display.h [new file with mode: 0644]
monitor/hcidump.c
monitor/l2cap.c [new file with mode: 0644]
monitor/l2cap.h [new file with mode: 0644]
monitor/ll.c [new file with mode: 0644]
monitor/ll.h [new file with mode: 0644]
monitor/lmp.c [new file with mode: 0644]
monitor/lmp.h [moved from serial/manager.h with 88% similarity]
monitor/main.c
monitor/packet.c
monitor/packet.h
monitor/sdp.c [new file with mode: 0644]
monitor/sdp.h [moved from input/manager.h with 88% similarity]
monitor/uuid.c [new file with mode: 0644]
monitor/uuid.h [moved from serial/port.h with 77% similarity]
monitor/vendor.c [moved from audio/unix.h with 78% similarity]
monitor/vendor.h [moved from network/manager.h with 85% similarity]
network/connection.h [deleted file]
network/manager.c [deleted file]
obexd/client/bluetooth.c [new file with mode: 0644]
obexd/client/bluetooth.h [new file with mode: 0644]
obexd/client/dbus.c [new file with mode: 0644]
obexd/client/dbus.h [new file with mode: 0644]
obexd/client/driver.c [new file with mode: 0644]
obexd/client/driver.h [new file with mode: 0644]
obexd/client/ftp.c [new file with mode: 0644]
obexd/client/ftp.h [new file with mode: 0644]
obexd/client/manager.c [new file with mode: 0644]
obexd/client/manager.h [new file with mode: 0644]
obexd/client/map-event.c [new file with mode: 0644]
obexd/client/map-event.h [new file with mode: 0644]
obexd/client/map.c [new file with mode: 0644]
obexd/client/map.h [new file with mode: 0644]
obexd/client/mns.c [new file with mode: 0644]
obexd/client/opp.c [new file with mode: 0644]
obexd/client/opp.h [new file with mode: 0644]
obexd/client/pbap.c [new file with mode: 0644]
obexd/client/pbap.h [new file with mode: 0644]
obexd/client/session.c [new file with mode: 0644]
obexd/client/session.h [new file with mode: 0644]
obexd/client/sync.c [new file with mode: 0644]
obexd/client/sync.h [new file with mode: 0644]
obexd/client/transfer.c [new file with mode: 0644]
obexd/client/transfer.h [new file with mode: 0644]
obexd/client/transport.c [new file with mode: 0644]
obexd/client/transport.h [moved from input/fakehid.h with 52% similarity]
obexd/plugins/bluetooth.c [new file with mode: 0644]
obexd/plugins/filesystem.c [new file with mode: 0644]
obexd/plugins/filesystem.h [new file with mode: 0644]
obexd/plugins/ftp.c [new file with mode: 0644]
obexd/plugins/ftp.h [new file with mode: 0644]
obexd/plugins/irmc.c [new file with mode: 0644]
obexd/plugins/mas.c [new file with mode: 0644]
obexd/plugins/messages-dummy.c [new file with mode: 0644]
obexd/plugins/messages.h [new file with mode: 0644]
obexd/plugins/opp.c [new file with mode: 0644]
obexd/plugins/pbap.c [new file with mode: 0644]
obexd/plugins/pcsuite.c [new file with mode: 0644]
obexd/plugins/phonebook-dummy.c [new file with mode: 0644]
obexd/plugins/phonebook.h [new file with mode: 0644]
obexd/plugins/vcard.c [new file with mode: 0644]
obexd/plugins/vcard.h [new file with mode: 0644]
obexd/src/genbuiltin [new file with mode: 0755]
obexd/src/log.c [new file with mode: 0644]
obexd/src/log.h [new file with mode: 0644]
obexd/src/main.c [new file with mode: 0644]
obexd/src/manager.c [new file with mode: 0644]
obexd/src/manager.h [new file with mode: 0644]
obexd/src/map_ap.h [new file with mode: 0644]
obexd/src/mimetype.c [new file with mode: 0644]
obexd/src/mimetype.h [new file with mode: 0644]
obexd/src/obex-priv.h [new file with mode: 0644]
obexd/src/obex.c [new file with mode: 0644]
obexd/src/obex.h [new file with mode: 0644]
obexd/src/obex.service.in [new file with mode: 0644]
obexd/src/obexd.h [moved from compat/pand.h with 54% similarity]
obexd/src/org.bluez.obex.service [new file with mode: 0644]
obexd/src/plugin.c [new file with mode: 0644]
obexd/src/plugin.h [moved from compat/dund.h with 57% similarity]
obexd/src/server.c [new file with mode: 0644]
obexd/src/server.h [new file with mode: 0644]
obexd/src/service.c [new file with mode: 0644]
obexd/src/service.h [new file with mode: 0644]
obexd/src/transport.c [new file with mode: 0644]
obexd/src/transport.h [moved from tools/kword.h with 58% similarity]
plugins/adaptername.c [deleted file]
plugins/autopair.c [new file with mode: 0644]
plugins/dbusoob.c [deleted file]
plugins/formfactor.c [deleted file]
plugins/gatt-example.c
plugins/hal.c [deleted file]
plugins/hciops.c [deleted file]
plugins/hostname.c [new file with mode: 0644]
plugins/maemo6.c [deleted file]
plugins/mgmtops.c [deleted file]
plugins/neard.c [new file with mode: 0644]
plugins/pnat.c [deleted file]
plugins/policy.c [new file with mode: 0644]
plugins/service.c [deleted file]
plugins/wiimote.c
profiles/alert/server.c [new file with mode: 0644]
profiles/audio/a2dp-codecs.h [moved from audio/a2dp-codecs.h with 81% similarity]
profiles/audio/a2dp.c [moved from audio/a2dp.c with 65% similarity]
profiles/audio/a2dp.h [moved from audio/a2dp.h with 52% similarity]
profiles/audio/avctp.c [new file with mode: 0644]
profiles/audio/avctp.h [new file with mode: 0644]
profiles/audio/avdtp.c [moved from audio/avdtp.c with 89% similarity]
profiles/audio/avdtp.h [moved from audio/avdtp.h with 92% similarity]
profiles/audio/avrcp.c [new file with mode: 0644]
profiles/audio/avrcp.h [moved from audio/avrcp.h with 67% similarity]
profiles/audio/control.c [new file with mode: 0644]
profiles/audio/control.h [moved from audio/control.h with 69% similarity]
profiles/audio/media.c [moved from audio/media.c with 64% similarity]
profiles/audio/media.h [moved from audio/media.h with 85% similarity]
profiles/audio/player.c [new file with mode: 0644]
profiles/audio/player.h [new file with mode: 0644]
profiles/audio/sink.c [new file with mode: 0644]
profiles/audio/sink.h [moved from audio/sink.h with 66% similarity]
profiles/audio/source.c [new file with mode: 0644]
profiles/audio/source.h [moved from audio/source.h with 67% similarity]
profiles/audio/transport.c [new file with mode: 0644]
profiles/audio/transport.h [moved from audio/transport.h with 76% similarity]
profiles/cups/cups.h [moved from cups/cups.h with 100% similarity]
profiles/cups/hcrp.c [moved from cups/hcrp.c with 100% similarity]
profiles/cups/main.c [moved from cups/main.c with 94% similarity]
profiles/cups/sdp.c [moved from cups/sdp.c with 100% similarity]
profiles/cups/spp.c [moved from cups/spp.c with 100% similarity]
profiles/cyclingspeed/cyclingspeed.c [new file with mode: 0644]
profiles/deviceinfo/deviceinfo.c [moved from deviceinfo/deviceinfo.c with 69% similarity]
profiles/gatt/gas.c [new file with mode: 0644]
profiles/health/hdp.c [moved from health/hdp.c with 86% similarity]
profiles/health/hdp.h [moved from health/hdp.h with 84% similarity]
profiles/health/hdp_main.c [moved from health/hdp_main.c with 78% similarity]
profiles/health/hdp_manager.c [moved from health/hdp_manager.c with 50% similarity]
profiles/health/hdp_manager.h [moved from health/hdp_manager.h with 95% similarity]
profiles/health/hdp_types.h [moved from health/hdp_types.h with 91% similarity]
profiles/health/hdp_util.c [moved from health/hdp_util.c with 93% similarity]
profiles/health/hdp_util.h [moved from health/hdp_util.h with 100% similarity]
profiles/health/mcap.c [moved from health/mcap.c with 98% similarity]
profiles/health/mcap.h [moved from health/mcap.h with 99% similarity]
profiles/health/mcap_internal.h [moved from health/mcap_internal.h with 97% similarity]
profiles/health/mcap_lib.h [moved from health/mcap_lib.h with 99% similarity]
profiles/health/mcap_sync.c [moved from health/mcap_sync.c with 99% similarity]
profiles/heartrate/heartrate.c [new file with mode: 0644]
profiles/iap/main.c [new file with mode: 0644]
profiles/input/device.c [new file with mode: 0644]
profiles/input/device.h [moved from input/device.h with 62% similarity]
profiles/input/hog.c [new file with mode: 0644]
profiles/input/input.conf [moved from input/input.conf with 100% similarity]
profiles/input/manager.c [moved from input/main.c with 53% similarity]
profiles/input/server.c [moved from input/server.c with 87% similarity]
profiles/input/server.h [moved from input/server.h with 100% similarity]
profiles/input/suspend-dummy.c [new file with mode: 0644]
profiles/input/suspend.h [new file with mode: 0644]
profiles/input/uhid_copy.h [new file with mode: 0644]
profiles/network/common.c [moved from network/common.c with 83% similarity]
profiles/network/common.h [moved from network/common.h with 91% similarity]
profiles/network/connection.c [moved from network/connection.c with 54% similarity]
profiles/network/connection.h [new file with mode: 0644]
profiles/network/manager.c [new file with mode: 0644]
profiles/network/network.conf [moved from network/network.conf with 100% similarity]
profiles/network/server.c [moved from network/server.c with 82% similarity]
profiles/network/server.h [moved from network/server.h with 84% similarity]
profiles/proximity/immalert.c [moved from proximity/immalert.c with 91% similarity]
profiles/proximity/immalert.h [moved from proximity/immalert.h with 92% similarity]
profiles/proximity/linkloss.c [moved from proximity/linkloss.c with 92% similarity]
profiles/proximity/linkloss.h [moved from proximity/linkloss.h with 92% similarity]
profiles/proximity/main.c [moved from proximity/main.c with 79% similarity]
profiles/proximity/manager.c [new file with mode: 0644]
profiles/proximity/manager.h [moved from proximity/manager.h with 93% similarity]
profiles/proximity/monitor.c [moved from proximity/monitor.c with 53% similarity]
profiles/proximity/monitor.h [moved from proximity/monitor.h with 63% similarity]
profiles/proximity/proximity.conf [moved from proximity/proximity.conf with 100% similarity]
profiles/proximity/reporter.c [moved from proximity/reporter.c with 66% similarity]
profiles/proximity/reporter.h [moved from proximity/reporter.h with 81% similarity]
profiles/sap/main.c [moved from sap/main.c with 79% similarity]
profiles/sap/manager.c [moved from sap/manager.c with 59% similarity]
profiles/sap/manager.h [moved from sap/manager.h with 95% similarity]
profiles/sap/sap-dummy.c [moved from sap/sap-dummy.c with 73% similarity]
profiles/sap/sap-u8500.c [moved from sap/sap-u8500.c with 94% similarity]
profiles/sap/sap.h [moved from sap/sap.h with 96% similarity]
profiles/sap/server.c [moved from sap/server.c with 74% similarity]
profiles/sap/server.h [moved from deviceinfo/manager.h with 82% similarity]
profiles/scanparam/scan.c [new file with mode: 0644]
profiles/thermometer/thermometer.c [new file with mode: 0644]
profiles/time/server.c [new file with mode: 0644]
proximity/manager.c [deleted file]
sap/server.h [deleted file]
sbc/formats.h [deleted file]
sbc/sbc.c [deleted file]
sbc/sbc.h [deleted file]
sbc/sbc_math.h [deleted file]
sbc/sbc_primitives.c [deleted file]
sbc/sbc_primitives.h [deleted file]
sbc/sbc_primitives_armv6.c [deleted file]
sbc/sbc_primitives_armv6.h [deleted file]
sbc/sbc_primitives_iwmmxt.c [deleted file]
sbc/sbc_primitives_mmx.c [deleted file]
sbc/sbc_primitives_neon.c [deleted file]
sbc/sbc_tables.h [deleted file]
sbc/sbcdec.c [deleted file]
sbc/sbcenc.c [deleted file]
sbc/sbcinfo.c [deleted file]
sbc/sbctester.c [deleted file]
scripts/bluetooth-serial.rules [deleted file]
scripts/bluetooth_serial [deleted file]
serial/manager.c [deleted file]
serial/port.c [deleted file]
serial/proxy.c [deleted file]
serial/proxy.h [deleted file]
serial/serial.conf [deleted file]
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/bluetoothd.8.in
src/dbus-common.c
src/dbus-common.h
src/device.c
src/device.h
src/eir.c
src/eir.h
src/error.c
src/event.c [deleted file]
src/event.h [deleted file]
src/glib-helper.c
src/glib-helper.h
src/hcid.h
src/log.c
src/log.h
src/main.c
src/main.conf
src/manager.c [deleted file]
src/manager.h [deleted file]
src/oob.c [deleted file]
src/oui.c
src/oui.h
src/plugin.c
src/ppoll.h [deleted file]
src/profile.c [new file with mode: 0644]
src/profile.h [new file with mode: 0644]
src/rfkill.c
src/sdp-client.c
src/sdp-xml.c
src/sdp-xml.h
src/sdpd-database.c
src/sdpd-request.c
src/sdpd-server.c
src/sdpd-service.c
src/sdpd.h
src/service.c [new file with mode: 0644]
src/service.h [new file with mode: 0644]
src/shared/btsnoop.c [new file with mode: 0644]
src/shared/btsnoop.h [new file with mode: 0644]
src/shared/hciemu.c [new file with mode: 0644]
src/shared/hciemu.h [new file with mode: 0644]
src/shared/mgmt.c [new file with mode: 0644]
src/shared/mgmt.h [new file with mode: 0644]
src/shared/pcap.c [new file with mode: 0644]
src/shared/pcap.h [moved from sbc/sbc_primitives_iwmmxt.h with 50% similarity]
src/shared/tester.c [new file with mode: 0644]
src/shared/tester.h [new file with mode: 0644]
src/shared/util.c [new file with mode: 0644]
src/shared/util.h [moved from sbc/sbc_primitives_mmx.h with 54% similarity]
src/storage.c
src/storage.h
src/systemd.c [new file with mode: 0644]
src/systemd.h [moved from alert/server.h with 80% similarity]
src/textfile.c
src/textfile.h
test/agent.c [deleted file]
test/attest.c [deleted file]
test/bdaddr.8 [deleted file]
test/bluezutils.py [new file with mode: 0644]
test/dbusdef.py
test/gaptest.c [deleted file]
test/hciemu.1 [deleted file]
test/hciemu.c [deleted file]
test/hsmicro [deleted file]
test/hsplay [deleted file]
test/hstest.c [deleted file]
test/ipctest.c [deleted file]
test/list-devices
test/lmptest.c [deleted file]
test/monitor-bluetooth
test/mpris-player.c [deleted file]
test/sap_client.py [moved from test/sap-client with 100% similarity]
test/sdptest.c [deleted file]
test/simple-agent
test/simple-endpoint
test/simple-player
test/simple-service
test/test-adapter
test/test-alert [new file with mode: 0755]
test/test-attrib [deleted file]
test/test-audio [deleted file]
test/test-cyclingspeed [new file with mode: 0755]
test/test-device
test/test-discovery
test/test-health
test/test-health-sink
test/test-heartrate [new file with mode: 0755]
test/test-hfp [new file with mode: 0755]
test/test-input [deleted file]
test/test-manager
test/test-nap
test/test-network
test/test-oob [deleted file]
test/test-profile [new file with mode: 0755]
test/test-proximity
test/test-sap-server
test/test-serial [deleted file]
test/test-serial-proxy [deleted file]
test/test-service [deleted file]
test/test-telephony [deleted file]
test/test-textfile.c [deleted file]
test/test-thermometer
test/uuidtest.c [deleted file]
thermometer/main.c [deleted file]
thermometer/manager.c [deleted file]
thermometer/manager.h [deleted file]
thermometer/thermometer.c [deleted file]
thermometer/thermometer.h [deleted file]
time/main.c [deleted file]
time/server.c [deleted file]
time/server.h [deleted file]
tools/amptest.c [new file with mode: 0644]
tools/avctrl.8 [deleted file]
tools/avctrl.c [deleted file]
tools/avinfo.c
tools/avtest.c [moved from test/avtest.c with 100% similarity]
tools/bccmd.1 [moved from tools/bccmd.8 with 97% similarity]
tools/bccmd.c
tools/bdaddr.c [moved from test/bdaddr.c with 98% similarity]
tools/bluetooth-player.c [new file with mode: 0644]
tools/btattach.c [new file with mode: 0644]
tools/btinfo.c [new file with mode: 0644]
tools/btiotest.c [moved from test/btiotest.c with 68% similarity]
tools/btmgmt.c [moved from mgmt/main.c with 56% similarity]
tools/btsnoop.c [new file with mode: 0644]
tools/ciptool.c
tools/cltest.c [new file with mode: 0644]
tools/csr_usb.c
tools/dfu.c [deleted file]
tools/dfu.h [deleted file]
tools/dfubabel.1 [deleted file]
tools/dfubabel.c [deleted file]
tools/dfutool.1 [deleted file]
tools/dfutool.c [deleted file]
tools/gap-tester.c [new file with mode: 0644]
tools/hciattach.1 [moved from tools/hciattach.8 with 98% similarity]
tools/hciattach.c
tools/hciattach.h
tools/hciattach_intel.c
tools/hciattach_ti.c
tools/hciconfig.1 [moved from tools/hciconfig.8 with 96% similarity]
tools/hciconfig.c
tools/hcidump.1 [new file with mode: 0644]
tools/hcidump.c [new file with mode: 0644]
tools/hcitool.c
tools/hid2hci.1 [moved from tools/hid2hci.8 with 97% similarity]
tools/hid2hci.c
tools/hid2hci.rules [moved from scripts/bluetooth-hid2hci.rules with 97% similarity]
tools/hwdb.c [new file with mode: 0644]
tools/l2cap-tester.c [new file with mode: 0644]
tools/l2ping.1 [moved from tools/l2ping.8 with 96% similarity]
tools/l2test.c [moved from test/l2test.c with 93% similarity]
tools/lexer.c [deleted file]
tools/lexer.l [deleted file]
tools/magic.btsnoop [new file with mode: 0644]
tools/mgmt-tester.c [new file with mode: 0644]
tools/mpris-player.c [new file with mode: 0644]
tools/obex-client-tool.c [new file with mode: 0644]
tools/obex-server-tool.c [new file with mode: 0644]
tools/obexctl.c [new file with mode: 0644]
tools/parser.c [deleted file]
tools/parser.h [deleted file]
tools/parser.y [deleted file]
tools/parser/amp.c [new file with mode: 0644]
tools/parser/att.c [new file with mode: 0644]
tools/parser/avctp.c [moved from serial/main.c with 50% similarity]
tools/parser/avdtp.c [new file with mode: 0644]
tools/parser/avrcp.c [new file with mode: 0644]
tools/parser/bnep.c [new file with mode: 0644]
tools/parser/bpa.c [moved from tools/kword.c with 58% similarity]
tools/parser/capi.c [new file with mode: 0644]
tools/parser/cmtp.c [new file with mode: 0644]
tools/parser/csr.c [new file with mode: 0644]
tools/parser/ericsson.c [moved from deviceinfo/main.c with 62% similarity]
tools/parser/hci.c [new file with mode: 0644]
tools/parser/hcrp.c [new file with mode: 0644]
tools/parser/hidp.c [new file with mode: 0644]
tools/parser/l2cap.c [new file with mode: 0644]
tools/parser/l2cap.h [new file with mode: 0644]
tools/parser/lmp.c [new file with mode: 0644]
tools/parser/obex.c [new file with mode: 0644]
tools/parser/parser.c [new file with mode: 0644]
tools/parser/parser.h [new file with mode: 0644]
tools/parser/ppp.c [new file with mode: 0644]
tools/parser/rfcomm.c [new file with mode: 0644]
tools/parser/rfcomm.h [new file with mode: 0644]
tools/parser/sap.c [new file with mode: 0644]
tools/parser/sdp.c [new file with mode: 0644]
tools/parser/sdp.h [new file with mode: 0644]
tools/parser/smp.c [new file with mode: 0644]
tools/parser/tcpip.c [new file with mode: 0644]
tools/ppporc.c [deleted file]
tools/rctest.1 [moved from test/rctest.1 with 100% similarity]
tools/rctest.c [moved from test/rctest.c with 89% similarity]
tools/rfcomm.1
tools/rfcomm.c
tools/rfcomm.conf [deleted file]
tools/sco-tester.c [new file with mode: 0644]
tools/scotest.c [moved from test/scotest.c with 77% similarity]
tools/sdptool.1
tools/sdptool.c
unit/test-crc.c [new file with mode: 0644]
unit/test-eir.c
unit/test-gdbus-client.c [new file with mode: 0644]
unit/test-gobex-apparam.c [new file with mode: 0644]
unit/test-gobex-header.c [new file with mode: 0644]
unit/test-gobex-packet.c [new file with mode: 0644]
unit/test-gobex-transfer.c [new file with mode: 0644]
unit/test-gobex.c [new file with mode: 0644]
unit/test-lib.c [new file with mode: 0644]
unit/test-mgmt.c [new file with mode: 0644]
unit/test-sdp.c [new file with mode: 0644]
unit/test-textfile.c [new file with mode: 0644]
unit/test-uuid.c [new file with mode: 0644]
unit/util.c [new file with mode: 0644]
unit/util.h [new file with mode: 0644]
ylwrap [deleted file]

diff --git a/AUTHORS b/AUTHORS
index 2eaa329..4cb3d63 100644 (file)
--- a/AUTHORS
+++ b/AUTHORS
@@ -59,3 +59,24 @@ 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>
+Paulo Alcantara <pcacjr@gmail.com>
+Jefferson Delfes <jefferson.delfes@openbossa.org>
+Andrzej Kaczmarek <andrzej.kaczmarek@tieto.com>
+Eder Ruiz Maria <eder.ruiz@openbossa.org>
+Mikel Astiz <mikel.astiz@bmw-carit.de>
+Chan-yeol Park <chanyeol.park@samsung.com>
+João Paulo Rechi Vita <jprvita@gmail.com>
+Larry Junior <larry.junior@openbossa.org>
+Raymond Liu <raymond.liu@intel.com>
+Radoslaw Jablonski <ext-jablonski.radoslaw@nokia.com>
+Rafal Michalski <michalski.raf@gmail.com>
+Dmitriy Paliy <dmitriy.paliy@nokia.com>
+Bartosz Szatkowski <bulislaw@linux.com>
+Lukasz Pawlik <lucas.pawlik@gmail.com>
+Slawomir Bochenski <lkslawek@gmail.com>
+Wayne Lee <waynelee@qualcomm.com>
+Ricky Yuen <ryuen@qualcomm.com>
+Takashi Sasai <sasai@sm.sony.co.jp>
+Andre Dieb Martins <andre.dieb@signove.com>
+Cristian Rodríguez <crrodriguez@opensuse.org>
+Alex Deymo <deymo@chromium.org>
index 0ea7db6..fc9b3d7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,121 @@
+ver 5.10:
+       Fix issue with discoverable timeout handling.
+       Fix issue with MAP messages and record version.
+       Fix issue with MAP messages and status events.
+       Fix issue with MAP messages and relative folders.
+       Fix issue with MAP messages and type property signals.
+       Fix issue with transfer size for OBEX GET operations.
+       Fix issue with AVRCP service class identifier.
+       Fix issue with AVRCP tracking seeked signal.
+       Add support for OBEX command line client.
+
+ver 5.9:
+       Fix issue with network service and adapter removal.
+       Fix issue with misleading OBEX error messages.
+       Fix issue with OBEX transport reference handling.
+       Fix issue with memory leak with MAP event handler.
+       Fix issue with missing MAP property changed signal.
+       Fix issue with message type property values.
+       Fix issue with empty UUID list for devices.
+       Fix issue with profile agent cancel method.
+       Remove dependency on USB library.
+
+ver 5.8:
+       Fix issue with missing OBEX session properties.
+       Fix issue with missing SDP service refresh.
+       Fix issue with SDP attribute range check.
+       Fix issue with priority for SDP transactions.
+       Fix issue with service discovery after pairing.
+       Fix issue with race condition in service list.
+       Fix issue with input service state transition.
+       Fix issue with default authorization for profiles.
+       Fix issue with AVRCP browsing channel connections.
+       Add support for AVRCP role agnostic sessions.
+
+ver 5.7:
+       Fix issue with missing UUID discovery during pairing.
+       Fix issue with broken patch for SDP range check handling.
+       Fix issue with AVRCP usage of UID=0 for paused/stopped.
+       Add support MAP notification dispatching.
+
+ver 5.6:
+       Fix issue with incoming connections without SDP record.
+       Fix issue with canceling ongoing device connections.
+       Fix issue with handling failed connection attempts.
+       Fix issue with pending resume during A2DP open failures.
+       Fix issue with registering AVRCP unsupported notification.
+       Fix issue with listing available AVRCP target settings.
+       Fix issue with missing error for OBEX SetPath commands.
+       Fix issue with missing OBEX session command queue.
+       Fix issue with retrieving multiple MAP event reports.
+       Add support for command line player utility.
+
+ver 5.5:
+       Fix issue with race condition between SDP and properties.
+       Fix issue with handling storage of private device addresses.
+       Fix issue with NFC out-of-band pairing and power states.
+       Fix issue with short name during device update handling.
+       Fix issue with handling AVRCP without A2DP being present.
+       Add support for handling AVRCP pass-through operations.
+       Add support for automatically reconnecting HID devices.
+       Add support for automatically pairing of devices.
+
+ver 5.4:
+       Fix issue with invalid memory access and SDP service search.
+       Add support for available player changed event for controller.
+       Add support for UIDs changed event for AVRCP controller.
+       Add support for mandatory AVRCP pass-through operations.
+       Add support for Message Notification Service (MNS) server.
+       Add support for agent methods within command line client.
+
+ver 5.3:
+       Fix issue with registering invalid profiles.
+       Fix issue with inconsistent A2DP transport state.
+       Fix issue with A2DP resume while in configured state.
+       Fix issue with buffer overflow when processing SDP response.
+       Fix issue with missing range check for SDP attribute response.
+       Fix issue with missing validation of SDP data elements.
+       Fix issue with missing fallback to static hostname.
+       Fix issue with default adapter assignment.
+
+ver 5.2:
+       Fix issue with connection handling for Low Energy.
+       Fix issue with broken device discovery handling.
+       Fix issue with invalid memory access within A2DP.
+       Fix issue with handling empty path name of SetPath.
+       Fix issue with handling Message Access Profile filters.
+       Fix issue with handling network service unregistration.
+       Fix issue with not handling bogus device pairing results.
+       Fix issue with initial service discovery and profile manager.
+       Add support for AVRCP volume notifications.
+       Add support for AVRCP browsing commands.
+
+ver 5.1:
+       Fix issue with crash when removing OBEX session.
+       Fix issue with HID device disconnected from kernel.
+       Fix issue with buffer overflow when parsing HID SDP record.
+       Fix issue with SDP_TEXT_STR16 and SDP_URL_STR16 parsing.
+       Add support for integration with systemd's hostname daemon.
+       Add support for separate adapter alias property.
+       Add support for adapter and device modalias properties.
+       Add support for official BlueZ device information.
+       Add support for asynchronous management interface handling.
+       Add tool for testing management interface compliance.
+       Add tool for testing SDP qualification requirements.
+       Add tool for testing various EIR and AD data records.
+
+ver 5.0:
+       Introduce D-Bus Properties and ObjectManager interfaces.
+       Add support for generic profile interface.
+       Add support for global agent interface.
+       Add support for integrated OBEX daemon.
+       Add support for integrated hcidump utility.
+       Add support for Bluetooth tracing and monitor utility.
+       Add support for Bluetooth command line client utility.
+       Remove support for Handsfree gateway handling.
+       Remove support for GStreamer A2DP and SBC elements.
+       Disable default installation of Bluetooth library.
+
 ver 4.101:
        Fix issue with missing BlueZ service file.
        Fix issue with aborting A2DP setup during AVDTP start.
index 1c214c6..8aed6f7 100644 (file)
@@ -9,8 +9,6 @@ noinst_LTLIBRARIES =
 
 bin_PROGRAMS =
 
-sbin_PROGRAMS =
-
 noinst_PROGRAMS =
 
 dist_man_MANS =
@@ -21,6 +19,10 @@ CLEANFILES =
 
 EXTRA_DIST =
 
+libexecdir = @libexecdir@/bluetooth
+
+libexec_PROGRAMS =
+
 includedir = @includedir@/bluetooth
 
 include_HEADERS =
@@ -29,27 +31,26 @@ AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS)
 AM_LDFLAGS = $(MISC_LDFLAGS)
 
 if DATAFILES
-dbusdir = $(sysconfdir)/dbus-1/system.d
-dbusservicedir = $(datadir)/dbus-1/system-services
-
+dbusdir = @DBUS_CONFDIR@/dbus-1/system.d
 dbus_DATA = src/bluetooth.conf
-dbusservice_DATA = src/org.bluez.service
 
 confdir = $(sysconfdir)/bluetooth
-
 conf_DATA =
 
 statedir = $(localstatedir)/lib/bluetooth
-
 state_DATA =
+endif
 
 if SYSTEMD
-systemdunitdir = @SYSTEMD_UNITDIR@
+systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
+systemdsystemunit_DATA = src/bluetooth.service
 
-systemdunit_DATA = src/bluetooth.service
-endif
+dbussystembusdir = @DBUS_SYSTEMBUSDIR@
+dbussystembus_DATA = src/org.bluez.service
 endif
 
+EXTRA_DIST += src/bluetooth.service.in src/org.bluez.service
+
 plugindir = $(libdir)/bluetooth/plugins
 
 if MAINTAINER_MODE
@@ -61,216 +62,58 @@ endif
 
 plugin_LTLIBRARIES =
 
+lib_sources = lib/bluetooth.c lib/hci.c lib/sdp.c
+lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+               lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+               lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+
+extra_headers = lib/mgmt.h lib/uuid.h lib/a2mp.h lib/amp.h
+extra_sources = lib/uuid.c
 
-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/a2mp.h
 local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
 
 BUILT_SOURCES = $(local_headers) src/builtin.h
 
+if LIBRARY
 include_HEADERS += $(lib_headers)
 
 lib_LTLIBRARIES += lib/libbluetooth.la
 
-lib_libbluetooth_la_SOURCES = $(lib_headers) \
-                               lib/bluetooth.c lib/hci.c lib/sdp.c lib/uuid.c
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 16:0:13
+lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
+lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17
 lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+endif
 
-noinst_LTLIBRARIES += lib/libbluetooth-private.la
-
-lib_libbluetooth_private_la_SOURCES = $(lib_libbluetooth_la_SOURCES)
-
-if SBC
-noinst_LTLIBRARIES += sbc/libsbc.la
-
-sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
-                       sbc/sbc_primitives.h sbc/sbc_primitives.c \
-                       sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
-                       sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \
-                       sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
-                       sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
-
-sbc_libsbc_la_CFLAGS = $(AM_CFLAGS) -finline-functions -fgcse-after-reload \
-                                       -funswitch-loops -funroll-loops
-
-noinst_PROGRAMS += sbc/sbcinfo sbc/sbcdec sbc/sbcenc
+noinst_LTLIBRARIES += lib/libbluetooth-internal.la
 
-sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h
-sbc_sbcdec_LDADD = sbc/libsbc.la
+lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \
+                                       $(extra_headers) $(extra_sources)
 
-sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h
-sbc_sbcenc_LDADD = sbc/libsbc.la
+noinst_LTLIBRARIES += gdbus/libgdbus-internal.la
 
-if SNDFILE
-noinst_PROGRAMS += sbc/sbctester
-
-sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm
-sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@
-endif
-endif
+gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \
+                               gdbus/mainloop.c gdbus/watch.c \
+                               gdbus/object.c gdbus/client.c gdbus/polkit.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
-
-gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
-                                       gdbus/object.c gdbus/polkit.c
+               attrib/gattrib.h attrib/gattrib.c \
+               attrib/gatt-service.h attrib/gatt-service.c
 
 btio_sources = btio/btio.h btio/btio.c
 
+gobex_sources = gobex/gobex.h gobex/gobex.c \
+                       gobex/gobex-defs.h gobex/gobex-defs.c \
+                       gobex/gobex-packet.c gobex/gobex-packet.h \
+                       gobex/gobex-header.c gobex/gobex-header.h \
+                       gobex/gobex-transfer.c gobex/gobex-debug.h \
+                       gobex/gobex-apparam.c gobex/gobex-apparam.h
+
 builtin_modules =
 builtin_sources =
 builtin_nodist =
-mcap_sources =
-
-if MCAP
-mcap_sources += health/mcap_lib.h health/mcap_internal.h \
-               health/mcap.h health/mcap.c \
-               health/mcap_sync.c
-endif
-
-if PNATPLUGIN
-builtin_modules += pnat
-builtin_sources += plugins/pnat.c
-endif
-
-if AUDIOPLUGIN
-builtin_modules += audio
-builtin_sources += audio/main.c \
-                       audio/manager.h audio/manager.c \
-                       audio/gateway.h audio/gateway.c \
-                       audio/headset.h audio/headset.c \
-                       audio/control.h audio/control.c \
-                       audio/avctp.h audio/avctp.c \
-                       audio/avrcp.h audio/avrcp.c \
-                       audio/device.h audio/device.c \
-                       audio/source.h audio/source.c \
-                       audio/sink.h audio/sink.c \
-                       audio/a2dp.h audio/a2dp.c \
-                       audio/avdtp.h audio/avdtp.c \
-                       audio/ipc.h audio/ipc.c \
-                       audio/unix.h audio/unix.c \
-                       audio/media.h audio/media.c \
-                       audio/transport.h audio/transport.c \
-                       audio/telephony.h audio/a2dp-codecs.h
-builtin_nodist += audio/telephony.c
-
-noinst_LIBRARIES += audio/libtelephony.a
-
-audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
-                               audio/telephony-maemo5.c audio/telephony-ofono.c \
-                               audio/telephony-maemo6.c
-endif
-
-if SAPPLUGIN
-builtin_modules += sap
-builtin_sources += sap/main.c \
-                       sap/manager.h sap/manager.c \
-                       sap/server.h sap/server.c \
-                       sap/sap.h
-
-builtin_nodist += sap/sap.c
-
-noinst_LIBRARIES += sap/libsap.a
-
-sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c
-endif
-
-if INPUTPLUGIN
-builtin_modules += input
-builtin_sources += input/main.c \
-                       input/manager.h input/manager.c \
-                       input/server.h input/server.c \
-                       input/device.h input/device.c \
-                       input/fakehid.c input/fakehid.h
-endif
-
-if SERIALPLUGIN
-builtin_modules += serial
-builtin_sources += serial/main.c \
-                       serial/manager.h serial/manager.c \
-                       serial/proxy.h serial/proxy.c \
-                       serial/port.h serial/port.c
-endif
-
-if NETWORKPLUGIN
-builtin_modules += network
-builtin_sources += network/main.c \
-                       network/manager.h network/manager.c \
-                       network/common.h network/common.c \
-                       network/server.h network/server.c \
-                       network/connection.h network/connection.c
-endif
-
-if SERVICEPLUGIN
-builtin_modules += service
-builtin_sources += plugins/service.c
-endif
-
-if HEALTHPLUGIN
-builtin_modules += health
-builtin_sources += health/hdp_main.c health/hdp_types.h \
-                       health/hdp_manager.h health/hdp_manager.c \
-                       health/hdp.h health/hdp.c \
-                       health/hdp_util.h health/hdp_util.c
-endif
 
-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 \
-                       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
-
-if HAL
-builtin_modules += hal
-builtin_sources += plugins/hal.c
-else
-builtin_modules += formfactor
-builtin_sources += plugins/formfactor.c
-endif
-
-EXTRA_DIST += plugins/hal.c plugins/formfactor.c
-
-builtin_modules += storage
-builtin_sources += plugins/storage.c
-
-builtin_modules += adaptername
-builtin_sources += plugins/adaptername.c
-
-if WIIMOTEPLUGIN
-builtin_modules += wiimote
-builtin_sources += plugins/wiimote.c
-endif
-
-if MAEMO6PLUGIN
-builtin_modules += maemo6
-builtin_sources += plugins/maemo6.c
-endif
-
-if DBUSOOBPLUGIN
-builtin_modules += dbusoob
-builtin_sources += plugins/dbusoob.c
-endif
+include Makefile.plugins
 
 if MAINTAINER_MODE
 plugin_LTLIBRARIES += plugins/external-dummy.la
@@ -280,12 +123,13 @@ plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
 plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
 endif
 
-sbin_PROGRAMS += src/bluetoothd
+libexec_PROGRAMS += src/bluetoothd
 
-src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+src_bluetoothd_SOURCES = $(builtin_sources) \
                        $(attrib_sources) $(btio_sources) \
-                       $(mcap_sources) src/bluetooth.ver \
+                       src/bluetooth.ver \
                        src/main.c src/log.h src/log.c \
+                       src/systemd.h src/systemd.c \
                        src/rfkill.c src/hcid.h src/sdpd.h \
                        src/sdpd-server.c src/sdpd-request.c \
                        src/sdpd-service.c src/sdpd-database.c \
@@ -294,23 +138,26 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/sdp-client.h src/sdp-client.c \
                        src/textfile.h src/textfile.c \
                        src/glib-helper.h src/glib-helper.c \
-                       src/oui.h src/oui.c src/uinput.h src/ppoll.h \
+                       src/uinput.h \
                        src/plugin.h src/plugin.c \
                        src/storage.h src/storage.c \
                        src/agent.h src/agent.c \
                        src/error.h src/error.c \
-                       src/manager.h src/manager.c \
                        src/adapter.h src/adapter.c \
+                       src/profile.h src/profile.c \
+                       src/service.h src/service.c \
                        src/device.h src/device.c src/attio.h \
                        src/dbus-common.c src/dbus-common.h \
-                       src/event.h src/event.c \
-                       src/oob.h src/oob.c src/eir.h src/eir.c
-src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
-                                                               -ldl -lrt
+                       src/eir.h src/eir.c \
+                       src/shared/util.h src/shared/util.c \
+                       src/shared/mgmt.h src/shared/mgmt.c
+src_bluetoothd_LDADD = lib/libbluetooth-internal.la gdbus/libgdbus-internal.la \
+                       @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
                                -Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
-src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la
+src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
+                               gdbus/libgdbus-internal.la src/bluetooth.service
 
 src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
                                        -DPLUGINDIR=\""$(build_plugindir)"\"
@@ -320,171 +167,160 @@ builtin_files = src/builtin.h $(builtin_nodist)
 
 nodist_src_bluetoothd_SOURCES = $(builtin_files)
 
-CLEANFILES += $(builtin_files)
+CLEANFILES += $(builtin_files) src/bluetooth.service
 
 man_MANS = src/bluetoothd.8
 
-if DATAFILES
-conf_DATA += src/main.conf
-endif
+EXTRA_DIST += src/genbuiltin src/bluetooth.conf \
+                       src/main.conf profiles/network/network.conf \
+                       profiles/input/input.conf profiles/proximity/proximity.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 \
-                       audio/telephony-maemo5.c audio/telephony-ofono.c \
-                       audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
-                       proximity/proximity.conf
-
-if ALSA
-alsadir = $(libdir)/alsa-lib
-
-alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \
-                               audio/libasound_module_ctl_bluetooth.la
-
-audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \
-                                       audio/rtp.h audio/ipc.h audio/ipc.c
-audio_libasound_module_pcm_bluetooth_la_LDFLAGS = $(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 = $(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_CFLAGS) @ALSA_CFLAGS@
+test_scripts =
 
-if DATAFILES
-alsaconfdir = $(datadir)/alsa
+include Makefile.tools
+include Makefile.obexd
+include Makefile.android
 
-alsaconf_DATA = audio/bluetooth.conf
-endif
-endif
+if HID2HCI
+rulesdir = @UDEV_DIR@/rules.d
 
-if AUDIOPLUGIN
-if GSTREAMER
-gstreamerdir = $(libdir)/gstreamer-0.10
-
-gstreamer_LTLIBRARIES = audio/libgstbluetooth.la
-
-audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \
-                               audio/gstsbcenc.h audio/gstsbcenc.c \
-                               audio/gstsbcdec.h audio/gstsbcdec.c \
-                               audio/gstsbcparse.h audio/gstsbcparse.c \
-                               audio/gstavdtpsink.h audio/gstavdtpsink.c \
-                               audio/gsta2dpsink.h audio/gsta2dpsink.c \
-                               audio/gstsbcutil.h audio/gstsbcutil.c \
-                               audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
-                               audio/rtp.h audio/ipc.h audio/ipc.c
-audio_libgstbluetooth_la_LDFLAGS = $(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@
+rules_DATA = tools/97-hid2hci.rules
+
+CLEANFILES += $(rules_DATA)
 endif
+
+EXTRA_DIST += tools/hid2hci.rules
+
+if TEST
+testdir = $(pkglibdir)/test
+test_SCRIPTS = $(test_scripts)
 endif
 
-EXTRA_DIST += audio/bluetooth.conf
+EXTRA_DIST += $(test_scripts)
 
+EXTRA_DIST += doc/assigned-numbers.txt doc/supported-features.txt
 
-include Makefile.tools
+EXTRA_DIST += doc/mgmt-api.txt \
+               doc/adapter-api.txt doc/device-api.txt \
+               doc/agent-api.txt doc/profile-api.txt \
+               doc/network-api.txt doc/media-api.txt \
+               doc/health-api.txt doc/sap-api.txt
 
-if DATAFILES
-rulesdir = @UDEV_DIR@/rules.d
+EXTRA_DIST += doc/alert-api.txt \
+               doc/proximity-api.txt doc/heartrate-api.txt \
+               doc/thermometer-api.txt doc/cyclingspeed-api.txt
 
-udev_files =
+EXTRA_DIST += doc/obex-api.txt doc/obex-agent-api.txt
 
-if HID2HCI
-udev_files += scripts/bluetooth-hid2hci.rules
-endif
+EXTRA_DIST += tools/magic.btsnoop
 
-if PCMCIA
-udevdir = @UDEV_DIR@
+AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
 
-udev_files += scripts/bluetooth-serial.rules
+AM_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
+                       -I$(srcdir)/gdbus -I$(srcdir)/btio
 
-dist_udev_SCRIPTS = scripts/bluetooth_serial
-endif
 
-rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
-endif
+unit_tests = unit/test-eir unit/test-uuid unit/test-textfile unit/test-crc
 
-CLEANFILES += $(rules_DATA)
+unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c
+unit_test_eir_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-EXTRA_DIST += scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules
+unit_test_uuid_SOURCES = unit/test-uuid.c
+unit_test_uuid_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-EXTRA_DIST += doc/manager-api.txt \
-               doc/adapter-api.txt doc/device-api.txt \
-               doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
-               doc/serial-api.txt doc/network-api.txt \
-               doc/input-api.txt doc/audio-api.txt doc/control-api.txt \
-               doc/hfp-api.txt doc/health-api.txt doc/sap-api.txt \
-               doc/media-api.txt doc/assigned-numbers.txt
+unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c
+unit_test_textfile_LDADD = @GLIB_LIBS@
 
-AM_YFLAGS = -d
+unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c
+unit_test_crc_LDADD = @GLIB_LIBS@
 
-AM_CFLAGS += @DBUS_CFLAGS@ @GLIB_CFLAGS@
+unit_tests += unit/test-mgmt
 
-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$(srcdir)/monitor
+unit_test_mgmt_SOURCES = unit/test-mgmt.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c
+unit_test_mgmt_LDADD = @GLIB_LIBS@
 
-if MCAP
-INCLUDES += -I$(builddir)/health
-endif
+unit_tests += unit/test-sdp
 
-unit_objects =
+unit_test_sdp_SOURCES = unit/test-sdp.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/sdpd.h src/sdpd-database.c \
+                               src/sdpd-service.c src/sdpd-request.c
+unit_test_sdp_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-if TEST
-unit_tests = unit/test-eir
+unit_tests += unit/test-gdbus-client
 
-noinst_PROGRAMS += $(unit_tests)
+unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
+unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
+                               @GLIB_LIBS@ @DBUS_LIBS@
 
-unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c
-unit_test_eir_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @CHECK_LIBS@
-unit_test_eir_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@
-unit_objects += $(unit_test_eir_OBJECTS)
-else
-unit_tests =
-endif
+unit_tests += unit/test-gobex-header unit/test-gobex-packet unit/test-gobex \
+                       unit/test-gobex-transfer unit/test-gobex-apparam
+
+unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex.c
+unit_test_gobex_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-packet.c
+unit_test_gobex_packet_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-header.c
+unit_test_gobex_header_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-transfer.c
+unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-apparam.c
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+
+unit_tests += unit/test-lib
+
+unit_test_lib_SOURCES = unit/test-lib.c
+unit_test_lib_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+noinst_PROGRAMS += $(unit_tests)
 
 TESTS = $(unit_tests)
 
 pkgconfigdir = $(libdir)/pkgconfig
 
-pkgconfig_DATA = bluez.pc
+if LIBRARY
+pkgconfig_DATA = lib/bluez.pc
+endif
 
-DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles
+DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \
+                                       --disable-systemd --disable-udev \
+                                       --enable-android
 
 DISTCLEANFILES = $(pkgconfig_DATA)
 
 MAINTAINERCLEANFILES = Makefile.in \
        aclocal.m4 configure config.h.in config.sub config.guess \
-       ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap
+       ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver
 
-src/builtin.h: src/genbuiltin $(builtin_sources)
-       $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
+               $(SED) -e 's,@libexecdir\@,$(libexecdir),g' \
+               < $< > $@
 
-audio/telephony.c: audio/@TELEPHONY_DRIVER@
-       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
+%.service: %.service.in Makefile
+       $(SED_PROCESS)
 
-sap/sap.c: sap/@SAP_DRIVER@
-       $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+src/builtin.h: src/genbuiltin $(builtin_sources)
+       $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
 
-scripts/%.rules:
-       $(AM_V_GEN)cp $(subst 97-,,$@) $@
+tools/%.rules:
+       $(AM_V_GEN)cp $(srcdir)/$(subst 97-,,$@) $@
 
 $(lib_libbluetooth_la_OBJECTS): $(local_headers)
 
 lib/bluetooth/%.h: lib/%.h
        $(AM_V_at)$(MKDIR_P) lib/bluetooth
-       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
+       $(AM_V_GEN)$(LN_S) -f $(abs_top_builddir)/$< $@
 
 clean-local:
        $(RM) -r lib/bluetooth
diff --git a/Makefile.android b/Makefile.android
new file mode 100644 (file)
index 0000000..3ceefd8
--- /dev/null
@@ -0,0 +1,10 @@
+if ANDROID
+noinst_PROGRAMS += android/bluetoothd
+
+android_bluetoothd_SOURCES = android/main.c src/log.c
+android_bluetoothd_LDADD = @GLIB_LIBS@
+endif
+
+EXTRA_DIST += android/Android.mk android/log.c
+
+EXTRA_DIST += android/hal-ipc-api.txt
index 358af59..677ad3e 100644 (file)
@@ -1,4 +1,4 @@
-# Makefile.in generated by automake 1.11.3 from Makefile.am.
+# Makefile.in generated by automake 1.11.6 from Makefile.am.
 # @configure_input@
 
 # Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
 
 
 VPATH = @srcdir@
+am__make_dryrun = \
+  { \
+    am__dry=no; \
+    case $$MAKEFLAGS in \
+      *\\[\ \  ]*) \
+        echo 'am--echo: ; @echo "AM"  OK' | $(MAKE) -f - 2>/dev/null \
+          | grep '^AM OK$$' >/dev/null || am__dry=yes;; \
+      *) \
+        for am__flg in $$MAKEFLAGS; do \
+          case $$am__flg in \
+            *=*|--*) ;; \
+            *n*) am__dry=yes; break;; \
+          esac; \
+        done;; \
+    esac; \
+    test $$am__dry = yes; \
+  }
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
 pkglibdir = $(libdir)/@PACKAGE@
@@ -39,173 +56,104 @@ PRE_UNINSTALL = :
 POST_UNINSTALL = :
 build_triplet = @build@
 host_triplet = @host@
-bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3) \
-       $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
-       $(am__EXEEXT_7)
-sbin_PROGRAMS = src/bluetoothd$(EXEEXT) $(am__EXEEXT_14) \
-       $(am__EXEEXT_15) $(am__EXEEXT_16)
-noinst_PROGRAMS = $(am__EXEEXT_8) $(am__EXEEXT_9) $(am__EXEEXT_10) \
-       $(am__EXEEXT_11) $(am__EXEEXT_13)
-@SBC_TRUE@am__append_1 = sbc/libsbc.la
-@SBC_TRUE@am__append_2 = sbc/sbcinfo sbc/sbcdec sbc/sbcenc
-@SBC_TRUE@@SNDFILE_TRUE@am__append_3 = sbc/sbctester
-@MCAP_TRUE@am__append_4 = health/mcap_lib.h health/mcap_internal.h \
-@MCAP_TRUE@            health/mcap.h health/mcap.c \
-@MCAP_TRUE@            health/mcap_sync.c
-
-@PNATPLUGIN_TRUE@am__append_5 = pnat
-@PNATPLUGIN_TRUE@am__append_6 = plugins/pnat.c
-@AUDIOPLUGIN_TRUE@am__append_7 = audio
-@AUDIOPLUGIN_TRUE@am__append_8 = audio/main.c \
-@AUDIOPLUGIN_TRUE@                     audio/manager.h audio/manager.c \
-@AUDIOPLUGIN_TRUE@                     audio/gateway.h audio/gateway.c \
-@AUDIOPLUGIN_TRUE@                     audio/headset.h audio/headset.c \
-@AUDIOPLUGIN_TRUE@                     audio/control.h audio/control.c \
-@AUDIOPLUGIN_TRUE@                     audio/avctp.h audio/avctp.c \
-@AUDIOPLUGIN_TRUE@                     audio/avrcp.h audio/avrcp.c \
-@AUDIOPLUGIN_TRUE@                     audio/device.h audio/device.c \
-@AUDIOPLUGIN_TRUE@                     audio/source.h audio/source.c \
-@AUDIOPLUGIN_TRUE@                     audio/sink.h audio/sink.c \
-@AUDIOPLUGIN_TRUE@                     audio/a2dp.h audio/a2dp.c \
-@AUDIOPLUGIN_TRUE@                     audio/avdtp.h audio/avdtp.c \
-@AUDIOPLUGIN_TRUE@                     audio/ipc.h audio/ipc.c \
-@AUDIOPLUGIN_TRUE@                     audio/unix.h audio/unix.c \
-@AUDIOPLUGIN_TRUE@                     audio/media.h audio/media.c \
-@AUDIOPLUGIN_TRUE@                     audio/transport.h audio/transport.c \
-@AUDIOPLUGIN_TRUE@                     audio/telephony.h audio/a2dp-codecs.h
-
-@AUDIOPLUGIN_TRUE@am__append_9 = audio/telephony.c
-@AUDIOPLUGIN_TRUE@am__append_10 = audio/libtelephony.a
-@SAPPLUGIN_TRUE@am__append_11 = sap
-@SAPPLUGIN_TRUE@am__append_12 = sap/main.c \
-@SAPPLUGIN_TRUE@                       sap/manager.h sap/manager.c \
-@SAPPLUGIN_TRUE@                       sap/server.h sap/server.c \
-@SAPPLUGIN_TRUE@                       sap/sap.h
-
-@SAPPLUGIN_TRUE@am__append_13 = sap/sap.c
-@SAPPLUGIN_TRUE@am__append_14 = sap/libsap.a
-@INPUTPLUGIN_TRUE@am__append_15 = input
-@INPUTPLUGIN_TRUE@am__append_16 = input/main.c \
-@INPUTPLUGIN_TRUE@                     input/manager.h input/manager.c \
-@INPUTPLUGIN_TRUE@                     input/server.h input/server.c \
-@INPUTPLUGIN_TRUE@                     input/device.h input/device.c \
-@INPUTPLUGIN_TRUE@                     input/fakehid.c input/fakehid.h
-
-@SERIALPLUGIN_TRUE@am__append_17 = serial
-@SERIALPLUGIN_TRUE@am__append_18 = serial/main.c \
-@SERIALPLUGIN_TRUE@                    serial/manager.h serial/manager.c \
-@SERIALPLUGIN_TRUE@                    serial/proxy.h serial/proxy.c \
-@SERIALPLUGIN_TRUE@                    serial/port.h serial/port.c
-
-@NETWORKPLUGIN_TRUE@am__append_19 = network
-@NETWORKPLUGIN_TRUE@am__append_20 = network/main.c \
-@NETWORKPLUGIN_TRUE@                   network/manager.h network/manager.c \
-@NETWORKPLUGIN_TRUE@                   network/common.h network/common.c \
-@NETWORKPLUGIN_TRUE@                   network/server.h network/server.c \
-@NETWORKPLUGIN_TRUE@                   network/connection.h network/connection.c
-
-@SERVICEPLUGIN_TRUE@am__append_21 = service
-@SERVICEPLUGIN_TRUE@am__append_22 = plugins/service.c
-@HEALTHPLUGIN_TRUE@am__append_23 = health
-@HEALTHPLUGIN_TRUE@am__append_24 = health/hdp_main.c health/hdp_types.h \
-@HEALTHPLUGIN_TRUE@                    health/hdp_manager.h health/hdp_manager.c \
-@HEALTHPLUGIN_TRUE@                    health/hdp.h health/hdp.c \
-@HEALTHPLUGIN_TRUE@                    health/hdp_util.h health/hdp_util.c
-
-@GATTMODULES_TRUE@am__append_25 = thermometer alert time gatt_example proximity \
-@GATTMODULES_TRUE@                     deviceinfo
-
-@GATTMODULES_TRUE@am__append_26 = thermometer/main.c \
-@GATTMODULES_TRUE@                     thermometer/manager.h thermometer/manager.c \
-@GATTMODULES_TRUE@                     thermometer/thermometer.h thermometer/thermometer.c \
-@GATTMODULES_TRUE@                     alert/main.c alert/server.h alert/server.c \
-@GATTMODULES_TRUE@                     time/main.c time/server.h time/server.c \
-@GATTMODULES_TRUE@                     plugins/gatt-example.c \
-@GATTMODULES_TRUE@                     proximity/main.c proximity/manager.h proximity/manager.c \
-@GATTMODULES_TRUE@                     proximity/monitor.h proximity/monitor.c \
-@GATTMODULES_TRUE@                     proximity/reporter.h proximity/reporter.c \
-@GATTMODULES_TRUE@                     proximity/linkloss.h proximity/linkloss.c \
-@GATTMODULES_TRUE@                     proximity/immalert.h proximity/immalert.c \
-@GATTMODULES_TRUE@                     deviceinfo/main.c \
-@GATTMODULES_TRUE@                     deviceinfo/manager.h deviceinfo/manager.c \
-@GATTMODULES_TRUE@                     deviceinfo/deviceinfo.h deviceinfo/deviceinfo.c
-
-@HAL_TRUE@am__append_27 = hal
-@HAL_TRUE@am__append_28 = plugins/hal.c
-@HAL_FALSE@am__append_29 = formfactor
-@HAL_FALSE@am__append_30 = plugins/formfactor.c
-@WIIMOTEPLUGIN_TRUE@am__append_31 = wiimote
-@WIIMOTEPLUGIN_TRUE@am__append_32 = plugins/wiimote.c
-@MAEMO6PLUGIN_TRUE@am__append_33 = maemo6
-@MAEMO6PLUGIN_TRUE@am__append_34 = plugins/maemo6.c
-@DBUSOOBPLUGIN_TRUE@am__append_35 = dbusoob
-@DBUSOOBPLUGIN_TRUE@am__append_36 = plugins/dbusoob.c
-@MAINTAINER_MODE_TRUE@am__append_37 = plugins/external-dummy.la
-DIST_COMMON = README $(am__configure_deps) \
-       $(am__dist_udev_SCRIPTS_DIST) $(dist_man_MANS) \
-       $(include_HEADERS) $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
-       $(srcdir)/Makefile.tools $(srcdir)/bluez.pc.in \
-       $(srcdir)/config.h.in $(top_srcdir)/configure \
-       $(top_srcdir)/doc/version.xml.in \
-       $(top_srcdir)/src/bluetooth.service.in \
+bin_PROGRAMS = $(am__EXEEXT_1) $(am__EXEEXT_2) $(am__EXEEXT_3)
+noinst_PROGRAMS = $(am__EXEEXT_4) $(am__EXEEXT_5) $(am__EXEEXT_6) \
+       $(am__EXEEXT_7) $(am__EXEEXT_8)
+libexec_PROGRAMS = src/bluetoothd$(EXEEXT) obexd/src/obexd$(EXEEXT)
+@LIBRARY_TRUE@am__append_1 = $(lib_headers)
+@LIBRARY_TRUE@am__append_2 = lib/libbluetooth.la
+DIST_COMMON = README $(am__configure_deps) $(am__include_HEADERS_DIST) \
+       $(dist_man_MANS) $(srcdir)/Makefile.am \
+       $(srcdir)/Makefile.android $(srcdir)/Makefile.in \
+       $(srcdir)/Makefile.obexd $(srcdir)/Makefile.plugins \
+       $(srcdir)/Makefile.tools $(srcdir)/config.h.in \
+       $(top_srcdir)/configure $(top_srcdir)/lib/bluez.pc.in \
        $(top_srcdir)/src/bluetoothd.8.in AUTHORS COPYING COPYING.LIB \
        ChangeLog INSTALL NEWS TODO compile config.guess config.sub \
-       depcomp install-sh ltmain.sh missing tools/lexer.c \
-       tools/parser.c tools/parser.h ylwrap
-@DATAFILES_TRUE@@TOOLS_TRUE@am__append_38 = tools/rfcomm.conf
-@TOOLS_TRUE@am__append_39 = tools/rfcomm tools/l2ping \
-@TOOLS_TRUE@                           tools/hcitool tools/sdptool tools/ciptool
-
-@TOOLS_TRUE@am__append_40 = tools/hciattach tools/hciconfig
-@TOOLS_TRUE@am__append_41 = tools/avinfo tools/ppporc \
-@TOOLS_TRUE@   tools/hcieventmask tools/hcisecfilter mgmt/btmgmt \
-@TOOLS_TRUE@   monitor/btmon emulator/btvirt
-@READLINE_TRUE@@TOOLS_TRUE@am__append_42 = attrib/gatttool
-@TOOLS_TRUE@am__append_43 = tools/rfcomm.1 tools/l2ping.8 \
-@TOOLS_TRUE@                   tools/hciattach.8 tools/hciconfig.8 \
-@TOOLS_TRUE@                   tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
-
-@TOOLS_FALSE@am__append_44 = tools/rfcomm.1 tools/l2ping.8 \
-@TOOLS_FALSE@                  tools/hciattach.8 tools/hciconfig.8 \
-@TOOLS_FALSE@                  tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
-
-@BCCMD_TRUE@am__append_45 = tools/bccmd
-@BCCMD_TRUE@@USB_TRUE@am__append_46 = tools/csr_usb.c
-@BCCMD_TRUE@@USB_TRUE@am__append_47 = @USB_LIBS@
-@BCCMD_TRUE@am__append_48 = tools/bccmd.8
-@BCCMD_FALSE@am__append_49 = tools/bccmd.8
+       depcomp install-sh ltmain.sh missing
+@MAINTAINER_MODE_TRUE@am__append_3 = gatt_example
+@MAINTAINER_MODE_TRUE@am__append_4 = plugins/gatt-example.c
+@EXPERIMENTAL_TRUE@am__append_5 = neard sap
+@EXPERIMENTAL_TRUE@am__append_6 = plugins/neard.c profiles/sap/main.c \
+@EXPERIMENTAL_TRUE@    profiles/sap/manager.h \
+@EXPERIMENTAL_TRUE@    profiles/sap/manager.c \
+@EXPERIMENTAL_TRUE@    profiles/sap/server.h profiles/sap/server.c \
+@EXPERIMENTAL_TRUE@    profiles/sap/sap.h profiles/sap/sap-dummy.c
+@EXPERIMENTAL_TRUE@am__append_7 = profiles/sap/libsap.a
+@EXPERIMENTAL_TRUE@am__append_8 = health
+@EXPERIMENTAL_TRUE@am__append_9 = profiles/health/mcap_lib.h profiles/health/mcap_internal.h \
+@EXPERIMENTAL_TRUE@                    profiles/health/mcap.h profiles/health/mcap.c \
+@EXPERIMENTAL_TRUE@                    profiles/health/mcap_sync.c \
+@EXPERIMENTAL_TRUE@                    profiles/health/hdp_main.c profiles/health/hdp_types.h \
+@EXPERIMENTAL_TRUE@                    profiles/health/hdp_manager.h \
+@EXPERIMENTAL_TRUE@                    profiles/health/hdp_manager.c \
+@EXPERIMENTAL_TRUE@                    profiles/health/hdp.h profiles/health/hdp.c \
+@EXPERIMENTAL_TRUE@                    profiles/health/hdp_util.h profiles/health/hdp_util.c
+
+@EXPERIMENTAL_TRUE@am__append_10 = alert time proximity thermometer \
+@EXPERIMENTAL_TRUE@    heartrate cyclingspeed
+@EXPERIMENTAL_TRUE@am__append_11 = profiles/alert/server.c \
+@EXPERIMENTAL_TRUE@    profiles/time/server.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/main.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/manager.h \
+@EXPERIMENTAL_TRUE@    profiles/proximity/manager.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/monitor.h \
+@EXPERIMENTAL_TRUE@    profiles/proximity/monitor.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/reporter.h \
+@EXPERIMENTAL_TRUE@    profiles/proximity/reporter.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/linkloss.h \
+@EXPERIMENTAL_TRUE@    profiles/proximity/linkloss.c \
+@EXPERIMENTAL_TRUE@    profiles/proximity/immalert.h \
+@EXPERIMENTAL_TRUE@    profiles/proximity/immalert.c \
+@EXPERIMENTAL_TRUE@    profiles/thermometer/thermometer.c \
+@EXPERIMENTAL_TRUE@    profiles/heartrate/heartrate.c \
+@EXPERIMENTAL_TRUE@    profiles/cyclingspeed/cyclingspeed.c
+@MAINTAINER_MODE_TRUE@am__append_12 = plugins/external-dummy.la
+@CLIENT_TRUE@am__append_13 = client/bluetoothctl
+@MONITOR_TRUE@am__append_14 = monitor/btmon
+@EXPERIMENTAL_TRUE@am__append_15 = emulator/btvirt emulator/b1ee \
+@EXPERIMENTAL_TRUE@    tools/mgmt-tester tools/gap-tester \
+@EXPERIMENTAL_TRUE@    tools/l2cap-tester tools/sco-tester \
+@EXPERIMENTAL_TRUE@    tools/bdaddr tools/avinfo tools/avtest \
+@EXPERIMENTAL_TRUE@    tools/scotest tools/amptest tools/hwdb \
+@EXPERIMENTAL_TRUE@    tools/hcieventmask tools/hcisecfilter \
+@EXPERIMENTAL_TRUE@    tools/btmgmt tools/btinfo tools/btattach \
+@EXPERIMENTAL_TRUE@    tools/btsnoop tools/btiotest tools/cltest \
+@EXPERIMENTAL_TRUE@    tools/mpris-player
+@TOOLS_TRUE@am__append_16 = tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
+@TOOLS_TRUE@                   tools/rfcomm tools/rctest tools/l2test tools/l2ping \
+@TOOLS_TRUE@                   tools/sdptool tools/ciptool tools/bccmd
+
+@TOOLS_TRUE@am__append_17 = tools/hciattach.1 tools/hciconfig.1 \
+@TOOLS_TRUE@                   tools/hcitool.1 tools/hcidump.1 \
+@TOOLS_TRUE@                   tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+@TOOLS_TRUE@                   tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+
+@TOOLS_FALSE@am__append_18 = tools/hciattach.1 tools/hciconfig.1 \
+@TOOLS_FALSE@                  tools/hcitool.1 tools/hcidump.1 \
+@TOOLS_FALSE@                  tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+@TOOLS_FALSE@                  tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
+
 @HID2HCI_TRUE@udev_PROGRAMS = tools/hid2hci$(EXEEXT)
-@HID2HCI_TRUE@am__append_50 = tools/hid2hci.8
-@HID2HCI_FALSE@am__append_51 = tools/hid2hci.8
-@DFUTOOL_TRUE@am__append_52 = tools/dfutool
-@DFUTOOL_TRUE@am__append_53 = tools/dfutool.1
-@DFUTOOL_FALSE@am__append_54 = tools/dfutool.1
-@USB_TRUE@am__append_55 = tools/dfubabel tools/avctrl
-@CUPS_TRUE@cups_PROGRAMS = cups/bluetooth$(EXEEXT)
-@TEST_TRUE@am__append_56 = test/hciemu
-@TEST_TRUE@am__append_57 = test/l2test test/rctest
-@TEST_TRUE@am__append_58 = test/gaptest test/sdptest test/scotest \
-@TEST_TRUE@    test/attest test/hstest test/avtest test/ipctest \
-@TEST_TRUE@    test/lmptest test/bdaddr test/agent test/btiotest \
-@TEST_TRUE@    test/test-textfile test/uuidtest test/mpris-player \
-@TEST_TRUE@    $(unit_tests)
-@TEST_TRUE@am__append_59 = test/rctest.1 test/hciemu.1
-@TEST_TRUE@am__append_60 = test/bdaddr.8
-@TEST_FALSE@am__append_61 = test/rctest.1 test/hciemu.1 test/bdaddr.8
-@HIDD_TRUE@am__append_62 = compat/hidd
-@HIDD_TRUE@am__append_63 = compat/hidd.1
-@HIDD_FALSE@am__append_64 = compat/hidd.1
-@PAND_TRUE@am__append_65 = compat/pand
-@PAND_TRUE@am__append_66 = compat/pand.1
-@PAND_FALSE@am__append_67 = compat/pand.1
-@DUND_TRUE@am__append_68 = compat/dund
-@DUND_TRUE@am__append_69 = compat/dund.1
-@DUND_FALSE@am__append_70 = compat/dund.1
-@DATAFILES_TRUE@@HID2HCI_TRUE@am__append_71 = scripts/bluetooth-hid2hci.rules
-@DATAFILES_TRUE@@PCMCIA_TRUE@am__append_72 = scripts/bluetooth-serial.rules
-@MCAP_TRUE@am__append_73 = -I$(builddir)/health
-@TEST_TRUE@am__append_74 = $(unit_test_eir_OBJECTS)
-TESTS = $(am__EXEEXT_12)
+@HID2HCI_TRUE@am__append_19 = tools/hid2hci.1
+@HID2HCI_FALSE@am__append_20 = tools/hid2hci.1
+@EXPERIMENTAL_TRUE@am__append_21 = tools/bdaddr.1
+@READLINE_TRUE@am__append_22 = attrib/gatttool \
+@READLINE_TRUE@                        tools/obex-client-tool tools/obex-server-tool \
+@READLINE_TRUE@                        tools/bluetooth-player tools/obexctl
+
+@EXPERIMENTAL_TRUE@am__append_23 = profiles/iap/iapd
+@CUPS_TRUE@cups_PROGRAMS = profiles/cups/bluetooth$(EXEEXT)
+@EXPERIMENTAL_TRUE@am__append_24 = pcsuite
+@EXPERIMENTAL_TRUE@am__append_25 = obexd/plugins/pcsuite.c
+@OBEX_TRUE@am__append_26 = irmc pbap
+@OBEX_TRUE@am__append_27 = obexd/plugins/irmc.c obexd/plugins/pbap.c \
+@OBEX_TRUE@    obexd/plugins/vcard.h obexd/plugins/vcard.c \
+@OBEX_TRUE@    obexd/plugins/phonebook.h \
+@OBEX_TRUE@    obexd/plugins/phonebook-dummy.c
+@ANDROID_TRUE@am__append_28 = android/bluetoothd
+@HID2HCI_TRUE@am__append_29 = $(rules_DATA)
+TESTS = $(am__EXEEXT_8)
 subdir = .
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
 am__aclocal_m4_deps = $(top_srcdir)/acinclude.m4 \
@@ -216,8 +164,7 @@ am__CONFIG_DISTCLEAN_FILES = config.status config.cache config.log \
  configure.lineno config.status.lineno
 mkinstalldirs = $(install_sh) -d
 CONFIG_HEADER = config.h
-CONFIG_CLEAN_FILES = doc/version.xml src/bluetoothd.8 \
-       src/bluetooth.service bluez.pc
+CONFIG_CLEAN_FILES = src/bluetoothd.8 lib/bluez.pc
 CONFIG_CLEAN_VPATH_FILES =
 LIBRARIES = $(noinst_LIBRARIES)
 ARFLAGS = cru
@@ -227,25 +174,14 @@ am__v_AR_0 = @echo "  AR    " $@;
 AM_V_at = $(am__v_at_@AM_V@)
 am__v_at_ = $(am__v_at_@AM_DEFAULT_V@)
 am__v_at_0 = @
-audio_libtelephony_a_AR = $(AR) $(ARFLAGS)
-audio_libtelephony_a_LIBADD =
-am__audio_libtelephony_a_SOURCES_DIST = audio/telephony.h \
-       audio/telephony-dummy.c audio/telephony-maemo5.c \
-       audio/telephony-ofono.c audio/telephony-maemo6.c
+profiles_sap_libsap_a_AR = $(AR) $(ARFLAGS)
+profiles_sap_libsap_a_LIBADD =
+am__profiles_sap_libsap_a_SOURCES_DIST = profiles/sap/sap.h \
+       profiles/sap/sap-u8500.c
 am__dirstamp = $(am__leading_dot)dirstamp
-@AUDIOPLUGIN_TRUE@am_audio_libtelephony_a_OBJECTS =  \
-@AUDIOPLUGIN_TRUE@     audio/telephony-dummy.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/telephony-maemo5.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/telephony-ofono.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/telephony-maemo6.$(OBJEXT)
-audio_libtelephony_a_OBJECTS = $(am_audio_libtelephony_a_OBJECTS)
-sap_libsap_a_AR = $(AR) $(ARFLAGS)
-sap_libsap_a_LIBADD =
-am__sap_libsap_a_SOURCES_DIST = sap/sap.h sap/sap-dummy.c \
-       sap/sap-u8500.c
-@SAPPLUGIN_TRUE@am_sap_libsap_a_OBJECTS = sap/sap-dummy.$(OBJEXT) \
-@SAPPLUGIN_TRUE@       sap/sap-u8500.$(OBJEXT)
-sap_libsap_a_OBJECTS = $(am_sap_libsap_a_OBJECTS)
+@EXPERIMENTAL_TRUE@am_profiles_sap_libsap_a_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    profiles/sap/sap-u8500.$(OBJEXT)
+profiles_sap_libsap_a_OBJECTS = $(am_profiles_sap_libsap_a_OBJECTS)
 am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`;
 am__vpath_adj = case $$p in \
     $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \
@@ -273,93 +209,47 @@ am__uninstall_files_from_dir = { \
     || { echo " ( cd '$$dir' && rm -f" $$files ")"; \
          $(am__cd) "$$dir" && rm -f $$files; }; \
   }
-am__installdirs = "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" \
-       "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \
+am__installdirs = "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" \
        "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" \
-       "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(udevdir)" \
-       "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(man1dir)" \
-       "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(alsaconfdir)" \
-       "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" \
-       "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(pkgconfigdir)" \
+       "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(udevdir)" \
+       "$(DESTDIR)$(testdir)" "$(DESTDIR)$(man1dir)" \
+       "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" \
+       "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbussessionbusdir)" \
+       "$(DESTDIR)$(dbussystembusdir)" "$(DESTDIR)$(pkgconfigdir)" \
        "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" \
-       "$(DESTDIR)$(systemdunitdir)" "$(DESTDIR)$(includedir)"
-LTLIBRARIES = $(alsa_LTLIBRARIES) $(gstreamer_LTLIBRARIES) \
-       $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) $(plugin_LTLIBRARIES)
-@ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES =  \
-@ALSA_TRUE@    lib/libbluetooth-private.la
-am__audio_libasound_module_ctl_bluetooth_la_SOURCES_DIST =  \
-       audio/ctl_bluetooth.c audio/rtp.h audio/ipc.h audio/ipc.c
-@ALSA_TRUE@am_audio_libasound_module_ctl_bluetooth_la_OBJECTS = audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo \
-@ALSA_TRUE@    audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo
-audio_libasound_module_ctl_bluetooth_la_OBJECTS =  \
-       $(am_audio_libasound_module_ctl_bluetooth_la_OBJECTS)
+       "$(DESTDIR)$(systemdsystemunitdir)" \
+       "$(DESTDIR)$(systemduserunitdir)" "$(DESTDIR)$(includedir)"
+LTLIBRARIES = $(lib_LTLIBRARIES) $(noinst_LTLIBRARIES) \
+       $(plugin_LTLIBRARIES)
+gdbus_libgdbus_internal_la_LIBADD =
+am_gdbus_libgdbus_internal_la_OBJECTS = gdbus/mainloop.lo \
+       gdbus/watch.lo gdbus/object.lo gdbus/client.lo gdbus/polkit.lo
+gdbus_libgdbus_internal_la_OBJECTS =  \
+       $(am_gdbus_libgdbus_internal_la_OBJECTS)
 AM_V_lt = $(am__v_lt_@AM_V@)
 am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@)
 am__v_lt_0 = --silent
-audio_libasound_module_ctl_bluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) \
-       --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
-       $(CCLD) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) \
-       $(CFLAGS) $(audio_libasound_module_ctl_bluetooth_la_LDFLAGS) \
-       $(LDFLAGS) -o $@
-@ALSA_TRUE@am_audio_libasound_module_ctl_bluetooth_la_rpath = -rpath \
-@ALSA_TRUE@    $(alsadir)
-@ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES =  \
-@ALSA_TRUE@    sbc/libsbc.la lib/libbluetooth-private.la
-am__audio_libasound_module_pcm_bluetooth_la_SOURCES_DIST =  \
-       audio/pcm_bluetooth.c audio/rtp.h audio/ipc.h audio/ipc.c
-@ALSA_TRUE@am_audio_libasound_module_pcm_bluetooth_la_OBJECTS = audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo \
-@ALSA_TRUE@    audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo
-audio_libasound_module_pcm_bluetooth_la_OBJECTS =  \
-       $(am_audio_libasound_module_pcm_bluetooth_la_OBJECTS)
-audio_libasound_module_pcm_bluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) \
-       --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link \
-       $(CCLD) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) \
-       $(CFLAGS) $(audio_libasound_module_pcm_bluetooth_la_LDFLAGS) \
-       $(LDFLAGS) -o $@
-@ALSA_TRUE@am_audio_libasound_module_pcm_bluetooth_la_rpath = -rpath \
-@ALSA_TRUE@    $(alsadir)
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_DEPENDENCIES =  \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     sbc/libsbc.la \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     lib/libbluetooth-private.la
-am__audio_libgstbluetooth_la_SOURCES_DIST = audio/gstbluetooth.c \
-       audio/gstpragma.h audio/gstsbcenc.h audio/gstsbcenc.c \
-       audio/gstsbcdec.h audio/gstsbcdec.c audio/gstsbcparse.h \
-       audio/gstsbcparse.c audio/gstavdtpsink.h audio/gstavdtpsink.c \
-       audio/gsta2dpsink.h audio/gsta2dpsink.c audio/gstsbcutil.h \
-       audio/gstsbcutil.c audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
-       audio/rtp.h audio/ipc.h audio/ipc.c
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_audio_libgstbluetooth_la_OBJECTS = audio/audio_libgstbluetooth_la-gstbluetooth.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstsbcenc.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstsbcdec.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstsbcparse.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstavdtpsink.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gsta2dpsink.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstsbcutil.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     audio/audio_libgstbluetooth_la-ipc.lo
-audio_libgstbluetooth_la_OBJECTS =  \
-       $(am_audio_libgstbluetooth_la_OBJECTS)
-audio_libgstbluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
-       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
-       $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) \
-       $(audio_libgstbluetooth_la_LDFLAGS) $(LDFLAGS) -o $@
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@am_audio_libgstbluetooth_la_rpath =  \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@     -rpath $(gstreamerdir)
-lib_libbluetooth_private_la_LIBADD =
+lib_libbluetooth_internal_la_LIBADD =
 am__objects_1 =
-am__objects_2 = $(am__objects_1) lib/bluetooth.lo lib/hci.lo \
-       lib/sdp.lo lib/uuid.lo
-am_lib_libbluetooth_private_la_OBJECTS = $(am__objects_2)
-lib_libbluetooth_private_la_OBJECTS =  \
-       $(am_lib_libbluetooth_private_la_OBJECTS)
+am__objects_2 = lib/bluetooth.lo lib/hci.lo lib/sdp.lo
+am__objects_3 = lib/uuid.lo
+am_lib_libbluetooth_internal_la_OBJECTS = $(am__objects_1) \
+       $(am__objects_2) $(am__objects_1) $(am__objects_3)
+lib_libbluetooth_internal_la_OBJECTS =  \
+       $(am_lib_libbluetooth_internal_la_OBJECTS)
 lib_libbluetooth_la_LIBADD =
-am_lib_libbluetooth_la_OBJECTS = $(am__objects_1) lib/bluetooth.lo \
-       lib/hci.lo lib/sdp.lo lib/uuid.lo
+am__lib_libbluetooth_la_SOURCES_DIST = lib/bluetooth.h lib/hci.h \
+       lib/hci_lib.h lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+       lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h lib/bluetooth.c \
+       lib/hci.c lib/sdp.c
+@LIBRARY_TRUE@am_lib_libbluetooth_la_OBJECTS = $(am__objects_1) \
+@LIBRARY_TRUE@ $(am__objects_2)
 lib_libbluetooth_la_OBJECTS = $(am_lib_libbluetooth_la_OBJECTS)
 lib_libbluetooth_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
        $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
        $(AM_CFLAGS) $(CFLAGS) $(lib_libbluetooth_la_LDFLAGS) \
        $(LDFLAGS) -o $@
+@LIBRARY_TRUE@am_lib_libbluetooth_la_rpath = -rpath $(libdir)
 plugins_external_dummy_la_LIBADD =
 am__plugins_external_dummy_la_SOURCES_DIST = plugins/external-dummy.c
 @MAINTAINER_MODE_TRUE@am_plugins_external_dummy_la_OBJECTS = plugins/plugins_external_dummy_la-external-dummy.lo
@@ -371,293 +261,343 @@ plugins_external_dummy_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
        $(plugins_external_dummy_la_LDFLAGS) $(LDFLAGS) -o $@
 @MAINTAINER_MODE_TRUE@am_plugins_external_dummy_la_rpath = -rpath \
 @MAINTAINER_MODE_TRUE@ $(plugindir)
-sbc_libsbc_la_LIBADD =
-am__sbc_libsbc_la_SOURCES_DIST = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h \
-       sbc/sbc_tables.h sbc/sbc_primitives.h sbc/sbc_primitives.c \
-       sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
-       sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \
-       sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
-       sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
-@SBC_TRUE@am_sbc_libsbc_la_OBJECTS = sbc/sbc_libsbc_la-sbc.lo \
-@SBC_TRUE@     sbc/sbc_libsbc_la-sbc_primitives.lo \
-@SBC_TRUE@     sbc/sbc_libsbc_la-sbc_primitives_mmx.lo \
-@SBC_TRUE@     sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo \
-@SBC_TRUE@     sbc/sbc_libsbc_la-sbc_primitives_neon.lo \
-@SBC_TRUE@     sbc/sbc_libsbc_la-sbc_primitives_armv6.lo
-sbc_libsbc_la_OBJECTS = $(am_sbc_libsbc_la_OBJECTS)
-sbc_libsbc_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
-       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(sbc_libsbc_la_CFLAGS) \
-       $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-@SBC_TRUE@am_sbc_libsbc_la_rpath =
-@TOOLS_TRUE@am__EXEEXT_1 = tools/rfcomm$(EXEEXT) tools/l2ping$(EXEEXT) \
-@TOOLS_TRUE@   tools/hcitool$(EXEEXT) tools/sdptool$(EXEEXT) \
-@TOOLS_TRUE@   tools/ciptool$(EXEEXT)
-@READLINE_TRUE@@TOOLS_TRUE@am__EXEEXT_2 = attrib/gatttool$(EXEEXT)
-@DFUTOOL_TRUE@am__EXEEXT_3 = tools/dfutool$(EXEEXT)
-@TEST_TRUE@am__EXEEXT_4 = test/l2test$(EXEEXT) test/rctest$(EXEEXT)
-@HIDD_TRUE@am__EXEEXT_5 = compat/hidd$(EXEEXT)
-@PAND_TRUE@am__EXEEXT_6 = compat/pand$(EXEEXT)
-@DUND_TRUE@am__EXEEXT_7 = compat/dund$(EXEEXT)
-@SBC_TRUE@am__EXEEXT_8 = sbc/sbcinfo$(EXEEXT) sbc/sbcdec$(EXEEXT) \
-@SBC_TRUE@     sbc/sbcenc$(EXEEXT)
-@SBC_TRUE@@SNDFILE_TRUE@am__EXEEXT_9 = sbc/sbctester$(EXEEXT)
-@TOOLS_TRUE@am__EXEEXT_10 = tools/avinfo$(EXEEXT) \
-@TOOLS_TRUE@   tools/ppporc$(EXEEXT) tools/hcieventmask$(EXEEXT) \
-@TOOLS_TRUE@   tools/hcisecfilter$(EXEEXT) mgmt/btmgmt$(EXEEXT) \
-@TOOLS_TRUE@   monitor/btmon$(EXEEXT) emulator/btvirt$(EXEEXT)
-@USB_TRUE@am__EXEEXT_11 = tools/dfubabel$(EXEEXT) \
-@USB_TRUE@     tools/avctrl$(EXEEXT)
-@TEST_TRUE@am__EXEEXT_12 = unit/test-eir$(EXEEXT)
-@TEST_TRUE@am__EXEEXT_13 = test/gaptest$(EXEEXT) test/sdptest$(EXEEXT) \
-@TEST_TRUE@    test/scotest$(EXEEXT) test/attest$(EXEEXT) \
-@TEST_TRUE@    test/hstest$(EXEEXT) test/avtest$(EXEEXT) \
-@TEST_TRUE@    test/ipctest$(EXEEXT) test/lmptest$(EXEEXT) \
-@TEST_TRUE@    test/bdaddr$(EXEEXT) test/agent$(EXEEXT) \
-@TEST_TRUE@    test/btiotest$(EXEEXT) test/test-textfile$(EXEEXT) \
-@TEST_TRUE@    test/uuidtest$(EXEEXT) test/mpris-player$(EXEEXT) \
-@TEST_TRUE@    $(am__EXEEXT_12)
-@TOOLS_TRUE@am__EXEEXT_14 = tools/hciattach$(EXEEXT) \
-@TOOLS_TRUE@   tools/hciconfig$(EXEEXT)
-@BCCMD_TRUE@am__EXEEXT_15 = tools/bccmd$(EXEEXT)
-@TEST_TRUE@am__EXEEXT_16 = test/hciemu$(EXEEXT)
-PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(noinst_PROGRAMS) \
-       $(sbin_PROGRAMS) $(udev_PROGRAMS)
+@CLIENT_TRUE@am__EXEEXT_1 = client/bluetoothctl$(EXEEXT)
+@MONITOR_TRUE@am__EXEEXT_2 = monitor/btmon$(EXEEXT)
+@TOOLS_TRUE@am__EXEEXT_3 = tools/hciattach$(EXEEXT) \
+@TOOLS_TRUE@   tools/hciconfig$(EXEEXT) tools/hcitool$(EXEEXT) \
+@TOOLS_TRUE@   tools/hcidump$(EXEEXT) tools/rfcomm$(EXEEXT) \
+@TOOLS_TRUE@   tools/rctest$(EXEEXT) tools/l2test$(EXEEXT) \
+@TOOLS_TRUE@   tools/l2ping$(EXEEXT) tools/sdptool$(EXEEXT) \
+@TOOLS_TRUE@   tools/ciptool$(EXEEXT) tools/bccmd$(EXEEXT)
+@EXPERIMENTAL_TRUE@am__EXEEXT_4 = emulator/btvirt$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    emulator/b1ee$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/mgmt-tester$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/gap-tester$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/l2cap-tester$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/sco-tester$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/bdaddr$(EXEEXT) tools/avinfo$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/avtest$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/scotest$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/amptest$(EXEEXT) tools/hwdb$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/hcieventmask$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/hcisecfilter$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/btmgmt$(EXEEXT) tools/btinfo$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/btattach$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/btsnoop$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/btiotest$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/cltest$(EXEEXT) \
+@EXPERIMENTAL_TRUE@    tools/mpris-player$(EXEEXT)
+@READLINE_TRUE@am__EXEEXT_5 = attrib/gatttool$(EXEEXT) \
+@READLINE_TRUE@        tools/obex-client-tool$(EXEEXT) \
+@READLINE_TRUE@        tools/obex-server-tool$(EXEEXT) \
+@READLINE_TRUE@        tools/bluetooth-player$(EXEEXT) \
+@READLINE_TRUE@        tools/obexctl$(EXEEXT)
+@EXPERIMENTAL_TRUE@am__EXEEXT_6 = profiles/iap/iapd$(EXEEXT)
+@ANDROID_TRUE@am__EXEEXT_7 = android/bluetoothd$(EXEEXT)
+am__EXEEXT_8 = unit/test-eir$(EXEEXT) unit/test-uuid$(EXEEXT) \
+       unit/test-textfile$(EXEEXT) unit/test-crc$(EXEEXT) \
+       unit/test-mgmt$(EXEEXT) unit/test-sdp$(EXEEXT) \
+       unit/test-gdbus-client$(EXEEXT) \
+       unit/test-gobex-header$(EXEEXT) \
+       unit/test-gobex-packet$(EXEEXT) unit/test-gobex$(EXEEXT) \
+       unit/test-gobex-transfer$(EXEEXT) \
+       unit/test-gobex-apparam$(EXEEXT) unit/test-lib$(EXEEXT)
+PROGRAMS = $(bin_PROGRAMS) $(cups_PROGRAMS) $(libexec_PROGRAMS) \
+       $(noinst_PROGRAMS) $(udev_PROGRAMS)
+am__android_bluetoothd_SOURCES_DIST = android/main.c src/log.c
+@ANDROID_TRUE@am_android_bluetoothd_OBJECTS = android/main.$(OBJEXT) \
+@ANDROID_TRUE@ src/log.$(OBJEXT)
+android_bluetoothd_OBJECTS = $(am_android_bluetoothd_OBJECTS)
+android_bluetoothd_DEPENDENCIES =
 am__attrib_gatttool_SOURCES_DIST = attrib/gatttool.c attrib/att.c \
        attrib/gatt.c attrib/gattrib.c btio/btio.c attrib/gatttool.h \
-       attrib/interactive.c attrib/utils.c src/log.c
-@READLINE_TRUE@@TOOLS_TRUE@am_attrib_gatttool_OBJECTS =  \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/gatttool.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/att.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/gatt.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/gattrib.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    btio/btio.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/interactive.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    attrib/utils.$(OBJEXT) \
-@READLINE_TRUE@@TOOLS_TRUE@    src/log.$(OBJEXT)
+       attrib/interactive.c attrib/utils.c src/log.c client/display.c \
+       client/display.h
+@READLINE_TRUE@am_attrib_gatttool_OBJECTS = attrib/gatttool.$(OBJEXT) \
+@READLINE_TRUE@        attrib/att.$(OBJEXT) attrib/gatt.$(OBJEXT) \
+@READLINE_TRUE@        attrib/gattrib.$(OBJEXT) btio/btio.$(OBJEXT) \
+@READLINE_TRUE@        attrib/interactive.$(OBJEXT) \
+@READLINE_TRUE@        attrib/utils.$(OBJEXT) src/log.$(OBJEXT) \
+@READLINE_TRUE@        client/display.$(OBJEXT)
 attrib_gatttool_OBJECTS = $(am_attrib_gatttool_OBJECTS)
-@READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_DEPENDENCIES =  \
-@READLINE_TRUE@@TOOLS_TRUE@    lib/libbluetooth-private.la
-am__compat_dund_SOURCES_DIST = compat/dund.c compat/dund.h \
-       compat/lib.h compat/sdp.h compat/sdp.c compat/dun.c \
-       compat/msdun.c src/textfile.h src/textfile.c
-@DUND_TRUE@am_compat_dund_OBJECTS = compat/dund.$(OBJEXT) \
-@DUND_TRUE@    compat/sdp.$(OBJEXT) compat/dun.$(OBJEXT) \
-@DUND_TRUE@    compat/msdun.$(OBJEXT) src/textfile.$(OBJEXT)
-compat_dund_OBJECTS = $(am_compat_dund_OBJECTS)
-@DUND_TRUE@compat_dund_DEPENDENCIES = lib/libbluetooth-private.la
-am__compat_hidd_SOURCES_DIST = compat/hidd.c compat/hidd.h \
-       src/uinput.h compat/sdp.h compat/sdp.c compat/fakehid.c \
-       src/textfile.h src/textfile.c
-@HIDD_TRUE@am_compat_hidd_OBJECTS = compat/hidd.$(OBJEXT) \
-@HIDD_TRUE@    compat/sdp.$(OBJEXT) compat/fakehid.$(OBJEXT) \
-@HIDD_TRUE@    src/textfile.$(OBJEXT)
-compat_hidd_OBJECTS = $(am_compat_hidd_OBJECTS)
-@HIDD_TRUE@compat_hidd_DEPENDENCIES = lib/libbluetooth-private.la
-am__compat_pand_SOURCES_DIST = compat/pand.c compat/pand.h \
-       compat/bnep.c compat/sdp.h compat/sdp.c src/textfile.h \
-       src/textfile.c
-@PAND_TRUE@am_compat_pand_OBJECTS = compat/pand.$(OBJEXT) \
-@PAND_TRUE@    compat/bnep.$(OBJEXT) compat/sdp.$(OBJEXT) \
-@PAND_TRUE@    src/textfile.$(OBJEXT)
-compat_pand_OBJECTS = $(am_compat_pand_OBJECTS)
-@PAND_TRUE@compat_pand_DEPENDENCIES = lib/libbluetooth-private.la
-am__cups_bluetooth_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
-       gdbus/watch.c gdbus/object.c gdbus/polkit.c cups/main.c \
-       cups/cups.h cups/sdp.c cups/spp.c cups/hcrp.c
-am__objects_3 = gdbus/mainloop.$(OBJEXT) gdbus/watch.$(OBJEXT) \
-       gdbus/object.$(OBJEXT) gdbus/polkit.$(OBJEXT)
-@CUPS_TRUE@am_cups_bluetooth_OBJECTS = $(am__objects_3) \
-@CUPS_TRUE@    cups/main.$(OBJEXT) cups/sdp.$(OBJEXT) \
-@CUPS_TRUE@    cups/spp.$(OBJEXT) cups/hcrp.$(OBJEXT)
-cups_bluetooth_OBJECTS = $(am_cups_bluetooth_OBJECTS)
-@CUPS_TRUE@cups_bluetooth_DEPENDENCIES = lib/libbluetooth-private.la
+@READLINE_TRUE@attrib_gatttool_DEPENDENCIES =  \
+@READLINE_TRUE@        lib/libbluetooth-internal.la
+am__client_bluetoothctl_SOURCES_DIST = client/main.c client/display.h \
+       client/display.c client/agent.h client/agent.c monitor/uuid.h \
+       monitor/uuid.c
+@CLIENT_TRUE@am_client_bluetoothctl_OBJECTS = client/main.$(OBJEXT) \
+@CLIENT_TRUE@  client/display.$(OBJEXT) client/agent.$(OBJEXT) \
+@CLIENT_TRUE@  monitor/uuid.$(OBJEXT)
+client_bluetoothctl_OBJECTS = $(am_client_bluetoothctl_OBJECTS)
+@CLIENT_TRUE@client_bluetoothctl_DEPENDENCIES =  \
+@CLIENT_TRUE@  gdbus/libgdbus-internal.la
+am__emulator_b1ee_SOURCES_DIST = emulator/b1ee.c monitor/mainloop.h \
+       monitor/mainloop.c
+@EXPERIMENTAL_TRUE@am_emulator_b1ee_OBJECTS = emulator/b1ee.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    monitor/mainloop.$(OBJEXT)
+emulator_b1ee_OBJECTS = $(am_emulator_b1ee_OBJECTS)
+emulator_b1ee_LDADD = $(LDADD)
 am__emulator_btvirt_SOURCES_DIST = 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
-@TOOLS_TRUE@am_emulator_btvirt_OBJECTS = emulator/main.$(OBJEXT) \
-@TOOLS_TRUE@   monitor/mainloop.$(OBJEXT) \
-@TOOLS_TRUE@   emulator/server.$(OBJEXT) emulator/vhci.$(OBJEXT) \
-@TOOLS_TRUE@   emulator/btdev.$(OBJEXT)
+       emulator/btdev.h emulator/btdev.c emulator/bthost.h \
+       emulator/bthost.c emulator/amp.h emulator/amp.c
+@EXPERIMENTAL_TRUE@am_emulator_btvirt_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    emulator/main.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    monitor/mainloop.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/server.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/vhci.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/amp.$(OBJEXT)
 emulator_btvirt_OBJECTS = $(am_emulator_btvirt_OBJECTS)
 emulator_btvirt_LDADD = $(LDADD)
-am__mgmt_btmgmt_SOURCES_DIST = mgmt/main.c src/glib-helper.c
-@TOOLS_TRUE@am_mgmt_btmgmt_OBJECTS = mgmt/main.$(OBJEXT) \
-@TOOLS_TRUE@   src/glib-helper.$(OBJEXT)
-mgmt_btmgmt_OBJECTS = $(am_mgmt_btmgmt_OBJECTS)
-@TOOLS_TRUE@mgmt_btmgmt_DEPENDENCIES = lib/libbluetooth-private.la
 am__monitor_btmon_SOURCES_DIST = 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
-@TOOLS_TRUE@am_monitor_btmon_OBJECTS = monitor/main.$(OBJEXT) \
-@TOOLS_TRUE@   monitor/mainloop.$(OBJEXT) \
-@TOOLS_TRUE@   monitor/hcidump.$(OBJEXT) \
-@TOOLS_TRUE@   monitor/btsnoop.$(OBJEXT) \
-@TOOLS_TRUE@   monitor/control.$(OBJEXT) monitor/packet.$(OBJEXT)
+       monitor/mainloop.h monitor/mainloop.c monitor/display.h \
+       monitor/display.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/vendor.h monitor/vendor.c monitor/lmp.h monitor/lmp.c \
+       monitor/l2cap.h monitor/l2cap.c monitor/uuid.h monitor/uuid.c \
+       monitor/sdp.h monitor/sdp.c monitor/crc.h monitor/crc.c \
+       monitor/ll.h monitor/ll.c
+@MONITOR_TRUE@am_monitor_btmon_OBJECTS = monitor/main.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/mainloop.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/display.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/hcidump.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/btsnoop.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/control.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/packet.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/vendor.$(OBJEXT) monitor/lmp.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/l2cap.$(OBJEXT) monitor/uuid.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/sdp.$(OBJEXT) monitor/crc.$(OBJEXT) \
+@MONITOR_TRUE@ monitor/ll.$(OBJEXT)
 monitor_btmon_OBJECTS = $(am_monitor_btmon_OBJECTS)
-@TOOLS_TRUE@monitor_btmon_DEPENDENCIES = lib/libbluetooth-private.la
-am__sbc_sbcdec_SOURCES_DIST = sbc/sbcdec.c sbc/formats.h
-@SBC_TRUE@am_sbc_sbcdec_OBJECTS = sbc/sbcdec.$(OBJEXT)
-sbc_sbcdec_OBJECTS = $(am_sbc_sbcdec_OBJECTS)
-@SBC_TRUE@sbc_sbcdec_DEPENDENCIES = sbc/libsbc.la
-am__sbc_sbcenc_SOURCES_DIST = sbc/sbcenc.c sbc/formats.h
-@SBC_TRUE@am_sbc_sbcenc_OBJECTS = sbc/sbcenc.$(OBJEXT)
-sbc_sbcenc_OBJECTS = $(am_sbc_sbcenc_OBJECTS)
-@SBC_TRUE@sbc_sbcenc_DEPENDENCIES = sbc/libsbc.la
-sbc_sbcinfo_SOURCES = sbc/sbcinfo.c
-sbc_sbcinfo_OBJECTS = sbc/sbcinfo.$(OBJEXT)
-sbc_sbcinfo_LDADD = $(LDADD)
-sbc_sbctester_SOURCES = sbc/sbctester.c
-sbc_sbctester_OBJECTS = sbc/sbctester.$(OBJEXT)
-sbc_sbctester_DEPENDENCIES =
-am__src_bluetoothd_SOURCES_DIST = gdbus/gdbus.h gdbus/mainloop.c \
-       gdbus/watch.c gdbus/object.c gdbus/polkit.c plugins/pnat.c \
-       audio/main.c audio/manager.h audio/manager.c audio/gateway.h \
-       audio/gateway.c audio/headset.h audio/headset.c \
-       audio/control.h audio/control.c audio/avctp.h audio/avctp.c \
-       audio/avrcp.h audio/avrcp.c audio/device.h audio/device.c \
-       audio/source.h audio/source.c audio/sink.h audio/sink.c \
-       audio/a2dp.h audio/a2dp.c audio/avdtp.h audio/avdtp.c \
-       audio/ipc.h audio/ipc.c audio/unix.h audio/unix.c \
-       audio/media.h audio/media.c audio/transport.h \
-       audio/transport.c audio/telephony.h audio/a2dp-codecs.h \
-       sap/main.c sap/manager.h sap/manager.c sap/server.h \
-       sap/server.c sap/sap.h input/main.c input/manager.h \
-       input/manager.c input/server.h input/server.c input/device.h \
-       input/device.c input/fakehid.c input/fakehid.h serial/main.c \
-       serial/manager.h serial/manager.c serial/proxy.h \
-       serial/proxy.c serial/port.h serial/port.c network/main.c \
-       network/manager.h network/manager.c network/common.h \
-       network/common.c network/server.h network/server.c \
-       network/connection.h network/connection.c plugins/service.c \
-       health/hdp_main.c health/hdp_types.h health/hdp_manager.h \
-       health/hdp_manager.c health/hdp.h health/hdp.c \
-       health/hdp_util.h health/hdp_util.c thermometer/main.c \
-       thermometer/manager.h thermometer/manager.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 \
-       plugins/hciops.c plugins/mgmtops.c plugins/hal.c \
-       plugins/formfactor.c plugins/storage.c plugins/adaptername.c \
-       plugins/wiimote.c plugins/maemo6.c plugins/dbusoob.c \
-       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 \
+@MONITOR_TRUE@monitor_btmon_DEPENDENCIES =  \
+@MONITOR_TRUE@ lib/libbluetooth-internal.la
+am__obexd_src_obexd_SOURCES_DIST = btio/btio.h btio/btio.c \
+       gobex/gobex.h gobex/gobex.c gobex/gobex-defs.h \
+       gobex/gobex-defs.c gobex/gobex-packet.c gobex/gobex-packet.h \
+       gobex/gobex-header.c gobex/gobex-header.h \
+       gobex/gobex-transfer.c gobex/gobex-debug.h \
+       gobex/gobex-apparam.c gobex/gobex-apparam.h \
+       obexd/plugins/filesystem.c obexd/plugins/filesystem.h \
+       obexd/plugins/bluetooth.c obexd/plugins/pcsuite.c \
+       obexd/plugins/opp.c obexd/plugins/ftp.c obexd/plugins/ftp.h \
+       obexd/plugins/irmc.c obexd/plugins/pbap.c \
+       obexd/plugins/vcard.h obexd/plugins/vcard.c \
+       obexd/plugins/phonebook.h obexd/plugins/phonebook-dummy.c \
+       obexd/plugins/mas.c obexd/src/map_ap.h \
+       obexd/plugins/messages.h obexd/plugins/messages-dummy.c \
+       obexd/client/mns.c obexd/client/map-event.h obexd/src/main.c \
+       obexd/src/obexd.h obexd/src/plugin.h obexd/src/plugin.c \
+       obexd/src/log.h obexd/src/log.c obexd/src/manager.h \
+       obexd/src/manager.c obexd/src/obex.h obexd/src/obex.c \
+       obexd/src/obex-priv.h obexd/src/mimetype.h \
+       obexd/src/mimetype.c obexd/src/service.h obexd/src/service.c \
+       obexd/src/transport.h obexd/src/transport.c obexd/src/server.h \
+       obexd/src/server.c obexd/client/manager.h \
+       obexd/client/manager.c obexd/client/session.h \
+       obexd/client/session.c obexd/client/bluetooth.h \
+       obexd/client/bluetooth.c obexd/client/sync.h \
+       obexd/client/sync.c obexd/client/pbap.h obexd/client/pbap.c \
+       obexd/client/ftp.h obexd/client/ftp.c obexd/client/opp.h \
+       obexd/client/opp.c obexd/client/map.h obexd/client/map.c \
+       obexd/client/map-event.c obexd/client/transfer.h \
+       obexd/client/transfer.c obexd/client/transport.h \
+       obexd/client/transport.c obexd/client/dbus.h \
+       obexd/client/dbus.c obexd/client/driver.h \
+       obexd/client/driver.c
+am__objects_4 = btio/obexd-btio.$(OBJEXT)
+am__objects_5 = gobex/obexd-gobex.$(OBJEXT) \
+       gobex/obexd-gobex-defs.$(OBJEXT) \
+       gobex/obexd-gobex-packet.$(OBJEXT) \
+       gobex/obexd-gobex-header.$(OBJEXT) \
+       gobex/obexd-gobex-transfer.$(OBJEXT) \
+       gobex/obexd-gobex-apparam.$(OBJEXT)
+@EXPERIMENTAL_TRUE@am__objects_6 =  \
+@EXPERIMENTAL_TRUE@    obexd/plugins/obexd-pcsuite.$(OBJEXT)
+@OBEX_TRUE@am__objects_7 = obexd/plugins/obexd-irmc.$(OBJEXT) \
+@OBEX_TRUE@    obexd/plugins/obexd-pbap.$(OBJEXT) \
+@OBEX_TRUE@    obexd/plugins/obexd-vcard.$(OBJEXT) \
+@OBEX_TRUE@    obexd/plugins/obexd-phonebook-dummy.$(OBJEXT)
+am__objects_8 = obexd/plugins/obexd-filesystem.$(OBJEXT) \
+       obexd/plugins/obexd-bluetooth.$(OBJEXT) $(am__objects_6) \
+       obexd/plugins/obexd-opp.$(OBJEXT) \
+       obexd/plugins/obexd-ftp.$(OBJEXT) $(am__objects_7) \
+       obexd/plugins/obexd-mas.$(OBJEXT) \
+       obexd/plugins/obexd-messages-dummy.$(OBJEXT) \
+       obexd/client/obexd-mns.$(OBJEXT)
+am_obexd_src_obexd_OBJECTS = $(am__objects_4) $(am__objects_5) \
+       $(am__objects_8) obexd/src/obexd-main.$(OBJEXT) \
+       obexd/src/obexd-plugin.$(OBJEXT) obexd/src/obexd-log.$(OBJEXT) \
+       obexd/src/obexd-manager.$(OBJEXT) \
+       obexd/src/obexd-obex.$(OBJEXT) \
+       obexd/src/obexd-mimetype.$(OBJEXT) \
+       obexd/src/obexd-service.$(OBJEXT) \
+       obexd/src/obexd-transport.$(OBJEXT) \
+       obexd/src/obexd-server.$(OBJEXT) \
+       obexd/client/obexd-manager.$(OBJEXT) \
+       obexd/client/obexd-session.$(OBJEXT) \
+       obexd/client/obexd-bluetooth.$(OBJEXT) \
+       obexd/client/obexd-sync.$(OBJEXT) \
+       obexd/client/obexd-pbap.$(OBJEXT) \
+       obexd/client/obexd-ftp.$(OBJEXT) \
+       obexd/client/obexd-opp.$(OBJEXT) \
+       obexd/client/obexd-map.$(OBJEXT) \
+       obexd/client/obexd-map-event.$(OBJEXT) \
+       obexd/client/obexd-transfer.$(OBJEXT) \
+       obexd/client/obexd-transport.$(OBJEXT) \
+       obexd/client/obexd-dbus.$(OBJEXT) \
+       obexd/client/obexd-driver.$(OBJEXT)
+am__objects_9 = $(am__objects_1)
+nodist_obexd_src_obexd_OBJECTS = $(am__objects_9)
+obexd_src_obexd_OBJECTS = $(am_obexd_src_obexd_OBJECTS) \
+       $(nodist_obexd_src_obexd_OBJECTS)
+obexd_src_obexd_DEPENDENCIES = lib/libbluetooth-internal.la \
+       gdbus/libgdbus-internal.la
+obexd_src_obexd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
+       $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
+       $(obexd_src_obexd_CFLAGS) $(CFLAGS) $(obexd_src_obexd_LDFLAGS) \
+       $(LDFLAGS) -o $@
+am__profiles_cups_bluetooth_SOURCES_DIST = profiles/cups/main.c \
+       profiles/cups/cups.h profiles/cups/sdp.c profiles/cups/spp.c \
+       profiles/cups/hcrp.c
+@CUPS_TRUE@am_profiles_cups_bluetooth_OBJECTS =  \
+@CUPS_TRUE@    profiles/cups/main.$(OBJEXT) \
+@CUPS_TRUE@    profiles/cups/sdp.$(OBJEXT) \
+@CUPS_TRUE@    profiles/cups/spp.$(OBJEXT) \
+@CUPS_TRUE@    profiles/cups/hcrp.$(OBJEXT)
+profiles_cups_bluetooth_OBJECTS =  \
+       $(am_profiles_cups_bluetooth_OBJECTS)
+@CUPS_TRUE@profiles_cups_bluetooth_DEPENDENCIES =  \
+@CUPS_TRUE@    lib/libbluetooth-internal.la \
+@CUPS_TRUE@    gdbus/libgdbus-internal.la
+am__profiles_iap_iapd_SOURCES_DIST = profiles/iap/main.c
+@EXPERIMENTAL_TRUE@am_profiles_iap_iapd_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    profiles/iap/main.$(OBJEXT)
+profiles_iap_iapd_OBJECTS = $(am_profiles_iap_iapd_OBJECTS)
+@EXPERIMENTAL_TRUE@profiles_iap_iapd_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    gdbus/libgdbus-internal.la
+am__src_bluetoothd_SOURCES_DIST = plugins/hostname.c plugins/wiimote.c \
+       plugins/autopair.c plugins/policy.c plugins/gatt-example.c \
+       plugins/neard.c profiles/sap/main.c profiles/sap/manager.h \
+       profiles/sap/manager.c profiles/sap/server.h \
+       profiles/sap/server.c profiles/sap/sap.h \
+       profiles/sap/sap-dummy.c profiles/audio/source.h \
+       profiles/audio/source.c profiles/audio/sink.h \
+       profiles/audio/sink.c profiles/audio/a2dp.h \
+       profiles/audio/a2dp.c profiles/audio/avdtp.h \
+       profiles/audio/avdtp.c profiles/audio/media.h \
+       profiles/audio/media.c profiles/audio/transport.h \
+       profiles/audio/transport.c profiles/audio/a2dp-codecs.h \
+       profiles/audio/control.h profiles/audio/control.c \
+       profiles/audio/avctp.h profiles/audio/avctp.c \
+       profiles/audio/avrcp.h profiles/audio/avrcp.c \
+       profiles/audio/player.h profiles/audio/player.c \
+       profiles/network/manager.c profiles/network/common.h \
+       profiles/network/common.c profiles/network/server.h \
+       profiles/network/server.c profiles/network/connection.h \
+       profiles/network/connection.c profiles/input/manager.c \
+       profiles/input/server.h profiles/input/server.c \
+       profiles/input/device.h profiles/input/device.c \
+       profiles/input/hog.c profiles/input/uhid_copy.h \
+       profiles/input/suspend.h profiles/input/suspend-dummy.c \
+       profiles/health/mcap_lib.h profiles/health/mcap_internal.h \
+       profiles/health/mcap.h profiles/health/mcap.c \
+       profiles/health/mcap_sync.c profiles/health/hdp_main.c \
+       profiles/health/hdp_types.h profiles/health/hdp_manager.h \
+       profiles/health/hdp_manager.c profiles/health/hdp.h \
+       profiles/health/hdp.c profiles/health/hdp_util.h \
+       profiles/health/hdp_util.c profiles/gatt/gas.c \
+       profiles/scanparam/scan.c profiles/deviceinfo/deviceinfo.c \
+       profiles/alert/server.c profiles/time/server.c \
+       profiles/proximity/main.c profiles/proximity/manager.h \
+       profiles/proximity/manager.c profiles/proximity/monitor.h \
+       profiles/proximity/monitor.c profiles/proximity/reporter.h \
+       profiles/proximity/reporter.c profiles/proximity/linkloss.h \
+       profiles/proximity/linkloss.c profiles/proximity/immalert.h \
+       profiles/proximity/immalert.c \
+       profiles/thermometer/thermometer.c \
+       profiles/heartrate/heartrate.c \
+       profiles/cyclingspeed/cyclingspeed.c attrib/att.h \
+       attrib/att-database.h attrib/att.c attrib/gatt.h attrib/gatt.c \
+       attrib/gattrib.h attrib/gattrib.c attrib/gatt-service.h \
        attrib/gatt-service.c btio/btio.h btio/btio.c \
-       health/mcap_lib.h health/mcap_internal.h health/mcap.h \
-       health/mcap.c health/mcap_sync.c src/bluetooth.ver src/main.c \
-       src/log.h src/log.c src/rfkill.c src/hcid.h src/sdpd.h \
+       src/bluetooth.ver src/main.c src/log.h src/log.c src/systemd.h \
+       src/systemd.c src/rfkill.c src/hcid.h src/sdpd.h \
        src/sdpd-server.c src/sdpd-request.c src/sdpd-service.c \
        src/sdpd-database.c src/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-helper.h \
-       src/glib-helper.c src/oui.h src/oui.c src/uinput.h src/ppoll.h \
-       src/plugin.h src/plugin.c src/storage.h src/storage.c \
-       src/agent.h src/agent.c src/error.h src/error.c src/manager.h \
-       src/manager.c src/adapter.h src/adapter.c src/device.h \
-       src/device.c src/attio.h src/dbus-common.c src/dbus-common.h \
-       src/event.h src/event.c src/oob.h src/oob.c src/eir.h \
-       src/eir.c
-am__objects_4 = gdbus/bluetoothd-mainloop.$(OBJEXT) \
-       gdbus/bluetoothd-watch.$(OBJEXT) \
-       gdbus/bluetoothd-object.$(OBJEXT) \
-       gdbus/bluetoothd-polkit.$(OBJEXT)
-@PNATPLUGIN_TRUE@am__objects_5 = plugins/bluetoothd-pnat.$(OBJEXT)
-@AUDIOPLUGIN_TRUE@am__objects_6 = audio/bluetoothd-main.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-manager.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-gateway.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-headset.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-control.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-avctp.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-avrcp.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-device.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-source.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-sink.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-a2dp.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-avdtp.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-ipc.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-unix.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-media.$(OBJEXT) \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-transport.$(OBJEXT)
-@SAPPLUGIN_TRUE@am__objects_7 = sap/bluetoothd-main.$(OBJEXT) \
-@SAPPLUGIN_TRUE@       sap/bluetoothd-manager.$(OBJEXT) \
-@SAPPLUGIN_TRUE@       sap/bluetoothd-server.$(OBJEXT)
-@INPUTPLUGIN_TRUE@am__objects_8 = input/bluetoothd-main.$(OBJEXT) \
-@INPUTPLUGIN_TRUE@     input/bluetoothd-manager.$(OBJEXT) \
-@INPUTPLUGIN_TRUE@     input/bluetoothd-server.$(OBJEXT) \
-@INPUTPLUGIN_TRUE@     input/bluetoothd-device.$(OBJEXT) \
-@INPUTPLUGIN_TRUE@     input/bluetoothd-fakehid.$(OBJEXT)
-@SERIALPLUGIN_TRUE@am__objects_9 = serial/bluetoothd-main.$(OBJEXT) \
-@SERIALPLUGIN_TRUE@    serial/bluetoothd-manager.$(OBJEXT) \
-@SERIALPLUGIN_TRUE@    serial/bluetoothd-proxy.$(OBJEXT) \
-@SERIALPLUGIN_TRUE@    serial/bluetoothd-port.$(OBJEXT)
-@NETWORKPLUGIN_TRUE@am__objects_10 =  \
-@NETWORKPLUGIN_TRUE@   network/bluetoothd-main.$(OBJEXT) \
-@NETWORKPLUGIN_TRUE@   network/bluetoothd-manager.$(OBJEXT) \
-@NETWORKPLUGIN_TRUE@   network/bluetoothd-common.$(OBJEXT) \
-@NETWORKPLUGIN_TRUE@   network/bluetoothd-server.$(OBJEXT) \
-@NETWORKPLUGIN_TRUE@   network/bluetoothd-connection.$(OBJEXT)
-@SERVICEPLUGIN_TRUE@am__objects_11 =  \
-@SERVICEPLUGIN_TRUE@   plugins/bluetoothd-service.$(OBJEXT)
-@HEALTHPLUGIN_TRUE@am__objects_12 =  \
-@HEALTHPLUGIN_TRUE@    health/bluetoothd-hdp_main.$(OBJEXT) \
-@HEALTHPLUGIN_TRUE@    health/bluetoothd-hdp_manager.$(OBJEXT) \
-@HEALTHPLUGIN_TRUE@    health/bluetoothd-hdp.$(OBJEXT) \
-@HEALTHPLUGIN_TRUE@    health/bluetoothd-hdp_util.$(OBJEXT)
-@GATTMODULES_TRUE@am__objects_13 =  \
-@GATTMODULES_TRUE@     thermometer/bluetoothd-main.$(OBJEXT) \
-@GATTMODULES_TRUE@     thermometer/bluetoothd-manager.$(OBJEXT) \
-@GATTMODULES_TRUE@     thermometer/bluetoothd-thermometer.$(OBJEXT) \
-@GATTMODULES_TRUE@     alert/bluetoothd-main.$(OBJEXT) \
-@GATTMODULES_TRUE@     alert/bluetoothd-server.$(OBJEXT) \
-@GATTMODULES_TRUE@     time/bluetoothd-main.$(OBJEXT) \
-@GATTMODULES_TRUE@     time/bluetoothd-server.$(OBJEXT) \
-@GATTMODULES_TRUE@     plugins/bluetoothd-gatt-example.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-main.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-manager.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-monitor.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-reporter.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-linkloss.$(OBJEXT) \
-@GATTMODULES_TRUE@     proximity/bluetoothd-immalert.$(OBJEXT) \
-@GATTMODULES_TRUE@     deviceinfo/bluetoothd-main.$(OBJEXT) \
-@GATTMODULES_TRUE@     deviceinfo/bluetoothd-manager.$(OBJEXT) \
-@GATTMODULES_TRUE@     deviceinfo/bluetoothd-deviceinfo.$(OBJEXT)
-@HAL_TRUE@am__objects_14 = plugins/bluetoothd-hal.$(OBJEXT)
-@HAL_FALSE@am__objects_15 = plugins/bluetoothd-formfactor.$(OBJEXT)
-@WIIMOTEPLUGIN_TRUE@am__objects_16 =  \
-@WIIMOTEPLUGIN_TRUE@   plugins/bluetoothd-wiimote.$(OBJEXT)
-@MAEMO6PLUGIN_TRUE@am__objects_17 =  \
-@MAEMO6PLUGIN_TRUE@    plugins/bluetoothd-maemo6.$(OBJEXT)
-@DBUSOOBPLUGIN_TRUE@am__objects_18 =  \
-@DBUSOOBPLUGIN_TRUE@   plugins/bluetoothd-dbusoob.$(OBJEXT)
-am__objects_19 = $(am__objects_5) $(am__objects_6) $(am__objects_7) \
-       $(am__objects_8) $(am__objects_9) $(am__objects_10) \
-       $(am__objects_11) $(am__objects_12) $(am__objects_13) \
-       plugins/bluetoothd-hciops.$(OBJEXT) \
-       plugins/bluetoothd-mgmtops.$(OBJEXT) $(am__objects_14) \
-       $(am__objects_15) plugins/bluetoothd-storage.$(OBJEXT) \
-       plugins/bluetoothd-adaptername.$(OBJEXT) $(am__objects_16) \
-       $(am__objects_17) $(am__objects_18)
-am__objects_20 = attrib/bluetoothd-att.$(OBJEXT) \
+       src/glib-helper.c src/uinput.h src/plugin.h src/plugin.c \
+       src/storage.h src/storage.c src/agent.h src/agent.c \
+       src/error.h src/error.c src/adapter.h src/adapter.c \
+       src/profile.h src/profile.c src/service.h src/service.c \
+       src/device.h src/device.c src/attio.h src/dbus-common.c \
+       src/dbus-common.h src/eir.h src/eir.c src/shared/util.h \
+       src/shared/util.c src/shared/mgmt.h src/shared/mgmt.c
+@MAINTAINER_MODE_TRUE@am__objects_10 = plugins/bluetoothd-gatt-example.$(OBJEXT)
+@EXPERIMENTAL_TRUE@am__objects_11 =  \
+@EXPERIMENTAL_TRUE@    plugins/bluetoothd-neard.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/sap/bluetoothd-main.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/sap/bluetoothd-manager.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/sap/bluetoothd-server.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/sap/bluetoothd-sap-dummy.$(OBJEXT)
+@EXPERIMENTAL_TRUE@am__objects_12 =  \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-mcap.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-mcap_sync.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-hdp_main.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-hdp_manager.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-hdp.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/health/bluetoothd-hdp_util.$(OBJEXT)
+@EXPERIMENTAL_TRUE@am__objects_13 =  \
+@EXPERIMENTAL_TRUE@    profiles/alert/bluetoothd-server.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/time/bluetoothd-server.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-main.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-manager.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-monitor.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-reporter.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-linkloss.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/proximity/bluetoothd-immalert.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/thermometer/bluetoothd-thermometer.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/heartrate/bluetoothd-heartrate.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    profiles/cyclingspeed/bluetoothd-cyclingspeed.$(OBJEXT)
+am__objects_14 = plugins/bluetoothd-hostname.$(OBJEXT) \
+       plugins/bluetoothd-wiimote.$(OBJEXT) \
+       plugins/bluetoothd-autopair.$(OBJEXT) \
+       plugins/bluetoothd-policy.$(OBJEXT) $(am__objects_10) \
+       $(am__objects_11) profiles/audio/bluetoothd-source.$(OBJEXT) \
+       profiles/audio/bluetoothd-sink.$(OBJEXT) \
+       profiles/audio/bluetoothd-a2dp.$(OBJEXT) \
+       profiles/audio/bluetoothd-avdtp.$(OBJEXT) \
+       profiles/audio/bluetoothd-media.$(OBJEXT) \
+       profiles/audio/bluetoothd-transport.$(OBJEXT) \
+       profiles/audio/bluetoothd-control.$(OBJEXT) \
+       profiles/audio/bluetoothd-avctp.$(OBJEXT) \
+       profiles/audio/bluetoothd-avrcp.$(OBJEXT) \
+       profiles/audio/bluetoothd-player.$(OBJEXT) \
+       profiles/network/bluetoothd-manager.$(OBJEXT) \
+       profiles/network/bluetoothd-common.$(OBJEXT) \
+       profiles/network/bluetoothd-server.$(OBJEXT) \
+       profiles/network/bluetoothd-connection.$(OBJEXT) \
+       profiles/input/bluetoothd-manager.$(OBJEXT) \
+       profiles/input/bluetoothd-server.$(OBJEXT) \
+       profiles/input/bluetoothd-device.$(OBJEXT) \
+       profiles/input/bluetoothd-hog.$(OBJEXT) \
+       profiles/input/bluetoothd-suspend-dummy.$(OBJEXT) \
+       $(am__objects_12) profiles/gatt/bluetoothd-gas.$(OBJEXT) \
+       profiles/scanparam/bluetoothd-scan.$(OBJEXT) \
+       profiles/deviceinfo/bluetoothd-deviceinfo.$(OBJEXT) \
+       $(am__objects_13)
+am__objects_15 = attrib/bluetoothd-att.$(OBJEXT) \
        attrib/bluetoothd-gatt.$(OBJEXT) \
        attrib/bluetoothd-gattrib.$(OBJEXT) \
-       attrib/bluetoothd-client.$(OBJEXT) \
        attrib/bluetoothd-gatt-service.$(OBJEXT)
-am__objects_21 = btio/bluetoothd-btio.$(OBJEXT)
-@MCAP_TRUE@am__objects_22 = health/bluetoothd-mcap.$(OBJEXT) \
-@MCAP_TRUE@    health/bluetoothd-mcap_sync.$(OBJEXT)
-am__objects_23 = $(am__objects_22)
-am_src_bluetoothd_OBJECTS = $(am__objects_4) $(am__objects_19) \
-       $(am__objects_20) $(am__objects_21) $(am__objects_23) \
-       src/bluetoothd-main.$(OBJEXT) src/bluetoothd-log.$(OBJEXT) \
+am__objects_16 = btio/bluetoothd-btio.$(OBJEXT)
+am_src_bluetoothd_OBJECTS = $(am__objects_14) $(am__objects_15) \
+       $(am__objects_16) src/bluetoothd-main.$(OBJEXT) \
+       src/bluetoothd-log.$(OBJEXT) src/bluetoothd-systemd.$(OBJEXT) \
        src/bluetoothd-rfkill.$(OBJEXT) \
        src/bluetoothd-sdpd-server.$(OBJEXT) \
        src/bluetoothd-sdpd-request.$(OBJEXT) \
@@ -668,121 +608,115 @@ am_src_bluetoothd_OBJECTS = $(am__objects_4) $(am__objects_19) \
        src/bluetoothd-sdp-client.$(OBJEXT) \
        src/bluetoothd-textfile.$(OBJEXT) \
        src/bluetoothd-glib-helper.$(OBJEXT) \
-       src/bluetoothd-oui.$(OBJEXT) src/bluetoothd-plugin.$(OBJEXT) \
+       src/bluetoothd-plugin.$(OBJEXT) \
        src/bluetoothd-storage.$(OBJEXT) \
        src/bluetoothd-agent.$(OBJEXT) src/bluetoothd-error.$(OBJEXT) \
-       src/bluetoothd-manager.$(OBJEXT) \
        src/bluetoothd-adapter.$(OBJEXT) \
+       src/bluetoothd-profile.$(OBJEXT) \
+       src/bluetoothd-service.$(OBJEXT) \
        src/bluetoothd-device.$(OBJEXT) \
        src/bluetoothd-dbus-common.$(OBJEXT) \
-       src/bluetoothd-event.$(OBJEXT) src/bluetoothd-oob.$(OBJEXT) \
-       src/bluetoothd-eir.$(OBJEXT)
-@AUDIOPLUGIN_TRUE@am__objects_24 =  \
-@AUDIOPLUGIN_TRUE@     audio/bluetoothd-telephony.$(OBJEXT)
-@SAPPLUGIN_TRUE@am__objects_25 = sap/bluetoothd-sap.$(OBJEXT)
-am__objects_26 = $(am__objects_24) $(am__objects_25)
-am__objects_27 = $(am__objects_26)
-nodist_src_bluetoothd_OBJECTS = $(am__objects_27)
+       src/bluetoothd-eir.$(OBJEXT) \
+       src/shared/bluetoothd-util.$(OBJEXT) \
+       src/shared/bluetoothd-mgmt.$(OBJEXT)
+nodist_src_bluetoothd_OBJECTS = $(am__objects_9)
 src_bluetoothd_OBJECTS = $(am_src_bluetoothd_OBJECTS) \
        $(nodist_src_bluetoothd_OBJECTS)
 src_bluetoothd_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \
        $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \
        $(src_bluetoothd_CFLAGS) $(CFLAGS) $(src_bluetoothd_LDFLAGS) \
        $(LDFLAGS) -o $@
-test_agent_SOURCES = test/agent.c
-test_agent_OBJECTS = test/agent.$(OBJEXT)
-test_agent_DEPENDENCIES =
-test_attest_SOURCES = test/attest.c
-test_attest_OBJECTS = test/attest.$(OBJEXT)
-@TEST_TRUE@test_attest_DEPENDENCIES = lib/libbluetooth-private.la
-test_avtest_SOURCES = test/avtest.c
-test_avtest_OBJECTS = test/avtest.$(OBJEXT)
-@TEST_TRUE@test_avtest_DEPENDENCIES = lib/libbluetooth-private.la
-am__test_bdaddr_SOURCES_DIST = test/bdaddr.c src/oui.h src/oui.c
-@TEST_TRUE@am_test_bdaddr_OBJECTS = test/bdaddr.$(OBJEXT) \
-@TEST_TRUE@    src/oui.$(OBJEXT)
-test_bdaddr_OBJECTS = $(am_test_bdaddr_OBJECTS)
-@TEST_TRUE@test_bdaddr_DEPENDENCIES = lib/libbluetooth-private.la
-am__test_btiotest_SOURCES_DIST = test/btiotest.c btio/btio.h \
-       btio/btio.c
-@TEST_TRUE@am_test_btiotest_OBJECTS = test/btiotest.$(OBJEXT) \
-@TEST_TRUE@    btio/btio.$(OBJEXT)
-test_btiotest_OBJECTS = $(am_test_btiotest_OBJECTS)
-@TEST_TRUE@test_btiotest_DEPENDENCIES = lib/libbluetooth-private.la
-test_gaptest_SOURCES = test/gaptest.c
-test_gaptest_OBJECTS = test/gaptest.$(OBJEXT)
-test_gaptest_DEPENDENCIES =
-test_hciemu_SOURCES = test/hciemu.c
-test_hciemu_OBJECTS = test/hciemu.$(OBJEXT)
-@TEST_TRUE@test_hciemu_DEPENDENCIES = lib/libbluetooth-private.la
-test_hstest_SOURCES = test/hstest.c
-test_hstest_OBJECTS = test/hstest.$(OBJEXT)
-@TEST_TRUE@test_hstest_DEPENDENCIES = lib/libbluetooth-private.la
-am__test_ipctest_SOURCES_DIST = test/ipctest.c audio/ipc.h audio/ipc.c
-@TEST_TRUE@am_test_ipctest_OBJECTS = test/ipctest.$(OBJEXT) \
-@TEST_TRUE@    audio/ipc.$(OBJEXT)
-test_ipctest_OBJECTS = $(am_test_ipctest_OBJECTS)
-@TEST_TRUE@test_ipctest_DEPENDENCIES = sbc/libsbc.la
-test_l2test_SOURCES = test/l2test.c
-test_l2test_OBJECTS = test/l2test.$(OBJEXT)
-@TEST_TRUE@test_l2test_DEPENDENCIES = lib/libbluetooth-private.la
-test_lmptest_SOURCES = test/lmptest.c
-test_lmptest_OBJECTS = test/lmptest.$(OBJEXT)
-@TEST_TRUE@test_lmptest_DEPENDENCIES = lib/libbluetooth-private.la
-am__test_mpris_player_SOURCES_DIST = test/mpris-player.c
-@TEST_TRUE@am_test_mpris_player_OBJECTS = test/mpris-player.$(OBJEXT)
-test_mpris_player_OBJECTS = $(am_test_mpris_player_OBJECTS)
-test_mpris_player_DEPENDENCIES =
-test_rctest_SOURCES = test/rctest.c
-test_rctest_OBJECTS = test/rctest.$(OBJEXT)
-@TEST_TRUE@test_rctest_DEPENDENCIES = lib/libbluetooth-private.la
-test_scotest_SOURCES = test/scotest.c
-test_scotest_OBJECTS = test/scotest.$(OBJEXT)
-@TEST_TRUE@test_scotest_DEPENDENCIES = lib/libbluetooth-private.la
-test_sdptest_SOURCES = test/sdptest.c
-test_sdptest_OBJECTS = test/sdptest.$(OBJEXT)
-@TEST_TRUE@test_sdptest_DEPENDENCIES = lib/libbluetooth-private.la
-am__test_test_textfile_SOURCES_DIST = test/test-textfile.c \
-       src/textfile.h src/textfile.c
-@TEST_TRUE@am_test_test_textfile_OBJECTS =  \
-@TEST_TRUE@    test/test-textfile.$(OBJEXT) src/textfile.$(OBJEXT)
-test_test_textfile_OBJECTS = $(am_test_test_textfile_OBJECTS)
-test_test_textfile_LDADD = $(LDADD)
-am__test_uuidtest_SOURCES_DIST = test/uuidtest.c
-@TEST_TRUE@am_test_uuidtest_OBJECTS = test/uuidtest.$(OBJEXT)
-test_uuidtest_OBJECTS = $(am_test_uuidtest_OBJECTS)
-@TEST_TRUE@test_uuidtest_DEPENDENCIES = lib/libbluetooth-private.la
-tools_avctrl_SOURCES = tools/avctrl.c
-tools_avctrl_OBJECTS = tools/avctrl.$(OBJEXT)
-tools_avctrl_DEPENDENCIES =
+tools_amptest_SOURCES = tools/amptest.c
+tools_amptest_OBJECTS = tools/amptest.$(OBJEXT)
+@EXPERIMENTAL_TRUE@tools_amptest_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 tools_avinfo_SOURCES = tools/avinfo.c
 tools_avinfo_OBJECTS = tools/avinfo.$(OBJEXT)
-@TOOLS_TRUE@tools_avinfo_DEPENDENCIES = lib/libbluetooth-private.la
+@EXPERIMENTAL_TRUE@tools_avinfo_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+tools_avtest_SOURCES = tools/avtest.c
+tools_avtest_OBJECTS = tools/avtest.$(OBJEXT)
+@EXPERIMENTAL_TRUE@tools_avtest_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 am__tools_bccmd_SOURCES_DIST = tools/bccmd.c tools/csr.h tools/csr.c \
-       tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \
-       tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c tools/csr_usb.c
-@BCCMD_TRUE@@USB_TRUE@am__objects_28 = tools/csr_usb.$(OBJEXT)
-@BCCMD_TRUE@am_tools_bccmd_OBJECTS = tools/bccmd.$(OBJEXT) \
-@BCCMD_TRUE@   tools/csr.$(OBJEXT) tools/csr_hci.$(OBJEXT) \
-@BCCMD_TRUE@   tools/csr_h4.$(OBJEXT) tools/csr_3wire.$(OBJEXT) \
-@BCCMD_TRUE@   tools/csr_bcsp.$(OBJEXT) tools/ubcsp.$(OBJEXT) \
-@BCCMD_TRUE@   $(am__objects_28)
+       tools/csr_hci.c tools/csr_usb.c tools/csr_h4.c \
+       tools/csr_3wire.c tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+@TOOLS_TRUE@am_tools_bccmd_OBJECTS = tools/bccmd.$(OBJEXT) \
+@TOOLS_TRUE@   tools/csr.$(OBJEXT) tools/csr_hci.$(OBJEXT) \
+@TOOLS_TRUE@   tools/csr_usb.$(OBJEXT) tools/csr_h4.$(OBJEXT) \
+@TOOLS_TRUE@   tools/csr_3wire.$(OBJEXT) tools/csr_bcsp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/ubcsp.$(OBJEXT)
 tools_bccmd_OBJECTS = $(am_tools_bccmd_OBJECTS)
-am__DEPENDENCIES_1 =
-@BCCMD_TRUE@tools_bccmd_DEPENDENCIES = lib/libbluetooth-private.la \
-@BCCMD_TRUE@   $(am__DEPENDENCIES_1)
+@TOOLS_TRUE@tools_bccmd_DEPENDENCIES = lib/libbluetooth-internal.la
+am__tools_bdaddr_SOURCES_DIST = tools/bdaddr.c src/oui.h src/oui.c
+@EXPERIMENTAL_TRUE@am_tools_bdaddr_OBJECTS = tools/bdaddr.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/oui.$(OBJEXT)
+tools_bdaddr_OBJECTS = $(am_tools_bdaddr_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_bdaddr_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_bluetooth_player_SOURCES_DIST = tools/bluetooth-player.c \
+       client/display.h client/display.c
+@READLINE_TRUE@am_tools_bluetooth_player_OBJECTS =  \
+@READLINE_TRUE@        tools/bluetooth-player.$(OBJEXT) \
+@READLINE_TRUE@        client/display.$(OBJEXT)
+tools_bluetooth_player_OBJECTS = $(am_tools_bluetooth_player_OBJECTS)
+@READLINE_TRUE@tools_bluetooth_player_DEPENDENCIES =  \
+@READLINE_TRUE@        gdbus/libgdbus-internal.la
+tools_btattach_SOURCES = tools/btattach.c
+tools_btattach_OBJECTS = tools/btattach.$(OBJEXT)
+tools_btattach_LDADD = $(LDADD)
+am__tools_btinfo_SOURCES_DIST = tools/btinfo.c
+@EXPERIMENTAL_TRUE@am_tools_btinfo_OBJECTS = tools/btinfo.$(OBJEXT)
+tools_btinfo_OBJECTS = $(am_tools_btinfo_OBJECTS)
+tools_btinfo_LDADD = $(LDADD)
+am__tools_btiotest_SOURCES_DIST = tools/btiotest.c btio/btio.h \
+       btio/btio.c
+@EXPERIMENTAL_TRUE@am_tools_btiotest_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/btiotest.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    btio/btio.$(OBJEXT)
+tools_btiotest_OBJECTS = $(am_tools_btiotest_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_btiotest_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_btmgmt_SOURCES_DIST = tools/btmgmt.c src/glib-helper.c \
+       src/eir.c src/shared/util.h src/shared/util.c \
+       src/shared/mgmt.h src/shared/mgmt.c
+@EXPERIMENTAL_TRUE@am_tools_btmgmt_OBJECTS = tools/btmgmt.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/glib-helper.$(OBJEXT) src/eir.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/util.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/mgmt.$(OBJEXT)
+tools_btmgmt_OBJECTS = $(am_tools_btmgmt_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_btmgmt_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_btsnoop_SOURCES_DIST = tools/btsnoop.c src/shared/pcap.h \
+       src/shared/pcap.c src/shared/btsnoop.h src/shared/btsnoop.c
+@EXPERIMENTAL_TRUE@am_tools_btsnoop_OBJECTS = tools/btsnoop.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/pcap.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/btsnoop.$(OBJEXT)
+tools_btsnoop_OBJECTS = $(am_tools_btsnoop_OBJECTS)
+tools_btsnoop_LDADD = $(LDADD)
 tools_ciptool_SOURCES = tools/ciptool.c
 tools_ciptool_OBJECTS = tools/ciptool.$(OBJEXT)
-@TOOLS_TRUE@tools_ciptool_DEPENDENCIES = lib/libbluetooth-private.la
-tools_dfubabel_SOURCES = tools/dfubabel.c
-tools_dfubabel_OBJECTS = tools/dfubabel.$(OBJEXT)
-tools_dfubabel_DEPENDENCIES =
-am__tools_dfutool_SOURCES_DIST = tools/dfutool.c tools/dfu.h \
-       tools/dfu.c
-@DFUTOOL_TRUE@am_tools_dfutool_OBJECTS = tools/dfutool.$(OBJEXT) \
-@DFUTOOL_TRUE@ tools/dfu.$(OBJEXT)
-tools_dfutool_OBJECTS = $(am_tools_dfutool_OBJECTS)
-tools_dfutool_DEPENDENCIES =
+@TOOLS_TRUE@tools_ciptool_DEPENDENCIES = lib/libbluetooth-internal.la
+am__tools_cltest_SOURCES_DIST = tools/cltest.c monitor/mainloop.h \
+       monitor/mainloop.c
+@EXPERIMENTAL_TRUE@am_tools_cltest_OBJECTS = tools/cltest.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    monitor/mainloop.$(OBJEXT)
+tools_cltest_OBJECTS = $(am_tools_cltest_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_cltest_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_gap_tester_SOURCES_DIST = tools/gap-tester.c monitor/bt.h \
+       emulator/btdev.h emulator/btdev.c emulator/bthost.h \
+       emulator/bthost.c src/shared/hciemu.h src/shared/hciemu.c \
+       src/shared/tester.h src/shared/tester.c
+@EXPERIMENTAL_TRUE@am_tools_gap_tester_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/gap-tester.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/hciemu.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/tester.$(OBJEXT)
+tools_gap_tester_OBJECTS = $(am_tools_gap_tester_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_gap_tester_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    gdbus/libgdbus-internal.la
 am__tools_hciattach_SOURCES_DIST = tools/hciattach.c tools/hciattach.h \
        tools/hciattach_st.c tools/hciattach_ti.c \
        tools/hciattach_tialt.c tools/hciattach_ath3k.c \
@@ -796,64 +730,235 @@ am__tools_hciattach_SOURCES_DIST = tools/hciattach.c tools/hciattach.h \
 @TOOLS_TRUE@   tools/hciattach_intel.$(OBJEXT)
 tools_hciattach_OBJECTS = $(am_tools_hciattach_OBJECTS)
 @TOOLS_TRUE@tools_hciattach_DEPENDENCIES =  \
-@TOOLS_TRUE@   lib/libbluetooth-private.la
+@TOOLS_TRUE@   lib/libbluetooth-internal.la
 am__tools_hciconfig_SOURCES_DIST = tools/hciconfig.c tools/csr.h \
-       tools/csr.c src/textfile.h src/textfile.c
+       tools/csr.c
 @TOOLS_TRUE@am_tools_hciconfig_OBJECTS = tools/hciconfig.$(OBJEXT) \
-@TOOLS_TRUE@   tools/csr.$(OBJEXT) src/textfile.$(OBJEXT)
+@TOOLS_TRUE@   tools/csr.$(OBJEXT)
 tools_hciconfig_OBJECTS = $(am_tools_hciconfig_OBJECTS)
 @TOOLS_TRUE@tools_hciconfig_DEPENDENCIES =  \
-@TOOLS_TRUE@   lib/libbluetooth-private.la
+@TOOLS_TRUE@   lib/libbluetooth-internal.la
+am__tools_hcidump_SOURCES_DIST = tools/hcidump.c tools/parser/parser.h \
+       tools/parser/parser.c tools/parser/lmp.c tools/parser/hci.c \
+       tools/parser/l2cap.h tools/parser/l2cap.c tools/parser/amp.c \
+       tools/parser/smp.c tools/parser/att.c tools/parser/sdp.h \
+       tools/parser/sdp.c tools/parser/rfcomm.h tools/parser/rfcomm.c \
+       tools/parser/bnep.c tools/parser/cmtp.c tools/parser/hidp.c \
+       tools/parser/hcrp.c tools/parser/avdtp.c tools/parser/avctp.c \
+       tools/parser/avrcp.c tools/parser/sap.c tools/parser/obex.c \
+       tools/parser/capi.c tools/parser/ppp.c tools/parser/tcpip.c \
+       tools/parser/ericsson.c tools/parser/csr.c tools/parser/bpa.c
+@TOOLS_TRUE@am_tools_hcidump_OBJECTS = tools/hcidump.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/parser.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/lmp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/hci.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/l2cap.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/amp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/smp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/att.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/sdp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/rfcomm.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/bnep.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/cmtp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/hidp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/hcrp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/avdtp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/avctp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/avrcp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/sap.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/obex.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/capi.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/ppp.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/tcpip.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/ericsson.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/csr.$(OBJEXT) \
+@TOOLS_TRUE@   tools/parser/bpa.$(OBJEXT)
+tools_hcidump_OBJECTS = $(am_tools_hcidump_OBJECTS)
+@TOOLS_TRUE@tools_hcidump_DEPENDENCIES = lib/libbluetooth-internal.la
 tools_hcieventmask_SOURCES = tools/hcieventmask.c
 tools_hcieventmask_OBJECTS = tools/hcieventmask.$(OBJEXT)
-@TOOLS_TRUE@tools_hcieventmask_DEPENDENCIES =  \
-@TOOLS_TRUE@   lib/libbluetooth-private.la
+@EXPERIMENTAL_TRUE@tools_hcieventmask_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 tools_hcisecfilter_SOURCES = tools/hcisecfilter.c
 tools_hcisecfilter_OBJECTS = tools/hcisecfilter.$(OBJEXT)
 tools_hcisecfilter_LDADD = $(LDADD)
-am__tools_hcitool_SOURCES_DIST = tools/hcitool.c src/oui.h src/oui.c \
-       src/textfile.h src/textfile.c
+am__tools_hcitool_SOURCES_DIST = tools/hcitool.c src/oui.h src/oui.c
 @TOOLS_TRUE@am_tools_hcitool_OBJECTS = tools/hcitool.$(OBJEXT) \
-@TOOLS_TRUE@   src/oui.$(OBJEXT) src/textfile.$(OBJEXT)
+@TOOLS_TRUE@   src/oui.$(OBJEXT)
 tools_hcitool_OBJECTS = $(am_tools_hcitool_OBJECTS)
-@TOOLS_TRUE@tools_hcitool_DEPENDENCIES = lib/libbluetooth-private.la
+@TOOLS_TRUE@tools_hcitool_DEPENDENCIES = lib/libbluetooth-internal.la
 tools_hid2hci_SOURCES = tools/hid2hci.c
 tools_hid2hci_OBJECTS = tools/hid2hci.$(OBJEXT)
 tools_hid2hci_DEPENDENCIES =
+tools_hwdb_SOURCES = tools/hwdb.c
+tools_hwdb_OBJECTS = tools/hwdb.$(OBJEXT)
+@EXPERIMENTAL_TRUE@tools_hwdb_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_l2cap_tester_SOURCES_DIST = tools/l2cap-tester.c \
+       monitor/bt.h emulator/btdev.h emulator/btdev.c \
+       emulator/bthost.h emulator/bthost.c src/shared/util.h \
+       src/shared/util.c src/shared/mgmt.h src/shared/mgmt.c \
+       src/shared/hciemu.h src/shared/hciemu.c src/shared/tester.h \
+       src/shared/tester.c
+@EXPERIMENTAL_TRUE@am_tools_l2cap_tester_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/l2cap-tester.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/util.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/mgmt.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/hciemu.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/tester.$(OBJEXT)
+tools_l2cap_tester_OBJECTS = $(am_tools_l2cap_tester_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_l2cap_tester_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 tools_l2ping_SOURCES = tools/l2ping.c
 tools_l2ping_OBJECTS = tools/l2ping.$(OBJEXT)
-@TOOLS_TRUE@tools_l2ping_DEPENDENCIES = lib/libbluetooth-private.la
-tools_ppporc_SOURCES = tools/ppporc.c
-tools_ppporc_OBJECTS = tools/ppporc.$(OBJEXT)
-@TOOLS_TRUE@tools_ppporc_DEPENDENCIES = lib/libbluetooth-private.la
-am__tools_rfcomm_SOURCES_DIST = tools/rfcomm.c tools/parser.y \
-       tools/lexer.l tools/kword.h tools/kword.c
-@TOOLS_TRUE@am_tools_rfcomm_OBJECTS = tools/rfcomm.$(OBJEXT) \
-@TOOLS_TRUE@   tools/parser.$(OBJEXT) tools/lexer.$(OBJEXT) \
-@TOOLS_TRUE@   tools/kword.$(OBJEXT)
-am__EXTRA_tools_rfcomm_SOURCES_DIST = tools/parser.h tools/parser.c \
-       tools/lexer.c
-tools_rfcomm_OBJECTS = $(am_tools_rfcomm_OBJECTS)
-@TOOLS_TRUE@tools_rfcomm_DEPENDENCIES = lib/libbluetooth-private.la
+@TOOLS_TRUE@tools_l2ping_DEPENDENCIES = lib/libbluetooth-internal.la
+tools_l2test_SOURCES = tools/l2test.c
+tools_l2test_OBJECTS = tools/l2test.$(OBJEXT)
+@TOOLS_TRUE@tools_l2test_DEPENDENCIES = lib/libbluetooth-internal.la
+am__tools_mgmt_tester_SOURCES_DIST = tools/mgmt-tester.c monitor/bt.h \
+       emulator/btdev.h emulator/btdev.c emulator/bthost.h \
+       emulator/bthost.c src/shared/util.h src/shared/util.c \
+       src/shared/mgmt.h src/shared/mgmt.c src/shared/hciemu.h \
+       src/shared/hciemu.c src/shared/tester.h src/shared/tester.c
+@EXPERIMENTAL_TRUE@am_tools_mgmt_tester_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/mgmt-tester.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/util.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/mgmt.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/hciemu.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/tester.$(OBJEXT)
+tools_mgmt_tester_OBJECTS = $(am_tools_mgmt_tester_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_mgmt_tester_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+am__tools_mpris_player_SOURCES_DIST = tools/mpris-player.c
+@EXPERIMENTAL_TRUE@am_tools_mpris_player_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/mpris-player.$(OBJEXT)
+tools_mpris_player_OBJECTS = $(am_tools_mpris_player_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_mpris_player_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    gdbus/libgdbus-internal.la
+am__tools_obex_client_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \
+       gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \
+       gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \
+       gobex/gobex-transfer.c gobex/gobex-debug.h \
+       gobex/gobex-apparam.c gobex/gobex-apparam.h btio/btio.h \
+       btio/btio.c tools/obex-client-tool.c
+am__objects_17 = gobex/gobex.$(OBJEXT) gobex/gobex-defs.$(OBJEXT) \
+       gobex/gobex-packet.$(OBJEXT) gobex/gobex-header.$(OBJEXT) \
+       gobex/gobex-transfer.$(OBJEXT) gobex/gobex-apparam.$(OBJEXT)
+am__objects_18 = btio/btio.$(OBJEXT)
+@READLINE_TRUE@am_tools_obex_client_tool_OBJECTS = $(am__objects_17) \
+@READLINE_TRUE@        $(am__objects_18) \
+@READLINE_TRUE@        tools/obex-client-tool.$(OBJEXT)
+tools_obex_client_tool_OBJECTS = $(am_tools_obex_client_tool_OBJECTS)
+@READLINE_TRUE@tools_obex_client_tool_DEPENDENCIES =  \
+@READLINE_TRUE@        lib/libbluetooth-internal.la
+am__tools_obex_server_tool_SOURCES_DIST = gobex/gobex.h gobex/gobex.c \
+       gobex/gobex-defs.h gobex/gobex-defs.c gobex/gobex-packet.c \
+       gobex/gobex-packet.h gobex/gobex-header.c gobex/gobex-header.h \
+       gobex/gobex-transfer.c gobex/gobex-debug.h \
+       gobex/gobex-apparam.c gobex/gobex-apparam.h btio/btio.h \
+       btio/btio.c tools/obex-server-tool.c
+@READLINE_TRUE@am_tools_obex_server_tool_OBJECTS = $(am__objects_17) \
+@READLINE_TRUE@        $(am__objects_18) \
+@READLINE_TRUE@        tools/obex-server-tool.$(OBJEXT)
+tools_obex_server_tool_OBJECTS = $(am_tools_obex_server_tool_OBJECTS)
+@READLINE_TRUE@tools_obex_server_tool_DEPENDENCIES =  \
+@READLINE_TRUE@        lib/libbluetooth-internal.la
+am__tools_obexctl_SOURCES_DIST = tools/obexctl.c client/display.h \
+       client/display.c
+@READLINE_TRUE@am_tools_obexctl_OBJECTS = tools/obexctl.$(OBJEXT) \
+@READLINE_TRUE@        client/display.$(OBJEXT)
+tools_obexctl_OBJECTS = $(am_tools_obexctl_OBJECTS)
+@READLINE_TRUE@tools_obexctl_DEPENDENCIES =  \
+@READLINE_TRUE@        gdbus/libgdbus-internal.la
+tools_rctest_SOURCES = tools/rctest.c
+tools_rctest_OBJECTS = tools/rctest.$(OBJEXT)
+@TOOLS_TRUE@tools_rctest_DEPENDENCIES = lib/libbluetooth-internal.la
+tools_rfcomm_SOURCES = tools/rfcomm.c
+tools_rfcomm_OBJECTS = tools/rfcomm.$(OBJEXT)
+@TOOLS_TRUE@tools_rfcomm_DEPENDENCIES = lib/libbluetooth-internal.la
+am__tools_sco_tester_SOURCES_DIST = tools/sco-tester.c monitor/bt.h \
+       emulator/btdev.h emulator/btdev.c emulator/bthost.h \
+       emulator/bthost.c src/shared/util.h src/shared/util.c \
+       src/shared/mgmt.h src/shared/mgmt.c src/shared/hciemu.h \
+       src/shared/hciemu.c src/shared/tester.h src/shared/tester.c
+@EXPERIMENTAL_TRUE@am_tools_sco_tester_OBJECTS =  \
+@EXPERIMENTAL_TRUE@    tools/sco-tester.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/btdev.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    emulator/bthost.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/util.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/mgmt.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/hciemu.$(OBJEXT) \
+@EXPERIMENTAL_TRUE@    src/shared/tester.$(OBJEXT)
+tools_sco_tester_OBJECTS = $(am_tools_sco_tester_OBJECTS)
+@EXPERIMENTAL_TRUE@tools_sco_tester_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
+tools_scotest_SOURCES = tools/scotest.c
+tools_scotest_OBJECTS = tools/scotest.$(OBJEXT)
+@EXPERIMENTAL_TRUE@tools_scotest_DEPENDENCIES =  \
+@EXPERIMENTAL_TRUE@    lib/libbluetooth-internal.la
 am__tools_sdptool_SOURCES_DIST = tools/sdptool.c src/sdp-xml.h \
        src/sdp-xml.c
 @TOOLS_TRUE@am_tools_sdptool_OBJECTS = tools/sdptool.$(OBJEXT) \
 @TOOLS_TRUE@   src/sdp-xml.$(OBJEXT)
 tools_sdptool_OBJECTS = $(am_tools_sdptool_OBJECTS)
-@TOOLS_TRUE@tools_sdptool_DEPENDENCIES = lib/libbluetooth-private.la
-am__unit_test_eir_SOURCES_DIST = unit/test-eir.c src/eir.c \
-       src/glib-helper.c
-@TEST_TRUE@am_unit_test_eir_OBJECTS =  \
-@TEST_TRUE@    unit/unit_test_eir-test-eir.$(OBJEXT) \
-@TEST_TRUE@    src/unit_test_eir-eir.$(OBJEXT) \
-@TEST_TRUE@    src/unit_test_eir-glib-helper.$(OBJEXT)
+@TOOLS_TRUE@tools_sdptool_DEPENDENCIES = lib/libbluetooth-internal.la
+am_unit_test_crc_OBJECTS = unit/test-crc.$(OBJEXT) \
+       monitor/crc.$(OBJEXT)
+unit_test_crc_OBJECTS = $(am_unit_test_crc_OBJECTS)
+unit_test_crc_DEPENDENCIES =
+am_unit_test_eir_OBJECTS = unit/test-eir.$(OBJEXT) src/eir.$(OBJEXT) \
+       src/glib-helper.$(OBJEXT)
 unit_test_eir_OBJECTS = $(am_unit_test_eir_OBJECTS)
-@TEST_TRUE@unit_test_eir_DEPENDENCIES = lib/libbluetooth-private.la
-unit_test_eir_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
-       $(LIBTOOLFLAGS) --mode=link $(CCLD) $(unit_test_eir_CFLAGS) \
-       $(CFLAGS) $(AM_LDFLAGS) $(LDFLAGS) -o $@
-am__dist_udev_SCRIPTS_DIST = scripts/bluetooth_serial
-SCRIPTS = $(dist_udev_SCRIPTS)
+unit_test_eir_DEPENDENCIES = lib/libbluetooth-internal.la
+am_unit_test_gdbus_client_OBJECTS = unit/test-gdbus-client.$(OBJEXT)
+unit_test_gdbus_client_OBJECTS = $(am_unit_test_gdbus_client_OBJECTS)
+unit_test_gdbus_client_DEPENDENCIES = gdbus/libgdbus-internal.la
+am_unit_test_gobex_OBJECTS = $(am__objects_17) unit/util.$(OBJEXT) \
+       unit/test-gobex.$(OBJEXT)
+unit_test_gobex_OBJECTS = $(am_unit_test_gobex_OBJECTS)
+unit_test_gobex_DEPENDENCIES =
+am_unit_test_gobex_apparam_OBJECTS = $(am__objects_17) \
+       unit/util.$(OBJEXT) unit/test-gobex-apparam.$(OBJEXT)
+unit_test_gobex_apparam_OBJECTS =  \
+       $(am_unit_test_gobex_apparam_OBJECTS)
+unit_test_gobex_apparam_DEPENDENCIES =
+am_unit_test_gobex_header_OBJECTS = $(am__objects_17) \
+       unit/util.$(OBJEXT) unit/test-gobex-header.$(OBJEXT)
+unit_test_gobex_header_OBJECTS = $(am_unit_test_gobex_header_OBJECTS)
+unit_test_gobex_header_DEPENDENCIES =
+am_unit_test_gobex_packet_OBJECTS = $(am__objects_17) \
+       unit/util.$(OBJEXT) unit/test-gobex-packet.$(OBJEXT)
+unit_test_gobex_packet_OBJECTS = $(am_unit_test_gobex_packet_OBJECTS)
+unit_test_gobex_packet_DEPENDENCIES =
+am_unit_test_gobex_transfer_OBJECTS = $(am__objects_17) \
+       unit/util.$(OBJEXT) unit/test-gobex-transfer.$(OBJEXT)
+unit_test_gobex_transfer_OBJECTS =  \
+       $(am_unit_test_gobex_transfer_OBJECTS)
+unit_test_gobex_transfer_DEPENDENCIES =
+am_unit_test_lib_OBJECTS = unit/test-lib.$(OBJEXT)
+unit_test_lib_OBJECTS = $(am_unit_test_lib_OBJECTS)
+unit_test_lib_DEPENDENCIES = lib/libbluetooth-internal.la
+am_unit_test_mgmt_OBJECTS = unit/test-mgmt.$(OBJEXT) \
+       src/shared/util.$(OBJEXT) src/shared/mgmt.$(OBJEXT)
+unit_test_mgmt_OBJECTS = $(am_unit_test_mgmt_OBJECTS)
+unit_test_mgmt_DEPENDENCIES =
+am_unit_test_sdp_OBJECTS = unit/test-sdp.$(OBJEXT) \
+       src/shared/util.$(OBJEXT) src/sdpd-database.$(OBJEXT) \
+       src/sdpd-service.$(OBJEXT) src/sdpd-request.$(OBJEXT)
+unit_test_sdp_OBJECTS = $(am_unit_test_sdp_OBJECTS)
+unit_test_sdp_DEPENDENCIES = lib/libbluetooth-internal.la
+am_unit_test_textfile_OBJECTS = unit/test-textfile.$(OBJEXT) \
+       src/textfile.$(OBJEXT)
+unit_test_textfile_OBJECTS = $(am_unit_test_textfile_OBJECTS)
+unit_test_textfile_DEPENDENCIES =
+am_unit_test_uuid_OBJECTS = unit/test-uuid.$(OBJEXT)
+unit_test_uuid_OBJECTS = $(am_unit_test_uuid_OBJECTS)
+unit_test_uuid_DEPENDENCIES = lib/libbluetooth-internal.la
+SCRIPTS = $(test_SCRIPTS)
 DEFAULT_INCLUDES = -I.@am__isrc@
 depcomp = $(SHELL) $(top_srcdir)/depcomp
 am__depfiles_maybe = depfiles
@@ -874,95 +979,106 @@ LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
 AM_V_CCLD = $(am__v_CCLD_@AM_V@)
 am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@)
 am__v_CCLD_0 = @echo "  CCLD  " $@;
-@MAINTAINER_MODE_FALSE@am__skiplex = test -f $@ ||
-LEXCOMPILE = $(LEX) $(AM_LFLAGS) $(LFLAGS)
-LTLEXCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
-       $(LIBTOOLFLAGS) --mode=compile $(LEX) $(AM_LFLAGS) $(LFLAGS)
-AM_V_LEX = $(am__v_LEX_@AM_V@)
-am__v_LEX_ = $(am__v_LEX_@AM_DEFAULT_V@)
-am__v_LEX_0 = @echo "  LEX   " $@;
-YLWRAP = $(top_srcdir)/ylwrap
-@MAINTAINER_MODE_FALSE@am__skipyacc = test -f $@ ||
-YACCCOMPILE = $(YACC) $(AM_YFLAGS) $(YFLAGS)
-LTYACCCOMPILE = $(LIBTOOL) $(AM_V_lt) $(AM_LIBTOOLFLAGS) \
-       $(LIBTOOLFLAGS) --mode=compile $(YACC) $(AM_YFLAGS) $(YFLAGS)
-AM_V_YACC = $(am__v_YACC_@AM_V@)
-am__v_YACC_ = $(am__v_YACC_@AM_DEFAULT_V@)
-am__v_YACC_0 = @echo "  YACC  " $@;
 AM_V_GEN = $(am__v_GEN_@AM_V@)
 am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@)
 am__v_GEN_0 = @echo "  GEN   " $@;
-SOURCES = $(audio_libtelephony_a_SOURCES) $(sap_libsap_a_SOURCES) \
-       $(audio_libasound_module_ctl_bluetooth_la_SOURCES) \
-       $(audio_libasound_module_pcm_bluetooth_la_SOURCES) \
-       $(audio_libgstbluetooth_la_SOURCES) \
-       $(lib_libbluetooth_private_la_SOURCES) \
+SOURCES = $(profiles_sap_libsap_a_SOURCES) \
+       $(gdbus_libgdbus_internal_la_SOURCES) \
+       $(lib_libbluetooth_internal_la_SOURCES) \
        $(lib_libbluetooth_la_SOURCES) \
-       $(plugins_external_dummy_la_SOURCES) $(sbc_libsbc_la_SOURCES) \
-       $(attrib_gatttool_SOURCES) $(compat_dund_SOURCES) \
-       $(compat_hidd_SOURCES) $(compat_pand_SOURCES) \
-       $(cups_bluetooth_SOURCES) $(emulator_btvirt_SOURCES) \
-       $(mgmt_btmgmt_SOURCES) $(monitor_btmon_SOURCES) \
-       $(sbc_sbcdec_SOURCES) $(sbc_sbcenc_SOURCES) sbc/sbcinfo.c \
-       sbc/sbctester.c $(src_bluetoothd_SOURCES) \
-       $(nodist_src_bluetoothd_SOURCES) test/agent.c test/attest.c \
-       test/avtest.c $(test_bdaddr_SOURCES) $(test_btiotest_SOURCES) \
-       test/gaptest.c test/hciemu.c test/hstest.c \
-       $(test_ipctest_SOURCES) test/l2test.c test/lmptest.c \
-       $(test_mpris_player_SOURCES) test/rctest.c test/scotest.c \
-       test/sdptest.c $(test_test_textfile_SOURCES) \
-       $(test_uuidtest_SOURCES) tools/avctrl.c tools/avinfo.c \
-       $(tools_bccmd_SOURCES) tools/ciptool.c tools/dfubabel.c \
-       $(tools_dfutool_SOURCES) $(tools_hciattach_SOURCES) \
-       $(tools_hciconfig_SOURCES) tools/hcieventmask.c \
+       $(plugins_external_dummy_la_SOURCES) \
+       $(android_bluetoothd_SOURCES) $(attrib_gatttool_SOURCES) \
+       $(client_bluetoothctl_SOURCES) $(emulator_b1ee_SOURCES) \
+       $(emulator_btvirt_SOURCES) $(monitor_btmon_SOURCES) \
+       $(obexd_src_obexd_SOURCES) $(nodist_obexd_src_obexd_SOURCES) \
+       $(profiles_cups_bluetooth_SOURCES) \
+       $(profiles_iap_iapd_SOURCES) $(src_bluetoothd_SOURCES) \
+       $(nodist_src_bluetoothd_SOURCES) tools/amptest.c \
+       tools/avinfo.c tools/avtest.c $(tools_bccmd_SOURCES) \
+       $(tools_bdaddr_SOURCES) $(tools_bluetooth_player_SOURCES) \
+       tools/btattach.c $(tools_btinfo_SOURCES) \
+       $(tools_btiotest_SOURCES) $(tools_btmgmt_SOURCES) \
+       $(tools_btsnoop_SOURCES) tools/ciptool.c \
+       $(tools_cltest_SOURCES) $(tools_gap_tester_SOURCES) \
+       $(tools_hciattach_SOURCES) $(tools_hciconfig_SOURCES) \
+       $(tools_hcidump_SOURCES) tools/hcieventmask.c \
        tools/hcisecfilter.c $(tools_hcitool_SOURCES) tools/hid2hci.c \
-       tools/l2ping.c tools/ppporc.c $(tools_rfcomm_SOURCES) \
-       $(EXTRA_tools_rfcomm_SOURCES) $(tools_sdptool_SOURCES) \
-       $(unit_test_eir_SOURCES)
-DIST_SOURCES = $(am__audio_libtelephony_a_SOURCES_DIST) \
-       $(am__sap_libsap_a_SOURCES_DIST) \
-       $(am__audio_libasound_module_ctl_bluetooth_la_SOURCES_DIST) \
-       $(am__audio_libasound_module_pcm_bluetooth_la_SOURCES_DIST) \
-       $(am__audio_libgstbluetooth_la_SOURCES_DIST) \
-       $(lib_libbluetooth_private_la_SOURCES) \
-       $(lib_libbluetooth_la_SOURCES) \
+       tools/hwdb.c $(tools_l2cap_tester_SOURCES) tools/l2ping.c \
+       tools/l2test.c $(tools_mgmt_tester_SOURCES) \
+       $(tools_mpris_player_SOURCES) \
+       $(tools_obex_client_tool_SOURCES) \
+       $(tools_obex_server_tool_SOURCES) $(tools_obexctl_SOURCES) \
+       tools/rctest.c tools/rfcomm.c $(tools_sco_tester_SOURCES) \
+       tools/scotest.c $(tools_sdptool_SOURCES) \
+       $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \
+       $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \
+       $(unit_test_gobex_apparam_SOURCES) \
+       $(unit_test_gobex_header_SOURCES) \
+       $(unit_test_gobex_packet_SOURCES) \
+       $(unit_test_gobex_transfer_SOURCES) $(unit_test_lib_SOURCES) \
+       $(unit_test_mgmt_SOURCES) $(unit_test_sdp_SOURCES) \
+       $(unit_test_textfile_SOURCES) $(unit_test_uuid_SOURCES)
+DIST_SOURCES = $(am__profiles_sap_libsap_a_SOURCES_DIST) \
+       $(gdbus_libgdbus_internal_la_SOURCES) \
+       $(lib_libbluetooth_internal_la_SOURCES) \
+       $(am__lib_libbluetooth_la_SOURCES_DIST) \
        $(am__plugins_external_dummy_la_SOURCES_DIST) \
-       $(am__sbc_libsbc_la_SOURCES_DIST) \
+       $(am__android_bluetoothd_SOURCES_DIST) \
        $(am__attrib_gatttool_SOURCES_DIST) \
-       $(am__compat_dund_SOURCES_DIST) \
-       $(am__compat_hidd_SOURCES_DIST) \
-       $(am__compat_pand_SOURCES_DIST) \
-       $(am__cups_bluetooth_SOURCES_DIST) \
+       $(am__client_bluetoothctl_SOURCES_DIST) \
+       $(am__emulator_b1ee_SOURCES_DIST) \
        $(am__emulator_btvirt_SOURCES_DIST) \
-       $(am__mgmt_btmgmt_SOURCES_DIST) \
        $(am__monitor_btmon_SOURCES_DIST) \
-       $(am__sbc_sbcdec_SOURCES_DIST) $(am__sbc_sbcenc_SOURCES_DIST) \
-       sbc/sbcinfo.c sbc/sbctester.c \
-       $(am__src_bluetoothd_SOURCES_DIST) test/agent.c test/attest.c \
-       test/avtest.c $(am__test_bdaddr_SOURCES_DIST) \
-       $(am__test_btiotest_SOURCES_DIST) test/gaptest.c test/hciemu.c \
-       test/hstest.c $(am__test_ipctest_SOURCES_DIST) test/l2test.c \
-       test/lmptest.c $(am__test_mpris_player_SOURCES_DIST) \
-       test/rctest.c test/scotest.c test/sdptest.c \
-       $(am__test_test_textfile_SOURCES_DIST) \
-       $(am__test_uuidtest_SOURCES_DIST) tools/avctrl.c \
-       tools/avinfo.c $(am__tools_bccmd_SOURCES_DIST) tools/ciptool.c \
-       tools/dfubabel.c $(am__tools_dfutool_SOURCES_DIST) \
+       $(am__obexd_src_obexd_SOURCES_DIST) \
+       $(am__profiles_cups_bluetooth_SOURCES_DIST) \
+       $(am__profiles_iap_iapd_SOURCES_DIST) \
+       $(am__src_bluetoothd_SOURCES_DIST) tools/amptest.c \
+       tools/avinfo.c tools/avtest.c $(am__tools_bccmd_SOURCES_DIST) \
+       $(am__tools_bdaddr_SOURCES_DIST) \
+       $(am__tools_bluetooth_player_SOURCES_DIST) tools/btattach.c \
+       $(am__tools_btinfo_SOURCES_DIST) \
+       $(am__tools_btiotest_SOURCES_DIST) \
+       $(am__tools_btmgmt_SOURCES_DIST) \
+       $(am__tools_btsnoop_SOURCES_DIST) tools/ciptool.c \
+       $(am__tools_cltest_SOURCES_DIST) \
+       $(am__tools_gap_tester_SOURCES_DIST) \
        $(am__tools_hciattach_SOURCES_DIST) \
-       $(am__tools_hciconfig_SOURCES_DIST) tools/hcieventmask.c \
+       $(am__tools_hciconfig_SOURCES_DIST) \
+       $(am__tools_hcidump_SOURCES_DIST) tools/hcieventmask.c \
        tools/hcisecfilter.c $(am__tools_hcitool_SOURCES_DIST) \
-       tools/hid2hci.c tools/l2ping.c tools/ppporc.c \
-       $(am__tools_rfcomm_SOURCES_DIST) \
-       $(am__EXTRA_tools_rfcomm_SOURCES_DIST) \
-       $(am__tools_sdptool_SOURCES_DIST) \
-       $(am__unit_test_eir_SOURCES_DIST)
+       tools/hid2hci.c tools/hwdb.c \
+       $(am__tools_l2cap_tester_SOURCES_DIST) tools/l2ping.c \
+       tools/l2test.c $(am__tools_mgmt_tester_SOURCES_DIST) \
+       $(am__tools_mpris_player_SOURCES_DIST) \
+       $(am__tools_obex_client_tool_SOURCES_DIST) \
+       $(am__tools_obex_server_tool_SOURCES_DIST) \
+       $(am__tools_obexctl_SOURCES_DIST) tools/rctest.c \
+       tools/rfcomm.c $(am__tools_sco_tester_SOURCES_DIST) \
+       tools/scotest.c $(am__tools_sdptool_SOURCES_DIST) \
+       $(unit_test_crc_SOURCES) $(unit_test_eir_SOURCES) \
+       $(unit_test_gdbus_client_SOURCES) $(unit_test_gobex_SOURCES) \
+       $(unit_test_gobex_apparam_SOURCES) \
+       $(unit_test_gobex_header_SOURCES) \
+       $(unit_test_gobex_packet_SOURCES) \
+       $(unit_test_gobex_transfer_SOURCES) $(unit_test_lib_SOURCES) \
+       $(unit_test_mgmt_SOURCES) $(unit_test_sdp_SOURCES) \
+       $(unit_test_textfile_SOURCES) $(unit_test_uuid_SOURCES)
+am__can_run_installinfo = \
+  case $$AM_UPDATE_INFO_DIR in \
+    n|no|NO) false;; \
+    *) (install-info --version) >/dev/null 2>&1;; \
+  esac
 man1dir = $(mandir)/man1
 man8dir = $(mandir)/man8
 NROFF = nroff
 MANS = $(dist_man_MANS) $(man_MANS)
-DATA = $(alsaconf_DATA) $(conf_DATA) $(dbus_DATA) $(dbusservice_DATA) \
-       $(pkgconfig_DATA) $(rules_DATA) $(state_DATA) \
-       $(systemdunit_DATA)
+DATA = $(conf_DATA) $(dbus_DATA) $(dbussessionbus_DATA) \
+       $(dbussystembus_DATA) $(pkgconfig_DATA) $(rules_DATA) \
+       $(state_DATA) $(systemdsystemunit_DATA) \
+       $(systemduserunit_DATA)
+am__include_HEADERS_DIST = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+       lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h lib/rfcomm.h \
+       lib/bnep.h lib/cmtp.h lib/hidp.h
 HEADERS = $(include_HEADERS)
 ETAGS = etags
 CTAGS = ctags
@@ -990,15 +1106,13 @@ am__remove_distdir = \
       && rm -rf "$(distdir)" \
       || { sleep 5 && rm -rf "$(distdir)"; }; \
   else :; fi
-DIST_ARCHIVES = $(distdir).tar.gz
 GZIP_ENV = --best
+DIST_ARCHIVES = $(distdir).tar.xz
 distuninstallcheck_listfiles = find . -type f -print
 am__distuninstallcheck_listfiles = $(distuninstallcheck_listfiles) \
   | sed 's|^\./|$(prefix)/|' | grep -v '$(infodir)/dir$$'
 distcleancheck_listfiles = find . -type f -print
 ACLOCAL = @ACLOCAL@
-ALSA_CFLAGS = @ALSA_CFLAGS@
-ALSA_LIBS = @ALSA_LIBS@
 AMTAR = @AMTAR@
 AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
 AR = @AR@
@@ -1009,14 +1123,15 @@ AWK = @AWK@
 CC = @CC@
 CCDEPMODE = @CCDEPMODE@
 CFLAGS = @CFLAGS@
-CHECK_CFLAGS = @CHECK_CFLAGS@
-CHECK_LIBS = @CHECK_LIBS@
 CONFIGDIR = @CONFIGDIR@
 CPP = @CPP@
 CPPFLAGS = @CPPFLAGS@
 CYGPATH_W = @CYGPATH_W@
 DBUS_CFLAGS = @DBUS_CFLAGS@
+DBUS_CONFDIR = @DBUS_CONFDIR@
 DBUS_LIBS = @DBUS_LIBS@
+DBUS_SESSIONBUSDIR = @DBUS_SESSIONBUSDIR@
+DBUS_SYSTEMBUSDIR = @DBUS_SYSTEMBUSDIR@
 DEFS = @DEFS@
 DEPDIR = @DEPDIR@
 DLLTOOL = @DLLTOOL@
@@ -1031,9 +1146,10 @@ FGREP = @FGREP@
 GLIB_CFLAGS = @GLIB_CFLAGS@
 GLIB_LIBS = @GLIB_LIBS@
 GREP = @GREP@
-GSTREAMER_CFLAGS = @GSTREAMER_CFLAGS@
-GSTREAMER_LIBS = @GSTREAMER_LIBS@
-GSTREAMER_PLUGINSDIR = @GSTREAMER_PLUGINSDIR@
+GTHREAD_CFLAGS = @GTHREAD_CFLAGS@
+GTHREAD_LIBS = @GTHREAD_LIBS@
+ICAL_CFLAGS = @ICAL_CFLAGS@
+ICAL_LIBS = @ICAL_LIBS@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -1041,9 +1157,6 @@ INSTALL_SCRIPT = @INSTALL_SCRIPT@
 INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
 LD = @LD@
 LDFLAGS = @LDFLAGS@
-LEX = @LEX@
-LEXLIB = @LEXLIB@
-LEX_OUTPUT_ROOT = @LEX_OUTPUT_ROOT@
 LIBOBJS = @LIBOBJS@
 LIBS = @LIBS@
 LIBTOOL = @LIBTOOL@
@@ -1074,26 +1187,17 @@ PKG_CONFIG = @PKG_CONFIG@
 PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@
 PKG_CONFIG_PATH = @PKG_CONFIG_PATH@
 RANLIB = @RANLIB@
-READLINE_LIBS = @READLINE_LIBS@
-SAP_DRIVER = @SAP_DRIVER@
 SED = @SED@
 SET_MAKE = @SET_MAKE@
 SHELL = @SHELL@
-SNDFILE_CFLAGS = @SNDFILE_CFLAGS@
-SNDFILE_LIBS = @SNDFILE_LIBS@
-STORAGEDIR = @STORAGEDIR@
 STRIP = @STRIP@
-SYSTEMD_UNITDIR = @SYSTEMD_UNITDIR@
-TELEPHONY_DRIVER = @TELEPHONY_DRIVER@
+SYSTEMD_SYSTEMUNITDIR = @SYSTEMD_SYSTEMUNITDIR@
+SYSTEMD_USERUNITDIR = @SYSTEMD_USERUNITDIR@
 UDEV_CFLAGS = @UDEV_CFLAGS@
 UDEV_DIR = @UDEV_DIR@
 UDEV_LIBS = @UDEV_LIBS@
-USB_CFLAGS = @USB_CFLAGS@
-USB_LIBS = @USB_LIBS@
 VERSION = @VERSION@
 WARNING_CFLAGS = @WARNING_CFLAGS@
-YACC = @YACC@
-YFLAGS = @YFLAGS@
 abs_builddir = @abs_builddir@
 abs_srcdir = @abs_srcdir@
 abs_top_builddir = @abs_top_builddir@
@@ -1128,7 +1232,7 @@ includedir = @includedir@/bluetooth
 infodir = @infodir@
 install_sh = @install_sh@
 libdir = @libdir@
-libexecdir = @libexecdir@
+libexecdir = @libexecdir@/bluetooth
 localedir = @localedir@
 localstatedir = @localstatedir@
 mandir = @mandir@
@@ -1147,126 +1251,118 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 AM_MAKEFLAGS = --no-print-directory
-lib_LTLIBRARIES = lib/libbluetooth.la
-noinst_LIBRARIES = $(am__append_10) $(am__append_14)
-noinst_LTLIBRARIES = lib/libbluetooth-private.la $(am__append_1)
-dist_man_MANS = $(am__append_43) $(am__append_48) $(am__append_50) \
-       $(am__append_53) $(am__append_59) $(am__append_63) \
-       $(am__append_66) $(am__append_69)
+lib_LTLIBRARIES = $(am__append_2)
+noinst_LIBRARIES = $(am__append_7)
+noinst_LTLIBRARIES = lib/libbluetooth-internal.la \
+       gdbus/libgdbus-internal.la
+dist_man_MANS = $(am__append_17) $(am__append_19)
 dist_noinst_MANS = 
-CLEANFILES = $(builtin_files) tools/lexer.c tools/parser.c \
-       tools/parser.h $(rules_DATA)
-EXTRA_DIST = plugins/hal.c plugins/formfactor.c 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 \
-       audio/telephony-maemo5.c audio/telephony-ofono.c \
-       audio/telephony-maemo6.c sap/sap-dummy.c sap/sap-u8500.c \
-       proximity/proximity.conf audio/bluetooth.conf $(am__append_44) \
-       tools/rfcomm.conf $(am__append_49) $(am__append_51) \
-       $(am__append_54) tools/dfubabel.1 tools/avctrl.8 \
-       $(am__append_60) $(am__append_61) 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-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/simple-player test/test-nap \
-       $(am__append_64) $(am__append_67) $(am__append_70) \
-       scripts/bluetooth-hid2hci.rules scripts/bluetooth-serial.rules \
-       doc/manager-api.txt doc/adapter-api.txt doc/device-api.txt \
-       doc/service-api.txt doc/agent-api.txt doc/attribute-api.txt \
-       doc/serial-api.txt doc/network-api.txt doc/input-api.txt \
-       doc/audio-api.txt doc/control-api.txt doc/hfp-api.txt \
-       doc/health-api.txt doc/sap-api.txt doc/media-api.txt \
-       doc/assigned-numbers.txt
-include_HEADERS = $(lib_headers)
+CLEANFILES = $(builtin_files) src/bluetooth.service \
+       obexd/src/builtin.h $(builtin_files) obexd/src/obex.service \
+       $(am__append_29)
+EXTRA_DIST = src/bluetooth.service.in src/org.bluez.service \
+       src/genbuiltin src/bluetooth.conf src/main.conf \
+       profiles/network/network.conf profiles/input/input.conf \
+       profiles/proximity/proximity.conf $(am__append_18) \
+       $(am__append_20) $(am__append_21) obexd/src/obex.service.in \
+       obexd/src/org.bluez.obex.service obexd/src/genbuiltin \
+       android/Android.mk android/log.c android/hal-ipc-api.txt \
+       tools/hid2hci.rules $(test_scripts) doc/assigned-numbers.txt \
+       doc/supported-features.txt doc/mgmt-api.txt \
+       doc/adapter-api.txt doc/device-api.txt doc/agent-api.txt \
+       doc/profile-api.txt doc/network-api.txt doc/media-api.txt \
+       doc/health-api.txt doc/sap-api.txt doc/alert-api.txt \
+       doc/proximity-api.txt doc/heartrate-api.txt \
+       doc/thermometer-api.txt doc/cyclingspeed-api.txt \
+       doc/obex-api.txt doc/obex-agent-api.txt tools/magic.btsnoop
+include_HEADERS = $(am__append_1)
 AM_CFLAGS = $(WARNING_CFLAGS) $(MISC_CFLAGS) @DBUS_CFLAGS@ \
        @GLIB_CFLAGS@ $(am__empty)
 AM_LDFLAGS = $(MISC_LDFLAGS)
-@DATAFILES_TRUE@dbusdir = $(sysconfdir)/dbus-1/system.d
-@DATAFILES_TRUE@dbusservicedir = $(datadir)/dbus-1/system-services
+@DATAFILES_TRUE@dbusdir = @DBUS_CONFDIR@/dbus-1/system.d
 @DATAFILES_TRUE@dbus_DATA = src/bluetooth.conf
-@DATAFILES_TRUE@dbusservice_DATA = src/org.bluez.service
 @DATAFILES_TRUE@confdir = $(sysconfdir)/bluetooth
-@DATAFILES_TRUE@conf_DATA = src/main.conf $(am__append_38)
+@DATAFILES_TRUE@conf_DATA = 
 @DATAFILES_TRUE@statedir = $(localstatedir)/lib/bluetooth
 @DATAFILES_TRUE@state_DATA = 
-@DATAFILES_TRUE@@SYSTEMD_TRUE@systemdunitdir = @SYSTEMD_UNITDIR@
-@DATAFILES_TRUE@@SYSTEMD_TRUE@systemdunit_DATA = src/bluetooth.service
+@SYSTEMD_TRUE@systemdsystemunitdir = @SYSTEMD_SYSTEMUNITDIR@
+@SYSTEMD_TRUE@systemdsystemunit_DATA = src/bluetooth.service
+@SYSTEMD_TRUE@dbussystembusdir = @DBUS_SYSTEMBUSDIR@
+@SYSTEMD_TRUE@dbussystembus_DATA = src/org.bluez.service
 plugindir = $(libdir)/bluetooth/plugins
 @MAINTAINER_MODE_FALSE@build_plugindir = $(plugindir)
 @MAINTAINER_MODE_TRUE@build_plugindir = $(abs_top_srcdir)/plugins/.libs
-plugin_LTLIBRARIES = $(am__append_37)
-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/a2mp.h
-
+plugin_LTLIBRARIES = $(am__append_12)
+lib_sources = lib/bluetooth.c lib/hci.c lib/sdp.c
+lib_headers = lib/bluetooth.h lib/hci.h lib/hci_lib.h \
+               lib/sco.h lib/l2cap.h lib/sdp.h lib/sdp_lib.h \
+               lib/rfcomm.h lib/bnep.h lib/cmtp.h lib/hidp.h
+
+extra_headers = lib/mgmt.h lib/uuid.h lib/a2mp.h lib/amp.h
+extra_sources = lib/uuid.c
 local_headers = $(foreach file,$(lib_headers), lib/bluetooth/$(notdir $(file)))
-BUILT_SOURCES = $(local_headers) src/builtin.h
-lib_libbluetooth_la_SOURCES = $(lib_headers) \
-                               lib/bluetooth.c lib/hci.c lib/sdp.c lib/uuid.c
-
-lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 16:0:13
-lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
-lib_libbluetooth_private_la_SOURCES = $(lib_libbluetooth_la_SOURCES)
-@SBC_TRUE@sbc_libsbc_la_SOURCES = sbc/sbc.h sbc/sbc.c sbc/sbc_math.h sbc/sbc_tables.h \
-@SBC_TRUE@                     sbc/sbc_primitives.h sbc/sbc_primitives.c \
-@SBC_TRUE@                     sbc/sbc_primitives_mmx.h sbc/sbc_primitives_mmx.c \
-@SBC_TRUE@                     sbc/sbc_primitives_iwmmxt.h sbc/sbc_primitives_iwmmxt.c \
-@SBC_TRUE@                     sbc/sbc_primitives_neon.h sbc/sbc_primitives_neon.c \
-@SBC_TRUE@                     sbc/sbc_primitives_armv6.h sbc/sbc_primitives_armv6.c
-
-@SBC_TRUE@sbc_libsbc_la_CFLAGS = $(AM_CFLAGS) -finline-functions -fgcse-after-reload \
-@SBC_TRUE@                                     -funswitch-loops -funroll-loops
-
-@SBC_TRUE@sbc_sbcdec_SOURCES = sbc/sbcdec.c sbc/formats.h
-@SBC_TRUE@sbc_sbcdec_LDADD = sbc/libsbc.la
-@SBC_TRUE@sbc_sbcenc_SOURCES = sbc/sbcenc.c sbc/formats.h
-@SBC_TRUE@sbc_sbcenc_LDADD = sbc/libsbc.la
-@SBC_TRUE@@SNDFILE_TRUE@sbc_sbctester_LDADD = @SNDFILE_LIBS@ -lm
-@SBC_TRUE@@SNDFILE_TRUE@sbc_sbctest_CFLAGS = $(AM_CFLAGS) @SNDFILE_CFLAGS@
+BUILT_SOURCES = $(local_headers) src/builtin.h obexd/src/builtin.h
+@LIBRARY_TRUE@lib_libbluetooth_la_SOURCES = $(lib_headers) $(lib_sources)
+@LIBRARY_TRUE@lib_libbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -version-info 20:1:17
+@LIBRARY_TRUE@lib_libbluetooth_la_DEPENDENCIES = $(local_headers)
+lib_libbluetooth_internal_la_SOURCES = $(lib_headers) $(lib_sources) \
+                                       $(extra_headers) $(extra_sources)
+
+gdbus_libgdbus_internal_la_SOURCES = gdbus/gdbus.h \
+                               gdbus/mainloop.c gdbus/watch.c \
+                               gdbus/object.c gdbus/client.c gdbus/polkit.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
-
-gdbus_sources = gdbus/gdbus.h gdbus/mainloop.c gdbus/watch.c \
-                                       gdbus/object.c gdbus/polkit.c
+               attrib/gattrib.h attrib/gattrib.c \
+               attrib/gatt-service.h attrib/gatt-service.c
 
 btio_sources = btio/btio.h btio/btio.c
-builtin_modules = $(am__append_5) $(am__append_7) $(am__append_11) \
-       $(am__append_15) $(am__append_17) $(am__append_19) \
-       $(am__append_21) $(am__append_23) $(am__append_25) hciops \
-       mgmtops $(am__append_27) $(am__append_29) storage adaptername \
-       $(am__append_31) $(am__append_33) $(am__append_35)
-builtin_sources = $(am__append_6) $(am__append_8) $(am__append_12) \
-       $(am__append_16) $(am__append_18) $(am__append_20) \
-       $(am__append_22) $(am__append_24) $(am__append_26) \
-       plugins/hciops.c plugins/mgmtops.c $(am__append_28) \
-       $(am__append_30) plugins/storage.c plugins/adaptername.c \
-       $(am__append_32) $(am__append_34) $(am__append_36)
-builtin_nodist = $(am__append_9) $(am__append_13)
-mcap_sources = $(am__append_4)
-@AUDIOPLUGIN_TRUE@audio_libtelephony_a_SOURCES = audio/telephony.h audio/telephony-dummy.c \
-@AUDIOPLUGIN_TRUE@                             audio/telephony-maemo5.c audio/telephony-ofono.c \
-@AUDIOPLUGIN_TRUE@                             audio/telephony-maemo6.c
-
-@SAPPLUGIN_TRUE@sap_libsap_a_SOURCES = sap/sap.h sap/sap-dummy.c sap/sap-u8500.c
+gobex_sources = gobex/gobex.h gobex/gobex.c \
+                       gobex/gobex-defs.h gobex/gobex-defs.c \
+                       gobex/gobex-packet.c gobex/gobex-packet.h \
+                       gobex/gobex-header.c gobex/gobex-header.h \
+                       gobex/gobex-transfer.c gobex/gobex-debug.h \
+                       gobex/gobex-apparam.c gobex/gobex-apparam.h
+
+builtin_modules = hostname wiimote autopair policy $(am__append_3) \
+       $(am__append_5) a2dp avrcp network input hog $(am__append_8) \
+       gatt scanparam deviceinfo $(am__append_10)
+builtin_sources = plugins/hostname.c plugins/wiimote.c \
+       plugins/autopair.c plugins/policy.c $(am__append_4) \
+       $(am__append_6) profiles/audio/source.h \
+       profiles/audio/source.c profiles/audio/sink.h \
+       profiles/audio/sink.c profiles/audio/a2dp.h \
+       profiles/audio/a2dp.c profiles/audio/avdtp.h \
+       profiles/audio/avdtp.c profiles/audio/media.h \
+       profiles/audio/media.c profiles/audio/transport.h \
+       profiles/audio/transport.c profiles/audio/a2dp-codecs.h \
+       profiles/audio/control.h profiles/audio/control.c \
+       profiles/audio/avctp.h profiles/audio/avctp.c \
+       profiles/audio/avrcp.h profiles/audio/avrcp.c \
+       profiles/audio/player.h profiles/audio/player.c \
+       profiles/network/manager.c profiles/network/common.h \
+       profiles/network/common.c profiles/network/server.h \
+       profiles/network/server.c profiles/network/connection.h \
+       profiles/network/connection.c profiles/input/manager.c \
+       profiles/input/server.h profiles/input/server.c \
+       profiles/input/device.h profiles/input/device.c \
+       profiles/input/hog.c profiles/input/uhid_copy.h \
+       profiles/input/suspend.h profiles/input/suspend-dummy.c \
+       $(am__append_9) profiles/gatt/gas.c profiles/scanparam/scan.c \
+       profiles/deviceinfo/deviceinfo.c $(am__append_11)
+builtin_nodist = 
+@EXPERIMENTAL_TRUE@profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
 @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_SOURCES = plugins/external-dummy.c
 @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version \
 @MAINTAINER_MODE_TRUE@                             -no-undefined
 
 @MAINTAINER_MODE_TRUE@plugins_external_dummy_la_CFLAGS = $(AM_CFLAGS) -fvisibility=hidden
-src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
+src_bluetoothd_SOURCES = $(builtin_sources) \
                        $(attrib_sources) $(btio_sources) \
-                       $(mcap_sources) src/bluetooth.ver \
+                       src/bluetooth.ver \
                        src/main.c src/log.h src/log.c \
+                       src/systemd.h src/systemd.c \
                        src/rfkill.c src/hcid.h src/sdpd.h \
                        src/sdpd-server.c src/sdpd-request.c \
                        src/sdpd-service.c src/sdpd-database.c \
@@ -1275,25 +1371,29 @@ src_bluetoothd_SOURCES = $(gdbus_sources) $(builtin_sources) \
                        src/sdp-client.h src/sdp-client.c \
                        src/textfile.h src/textfile.c \
                        src/glib-helper.h src/glib-helper.c \
-                       src/oui.h src/oui.c src/uinput.h src/ppoll.h \
+                       src/uinput.h \
                        src/plugin.h src/plugin.c \
                        src/storage.h src/storage.c \
                        src/agent.h src/agent.c \
                        src/error.h src/error.c \
-                       src/manager.h src/manager.c \
                        src/adapter.h src/adapter.c \
+                       src/profile.h src/profile.c \
+                       src/service.h src/service.c \
                        src/device.h src/device.c src/attio.h \
                        src/dbus-common.c src/dbus-common.h \
-                       src/event.h src/event.c \
-                       src/oob.h src/oob.c src/eir.h src/eir.c
+                       src/eir.h src/eir.c \
+                       src/shared/util.h src/shared/util.c \
+                       src/shared/mgmt.h src/shared/mgmt.c
 
-src_bluetoothd_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @DBUS_LIBS@ \
-                                                               -ldl -lrt
+src_bluetoothd_LDADD = lib/libbluetooth-internal.la gdbus/libgdbus-internal.la \
+                       @GLIB_LIBS@ @DBUS_LIBS@ -ldl -lrt
 
 src_bluetoothd_LDFLAGS = $(AM_LDFLAGS) -Wl,--export-dynamic \
                                -Wl,--version-script=$(srcdir)/src/bluetooth.ver
 
-src_bluetoothd_DEPENDENCIES = lib/libbluetooth-private.la
+src_bluetoothd_DEPENDENCIES = lib/libbluetooth-internal.la \
+                               gdbus/libgdbus-internal.la src/bluetooth.service
+
 src_bluetoothd_CFLAGS = $(AM_CFLAGS) -DBLUETOOTH_PLUGIN_BUILTIN \
                                        -DPLUGINDIR=\""$(build_plugindir)"\"
 
@@ -1301,60 +1401,84 @@ src_bluetoothd_SHORTNAME = bluetoothd
 builtin_files = src/builtin.h $(builtin_nodist)
 nodist_src_bluetoothd_SOURCES = $(builtin_files)
 man_MANS = src/bluetoothd.8
-@ALSA_TRUE@alsadir = $(libdir)/alsa-lib
-@ALSA_TRUE@alsa_LTLIBRARIES = audio/libasound_module_pcm_bluetooth.la \
-@ALSA_TRUE@                            audio/libasound_module_ctl_bluetooth.la
-
-@ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_SOURCES = audio/pcm_bluetooth.c \
-@ALSA_TRUE@                                    audio/rtp.h audio/ipc.h audio/ipc.c
-
-@ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \
-@ALSA_TRUE@                                              -avoid-version
-
-@ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_LIBADD = sbc/libsbc.la \
-@ALSA_TRUE@                                    lib/libbluetooth-private.la @ALSA_LIBS@
-
-@ALSA_TRUE@audio_libasound_module_pcm_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@
-@ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_SOURCES = audio/ctl_bluetooth.c \
-@ALSA_TRUE@                                    audio/rtp.h audio/ipc.h audio/ipc.c
-
-@ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module \
-@ALSA_TRUE@                                              -avoid-version
-
-@ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_LIBADD = \
-@ALSA_TRUE@                                    lib/libbluetooth-private.la @ALSA_LIBS@
-
-@ALSA_TRUE@audio_libasound_module_ctl_bluetooth_la_CFLAGS = $(AM_CFLAGS) @ALSA_CFLAGS@
-@ALSA_TRUE@@DATAFILES_TRUE@alsaconfdir = $(datadir)/alsa
-@ALSA_TRUE@@DATAFILES_TRUE@alsaconf_DATA = audio/bluetooth.conf
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamerdir = $(libdir)/gstreamer-0.10
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@gstreamer_LTLIBRARIES = audio/libgstbluetooth.la
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_SOURCES = audio/gstbluetooth.c audio/gstpragma.h \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstsbcenc.h audio/gstsbcenc.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstsbcdec.h audio/gstsbcdec.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstsbcparse.h audio/gstsbcparse.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstavdtpsink.h audio/gstavdtpsink.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gsta2dpsink.h audio/gsta2dpsink.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstsbcutil.h audio/gstsbcutil.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/gstrtpsbcpay.h audio/gstrtpsbcpay.c \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                             audio/rtp.h audio/ipc.h audio/ipc.c
-
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_LDFLAGS = $(AM_LDFLAGS) -module -avoid-version
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_LIBADD = sbc/libsbc.la lib/libbluetooth-private.la \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                                             @DBUS_LIBS@ @GSTREAMER_LIBS@ \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                                             -lgstaudio-0.10 -lgstrtp-0.10
-
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@audio_libgstbluetooth_la_CFLAGS = -fvisibility=hidden -fno-strict-aliasing \
-@AUDIOPLUGIN_TRUE@@GSTREAMER_TRUE@                               $(AM_CFLAGS) @DBUS_CFLAGS@ @GSTREAMER_CFLAGS@
-
-@TOOLS_TRUE@tools_rfcomm_SOURCES = tools/rfcomm.c tools/parser.y tools/lexer.l \
-@TOOLS_TRUE@                                   tools/kword.h tools/kword.c
-
-@TOOLS_TRUE@EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \
-@TOOLS_TRUE@                                                   tools/lexer.c
-
-@TOOLS_TRUE@tools_rfcomm_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_l2ping_LDADD = lib/libbluetooth-private.la
+test_scripts = test/sap_client.py test/bluezutils.py test/dbusdef.py \
+       test/monitor-bluetooth test/list-devices test/test-discovery \
+       test/test-manager test/test-adapter test/test-device \
+       test/simple-agent test/simple-service test/simple-endpoint \
+       test/test-sap-server test/test-proximity test/test-network \
+       test/test-thermometer test/test-profile 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/simple-player test/test-nap \
+       test/test-heartrate test/test-alert test/test-hfp \
+       test/test-cyclingspeed
+@CLIENT_TRUE@client_bluetoothctl_SOURCES = client/main.c \
+@CLIENT_TRUE@                                  client/display.h client/display.c \
+@CLIENT_TRUE@                                  client/agent.h client/agent.c \
+@CLIENT_TRUE@                                  monitor/uuid.h monitor/uuid.c
+
+@CLIENT_TRUE@client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
+@CLIENT_TRUE@                          -lreadline
+
+@MONITOR_TRUE@monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
+@MONITOR_TRUE@                                 monitor/mainloop.h monitor/mainloop.c \
+@MONITOR_TRUE@                                 monitor/display.h monitor/display.c \
+@MONITOR_TRUE@                                 monitor/hcidump.h monitor/hcidump.c \
+@MONITOR_TRUE@                                 monitor/btsnoop.h monitor/btsnoop.c \
+@MONITOR_TRUE@                                 monitor/control.h monitor/control.c \
+@MONITOR_TRUE@                                 monitor/packet.h monitor/packet.c \
+@MONITOR_TRUE@                                 monitor/vendor.h monitor/vendor.c \
+@MONITOR_TRUE@                                 monitor/lmp.h monitor/lmp.c \
+@MONITOR_TRUE@                                 monitor/l2cap.h monitor/l2cap.c \
+@MONITOR_TRUE@                                 monitor/uuid.h monitor/uuid.c \
+@MONITOR_TRUE@                                 monitor/sdp.h monitor/sdp.c \
+@MONITOR_TRUE@                                 monitor/crc.h monitor/crc.c \
+@MONITOR_TRUE@                                 monitor/ll.h monitor/ll.c
+
+@MONITOR_TRUE@monitor_btmon_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                                    monitor/mainloop.h monitor/mainloop.c \
+@EXPERIMENTAL_TRUE@                                    emulator/server.h emulator/server.c \
+@EXPERIMENTAL_TRUE@                                    emulator/vhci.h emulator/vhci.c \
+@EXPERIMENTAL_TRUE@                                    emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                                    emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                                    emulator/amp.h emulator/amp.c
+
+@EXPERIMENTAL_TRUE@emulator_b1ee_SOURCES = emulator/b1ee.c monitor/mainloop.h monitor/mainloop.c
+@EXPERIMENTAL_TRUE@tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                            src/shared/util.h src/shared/util.c \
+@EXPERIMENTAL_TRUE@                            src/shared/mgmt.h src/shared/mgmt.c \
+@EXPERIMENTAL_TRUE@                            src/shared/hciemu.h src/shared/hciemu.c \
+@EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
+
+@EXPERIMENTAL_TRUE@tools_mgmt_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@EXPERIMENTAL_TRUE@tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                            src/shared/util.h src/shared/util.c \
+@EXPERIMENTAL_TRUE@                            src/shared/mgmt.h src/shared/mgmt.c \
+@EXPERIMENTAL_TRUE@                            src/shared/hciemu.h src/shared/hciemu.c \
+@EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
+
+@EXPERIMENTAL_TRUE@tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@EXPERIMENTAL_TRUE@tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                            src/shared/hciemu.h src/shared/hciemu.c \
+@EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
+
+@EXPERIMENTAL_TRUE@tools_gap_tester_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+@EXPERIMENTAL_TRUE@tools_sco_tester_SOURCES = tools/sco-tester.c monitor/bt.h \
+@EXPERIMENTAL_TRUE@                            emulator/btdev.h emulator/btdev.c \
+@EXPERIMENTAL_TRUE@                            emulator/bthost.h emulator/bthost.c \
+@EXPERIMENTAL_TRUE@                            src/shared/util.h src/shared/util.c \
+@EXPERIMENTAL_TRUE@                            src/shared/mgmt.h src/shared/mgmt.c \
+@EXPERIMENTAL_TRUE@                            src/shared/hciemu.h src/shared/hciemu.c \
+@EXPERIMENTAL_TRUE@                            src/shared/tester.h src/shared/tester.c
+
+@EXPERIMENTAL_TRUE@tools_sco_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 @TOOLS_TRUE@tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
 @TOOLS_TRUE@                                           tools/hciattach_st.c \
 @TOOLS_TRUE@                                           tools/hciattach_ti.c \
@@ -1363,129 +1487,259 @@ man_MANS = src/bluetoothd.8
 @TOOLS_TRUE@                                           tools/hciattach_qualcomm.c \
 @TOOLS_TRUE@                                           tools/hciattach_intel.c
 
-@TOOLS_TRUE@tools_hciattach_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c \
-@TOOLS_TRUE@                                           src/textfile.h src/textfile.c
-
-@TOOLS_TRUE@tools_hciconfig_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
-@TOOLS_TRUE@                                           src/textfile.h src/textfile.c
-
-@TOOLS_TRUE@tools_hcitool_LDADD = lib/libbluetooth-private.la
+@TOOLS_TRUE@tools_hciattach_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
+@TOOLS_TRUE@tools_hciconfig_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c
+@TOOLS_TRUE@tools_hcitool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ @UDEV_LIBS@
+@TOOLS_TRUE@tools_hcidump_SOURCES = tools/hcidump.c \
+@TOOLS_TRUE@                           tools/parser/parser.h tools/parser/parser.c \
+@TOOLS_TRUE@                           tools/parser/lmp.c \
+@TOOLS_TRUE@                           tools/parser/hci.c \
+@TOOLS_TRUE@                           tools/parser/l2cap.h tools/parser/l2cap.c \
+@TOOLS_TRUE@                           tools/parser/amp.c \
+@TOOLS_TRUE@                           tools/parser/smp.c \
+@TOOLS_TRUE@                           tools/parser/att.c \
+@TOOLS_TRUE@                           tools/parser/sdp.h tools/parser/sdp.c \
+@TOOLS_TRUE@                           tools/parser/rfcomm.h tools/parser/rfcomm.c \
+@TOOLS_TRUE@                           tools/parser/bnep.c \
+@TOOLS_TRUE@                           tools/parser/cmtp.c \
+@TOOLS_TRUE@                           tools/parser/hidp.c \
+@TOOLS_TRUE@                           tools/parser/hcrp.c \
+@TOOLS_TRUE@                           tools/parser/avdtp.c \
+@TOOLS_TRUE@                           tools/parser/avctp.c \
+@TOOLS_TRUE@                           tools/parser/avrcp.c \
+@TOOLS_TRUE@                           tools/parser/sap.c \
+@TOOLS_TRUE@                           tools/parser/obex.c \
+@TOOLS_TRUE@                           tools/parser/capi.c \
+@TOOLS_TRUE@                           tools/parser/ppp.c \
+@TOOLS_TRUE@                           tools/parser/tcpip.c \
+@TOOLS_TRUE@                           tools/parser/ericsson.c \
+@TOOLS_TRUE@                           tools/parser/csr.c \
+@TOOLS_TRUE@                           tools/parser/bpa.c
+
+@TOOLS_TRUE@tools_hcidump_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_rfcomm_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_rctest_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_l2test_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_l2ping_LDADD = lib/libbluetooth-internal.la
 @TOOLS_TRUE@tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
-@TOOLS_TRUE@tools_sdptool_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_ciptool_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_avinfo_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_ppporc_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@mgmt_btmgmt_SOURCES = mgmt/main.c src/glib-helper.c
-@TOOLS_TRUE@mgmt_btmgmt_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@
-@TOOLS_TRUE@monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
-@TOOLS_TRUE@                                   monitor/mainloop.h monitor/mainloop.c \
-@TOOLS_TRUE@                                   monitor/hcidump.h monitor/hcidump.c \
-@TOOLS_TRUE@                                   monitor/btsnoop.h monitor/btsnoop.c \
-@TOOLS_TRUE@                                   monitor/control.h monitor/control.c \
-@TOOLS_TRUE@                                   monitor/packet.h monitor/packet.c
-
-@TOOLS_TRUE@monitor_btmon_LDADD = lib/libbluetooth-private.la
-@TOOLS_TRUE@emulator_btvirt_SOURCES = emulator/main.c monitor/bt.h \
-@TOOLS_TRUE@                                   monitor/mainloop.h monitor/mainloop.c \
-@TOOLS_TRUE@                                   emulator/server.h emulator/server.c \
-@TOOLS_TRUE@                                   emulator/vhci.h emulator/vhci.c \
-@TOOLS_TRUE@                                   emulator/btdev.h emulator/btdev.c
-
-@READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
-@READLINE_TRUE@@TOOLS_TRUE@                            attrib/gattrib.c btio/btio.c \
-@READLINE_TRUE@@TOOLS_TRUE@                            attrib/gatttool.h attrib/interactive.c \
-@READLINE_TRUE@@TOOLS_TRUE@                            attrib/utils.c src/log.c
-
-@READLINE_TRUE@@TOOLS_TRUE@attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@
-@BCCMD_TRUE@tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h \
-@BCCMD_TRUE@   tools/csr.c tools/csr_hci.c tools/csr_h4.c \
-@BCCMD_TRUE@   tools/csr_3wire.c tools/csr_bcsp.c tools/ubcsp.h \
-@BCCMD_TRUE@   tools/ubcsp.c $(am__append_46)
-@BCCMD_TRUE@tools_bccmd_LDADD = lib/libbluetooth-private.la \
-@BCCMD_TRUE@   $(am__append_47)
-@DATAFILES_TRUE@@PCMCIA_TRUE@udevdir = @UDEV_DIR@
+@TOOLS_TRUE@tools_sdptool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@TOOLS_TRUE@tools_ciptool_LDADD = lib/libbluetooth-internal.la
+@TOOLS_TRUE@tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
+@TOOLS_TRUE@                   tools/csr_hci.c tools/csr_usb.c \
+@TOOLS_TRUE@                   tools/csr_h4.c tools/csr_3wire.c \
+@TOOLS_TRUE@                   tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
+
+@TOOLS_TRUE@tools_bccmd_LDADD = lib/libbluetooth-internal.la
 @HID2HCI_TRUE@udevdir = @UDEV_DIR@
-@HID2HCI_TRUE@tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@
-@DFUTOOL_TRUE@tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c
-@DFUTOOL_TRUE@tools_dfutool_LDADD = @USB_LIBS@
-@USB_TRUE@tools_dfubabel_LDADD = @USB_LIBS@
-@USB_TRUE@tools_avctrl_LDADD = @USB_LIBS@
+@HID2HCI_TRUE@tools_hid2hci_LDADD = @UDEV_LIBS@
+@EXPERIMENTAL_TRUE@tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
+@EXPERIMENTAL_TRUE@tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
+@EXPERIMENTAL_TRUE@tools_avinfo_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_avtest_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_scotest_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_amptest_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_hwdb_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
+@EXPERIMENTAL_TRUE@tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c src/eir.c \
+@EXPERIMENTAL_TRUE@                            src/shared/util.h src/shared/util.c \
+@EXPERIMENTAL_TRUE@                            src/shared/mgmt.h src/shared/mgmt.c
+
+@EXPERIMENTAL_TRUE@tools_btmgmt_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@EXPERIMENTAL_TRUE@tools_btinfo_SOURCES = tools/btinfo.c
+@EXPERIMENTAL_TRUE@tools_btsnoop_SOURCES = tools/btsnoop.c \
+@EXPERIMENTAL_TRUE@                            src/shared/pcap.h src/shared/pcap.c \
+@EXPERIMENTAL_TRUE@                            src/shared/btsnoop.h src/shared/btsnoop.c
+
+@EXPERIMENTAL_TRUE@tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
+@EXPERIMENTAL_TRUE@tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@EXPERIMENTAL_TRUE@tools_mpris_player_SOURCES = tools/mpris-player.c
+@EXPERIMENTAL_TRUE@tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+@EXPERIMENTAL_TRUE@tools_cltest_SOURCES = tools/cltest.c monitor/mainloop.h monitor/mainloop.c
+@EXPERIMENTAL_TRUE@tools_cltest_LDADD = lib/libbluetooth-internal.la
+@READLINE_TRUE@attrib_gatttool_SOURCES = attrib/gatttool.c attrib/att.c attrib/gatt.c \
+@READLINE_TRUE@                                attrib/gattrib.c btio/btio.c \
+@READLINE_TRUE@                                attrib/gatttool.h attrib/interactive.c \
+@READLINE_TRUE@                                attrib/utils.c src/log.c client/display.c \
+@READLINE_TRUE@                                client/display.h
+
+@READLINE_TRUE@attrib_gatttool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lreadline
+@READLINE_TRUE@tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+@READLINE_TRUE@                                                tools/obex-client-tool.c
+
+@READLINE_TRUE@tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
+@READLINE_TRUE@                                                @GLIB_LIBS@ -lreadline
+
+@READLINE_TRUE@tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+@READLINE_TRUE@                                                tools/obex-server-tool.c
+
+@READLINE_TRUE@tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+@READLINE_TRUE@tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \
+@READLINE_TRUE@                                client/display.h client/display.c
+
+@READLINE_TRUE@tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \
+@READLINE_TRUE@                                @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+@READLINE_TRUE@tools_obexctl_SOURCES = tools/obexctl.c \
+@READLINE_TRUE@                                client/display.h client/display.c
+
+@READLINE_TRUE@tools_obexctl_LDADD = gdbus/libgdbus-internal.la \
+@READLINE_TRUE@                                @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+@EXPERIMENTAL_TRUE@profiles_iap_iapd_SOURCES = profiles/iap/main.c
+@EXPERIMENTAL_TRUE@profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 @CUPS_TRUE@cupsdir = $(libdir)/cups/backend
-@CUPS_TRUE@cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
-@CUPS_TRUE@                                    cups/sdp.c cups/spp.c cups/hcrp.c
-
-@CUPS_TRUE@cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la
-@TEST_TRUE@test_hciemu_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_l2test_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_rctest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_gaptest_LDADD = @DBUS_LIBS@
-@TEST_TRUE@test_sdptest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_scotest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_attest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_hstest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_avtest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_lmptest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c
-@TEST_TRUE@test_ipctest_LDADD = @GLIB_LIBS@ sbc/libsbc.la
-@TEST_TRUE@test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c
-@TEST_TRUE@test_bdaddr_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_agent_LDADD = @DBUS_LIBS@
-@TEST_TRUE@test_btiotest_SOURCES = test/btiotest.c btio/btio.h btio/btio.c
-@TEST_TRUE@test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la
-@TEST_TRUE@test_uuidtest_SOURCES = test/uuidtest.c
-@TEST_TRUE@test_uuidtest_LDADD = lib/libbluetooth-private.la
-@TEST_TRUE@test_mpris_player_SOURCES = test/mpris-player.c
-@TEST_TRUE@test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@
-@TEST_TRUE@test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
-@HIDD_TRUE@compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \
-@HIDD_TRUE@                            compat/sdp.h compat/sdp.c compat/fakehid.c \
-@HIDD_TRUE@                                            src/textfile.h src/textfile.c
-
-@HIDD_TRUE@compat_hidd_LDADD = -lm lib/libbluetooth-private.la
-@PAND_TRUE@compat_pand_SOURCES = compat/pand.c compat/pand.h \
-@PAND_TRUE@                            compat/bnep.c compat/sdp.h compat/sdp.c \
-@PAND_TRUE@                                            src/textfile.h src/textfile.c
-
-@PAND_TRUE@compat_pand_LDADD = lib/libbluetooth-private.la
-@DUND_TRUE@compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \
-@DUND_TRUE@                    compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \
-@DUND_TRUE@                                            src/textfile.h src/textfile.c
-
-@DUND_TRUE@compat_dund_LDADD = lib/libbluetooth-private.la
-@DATAFILES_TRUE@rulesdir = @UDEV_DIR@/rules.d
-@DATAFILES_TRUE@udev_files = $(am__append_71) $(am__append_72)
-@DATAFILES_TRUE@@PCMCIA_TRUE@dist_udev_SCRIPTS = scripts/bluetooth_serial
-@DATAFILES_TRUE@rules_DATA = $(foreach file,$(udev_files), scripts/97-$(notdir $(file)))
-AM_YFLAGS = -d
-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$(srcdir)/monitor $(am__append_73)
-unit_objects = $(am__append_74)
-@TEST_FALSE@unit_tests = 
-@TEST_TRUE@unit_tests = unit/test-eir
-@TEST_TRUE@unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c
-@TEST_TRUE@unit_test_eir_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @CHECK_LIBS@
-@TEST_TRUE@unit_test_eir_CFLAGS = $(AM_CFLAGS) @CHECK_CFLAGS@
+@CUPS_TRUE@profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \
+@CUPS_TRUE@                                    profiles/cups/cups.h \
+@CUPS_TRUE@                                    profiles/cups/sdp.c \
+@CUPS_TRUE@                                    profiles/cups/spp.c \
+@CUPS_TRUE@                                    profiles/cups/hcrp.c
+
+@CUPS_TRUE@profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+@CUPS_TRUE@                            lib/libbluetooth-internal.la \
+@CUPS_TRUE@                            gdbus/libgdbus-internal.la
+
+@SYSTEMD_TRUE@systemduserunitdir = @SYSTEMD_USERUNITDIR@
+@SYSTEMD_TRUE@systemduserunit_DATA = obexd/src/obex.service
+@SYSTEMD_TRUE@dbussessionbusdir = @DBUS_SESSIONBUSDIR@
+@SYSTEMD_TRUE@dbussessionbus_DATA = obexd/src/org.bluez.obex.service
+obex_plugindir = $(libdir)/obex/plugins
+obexd_builtin_modules = filesystem bluetooth $(am__append_24) opp ftp \
+       $(am__append_26) mas mns
+obexd_builtin_sources = obexd/plugins/filesystem.c \
+       obexd/plugins/filesystem.h obexd/plugins/bluetooth.c \
+       $(am__append_25) obexd/plugins/opp.c obexd/plugins/ftp.c \
+       obexd/plugins/ftp.h $(am__append_27) obexd/plugins/mas.c \
+       obexd/src/map_ap.h obexd/plugins/messages.h \
+       obexd/plugins/messages-dummy.c obexd/client/mns.c \
+       obexd/src/map_ap.h obexd/client/map-event.h
+obexd_builtin_nodist = 
+obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
+                       $(obexd_builtin_sources) \
+                       obexd/src/main.c obexd/src/obexd.h \
+                       obexd/src/plugin.h obexd/src/plugin.c \
+                       obexd/src/log.h obexd/src/log.c \
+                       obexd/src/manager.h obexd/src/manager.c \
+                       obexd/src/obex.h obexd/src/obex.c obexd/src/obex-priv.h \
+                       obexd/src/mimetype.h obexd/src/mimetype.c \
+                       obexd/src/service.h obexd/src/service.c \
+                       obexd/src/transport.h obexd/src/transport.c \
+                       obexd/src/server.h obexd/src/server.c \
+                       obexd/client/manager.h obexd/client/manager.c \
+                       obexd/client/session.h obexd/client/session.c \
+                       obexd/client/bluetooth.h obexd/client/bluetooth.c \
+                       obexd/client/sync.h obexd/client/sync.c \
+                       obexd/client/pbap.h obexd/client/pbap.c \
+                       obexd/client/ftp.h obexd/client/ftp.c \
+                       obexd/client/opp.h obexd/client/opp.c \
+                       obexd/client/map.h obexd/client/map.c \
+                       obexd/client/map-event.h obexd/client/map-event.c \
+                       obexd/client/transfer.h obexd/client/transfer.c \
+                       obexd/client/transport.h obexd/client/transport.c \
+                       obexd/client/dbus.h obexd/client/dbus.c \
+                       obexd/client/driver.h obexd/client/driver.c \
+                       obexd/src/map_ap.h
+
+obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
+                       gdbus/libgdbus-internal.la \
+                       @ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
+
+obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
+obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
+                               @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \
+                               -DPLUGINDIR=\""$(obex_plugindir)"\" \
+                               -fPIC -D_FILE_OFFSET_BITS=64
+
+obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src  \
+                               -I$(srcdir)/obexd/src -I$(srcdir)/btio \
+                               -I$(srcdir)/gobex -I$(srcdir)/gdbus
+
+obexd_src_obexd_SHORTNAME = obexd
+obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist)
+nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files)
+@ANDROID_TRUE@android_bluetoothd_SOURCES = android/main.c src/log.c
+@ANDROID_TRUE@android_bluetoothd_LDADD = @GLIB_LIBS@
+@HID2HCI_TRUE@rulesdir = @UDEV_DIR@/rules.d
+@HID2HCI_TRUE@rules_DATA = tools/97-hid2hci.rules
+@TEST_TRUE@testdir = $(pkglibdir)/test
+@TEST_TRUE@test_SCRIPTS = $(test_scripts)
+AM_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/src -I$(srcdir)/src \
+                       -I$(srcdir)/gdbus -I$(srcdir)/btio
+
+unit_tests = unit/test-eir unit/test-uuid unit/test-textfile \
+       unit/test-crc unit/test-mgmt unit/test-sdp \
+       unit/test-gdbus-client unit/test-gobex-header \
+       unit/test-gobex-packet unit/test-gobex \
+       unit/test-gobex-transfer unit/test-gobex-apparam unit/test-lib
+unit_test_eir_SOURCES = unit/test-eir.c src/eir.c src/glib-helper.c
+unit_test_eir_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_uuid_SOURCES = unit/test-uuid.c
+unit_test_uuid_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_textfile_SOURCES = unit/test-textfile.c src/textfile.h src/textfile.c
+unit_test_textfile_LDADD = @GLIB_LIBS@
+unit_test_crc_SOURCES = unit/test-crc.c monitor/crc.h monitor/crc.c
+unit_test_crc_LDADD = @GLIB_LIBS@
+unit_test_mgmt_SOURCES = unit/test-mgmt.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c
+
+unit_test_mgmt_LDADD = @GLIB_LIBS@
+unit_test_sdp_SOURCES = unit/test-sdp.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/sdpd.h src/sdpd-database.c \
+                               src/sdpd-service.c src/sdpd-request.c
+
+unit_test_sdp_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+unit_test_gdbus_client_SOURCES = unit/test-gdbus-client.c
+unit_test_gdbus_client_LDADD = gdbus/libgdbus-internal.la \
+                               @GLIB_LIBS@ @DBUS_LIBS@
+
+unit_test_gobex_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex.c
+
+unit_test_gobex_LDADD = @GLIB_LIBS@
+unit_test_gobex_packet_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-packet.c
+
+unit_test_gobex_packet_LDADD = @GLIB_LIBS@
+unit_test_gobex_header_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-header.c
+
+unit_test_gobex_header_LDADD = @GLIB_LIBS@
+unit_test_gobex_transfer_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-transfer.c
+
+unit_test_gobex_transfer_LDADD = @GLIB_LIBS@
+unit_test_gobex_apparam_SOURCES = $(gobex_sources) unit/util.c unit/util.h \
+                                               unit/test-gobex-apparam.c
+
+unit_test_gobex_apparam_LDADD = @GLIB_LIBS@
+unit_test_lib_SOURCES = unit/test-lib.c
+unit_test_lib_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 pkgconfigdir = $(libdir)/pkgconfig
-pkgconfig_DATA = bluez.pc
-DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles
+@LIBRARY_TRUE@pkgconfig_DATA = lib/bluez.pc
+DISTCHECK_CONFIGURE_FLAGS = --disable-datafiles --enable-library \
+                                       --disable-systemd --disable-udev \
+                                       --enable-android
+
 DISTCLEANFILES = $(pkgconfig_DATA)
 MAINTAINERCLEANFILES = Makefile.in \
        aclocal.m4 configure config.h.in config.sub config.guess \
-       ltmain.sh depcomp compile missing install-sh mkinstalldirs ylwrap
+       ltmain.sh depcomp compile missing install-sh mkinstalldirs test-driver
+
+SED_PROCESS = $(AM_V_GEN)$(MKDIR_P) $(dir $@) && \
+               $(SED) -e 's,@libexecdir\@,$(libexecdir),g' \
+               < $< > $@
 
 all: $(BUILT_SOURCES) config.h
        $(MAKE) $(AM_MAKEFLAGS) all-am
 
 .SUFFIXES:
-.SUFFIXES: .c .l .lo .o .obj .y
+.SUFFIXES: .c .lo .o .obj
 am--refresh: Makefile
        @:
-$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.tools $(am__configure_deps)
+$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android $(am__configure_deps)
        @for dep in $?; do \
          case '$(am__configure_deps)' in \
            *$$dep*) \
@@ -1508,7 +1762,7 @@ Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status
            echo ' cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe)'; \
            cd $(top_builddir) && $(SHELL) ./config.status $@ $(am__depfiles_maybe);; \
        esac;
-$(srcdir)/Makefile.tools:
+$(srcdir)/Makefile.plugins $(srcdir)/Makefile.tools $(srcdir)/Makefile.obexd $(srcdir)/Makefile.android:
 
 $(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES)
        $(SHELL) ./config.status --recheck
@@ -1533,114 +1787,27 @@ $(srcdir)/config.h.in: @MAINTAINER_MODE_TRUE@ $(am__configure_deps)
 
 distclean-hdr:
        -rm -f config.h stamp-h1
-doc/version.xml: $(top_builddir)/config.status $(top_srcdir)/doc/version.xml.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
 src/bluetoothd.8: $(top_builddir)/config.status $(top_srcdir)/src/bluetoothd.8.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
-src/bluetooth.service: $(top_builddir)/config.status $(top_srcdir)/src/bluetooth.service.in
-       cd $(top_builddir) && $(SHELL) ./config.status $@
-bluez.pc: $(top_builddir)/config.status $(srcdir)/bluez.pc.in
+lib/bluez.pc: $(top_builddir)/config.status $(top_srcdir)/lib/bluez.pc.in
        cd $(top_builddir) && $(SHELL) ./config.status $@
 
 clean-noinstLIBRARIES:
        -test -z "$(noinst_LIBRARIES)" || rm -f $(noinst_LIBRARIES)
-audio/$(am__dirstamp):
-       @$(MKDIR_P) audio
-       @: > audio/$(am__dirstamp)
-audio/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) audio/$(DEPDIR)
-       @: > audio/$(DEPDIR)/$(am__dirstamp)
-audio/telephony-dummy.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/telephony-maemo5.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/telephony-ofono.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/telephony-maemo6.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/libtelephony.a: $(audio_libtelephony_a_OBJECTS) $(audio_libtelephony_a_DEPENDENCIES) $(EXTRA_audio_libtelephony_a_DEPENDENCIES) audio/$(am__dirstamp)
-       $(AM_V_at)-rm -f audio/libtelephony.a
-       $(AM_V_AR)$(audio_libtelephony_a_AR) audio/libtelephony.a $(audio_libtelephony_a_OBJECTS) $(audio_libtelephony_a_LIBADD)
-       $(AM_V_at)$(RANLIB) audio/libtelephony.a
-sap/$(am__dirstamp):
-       @$(MKDIR_P) sap
-       @: > sap/$(am__dirstamp)
-sap/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) sap/$(DEPDIR)
-       @: > sap/$(DEPDIR)/$(am__dirstamp)
-sap/sap-dummy.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
-sap/sap-u8500.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
-sap/libsap.a: $(sap_libsap_a_OBJECTS) $(sap_libsap_a_DEPENDENCIES) $(EXTRA_sap_libsap_a_DEPENDENCIES) sap/$(am__dirstamp)
-       $(AM_V_at)-rm -f sap/libsap.a
-       $(AM_V_AR)$(sap_libsap_a_AR) sap/libsap.a $(sap_libsap_a_OBJECTS) $(sap_libsap_a_LIBADD)
-       $(AM_V_at)$(RANLIB) sap/libsap.a
-install-alsaLTLIBRARIES: $(alsa_LTLIBRARIES)
-       @$(NORMAL_INSTALL)
-       test -z "$(alsadir)" || $(MKDIR_P) "$(DESTDIR)$(alsadir)"
-       @list='$(alsa_LTLIBRARIES)'; test -n "$(alsadir)" || list=; \
-       list2=; for p in $$list; do \
-         if test -f $$p; then \
-           list2="$$list2 $$p"; \
-         else :; fi; \
-       done; \
-       test -z "$$list2" || { \
-         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(alsadir)'"; \
-         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(alsadir)"; \
-       }
-
-uninstall-alsaLTLIBRARIES:
-       @$(NORMAL_UNINSTALL)
-       @list='$(alsa_LTLIBRARIES)'; test -n "$(alsadir)" || list=; \
-       for p in $$list; do \
-         $(am__strip_dir) \
-         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(alsadir)/$$f'"; \
-         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(alsadir)/$$f"; \
-       done
-
-clean-alsaLTLIBRARIES:
-       -test -z "$(alsa_LTLIBRARIES)" || rm -f $(alsa_LTLIBRARIES)
-       @list='$(alsa_LTLIBRARIES)'; for p in $$list; do \
-         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
-         test "$$dir" != "$$p" || dir=.; \
-         echo "rm -f \"$${dir}/so_locations\""; \
-         rm -f "$${dir}/so_locations"; \
-       done
-install-gstreamerLTLIBRARIES: $(gstreamer_LTLIBRARIES)
-       @$(NORMAL_INSTALL)
-       test -z "$(gstreamerdir)" || $(MKDIR_P) "$(DESTDIR)$(gstreamerdir)"
-       @list='$(gstreamer_LTLIBRARIES)'; test -n "$(gstreamerdir)" || list=; \
-       list2=; for p in $$list; do \
-         if test -f $$p; then \
-           list2="$$list2 $$p"; \
-         else :; fi; \
-       done; \
-       test -z "$$list2" || { \
-         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(gstreamerdir)'"; \
-         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(gstreamerdir)"; \
-       }
-
-uninstall-gstreamerLTLIBRARIES:
-       @$(NORMAL_UNINSTALL)
-       @list='$(gstreamer_LTLIBRARIES)'; test -n "$(gstreamerdir)" || list=; \
-       for p in $$list; do \
-         $(am__strip_dir) \
-         echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(gstreamerdir)/$$f'"; \
-         $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(gstreamerdir)/$$f"; \
-       done
-
-clean-gstreamerLTLIBRARIES:
-       -test -z "$(gstreamer_LTLIBRARIES)" || rm -f $(gstreamer_LTLIBRARIES)
-       @list='$(gstreamer_LTLIBRARIES)'; for p in $$list; do \
-         dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
-         test "$$dir" != "$$p" || dir=.; \
-         echo "rm -f \"$${dir}/so_locations\""; \
-         rm -f "$${dir}/so_locations"; \
-       done
+profiles/sap/$(am__dirstamp):
+       @$(MKDIR_P) profiles/sap
+       @: > profiles/sap/$(am__dirstamp)
+profiles/sap/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/sap/$(DEPDIR)
+       @: > profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/sap-u8500.$(OBJEXT): profiles/sap/$(am__dirstamp) \
+       profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/libsap.a: $(profiles_sap_libsap_a_OBJECTS) $(profiles_sap_libsap_a_DEPENDENCIES) $(EXTRA_profiles_sap_libsap_a_DEPENDENCIES) profiles/sap/$(am__dirstamp)
+       $(AM_V_at)-rm -f profiles/sap/libsap.a
+       $(AM_V_AR)$(profiles_sap_libsap_a_AR) profiles/sap/libsap.a $(profiles_sap_libsap_a_OBJECTS) $(profiles_sap_libsap_a_LIBADD)
+       $(AM_V_at)$(RANLIB) profiles/sap/libsap.a
 install-libLTLIBRARIES: $(lib_LTLIBRARIES)
        @$(NORMAL_INSTALL)
-       test -z "$(libdir)" || $(MKDIR_P) "$(DESTDIR)$(libdir)"
        @list='$(lib_LTLIBRARIES)'; test -n "$(libdir)" || list=; \
        list2=; for p in $$list; do \
          if test -f $$p; then \
@@ -1648,6 +1815,8 @@ install-libLTLIBRARIES: $(lib_LTLIBRARIES)
          else :; fi; \
        done; \
        test -z "$$list2" || { \
+         echo " $(MKDIR_P) '$(DESTDIR)$(libdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(libdir)" || exit 1; \
          echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(libdir)'"; \
          $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(libdir)"; \
        }
@@ -1680,7 +1849,6 @@ clean-noinstLTLIBRARIES:
        done
 install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
        @$(NORMAL_INSTALL)
-       test -z "$(plugindir)" || $(MKDIR_P) "$(DESTDIR)$(plugindir)"
        @list='$(plugin_LTLIBRARIES)'; test -n "$(plugindir)" || list=; \
        list2=; for p in $$list; do \
          if test -f $$p; then \
@@ -1688,6 +1856,8 @@ install-pluginLTLIBRARIES: $(plugin_LTLIBRARIES)
          else :; fi; \
        done; \
        test -z "$$list2" || { \
+         echo " $(MKDIR_P) '$(DESTDIR)$(plugindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(plugindir)" || exit 1; \
          echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(plugindir)'"; \
          $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(plugindir)"; \
        }
@@ -1709,38 +1879,20 @@ clean-pluginLTLIBRARIES:
          echo "rm -f \"$${dir}/so_locations\""; \
          rm -f "$${dir}/so_locations"; \
        done
-audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo:  \
-       audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo:  \
-       audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp)
-audio/libasound_module_ctl_bluetooth.la: $(audio_libasound_module_ctl_bluetooth_la_OBJECTS) $(audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES) $(EXTRA_audio_libasound_module_ctl_bluetooth_la_DEPENDENCIES) audio/$(am__dirstamp)
-       $(AM_V_CCLD)$(audio_libasound_module_ctl_bluetooth_la_LINK) $(am_audio_libasound_module_ctl_bluetooth_la_rpath) $(audio_libasound_module_ctl_bluetooth_la_OBJECTS) $(audio_libasound_module_ctl_bluetooth_la_LIBADD) $(LIBS)
-audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo:  \
-       audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo:  \
-       audio/$(am__dirstamp) audio/$(DEPDIR)/$(am__dirstamp)
-audio/libasound_module_pcm_bluetooth.la: $(audio_libasound_module_pcm_bluetooth_la_OBJECTS) $(audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES) $(EXTRA_audio_libasound_module_pcm_bluetooth_la_DEPENDENCIES) audio/$(am__dirstamp)
-       $(AM_V_CCLD)$(audio_libasound_module_pcm_bluetooth_la_LINK) $(am_audio_libasound_module_pcm_bluetooth_la_rpath) $(audio_libasound_module_pcm_bluetooth_la_OBJECTS) $(audio_libasound_module_pcm_bluetooth_la_LIBADD) $(LIBS)
-audio/audio_libgstbluetooth_la-gstbluetooth.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstsbcenc.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstsbcdec.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstsbcparse.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstavdtpsink.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gsta2dpsink.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstsbcutil.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/audio_libgstbluetooth_la-ipc.lo: audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/libgstbluetooth.la: $(audio_libgstbluetooth_la_OBJECTS) $(audio_libgstbluetooth_la_DEPENDENCIES) $(EXTRA_audio_libgstbluetooth_la_DEPENDENCIES) audio/$(am__dirstamp)
-       $(AM_V_CCLD)$(audio_libgstbluetooth_la_LINK) $(am_audio_libgstbluetooth_la_rpath) $(audio_libgstbluetooth_la_OBJECTS) $(audio_libgstbluetooth_la_LIBADD) $(LIBS)
+gdbus/$(am__dirstamp):
+       @$(MKDIR_P) gdbus
+       @: > gdbus/$(am__dirstamp)
+gdbus/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) gdbus/$(DEPDIR)
+       @: > gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/mainloop.lo: gdbus/$(am__dirstamp) \
+       gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/watch.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/object.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/client.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/polkit.lo: gdbus/$(am__dirstamp) gdbus/$(DEPDIR)/$(am__dirstamp)
+gdbus/libgdbus-internal.la: $(gdbus_libgdbus_internal_la_OBJECTS) $(gdbus_libgdbus_internal_la_DEPENDENCIES) $(EXTRA_gdbus_libgdbus_internal_la_DEPENDENCIES) gdbus/$(am__dirstamp)
+       $(AM_V_CCLD)$(LINK)  $(gdbus_libgdbus_internal_la_OBJECTS) $(gdbus_libgdbus_internal_la_LIBADD) $(LIBS)
 lib/$(am__dirstamp):
        @$(MKDIR_P) lib
        @: > lib/$(am__dirstamp)
@@ -1751,10 +1903,10 @@ lib/bluetooth.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp)
 lib/hci.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp)
 lib/sdp.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp)
 lib/uuid.lo: lib/$(am__dirstamp) lib/$(DEPDIR)/$(am__dirstamp)
-lib/libbluetooth-private.la: $(lib_libbluetooth_private_la_OBJECTS) $(lib_libbluetooth_private_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_private_la_DEPENDENCIES) lib/$(am__dirstamp)
-       $(AM_V_CCLD)$(LINK)  $(lib_libbluetooth_private_la_OBJECTS) $(lib_libbluetooth_private_la_LIBADD) $(LIBS)
+lib/libbluetooth-internal.la: $(lib_libbluetooth_internal_la_OBJECTS) $(lib_libbluetooth_internal_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_internal_la_DEPENDENCIES) lib/$(am__dirstamp)
+       $(AM_V_CCLD)$(LINK)  $(lib_libbluetooth_internal_la_OBJECTS) $(lib_libbluetooth_internal_la_LIBADD) $(LIBS)
 lib/libbluetooth.la: $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_DEPENDENCIES) $(EXTRA_lib_libbluetooth_la_DEPENDENCIES) lib/$(am__dirstamp)
-       $(AM_V_CCLD)$(lib_libbluetooth_la_LINK) -rpath $(libdir) $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_LIBADD) $(LIBS)
+       $(AM_V_CCLD)$(lib_libbluetooth_la_LINK) $(am_lib_libbluetooth_la_rpath) $(lib_libbluetooth_la_OBJECTS) $(lib_libbluetooth_la_LIBADD) $(LIBS)
 plugins/$(am__dirstamp):
        @$(MKDIR_P) plugins
        @: > plugins/$(am__dirstamp)
@@ -1765,30 +1917,13 @@ plugins/plugins_external_dummy_la-external-dummy.lo:  \
        plugins/$(am__dirstamp) plugins/$(DEPDIR)/$(am__dirstamp)
 plugins/external-dummy.la: $(plugins_external_dummy_la_OBJECTS) $(plugins_external_dummy_la_DEPENDENCIES) $(EXTRA_plugins_external_dummy_la_DEPENDENCIES) plugins/$(am__dirstamp)
        $(AM_V_CCLD)$(plugins_external_dummy_la_LINK) $(am_plugins_external_dummy_la_rpath) $(plugins_external_dummy_la_OBJECTS) $(plugins_external_dummy_la_LIBADD) $(LIBS)
-sbc/$(am__dirstamp):
-       @$(MKDIR_P) sbc
-       @: > sbc/$(am__dirstamp)
-sbc/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) sbc/$(DEPDIR)
-       @: > sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc_primitives.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc_primitives_mmx.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc_primitives_neon.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/libsbc.la: $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_DEPENDENCIES) $(EXTRA_sbc_libsbc_la_DEPENDENCIES) sbc/$(am__dirstamp)
-       $(AM_V_CCLD)$(sbc_libsbc_la_LINK) $(am_sbc_libsbc_la_rpath) $(sbc_libsbc_la_OBJECTS) $(sbc_libsbc_la_LIBADD) $(LIBS)
 install-binPROGRAMS: $(bin_PROGRAMS)
        @$(NORMAL_INSTALL)
-       test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
        @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \
+       fi; \
        for p in $$list; do echo "$$p $$p"; done | \
        sed 's/$(EXEEXT)$$//' | \
        while read p p1; do if test -f $$p || test -f $$p1; \
@@ -1830,8 +1965,11 @@ clean-binPROGRAMS:
        rm -f $$list
 install-cupsPROGRAMS: $(cups_PROGRAMS)
        @$(NORMAL_INSTALL)
-       test -z "$(cupsdir)" || $(MKDIR_P) "$(DESTDIR)$(cupsdir)"
        @list='$(cups_PROGRAMS)'; test -n "$(cupsdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(cupsdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(cupsdir)" || exit 1; \
+       fi; \
        for p in $$list; do echo "$$p $$p"; done | \
        sed 's/$(EXEEXT)$$//' | \
        while read p p1; do if test -f $$p || test -f $$p1; \
@@ -1871,19 +2009,13 @@ clean-cupsPROGRAMS:
        list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
        echo " rm -f" $$list; \
        rm -f $$list
-
-clean-noinstPROGRAMS:
-       @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
-       echo " rm -f" $$list; \
-       rm -f $$list || exit $$?; \
-       test -n "$(EXEEXT)" || exit 0; \
-       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
-       echo " rm -f" $$list; \
-       rm -f $$list
-install-sbinPROGRAMS: $(sbin_PROGRAMS)
+install-libexecPROGRAMS: $(libexec_PROGRAMS)
        @$(NORMAL_INSTALL)
-       test -z "$(sbindir)" || $(MKDIR_P) "$(DESTDIR)$(sbindir)"
-       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \
+       fi; \
        for p in $$list; do echo "$$p $$p"; done | \
        sed 's/$(EXEEXT)$$//' | \
        while read p p1; do if test -f $$p || test -f $$p1; \
@@ -1900,23 +2032,32 @@ install-sbinPROGRAMS: $(sbin_PROGRAMS)
        while read type dir files; do \
            if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
            test -z "$$files" || { \
-           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(sbindir)$$dir'"; \
-           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(sbindir)$$dir" || exit $$?; \
+           echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \
+           $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \
            } \
        ; done
 
-uninstall-sbinPROGRAMS:
+uninstall-libexecPROGRAMS:
        @$(NORMAL_UNINSTALL)
-       @list='$(sbin_PROGRAMS)'; test -n "$(sbindir)" || list=; \
+       @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \
        files=`for p in $$list; do echo "$$p"; done | \
          sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \
              -e 's/$$/$(EXEEXT)/' `; \
        test -n "$$list" || exit 0; \
-       echo " ( cd '$(DESTDIR)$(sbindir)' && rm -f" $$files ")"; \
-       cd "$(DESTDIR)$(sbindir)" && rm -f $$files
+       echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \
+       cd "$(DESTDIR)$(libexecdir)" && rm -f $$files
 
-clean-sbinPROGRAMS:
-       @list='$(sbin_PROGRAMS)'; test -n "$$list" || exit 0; \
+clean-libexecPROGRAMS:
+       @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \
+       echo " rm -f" $$list; \
+       rm -f $$list || exit $$?; \
+       test -n "$(EXEEXT)" || exit 0; \
+       list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
+       echo " rm -f" $$list; \
+       rm -f $$list
+
+clean-noinstPROGRAMS:
+       @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \
        echo " rm -f" $$list; \
        rm -f $$list || exit $$?; \
        test -n "$(EXEEXT)" || exit 0; \
@@ -1925,8 +2066,11 @@ clean-sbinPROGRAMS:
        rm -f $$list
 install-udevPROGRAMS: $(udev_PROGRAMS)
        @$(NORMAL_INSTALL)
-       test -z "$(udevdir)" || $(MKDIR_P) "$(DESTDIR)$(udevdir)"
        @list='$(udev_PROGRAMS)'; test -n "$(udevdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(udevdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(udevdir)" || exit 1; \
+       fi; \
        for p in $$list; do echo "$$p $$p"; done | \
        sed 's/$(EXEEXT)$$//' | \
        while read p p1; do if test -f $$p || test -f $$p1; \
@@ -1966,6 +2110,24 @@ clean-udevPROGRAMS:
        list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \
        echo " rm -f" $$list; \
        rm -f $$list
+android/$(am__dirstamp):
+       @$(MKDIR_P) android
+       @: > android/$(am__dirstamp)
+android/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) android/$(DEPDIR)
+       @: > android/$(DEPDIR)/$(am__dirstamp)
+android/main.$(OBJEXT): android/$(am__dirstamp) \
+       android/$(DEPDIR)/$(am__dirstamp)
+src/$(am__dirstamp):
+       @$(MKDIR_P) src
+       @: > src/$(am__dirstamp)
+src/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) src/$(DEPDIR)
+       @: > src/$(DEPDIR)/$(am__dirstamp)
+src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+android/bluetoothd$(EXEEXT): $(android_bluetoothd_OBJECTS) $(android_bluetoothd_DEPENDENCIES) $(EXTRA_android_bluetoothd_DEPENDENCIES) android/$(am__dirstamp)
+       @rm -f android/bluetoothd$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(android_bluetoothd_OBJECTS) $(android_bluetoothd_LDADD) $(LIBS)
 attrib/$(am__dirstamp):
        @$(MKDIR_P) attrib
        @: > attrib/$(am__dirstamp)
@@ -1992,120 +2154,64 @@ attrib/interactive.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/utils.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
-src/$(am__dirstamp):
-       @$(MKDIR_P) src
-       @: > src/$(am__dirstamp)
-src/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) src/$(DEPDIR)
-       @: > src/$(DEPDIR)/$(am__dirstamp)
-src/log.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+client/$(am__dirstamp):
+       @$(MKDIR_P) client
+       @: > client/$(am__dirstamp)
+client/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) client/$(DEPDIR)
+       @: > client/$(DEPDIR)/$(am__dirstamp)
+client/display.$(OBJEXT): client/$(am__dirstamp) \
+       client/$(DEPDIR)/$(am__dirstamp)
 attrib/gatttool$(EXEEXT): $(attrib_gatttool_OBJECTS) $(attrib_gatttool_DEPENDENCIES) $(EXTRA_attrib_gatttool_DEPENDENCIES) attrib/$(am__dirstamp)
        @rm -f attrib/gatttool$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(attrib_gatttool_OBJECTS) $(attrib_gatttool_LDADD) $(LIBS)
-compat/$(am__dirstamp):
-       @$(MKDIR_P) compat
-       @: > compat/$(am__dirstamp)
-compat/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) compat/$(DEPDIR)
-       @: > compat/$(DEPDIR)/$(am__dirstamp)
-compat/dund.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/sdp.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/dun.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/msdun.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-src/textfile.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-compat/dund$(EXEEXT): $(compat_dund_OBJECTS) $(compat_dund_DEPENDENCIES) $(EXTRA_compat_dund_DEPENDENCIES) compat/$(am__dirstamp)
-       @rm -f compat/dund$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(compat_dund_OBJECTS) $(compat_dund_LDADD) $(LIBS)
-compat/hidd.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/fakehid.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/hidd$(EXEEXT): $(compat_hidd_OBJECTS) $(compat_hidd_DEPENDENCIES) $(EXTRA_compat_hidd_DEPENDENCIES) compat/$(am__dirstamp)
-       @rm -f compat/hidd$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(compat_hidd_OBJECTS) $(compat_hidd_LDADD) $(LIBS)
-compat/pand.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/bnep.$(OBJEXT): compat/$(am__dirstamp) \
-       compat/$(DEPDIR)/$(am__dirstamp)
-compat/pand$(EXEEXT): $(compat_pand_OBJECTS) $(compat_pand_DEPENDENCIES) $(EXTRA_compat_pand_DEPENDENCIES) compat/$(am__dirstamp)
-       @rm -f compat/pand$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(compat_pand_OBJECTS) $(compat_pand_LDADD) $(LIBS)
-gdbus/$(am__dirstamp):
-       @$(MKDIR_P) gdbus
-       @: > gdbus/$(am__dirstamp)
-gdbus/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) gdbus/$(DEPDIR)
-       @: > gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/mainloop.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/watch.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/object.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/polkit.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-cups/$(am__dirstamp):
-       @$(MKDIR_P) cups
-       @: > cups/$(am__dirstamp)
-cups/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) cups/$(DEPDIR)
-       @: > cups/$(DEPDIR)/$(am__dirstamp)
-cups/main.$(OBJEXT): cups/$(am__dirstamp) \
-       cups/$(DEPDIR)/$(am__dirstamp)
-cups/sdp.$(OBJEXT): cups/$(am__dirstamp) \
-       cups/$(DEPDIR)/$(am__dirstamp)
-cups/spp.$(OBJEXT): cups/$(am__dirstamp) \
-       cups/$(DEPDIR)/$(am__dirstamp)
-cups/hcrp.$(OBJEXT): cups/$(am__dirstamp) \
-       cups/$(DEPDIR)/$(am__dirstamp)
-cups/bluetooth$(EXEEXT): $(cups_bluetooth_OBJECTS) $(cups_bluetooth_DEPENDENCIES) $(EXTRA_cups_bluetooth_DEPENDENCIES) cups/$(am__dirstamp)
-       @rm -f cups/bluetooth$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(cups_bluetooth_OBJECTS) $(cups_bluetooth_LDADD) $(LIBS)
+client/main.$(OBJEXT): client/$(am__dirstamp) \
+       client/$(DEPDIR)/$(am__dirstamp)
+client/agent.$(OBJEXT): client/$(am__dirstamp) \
+       client/$(DEPDIR)/$(am__dirstamp)
+monitor/$(am__dirstamp):
+       @$(MKDIR_P) monitor
+       @: > monitor/$(am__dirstamp)
+monitor/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) monitor/$(DEPDIR)
+       @: > monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/uuid.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+client/bluetoothctl$(EXEEXT): $(client_bluetoothctl_OBJECTS) $(client_bluetoothctl_DEPENDENCIES) $(EXTRA_client_bluetoothctl_DEPENDENCIES) client/$(am__dirstamp)
+       @rm -f client/bluetoothctl$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(client_bluetoothctl_OBJECTS) $(client_bluetoothctl_LDADD) $(LIBS)
 emulator/$(am__dirstamp):
        @$(MKDIR_P) emulator
        @: > emulator/$(am__dirstamp)
 emulator/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) emulator/$(DEPDIR)
        @: > emulator/$(DEPDIR)/$(am__dirstamp)
-emulator/main.$(OBJEXT): emulator/$(am__dirstamp) \
+emulator/b1ee.$(OBJEXT): emulator/$(am__dirstamp) \
        emulator/$(DEPDIR)/$(am__dirstamp)
-monitor/$(am__dirstamp):
-       @$(MKDIR_P) monitor
-       @: > monitor/$(am__dirstamp)
-monitor/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) monitor/$(DEPDIR)
-       @: > monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/mainloop.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
+emulator/b1ee$(EXEEXT): $(emulator_b1ee_OBJECTS) $(emulator_b1ee_DEPENDENCIES) $(EXTRA_emulator_b1ee_DEPENDENCIES) emulator/$(am__dirstamp)
+       @rm -f emulator/b1ee$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(emulator_b1ee_OBJECTS) $(emulator_b1ee_LDADD) $(LIBS)
+emulator/main.$(OBJEXT): emulator/$(am__dirstamp) \
+       emulator/$(DEPDIR)/$(am__dirstamp)
 emulator/server.$(OBJEXT): emulator/$(am__dirstamp) \
        emulator/$(DEPDIR)/$(am__dirstamp)
 emulator/vhci.$(OBJEXT): emulator/$(am__dirstamp) \
        emulator/$(DEPDIR)/$(am__dirstamp)
 emulator/btdev.$(OBJEXT): emulator/$(am__dirstamp) \
        emulator/$(DEPDIR)/$(am__dirstamp)
+emulator/bthost.$(OBJEXT): emulator/$(am__dirstamp) \
+       emulator/$(DEPDIR)/$(am__dirstamp)
+emulator/amp.$(OBJEXT): emulator/$(am__dirstamp) \
+       emulator/$(DEPDIR)/$(am__dirstamp)
 emulator/btvirt$(EXEEXT): $(emulator_btvirt_OBJECTS) $(emulator_btvirt_DEPENDENCIES) $(EXTRA_emulator_btvirt_DEPENDENCIES) emulator/$(am__dirstamp)
        @rm -f emulator/btvirt$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(emulator_btvirt_OBJECTS) $(emulator_btvirt_LDADD) $(LIBS)
-mgmt/$(am__dirstamp):
-       @$(MKDIR_P) mgmt
-       @: > mgmt/$(am__dirstamp)
-mgmt/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) mgmt/$(DEPDIR)
-       @: > mgmt/$(DEPDIR)/$(am__dirstamp)
-mgmt/main.$(OBJEXT): mgmt/$(am__dirstamp) \
-       mgmt/$(DEPDIR)/$(am__dirstamp)
-src/glib-helper.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-mgmt/btmgmt$(EXEEXT): $(mgmt_btmgmt_OBJECTS) $(mgmt_btmgmt_DEPENDENCIES) $(EXTRA_mgmt_btmgmt_DEPENDENCIES) mgmt/$(am__dirstamp)
-       @rm -f mgmt/btmgmt$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(mgmt_btmgmt_OBJECTS) $(mgmt_btmgmt_LDADD) $(LIBS)
 monitor/main.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/display.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/hcidump.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/btsnoop.$(OBJEXT): monitor/$(am__dirstamp) \
@@ -2114,243 +2220,395 @@ monitor/control.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/packet.$(OBJEXT): monitor/$(am__dirstamp) \
        monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/vendor.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/lmp.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/l2cap.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/sdp.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/crc.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
+monitor/ll.$(OBJEXT): monitor/$(am__dirstamp) \
+       monitor/$(DEPDIR)/$(am__dirstamp)
 monitor/btmon$(EXEEXT): $(monitor_btmon_OBJECTS) $(monitor_btmon_DEPENDENCIES) $(EXTRA_monitor_btmon_DEPENDENCIES) monitor/$(am__dirstamp)
        @rm -f monitor/btmon$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(monitor_btmon_OBJECTS) $(monitor_btmon_LDADD) $(LIBS)
-sbc/sbcdec.$(OBJEXT): sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbcdec$(EXEEXT): $(sbc_sbcdec_OBJECTS) $(sbc_sbcdec_DEPENDENCIES) $(EXTRA_sbc_sbcdec_DEPENDENCIES) sbc/$(am__dirstamp)
-       @rm -f sbc/sbcdec$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(sbc_sbcdec_OBJECTS) $(sbc_sbcdec_LDADD) $(LIBS)
-sbc/sbcenc.$(OBJEXT): sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbcenc$(EXEEXT): $(sbc_sbcenc_OBJECTS) $(sbc_sbcenc_DEPENDENCIES) $(EXTRA_sbc_sbcenc_DEPENDENCIES) sbc/$(am__dirstamp)
-       @rm -f sbc/sbcenc$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(sbc_sbcenc_OBJECTS) $(sbc_sbcenc_LDADD) $(LIBS)
-sbc/sbcinfo.$(OBJEXT): sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbcinfo$(EXEEXT): $(sbc_sbcinfo_OBJECTS) $(sbc_sbcinfo_DEPENDENCIES) $(EXTRA_sbc_sbcinfo_DEPENDENCIES) sbc/$(am__dirstamp)
-       @rm -f sbc/sbcinfo$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(sbc_sbcinfo_OBJECTS) $(sbc_sbcinfo_LDADD) $(LIBS)
-sbc/sbctester.$(OBJEXT): sbc/$(am__dirstamp) \
-       sbc/$(DEPDIR)/$(am__dirstamp)
-sbc/sbctester$(EXEEXT): $(sbc_sbctester_OBJECTS) $(sbc_sbctester_DEPENDENCIES) $(EXTRA_sbc_sbctester_DEPENDENCIES) sbc/$(am__dirstamp)
-       @rm -f sbc/sbctester$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(sbc_sbctester_OBJECTS) $(sbc_sbctester_LDADD) $(LIBS)
-gdbus/bluetoothd-mainloop.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/bluetoothd-watch.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/bluetoothd-object.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-gdbus/bluetoothd-polkit.$(OBJEXT): gdbus/$(am__dirstamp) \
-       gdbus/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-pnat.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-main.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-manager.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-gateway.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-headset.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-control.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-avctp.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-avrcp.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-device.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-source.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-sink.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-a2dp.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-avdtp.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-ipc.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-unix.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-media.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-transport.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-sap/bluetoothd-main.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
-sap/bluetoothd-manager.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
-sap/bluetoothd-server.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
-input/$(am__dirstamp):
-       @$(MKDIR_P) input
-       @: > input/$(am__dirstamp)
-input/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) input/$(DEPDIR)
-       @: > input/$(DEPDIR)/$(am__dirstamp)
-input/bluetoothd-main.$(OBJEXT): input/$(am__dirstamp) \
-       input/$(DEPDIR)/$(am__dirstamp)
-input/bluetoothd-manager.$(OBJEXT): input/$(am__dirstamp) \
-       input/$(DEPDIR)/$(am__dirstamp)
-input/bluetoothd-server.$(OBJEXT): input/$(am__dirstamp) \
-       input/$(DEPDIR)/$(am__dirstamp)
-input/bluetoothd-device.$(OBJEXT): input/$(am__dirstamp) \
-       input/$(DEPDIR)/$(am__dirstamp)
-input/bluetoothd-fakehid.$(OBJEXT): input/$(am__dirstamp) \
-       input/$(DEPDIR)/$(am__dirstamp)
-serial/$(am__dirstamp):
-       @$(MKDIR_P) serial
-       @: > serial/$(am__dirstamp)
-serial/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) serial/$(DEPDIR)
-       @: > serial/$(DEPDIR)/$(am__dirstamp)
-serial/bluetoothd-main.$(OBJEXT): serial/$(am__dirstamp) \
-       serial/$(DEPDIR)/$(am__dirstamp)
-serial/bluetoothd-manager.$(OBJEXT): serial/$(am__dirstamp) \
-       serial/$(DEPDIR)/$(am__dirstamp)
-serial/bluetoothd-proxy.$(OBJEXT): serial/$(am__dirstamp) \
-       serial/$(DEPDIR)/$(am__dirstamp)
-serial/bluetoothd-port.$(OBJEXT): serial/$(am__dirstamp) \
-       serial/$(DEPDIR)/$(am__dirstamp)
-network/$(am__dirstamp):
-       @$(MKDIR_P) network
-       @: > network/$(am__dirstamp)
-network/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) network/$(DEPDIR)
-       @: > network/$(DEPDIR)/$(am__dirstamp)
-network/bluetoothd-main.$(OBJEXT): network/$(am__dirstamp) \
-       network/$(DEPDIR)/$(am__dirstamp)
-network/bluetoothd-manager.$(OBJEXT): network/$(am__dirstamp) \
-       network/$(DEPDIR)/$(am__dirstamp)
-network/bluetoothd-common.$(OBJEXT): network/$(am__dirstamp) \
-       network/$(DEPDIR)/$(am__dirstamp)
-network/bluetoothd-server.$(OBJEXT): network/$(am__dirstamp) \
-       network/$(DEPDIR)/$(am__dirstamp)
-network/bluetoothd-connection.$(OBJEXT): network/$(am__dirstamp) \
-       network/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-service.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-health/$(am__dirstamp):
-       @$(MKDIR_P) health
-       @: > health/$(am__dirstamp)
-health/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) health/$(DEPDIR)
-       @: > health/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-hdp_main.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-hdp_manager.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-hdp.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-hdp_util.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
-thermometer/$(am__dirstamp):
-       @$(MKDIR_P) thermometer
-       @: > thermometer/$(am__dirstamp)
-thermometer/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) thermometer/$(DEPDIR)
-       @: > thermometer/$(DEPDIR)/$(am__dirstamp)
-thermometer/bluetoothd-main.$(OBJEXT): thermometer/$(am__dirstamp) \
-       thermometer/$(DEPDIR)/$(am__dirstamp)
-thermometer/bluetoothd-manager.$(OBJEXT): thermometer/$(am__dirstamp) \
-       thermometer/$(DEPDIR)/$(am__dirstamp)
-thermometer/bluetoothd-thermometer.$(OBJEXT):  \
-       thermometer/$(am__dirstamp) \
-       thermometer/$(DEPDIR)/$(am__dirstamp)
-alert/$(am__dirstamp):
-       @$(MKDIR_P) alert
-       @: > alert/$(am__dirstamp)
-alert/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) alert/$(DEPDIR)
-       @: > alert/$(DEPDIR)/$(am__dirstamp)
-alert/bluetoothd-main.$(OBJEXT): alert/$(am__dirstamp) \
-       alert/$(DEPDIR)/$(am__dirstamp)
-alert/bluetoothd-server.$(OBJEXT): alert/$(am__dirstamp) \
-       alert/$(DEPDIR)/$(am__dirstamp)
-time/$(am__dirstamp):
-       @$(MKDIR_P) time
-       @: > time/$(am__dirstamp)
-time/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) time/$(DEPDIR)
-       @: > time/$(DEPDIR)/$(am__dirstamp)
-time/bluetoothd-main.$(OBJEXT): time/$(am__dirstamp) \
-       time/$(DEPDIR)/$(am__dirstamp)
-time/bluetoothd-server.$(OBJEXT): time/$(am__dirstamp) \
-       time/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-gatt-example.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-proximity/$(am__dirstamp):
-       @$(MKDIR_P) proximity
-       @: > proximity/$(am__dirstamp)
-proximity/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) proximity/$(DEPDIR)
-       @: > proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-main.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-manager.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-monitor.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-reporter.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-linkloss.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-proximity/bluetoothd-immalert.$(OBJEXT): proximity/$(am__dirstamp) \
-       proximity/$(DEPDIR)/$(am__dirstamp)
-deviceinfo/$(am__dirstamp):
-       @$(MKDIR_P) deviceinfo
-       @: > deviceinfo/$(am__dirstamp)
-deviceinfo/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) deviceinfo/$(DEPDIR)
-       @: > deviceinfo/$(DEPDIR)/$(am__dirstamp)
-deviceinfo/bluetoothd-main.$(OBJEXT): deviceinfo/$(am__dirstamp) \
-       deviceinfo/$(DEPDIR)/$(am__dirstamp)
-deviceinfo/bluetoothd-manager.$(OBJEXT): deviceinfo/$(am__dirstamp) \
-       deviceinfo/$(DEPDIR)/$(am__dirstamp)
-deviceinfo/bluetoothd-deviceinfo.$(OBJEXT):  \
-       deviceinfo/$(am__dirstamp) \
-       deviceinfo/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-hciops.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-mgmtops.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-hal.$(OBJEXT): plugins/$(am__dirstamp) \
-       plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-formfactor.$(OBJEXT): plugins/$(am__dirstamp) \
+btio/obexd-btio.$(OBJEXT): btio/$(am__dirstamp) \
+       btio/$(DEPDIR)/$(am__dirstamp)
+gobex/$(am__dirstamp):
+       @$(MKDIR_P) gobex
+       @: > gobex/$(am__dirstamp)
+gobex/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) gobex/$(DEPDIR)
+       @: > gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex-defs.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex-packet.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex-header.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex-transfer.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/obexd-gobex-apparam.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/$(am__dirstamp):
+       @$(MKDIR_P) obexd/plugins
+       @: > obexd/plugins/$(am__dirstamp)
+obexd/plugins/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) obexd/plugins/$(DEPDIR)
+       @: > obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-filesystem.$(OBJEXT):  \
+       obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-bluetooth.$(OBJEXT):  \
+       obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-pcsuite.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-opp.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-ftp.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-irmc.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-pbap.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-vcard.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-phonebook-dummy.$(OBJEXT):  \
+       obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-mas.$(OBJEXT): obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/plugins/obexd-messages-dummy.$(OBJEXT):  \
+       obexd/plugins/$(am__dirstamp) \
+       obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+obexd/client/$(am__dirstamp):
+       @$(MKDIR_P) obexd/client
+       @: > obexd/client/$(am__dirstamp)
+obexd/client/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) obexd/client/$(DEPDIR)
+       @: > obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-mns.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/src/$(am__dirstamp):
+       @$(MKDIR_P) obexd/src
+       @: > obexd/src/$(am__dirstamp)
+obexd/src/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) obexd/src/$(DEPDIR)
+       @: > obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-main.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-plugin.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-log.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-manager.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-obex.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-mimetype.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-service.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-transport.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd-server.$(OBJEXT): obexd/src/$(am__dirstamp) \
+       obexd/src/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-manager.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-session.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-bluetooth.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-sync.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-pbap.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-ftp.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-opp.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-map.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-map-event.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-transfer.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-transport.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-dbus.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/client/obexd-driver.$(OBJEXT): obexd/client/$(am__dirstamp) \
+       obexd/client/$(DEPDIR)/$(am__dirstamp)
+obexd/src/obexd$(EXEEXT): $(obexd_src_obexd_OBJECTS) $(obexd_src_obexd_DEPENDENCIES) $(EXTRA_obexd_src_obexd_DEPENDENCIES) obexd/src/$(am__dirstamp)
+       @rm -f obexd/src/obexd$(EXEEXT)
+       $(AM_V_CCLD)$(obexd_src_obexd_LINK) $(obexd_src_obexd_OBJECTS) $(obexd_src_obexd_LDADD) $(LIBS)
+profiles/cups/$(am__dirstamp):
+       @$(MKDIR_P) profiles/cups
+       @: > profiles/cups/$(am__dirstamp)
+profiles/cups/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/cups/$(DEPDIR)
+       @: > profiles/cups/$(DEPDIR)/$(am__dirstamp)
+profiles/cups/main.$(OBJEXT): profiles/cups/$(am__dirstamp) \
+       profiles/cups/$(DEPDIR)/$(am__dirstamp)
+profiles/cups/sdp.$(OBJEXT): profiles/cups/$(am__dirstamp) \
+       profiles/cups/$(DEPDIR)/$(am__dirstamp)
+profiles/cups/spp.$(OBJEXT): profiles/cups/$(am__dirstamp) \
+       profiles/cups/$(DEPDIR)/$(am__dirstamp)
+profiles/cups/hcrp.$(OBJEXT): profiles/cups/$(am__dirstamp) \
+       profiles/cups/$(DEPDIR)/$(am__dirstamp)
+profiles/cups/bluetooth$(EXEEXT): $(profiles_cups_bluetooth_OBJECTS) $(profiles_cups_bluetooth_DEPENDENCIES) $(EXTRA_profiles_cups_bluetooth_DEPENDENCIES) profiles/cups/$(am__dirstamp)
+       @rm -f profiles/cups/bluetooth$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(profiles_cups_bluetooth_OBJECTS) $(profiles_cups_bluetooth_LDADD) $(LIBS)
+profiles/iap/$(am__dirstamp):
+       @$(MKDIR_P) profiles/iap
+       @: > profiles/iap/$(am__dirstamp)
+profiles/iap/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/iap/$(DEPDIR)
+       @: > profiles/iap/$(DEPDIR)/$(am__dirstamp)
+profiles/iap/main.$(OBJEXT): profiles/iap/$(am__dirstamp) \
+       profiles/iap/$(DEPDIR)/$(am__dirstamp)
+profiles/iap/iapd$(EXEEXT): $(profiles_iap_iapd_OBJECTS) $(profiles_iap_iapd_DEPENDENCIES) $(EXTRA_profiles_iap_iapd_DEPENDENCIES) profiles/iap/$(am__dirstamp)
+       @rm -f profiles/iap/iapd$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(profiles_iap_iapd_OBJECTS) $(profiles_iap_iapd_LDADD) $(LIBS)
+plugins/bluetoothd-hostname.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-storage.$(OBJEXT): plugins/$(am__dirstamp) \
+plugins/bluetoothd-wiimote.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-adaptername.$(OBJEXT): plugins/$(am__dirstamp) \
+plugins/bluetoothd-autopair.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-wiimote.$(OBJEXT): plugins/$(am__dirstamp) \
+plugins/bluetoothd-policy.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-maemo6.$(OBJEXT): plugins/$(am__dirstamp) \
+plugins/bluetoothd-gatt-example.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
-plugins/bluetoothd-dbusoob.$(OBJEXT): plugins/$(am__dirstamp) \
+plugins/bluetoothd-neard.$(OBJEXT): plugins/$(am__dirstamp) \
        plugins/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/bluetoothd-main.$(OBJEXT): profiles/sap/$(am__dirstamp) \
+       profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/bluetoothd-manager.$(OBJEXT):  \
+       profiles/sap/$(am__dirstamp) \
+       profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/bluetoothd-server.$(OBJEXT):  \
+       profiles/sap/$(am__dirstamp) \
+       profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/sap/bluetoothd-sap-dummy.$(OBJEXT):  \
+       profiles/sap/$(am__dirstamp) \
+       profiles/sap/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/$(am__dirstamp):
+       @$(MKDIR_P) profiles/audio
+       @: > profiles/audio/$(am__dirstamp)
+profiles/audio/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/audio/$(DEPDIR)
+       @: > profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-source.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-sink.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-a2dp.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-avdtp.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-media.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-transport.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-control.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-avctp.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-avrcp.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/audio/bluetoothd-player.$(OBJEXT):  \
+       profiles/audio/$(am__dirstamp) \
+       profiles/audio/$(DEPDIR)/$(am__dirstamp)
+profiles/network/$(am__dirstamp):
+       @$(MKDIR_P) profiles/network
+       @: > profiles/network/$(am__dirstamp)
+profiles/network/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/network/$(DEPDIR)
+       @: > profiles/network/$(DEPDIR)/$(am__dirstamp)
+profiles/network/bluetoothd-manager.$(OBJEXT):  \
+       profiles/network/$(am__dirstamp) \
+       profiles/network/$(DEPDIR)/$(am__dirstamp)
+profiles/network/bluetoothd-common.$(OBJEXT):  \
+       profiles/network/$(am__dirstamp) \
+       profiles/network/$(DEPDIR)/$(am__dirstamp)
+profiles/network/bluetoothd-server.$(OBJEXT):  \
+       profiles/network/$(am__dirstamp) \
+       profiles/network/$(DEPDIR)/$(am__dirstamp)
+profiles/network/bluetoothd-connection.$(OBJEXT):  \
+       profiles/network/$(am__dirstamp) \
+       profiles/network/$(DEPDIR)/$(am__dirstamp)
+profiles/input/$(am__dirstamp):
+       @$(MKDIR_P) profiles/input
+       @: > profiles/input/$(am__dirstamp)
+profiles/input/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/input/$(DEPDIR)
+       @: > profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/input/bluetoothd-manager.$(OBJEXT):  \
+       profiles/input/$(am__dirstamp) \
+       profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/input/bluetoothd-server.$(OBJEXT):  \
+       profiles/input/$(am__dirstamp) \
+       profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/input/bluetoothd-device.$(OBJEXT):  \
+       profiles/input/$(am__dirstamp) \
+       profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/input/bluetoothd-hog.$(OBJEXT):  \
+       profiles/input/$(am__dirstamp) \
+       profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/input/bluetoothd-suspend-dummy.$(OBJEXT):  \
+       profiles/input/$(am__dirstamp) \
+       profiles/input/$(DEPDIR)/$(am__dirstamp)
+profiles/health/$(am__dirstamp):
+       @$(MKDIR_P) profiles/health
+       @: > profiles/health/$(am__dirstamp)
+profiles/health/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/health/$(DEPDIR)
+       @: > profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-mcap.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-mcap_sync.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-hdp_main.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-hdp_manager.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-hdp.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/health/bluetoothd-hdp_util.$(OBJEXT):  \
+       profiles/health/$(am__dirstamp) \
+       profiles/health/$(DEPDIR)/$(am__dirstamp)
+profiles/gatt/$(am__dirstamp):
+       @$(MKDIR_P) profiles/gatt
+       @: > profiles/gatt/$(am__dirstamp)
+profiles/gatt/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/gatt/$(DEPDIR)
+       @: > profiles/gatt/$(DEPDIR)/$(am__dirstamp)
+profiles/gatt/bluetoothd-gas.$(OBJEXT): profiles/gatt/$(am__dirstamp) \
+       profiles/gatt/$(DEPDIR)/$(am__dirstamp)
+profiles/scanparam/$(am__dirstamp):
+       @$(MKDIR_P) profiles/scanparam
+       @: > profiles/scanparam/$(am__dirstamp)
+profiles/scanparam/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/scanparam/$(DEPDIR)
+       @: > profiles/scanparam/$(DEPDIR)/$(am__dirstamp)
+profiles/scanparam/bluetoothd-scan.$(OBJEXT):  \
+       profiles/scanparam/$(am__dirstamp) \
+       profiles/scanparam/$(DEPDIR)/$(am__dirstamp)
+profiles/deviceinfo/$(am__dirstamp):
+       @$(MKDIR_P) profiles/deviceinfo
+       @: > profiles/deviceinfo/$(am__dirstamp)
+profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/deviceinfo/$(DEPDIR)
+       @: > profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp)
+profiles/deviceinfo/bluetoothd-deviceinfo.$(OBJEXT):  \
+       profiles/deviceinfo/$(am__dirstamp) \
+       profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp)
+profiles/alert/$(am__dirstamp):
+       @$(MKDIR_P) profiles/alert
+       @: > profiles/alert/$(am__dirstamp)
+profiles/alert/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/alert/$(DEPDIR)
+       @: > profiles/alert/$(DEPDIR)/$(am__dirstamp)
+profiles/alert/bluetoothd-server.$(OBJEXT):  \
+       profiles/alert/$(am__dirstamp) \
+       profiles/alert/$(DEPDIR)/$(am__dirstamp)
+profiles/time/$(am__dirstamp):
+       @$(MKDIR_P) profiles/time
+       @: > profiles/time/$(am__dirstamp)
+profiles/time/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/time/$(DEPDIR)
+       @: > profiles/time/$(DEPDIR)/$(am__dirstamp)
+profiles/time/bluetoothd-server.$(OBJEXT):  \
+       profiles/time/$(am__dirstamp) \
+       profiles/time/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/$(am__dirstamp):
+       @$(MKDIR_P) profiles/proximity
+       @: > profiles/proximity/$(am__dirstamp)
+profiles/proximity/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/proximity/$(DEPDIR)
+       @: > profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-main.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-manager.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-monitor.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-reporter.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-linkloss.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/proximity/bluetoothd-immalert.$(OBJEXT):  \
+       profiles/proximity/$(am__dirstamp) \
+       profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+profiles/thermometer/$(am__dirstamp):
+       @$(MKDIR_P) profiles/thermometer
+       @: > profiles/thermometer/$(am__dirstamp)
+profiles/thermometer/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/thermometer/$(DEPDIR)
+       @: > profiles/thermometer/$(DEPDIR)/$(am__dirstamp)
+profiles/thermometer/bluetoothd-thermometer.$(OBJEXT):  \
+       profiles/thermometer/$(am__dirstamp) \
+       profiles/thermometer/$(DEPDIR)/$(am__dirstamp)
+profiles/heartrate/$(am__dirstamp):
+       @$(MKDIR_P) profiles/heartrate
+       @: > profiles/heartrate/$(am__dirstamp)
+profiles/heartrate/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/heartrate/$(DEPDIR)
+       @: > profiles/heartrate/$(DEPDIR)/$(am__dirstamp)
+profiles/heartrate/bluetoothd-heartrate.$(OBJEXT):  \
+       profiles/heartrate/$(am__dirstamp) \
+       profiles/heartrate/$(DEPDIR)/$(am__dirstamp)
+profiles/cyclingspeed/$(am__dirstamp):
+       @$(MKDIR_P) profiles/cyclingspeed
+       @: > profiles/cyclingspeed/$(am__dirstamp)
+profiles/cyclingspeed/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) profiles/cyclingspeed/$(DEPDIR)
+       @: > profiles/cyclingspeed/$(DEPDIR)/$(am__dirstamp)
+profiles/cyclingspeed/bluetoothd-cyclingspeed.$(OBJEXT):  \
+       profiles/cyclingspeed/$(am__dirstamp) \
+       profiles/cyclingspeed/$(DEPDIR)/$(am__dirstamp)
 attrib/bluetoothd-att.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/bluetoothd-gatt.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/bluetoothd-gattrib.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
-attrib/bluetoothd-client.$(OBJEXT): attrib/$(am__dirstamp) \
-       attrib/$(DEPDIR)/$(am__dirstamp)
 attrib/bluetoothd-gatt-service.$(OBJEXT): attrib/$(am__dirstamp) \
        attrib/$(DEPDIR)/$(am__dirstamp)
 btio/bluetoothd-btio.$(OBJEXT): btio/$(am__dirstamp) \
        btio/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-mcap.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
-health/bluetoothd-mcap_sync.$(OBJEXT): health/$(am__dirstamp) \
-       health/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-main.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-log.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
+src/bluetoothd-systemd.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-rfkill.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-sdpd-server.$(OBJEXT): src/$(am__dirstamp) \
@@ -2371,8 +2629,6 @@ src/bluetoothd-textfile.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-glib-helper.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-oui.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-plugin.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-storage.$(OBJEXT): src/$(am__dirstamp) \
@@ -2381,143 +2637,60 @@ src/bluetoothd-agent.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-error.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-manager.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-adapter.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-device.$(OBJEXT): src/$(am__dirstamp) \
+src/bluetoothd-profile.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-dbus-common.$(OBJEXT): src/$(am__dirstamp) \
+src/bluetoothd-service.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-event.$(OBJEXT): src/$(am__dirstamp) \
+src/bluetoothd-device.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-src/bluetoothd-oob.$(OBJEXT): src/$(am__dirstamp) \
+src/bluetoothd-dbus-common.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd-eir.$(OBJEXT): src/$(am__dirstamp) \
        src/$(DEPDIR)/$(am__dirstamp)
-audio/bluetoothd-telephony.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-sap/bluetoothd-sap.$(OBJEXT): sap/$(am__dirstamp) \
-       sap/$(DEPDIR)/$(am__dirstamp)
+src/shared/$(am__dirstamp):
+       @$(MKDIR_P) src/shared
+       @: > src/shared/$(am__dirstamp)
+src/shared/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) src/shared/$(DEPDIR)
+       @: > src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/bluetoothd-util.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/bluetoothd-mgmt.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
 src/bluetoothd$(EXEEXT): $(src_bluetoothd_OBJECTS) $(src_bluetoothd_DEPENDENCIES) $(EXTRA_src_bluetoothd_DEPENDENCIES) src/$(am__dirstamp)
        @rm -f src/bluetoothd$(EXEEXT)
        $(AM_V_CCLD)$(src_bluetoothd_LINK) $(src_bluetoothd_OBJECTS) $(src_bluetoothd_LDADD) $(LIBS)
-test/$(am__dirstamp):
-       @$(MKDIR_P) test
-       @: > test/$(am__dirstamp)
-test/$(DEPDIR)/$(am__dirstamp):
-       @$(MKDIR_P) test/$(DEPDIR)
-       @: > test/$(DEPDIR)/$(am__dirstamp)
-test/agent.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/agent$(EXEEXT): $(test_agent_OBJECTS) $(test_agent_DEPENDENCIES) $(EXTRA_test_agent_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/agent$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_agent_OBJECTS) $(test_agent_LDADD) $(LIBS)
-test/attest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/attest$(EXEEXT): $(test_attest_OBJECTS) $(test_attest_DEPENDENCIES) $(EXTRA_test_attest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/attest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_attest_OBJECTS) $(test_attest_LDADD) $(LIBS)
-test/avtest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/avtest$(EXEEXT): $(test_avtest_OBJECTS) $(test_avtest_DEPENDENCIES) $(EXTRA_test_avtest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/avtest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_avtest_OBJECTS) $(test_avtest_LDADD) $(LIBS)
-test/bdaddr.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-src/oui.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
-test/bdaddr$(EXEEXT): $(test_bdaddr_OBJECTS) $(test_bdaddr_DEPENDENCIES) $(EXTRA_test_bdaddr_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/bdaddr$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_bdaddr_OBJECTS) $(test_bdaddr_LDADD) $(LIBS)
-test/btiotest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/btiotest$(EXEEXT): $(test_btiotest_OBJECTS) $(test_btiotest_DEPENDENCIES) $(EXTRA_test_btiotest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/btiotest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_btiotest_OBJECTS) $(test_btiotest_LDADD) $(LIBS)
-test/gaptest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/gaptest$(EXEEXT): $(test_gaptest_OBJECTS) $(test_gaptest_DEPENDENCIES) $(EXTRA_test_gaptest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/gaptest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_gaptest_OBJECTS) $(test_gaptest_LDADD) $(LIBS)
-test/hciemu.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/hciemu$(EXEEXT): $(test_hciemu_OBJECTS) $(test_hciemu_DEPENDENCIES) $(EXTRA_test_hciemu_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/hciemu$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_hciemu_OBJECTS) $(test_hciemu_LDADD) $(LIBS)
-test/hstest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/hstest$(EXEEXT): $(test_hstest_OBJECTS) $(test_hstest_DEPENDENCIES) $(EXTRA_test_hstest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/hstest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_hstest_OBJECTS) $(test_hstest_LDADD) $(LIBS)
-test/ipctest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-audio/ipc.$(OBJEXT): audio/$(am__dirstamp) \
-       audio/$(DEPDIR)/$(am__dirstamp)
-test/ipctest$(EXEEXT): $(test_ipctest_OBJECTS) $(test_ipctest_DEPENDENCIES) $(EXTRA_test_ipctest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/ipctest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_ipctest_OBJECTS) $(test_ipctest_LDADD) $(LIBS)
-test/l2test.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/l2test$(EXEEXT): $(test_l2test_OBJECTS) $(test_l2test_DEPENDENCIES) $(EXTRA_test_l2test_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/l2test$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_l2test_OBJECTS) $(test_l2test_LDADD) $(LIBS)
-test/lmptest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/lmptest$(EXEEXT): $(test_lmptest_OBJECTS) $(test_lmptest_DEPENDENCIES) $(EXTRA_test_lmptest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/lmptest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_lmptest_OBJECTS) $(test_lmptest_LDADD) $(LIBS)
-test/mpris-player.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/mpris-player$(EXEEXT): $(test_mpris_player_OBJECTS) $(test_mpris_player_DEPENDENCIES) $(EXTRA_test_mpris_player_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/mpris-player$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_mpris_player_OBJECTS) $(test_mpris_player_LDADD) $(LIBS)
-test/rctest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/rctest$(EXEEXT): $(test_rctest_OBJECTS) $(test_rctest_DEPENDENCIES) $(EXTRA_test_rctest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/rctest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_rctest_OBJECTS) $(test_rctest_LDADD) $(LIBS)
-test/scotest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/scotest$(EXEEXT): $(test_scotest_OBJECTS) $(test_scotest_DEPENDENCIES) $(EXTRA_test_scotest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/scotest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_scotest_OBJECTS) $(test_scotest_LDADD) $(LIBS)
-test/sdptest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/sdptest$(EXEEXT): $(test_sdptest_OBJECTS) $(test_sdptest_DEPENDENCIES) $(EXTRA_test_sdptest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/sdptest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_sdptest_OBJECTS) $(test_sdptest_LDADD) $(LIBS)
-test/test-textfile.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/test-textfile$(EXEEXT): $(test_test_textfile_OBJECTS) $(test_test_textfile_DEPENDENCIES) $(EXTRA_test_test_textfile_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/test-textfile$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_test_textfile_OBJECTS) $(test_test_textfile_LDADD) $(LIBS)
-test/uuidtest.$(OBJEXT): test/$(am__dirstamp) \
-       test/$(DEPDIR)/$(am__dirstamp)
-test/uuidtest$(EXEEXT): $(test_uuidtest_OBJECTS) $(test_uuidtest_DEPENDENCIES) $(EXTRA_test_uuidtest_DEPENDENCIES) test/$(am__dirstamp)
-       @rm -f test/uuidtest$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(test_uuidtest_OBJECTS) $(test_uuidtest_LDADD) $(LIBS)
 tools/$(am__dirstamp):
        @$(MKDIR_P) tools
        @: > tools/$(am__dirstamp)
 tools/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) tools/$(DEPDIR)
        @: > tools/$(DEPDIR)/$(am__dirstamp)
-tools/avctrl.$(OBJEXT): tools/$(am__dirstamp) \
+tools/amptest.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/avctrl$(EXEEXT): $(tools_avctrl_OBJECTS) $(tools_avctrl_DEPENDENCIES) $(EXTRA_tools_avctrl_DEPENDENCIES) tools/$(am__dirstamp)
-       @rm -f tools/avctrl$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(tools_avctrl_OBJECTS) $(tools_avctrl_LDADD) $(LIBS)
+tools/amptest$(EXEEXT): $(tools_amptest_OBJECTS) $(tools_amptest_DEPENDENCIES) $(EXTRA_tools_amptest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/amptest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_amptest_OBJECTS) $(tools_amptest_LDADD) $(LIBS)
 tools/avinfo.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/avinfo$(EXEEXT): $(tools_avinfo_OBJECTS) $(tools_avinfo_DEPENDENCIES) $(EXTRA_tools_avinfo_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/avinfo$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_avinfo_OBJECTS) $(tools_avinfo_LDADD) $(LIBS)
+tools/avtest.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/avtest$(EXEEXT): $(tools_avtest_OBJECTS) $(tools_avtest_DEPENDENCIES) $(EXTRA_tools_avtest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/avtest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_avtest_OBJECTS) $(tools_avtest_LDADD) $(LIBS)
 tools/bccmd.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/csr.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/csr_hci.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
+tools/csr_usb.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
 tools/csr_h4.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/csr_3wire.$(OBJEXT): tools/$(am__dirstamp) \
@@ -2526,28 +2699,75 @@ tools/csr_bcsp.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/ubcsp.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/csr_usb.$(OBJEXT): tools/$(am__dirstamp) \
-       tools/$(DEPDIR)/$(am__dirstamp)
 tools/bccmd$(EXEEXT): $(tools_bccmd_OBJECTS) $(tools_bccmd_DEPENDENCIES) $(EXTRA_tools_bccmd_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/bccmd$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_bccmd_OBJECTS) $(tools_bccmd_LDADD) $(LIBS)
+tools/bdaddr.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+src/oui.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+tools/bdaddr$(EXEEXT): $(tools_bdaddr_OBJECTS) $(tools_bdaddr_DEPENDENCIES) $(EXTRA_tools_bdaddr_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/bdaddr$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_bdaddr_OBJECTS) $(tools_bdaddr_LDADD) $(LIBS)
+tools/bluetooth-player.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/bluetooth-player$(EXEEXT): $(tools_bluetooth_player_OBJECTS) $(tools_bluetooth_player_DEPENDENCIES) $(EXTRA_tools_bluetooth_player_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/bluetooth-player$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_bluetooth_player_OBJECTS) $(tools_bluetooth_player_LDADD) $(LIBS)
+tools/btattach.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/btattach$(EXEEXT): $(tools_btattach_OBJECTS) $(tools_btattach_DEPENDENCIES) $(EXTRA_tools_btattach_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/btattach$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_btattach_OBJECTS) $(tools_btattach_LDADD) $(LIBS)
+tools/btinfo.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/btinfo$(EXEEXT): $(tools_btinfo_OBJECTS) $(tools_btinfo_DEPENDENCIES) $(EXTRA_tools_btinfo_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/btinfo$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_btinfo_OBJECTS) $(tools_btinfo_LDADD) $(LIBS)
+tools/btiotest.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/btiotest$(EXEEXT): $(tools_btiotest_OBJECTS) $(tools_btiotest_DEPENDENCIES) $(EXTRA_tools_btiotest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/btiotest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_btiotest_OBJECTS) $(tools_btiotest_LDADD) $(LIBS)
+tools/btmgmt.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+src/glib-helper.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/eir.$(OBJEXT): src/$(am__dirstamp) src/$(DEPDIR)/$(am__dirstamp)
+src/shared/util.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/mgmt.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+tools/btmgmt$(EXEEXT): $(tools_btmgmt_OBJECTS) $(tools_btmgmt_DEPENDENCIES) $(EXTRA_tools_btmgmt_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/btmgmt$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_btmgmt_OBJECTS) $(tools_btmgmt_LDADD) $(LIBS)
+tools/btsnoop.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+src/shared/pcap.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/btsnoop.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+tools/btsnoop$(EXEEXT): $(tools_btsnoop_OBJECTS) $(tools_btsnoop_DEPENDENCIES) $(EXTRA_tools_btsnoop_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/btsnoop$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_btsnoop_OBJECTS) $(tools_btsnoop_LDADD) $(LIBS)
 tools/ciptool.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/ciptool$(EXEEXT): $(tools_ciptool_OBJECTS) $(tools_ciptool_DEPENDENCIES) $(EXTRA_tools_ciptool_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/ciptool$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_ciptool_OBJECTS) $(tools_ciptool_LDADD) $(LIBS)
-tools/dfubabel.$(OBJEXT): tools/$(am__dirstamp) \
+tools/cltest.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/dfubabel$(EXEEXT): $(tools_dfubabel_OBJECTS) $(tools_dfubabel_DEPENDENCIES) $(EXTRA_tools_dfubabel_DEPENDENCIES) tools/$(am__dirstamp)
-       @rm -f tools/dfubabel$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(tools_dfubabel_OBJECTS) $(tools_dfubabel_LDADD) $(LIBS)
-tools/dfutool.$(OBJEXT): tools/$(am__dirstamp) \
+tools/cltest$(EXEEXT): $(tools_cltest_OBJECTS) $(tools_cltest_DEPENDENCIES) $(EXTRA_tools_cltest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/cltest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_cltest_OBJECTS) $(tools_cltest_LDADD) $(LIBS)
+tools/gap-tester.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/dfu.$(OBJEXT): tools/$(am__dirstamp) \
-       tools/$(DEPDIR)/$(am__dirstamp)
-tools/dfutool$(EXEEXT): $(tools_dfutool_OBJECTS) $(tools_dfutool_DEPENDENCIES) $(EXTRA_tools_dfutool_DEPENDENCIES) tools/$(am__dirstamp)
-       @rm -f tools/dfutool$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(tools_dfutool_OBJECTS) $(tools_dfutool_LDADD) $(LIBS)
+src/shared/hciemu.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+src/shared/tester.$(OBJEXT): src/shared/$(am__dirstamp) \
+       src/shared/$(DEPDIR)/$(am__dirstamp)
+tools/gap-tester$(EXEEXT): $(tools_gap_tester_OBJECTS) $(tools_gap_tester_DEPENDENCIES) $(EXTRA_tools_gap_tester_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/gap-tester$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_gap_tester_OBJECTS) $(tools_gap_tester_LDADD) $(LIBS)
 tools/hciattach.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/hciattach_st.$(OBJEXT): tools/$(am__dirstamp) \
@@ -2570,6 +2790,65 @@ tools/hciconfig.$(OBJEXT): tools/$(am__dirstamp) \
 tools/hciconfig$(EXEEXT): $(tools_hciconfig_OBJECTS) $(tools_hciconfig_DEPENDENCIES) $(EXTRA_tools_hciconfig_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/hciconfig$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_hciconfig_OBJECTS) $(tools_hciconfig_LDADD) $(LIBS)
+tools/hcidump.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/parser/$(am__dirstamp):
+       @$(MKDIR_P) tools/parser
+       @: > tools/parser/$(am__dirstamp)
+tools/parser/$(DEPDIR)/$(am__dirstamp):
+       @$(MKDIR_P) tools/parser/$(DEPDIR)
+       @: > tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/parser.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/lmp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/hci.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/l2cap.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/amp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/smp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/att.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/sdp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/rfcomm.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/bnep.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/cmtp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/hidp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/hcrp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/avdtp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/avctp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/avrcp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/sap.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/obex.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/capi.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/ppp.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/tcpip.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/ericsson.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/csr.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/parser/bpa.$(OBJEXT): tools/parser/$(am__dirstamp) \
+       tools/parser/$(DEPDIR)/$(am__dirstamp)
+tools/hcidump$(EXEEXT): $(tools_hcidump_OBJECTS) $(tools_hcidump_DEPENDENCIES) $(EXTRA_tools_hcidump_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/hcidump$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_hcidump_OBJECTS) $(tools_hcidump_LDADD) $(LIBS)
 tools/hcieventmask.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/hcieventmask$(EXEEXT): $(tools_hcieventmask_OBJECTS) $(tools_hcieventmask_DEPENDENCIES) $(EXTRA_tools_hcieventmask_DEPENDENCIES) tools/$(am__dirstamp)
@@ -2590,30 +2869,83 @@ tools/hid2hci.$(OBJEXT): tools/$(am__dirstamp) \
 tools/hid2hci$(EXEEXT): $(tools_hid2hci_OBJECTS) $(tools_hid2hci_DEPENDENCIES) $(EXTRA_tools_hid2hci_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/hid2hci$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_hid2hci_OBJECTS) $(tools_hid2hci_LDADD) $(LIBS)
+tools/hwdb.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/hwdb$(EXEEXT): $(tools_hwdb_OBJECTS) $(tools_hwdb_DEPENDENCIES) $(EXTRA_tools_hwdb_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/hwdb$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_hwdb_OBJECTS) $(tools_hwdb_LDADD) $(LIBS)
+tools/l2cap-tester.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/l2cap-tester$(EXEEXT): $(tools_l2cap_tester_OBJECTS) $(tools_l2cap_tester_DEPENDENCIES) $(EXTRA_tools_l2cap_tester_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/l2cap-tester$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_l2cap_tester_OBJECTS) $(tools_l2cap_tester_LDADD) $(LIBS)
 tools/l2ping.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/l2ping$(EXEEXT): $(tools_l2ping_OBJECTS) $(tools_l2ping_DEPENDENCIES) $(EXTRA_tools_l2ping_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/l2ping$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_l2ping_OBJECTS) $(tools_l2ping_LDADD) $(LIBS)
-tools/ppporc.$(OBJEXT): tools/$(am__dirstamp) \
+tools/l2test.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/ppporc$(EXEEXT): $(tools_ppporc_OBJECTS) $(tools_ppporc_DEPENDENCIES) $(EXTRA_tools_ppporc_DEPENDENCIES) tools/$(am__dirstamp)
-       @rm -f tools/ppporc$(EXEEXT)
-       $(AM_V_CCLD)$(LINK) $(tools_ppporc_OBJECTS) $(tools_ppporc_LDADD) $(LIBS)
-tools/rfcomm.$(OBJEXT): tools/$(am__dirstamp) \
+tools/l2test$(EXEEXT): $(tools_l2test_OBJECTS) $(tools_l2test_DEPENDENCIES) $(EXTRA_tools_l2test_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/l2test$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_l2test_OBJECTS) $(tools_l2test_LDADD) $(LIBS)
+tools/mgmt-tester.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/mgmt-tester$(EXEEXT): $(tools_mgmt_tester_OBJECTS) $(tools_mgmt_tester_DEPENDENCIES) $(EXTRA_tools_mgmt_tester_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/mgmt-tester$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_mgmt_tester_OBJECTS) $(tools_mgmt_tester_LDADD) $(LIBS)
+tools/mpris-player.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/mpris-player$(EXEEXT): $(tools_mpris_player_OBJECTS) $(tools_mpris_player_DEPENDENCIES) $(EXTRA_tools_mpris_player_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/mpris-player$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_mpris_player_OBJECTS) $(tools_mpris_player_LDADD) $(LIBS)
+gobex/gobex.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-defs.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-packet.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-header.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-transfer.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+gobex/gobex-apparam.$(OBJEXT): gobex/$(am__dirstamp) \
+       gobex/$(DEPDIR)/$(am__dirstamp)
+tools/obex-client-tool.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/parser.h: tools/parser.c
-       @if test ! -f $@; then rm -f tools/parser.c; else :; fi
-       @if test ! -f $@; then $(MAKE) $(AM_MAKEFLAGS) tools/parser.c; else :; fi
-tools/parser.$(OBJEXT): tools/$(am__dirstamp) \
+tools/obex-client-tool$(EXEEXT): $(tools_obex_client_tool_OBJECTS) $(tools_obex_client_tool_DEPENDENCIES) $(EXTRA_tools_obex_client_tool_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/obex-client-tool$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_obex_client_tool_OBJECTS) $(tools_obex_client_tool_LDADD) $(LIBS)
+tools/obex-server-tool.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/lexer.$(OBJEXT): tools/$(am__dirstamp) \
+tools/obex-server-tool$(EXEEXT): $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_DEPENDENCIES) $(EXTRA_tools_obex_server_tool_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/obex-server-tool$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_obex_server_tool_OBJECTS) $(tools_obex_server_tool_LDADD) $(LIBS)
+tools/obexctl.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
-tools/kword.$(OBJEXT): tools/$(am__dirstamp) \
+tools/obexctl$(EXEEXT): $(tools_obexctl_OBJECTS) $(tools_obexctl_DEPENDENCIES) $(EXTRA_tools_obexctl_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/obexctl$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_obexctl_OBJECTS) $(tools_obexctl_LDADD) $(LIBS)
+tools/rctest.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/rctest$(EXEEXT): $(tools_rctest_OBJECTS) $(tools_rctest_DEPENDENCIES) $(EXTRA_tools_rctest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/rctest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_rctest_OBJECTS) $(tools_rctest_LDADD) $(LIBS)
+tools/rfcomm.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 tools/rfcomm$(EXEEXT): $(tools_rfcomm_OBJECTS) $(tools_rfcomm_DEPENDENCIES) $(EXTRA_tools_rfcomm_DEPENDENCIES) tools/$(am__dirstamp)
        @rm -f tools/rfcomm$(EXEEXT)
        $(AM_V_CCLD)$(LINK) $(tools_rfcomm_OBJECTS) $(tools_rfcomm_LDADD) $(LIBS)
+tools/sco-tester.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/sco-tester$(EXEEXT): $(tools_sco_tester_OBJECTS) $(tools_sco_tester_DEPENDENCIES) $(EXTRA_tools_sco_tester_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/sco-tester$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_sco_tester_OBJECTS) $(tools_sco_tester_LDADD) $(LIBS)
+tools/scotest.$(OBJEXT): tools/$(am__dirstamp) \
+       tools/$(DEPDIR)/$(am__dirstamp)
+tools/scotest$(EXEEXT): $(tools_scotest_OBJECTS) $(tools_scotest_DEPENDENCIES) $(EXTRA_tools_scotest_DEPENDENCIES) tools/$(am__dirstamp)
+       @rm -f tools/scotest$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(tools_scotest_OBJECTS) $(tools_scotest_LDADD) $(LIBS)
 tools/sdptool.$(OBJEXT): tools/$(am__dirstamp) \
        tools/$(DEPDIR)/$(am__dirstamp)
 src/sdp-xml.$(OBJEXT): src/$(am__dirstamp) \
@@ -2627,19 +2959,88 @@ unit/$(am__dirstamp):
 unit/$(DEPDIR)/$(am__dirstamp):
        @$(MKDIR_P) unit/$(DEPDIR)
        @: > unit/$(DEPDIR)/$(am__dirstamp)
-unit/unit_test_eir-test-eir.$(OBJEXT): unit/$(am__dirstamp) \
+unit/test-crc.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-crc$(EXEEXT): $(unit_test_crc_OBJECTS) $(unit_test_crc_DEPENDENCIES) $(EXTRA_unit_test_crc_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-crc$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_crc_OBJECTS) $(unit_test_crc_LDADD) $(LIBS)
+unit/test-eir.$(OBJEXT): unit/$(am__dirstamp) \
        unit/$(DEPDIR)/$(am__dirstamp)
-src/unit_test_eir-eir.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
-src/unit_test_eir-glib-helper.$(OBJEXT): src/$(am__dirstamp) \
-       src/$(DEPDIR)/$(am__dirstamp)
 unit/test-eir$(EXEEXT): $(unit_test_eir_OBJECTS) $(unit_test_eir_DEPENDENCIES) $(EXTRA_unit_test_eir_DEPENDENCIES) unit/$(am__dirstamp)
        @rm -f unit/test-eir$(EXEEXT)
-       $(AM_V_CCLD)$(unit_test_eir_LINK) $(unit_test_eir_OBJECTS) $(unit_test_eir_LDADD) $(LIBS)
-install-dist_udevSCRIPTS: $(dist_udev_SCRIPTS)
+       $(AM_V_CCLD)$(LINK) $(unit_test_eir_OBJECTS) $(unit_test_eir_LDADD) $(LIBS)
+unit/test-gdbus-client.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gdbus-client$(EXEEXT): $(unit_test_gdbus_client_OBJECTS) $(unit_test_gdbus_client_DEPENDENCIES) $(EXTRA_unit_test_gdbus_client_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gdbus-client$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gdbus_client_OBJECTS) $(unit_test_gdbus_client_LDADD) $(LIBS)
+unit/util.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex$(EXEEXT): $(unit_test_gobex_OBJECTS) $(unit_test_gobex_DEPENDENCIES) $(EXTRA_unit_test_gobex_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_OBJECTS) $(unit_test_gobex_LDADD) $(LIBS)
+unit/test-gobex-apparam.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-apparam$(EXEEXT): $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_DEPENDENCIES) $(EXTRA_unit_test_gobex_apparam_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex-apparam$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_apparam_OBJECTS) $(unit_test_gobex_apparam_LDADD) $(LIBS)
+unit/test-gobex-header.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-header$(EXEEXT): $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_DEPENDENCIES) $(EXTRA_unit_test_gobex_header_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex-header$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_header_OBJECTS) $(unit_test_gobex_header_LDADD) $(LIBS)
+unit/test-gobex-packet.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-packet$(EXEEXT): $(unit_test_gobex_packet_OBJECTS) $(unit_test_gobex_packet_DEPENDENCIES) $(EXTRA_unit_test_gobex_packet_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex-packet$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_packet_OBJECTS) $(unit_test_gobex_packet_LDADD) $(LIBS)
+unit/test-gobex-transfer.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-gobex-transfer$(EXEEXT): $(unit_test_gobex_transfer_OBJECTS) $(unit_test_gobex_transfer_DEPENDENCIES) $(EXTRA_unit_test_gobex_transfer_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-gobex-transfer$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_gobex_transfer_OBJECTS) $(unit_test_gobex_transfer_LDADD) $(LIBS)
+unit/test-lib.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-lib$(EXEEXT): $(unit_test_lib_OBJECTS) $(unit_test_lib_DEPENDENCIES) $(EXTRA_unit_test_lib_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-lib$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_lib_OBJECTS) $(unit_test_lib_LDADD) $(LIBS)
+unit/test-mgmt.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-mgmt$(EXEEXT): $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_DEPENDENCIES) $(EXTRA_unit_test_mgmt_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-mgmt$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_mgmt_OBJECTS) $(unit_test_mgmt_LDADD) $(LIBS)
+unit/test-sdp.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-database.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-service.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+src/sdpd-request.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+unit/test-sdp$(EXEEXT): $(unit_test_sdp_OBJECTS) $(unit_test_sdp_DEPENDENCIES) $(EXTRA_unit_test_sdp_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-sdp$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_sdp_OBJECTS) $(unit_test_sdp_LDADD) $(LIBS)
+unit/test-textfile.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+src/textfile.$(OBJEXT): src/$(am__dirstamp) \
+       src/$(DEPDIR)/$(am__dirstamp)
+unit/test-textfile$(EXEEXT): $(unit_test_textfile_OBJECTS) $(unit_test_textfile_DEPENDENCIES) $(EXTRA_unit_test_textfile_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-textfile$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_textfile_OBJECTS) $(unit_test_textfile_LDADD) $(LIBS)
+unit/test-uuid.$(OBJEXT): unit/$(am__dirstamp) \
+       unit/$(DEPDIR)/$(am__dirstamp)
+unit/test-uuid$(EXEEXT): $(unit_test_uuid_OBJECTS) $(unit_test_uuid_DEPENDENCIES) $(EXTRA_unit_test_uuid_DEPENDENCIES) unit/$(am__dirstamp)
+       @rm -f unit/test-uuid$(EXEEXT)
+       $(AM_V_CCLD)$(LINK) $(unit_test_uuid_OBJECTS) $(unit_test_uuid_LDADD) $(LIBS)
+install-testSCRIPTS: $(test_SCRIPTS)
        @$(NORMAL_INSTALL)
-       test -z "$(udevdir)" || $(MKDIR_P) "$(DESTDIR)$(udevdir)"
-       @list='$(dist_udev_SCRIPTS)'; test -n "$(udevdir)" || list=; \
+       @list='$(test_SCRIPTS)'; test -n "$(testdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(testdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(testdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          if test -f "$$d$$p"; then echo "$$d$$p"; echo "$$p"; else :; fi; \
@@ -2657,25 +3058,23 @@ install-dist_udevSCRIPTS: $(dist_udev_SCRIPTS)
        while read type dir files; do \
             if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \
             test -z "$$files" || { \
-              echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(udevdir)$$dir'"; \
-              $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(udevdir)$$dir" || exit $$?; \
+              echo " $(INSTALL_SCRIPT) $$files '$(DESTDIR)$(testdir)$$dir'"; \
+              $(INSTALL_SCRIPT) $$files "$(DESTDIR)$(testdir)$$dir" || exit $$?; \
             } \
        ; done
 
-uninstall-dist_udevSCRIPTS:
+uninstall-testSCRIPTS:
        @$(NORMAL_UNINSTALL)
-       @list='$(dist_udev_SCRIPTS)'; test -n "$(udevdir)" || exit 0; \
+       @list='$(test_SCRIPTS)'; test -n "$(testdir)" || exit 0; \
        files=`for p in $$list; do echo "$$p"; done | \
               sed -e 's,.*/,,;$(transform)'`; \
-       dir='$(DESTDIR)$(udevdir)'; $(am__uninstall_files_from_dir)
+       dir='$(DESTDIR)$(testdir)'; $(am__uninstall_files_from_dir)
 
 mostlyclean-compile:
        -rm -f *.$(OBJEXT)
-       -rm -f alert/bluetoothd-main.$(OBJEXT)
-       -rm -f alert/bluetoothd-server.$(OBJEXT)
+       -rm -f android/main.$(OBJEXT)
        -rm -f attrib/att.$(OBJEXT)
        -rm -f attrib/bluetoothd-att.$(OBJEXT)
-       -rm -f attrib/bluetoothd-client.$(OBJEXT)
        -rm -f attrib/bluetoothd-gatt-service.$(OBJEXT)
        -rm -f attrib/bluetoothd-gatt.$(OBJEXT)
        -rm -f attrib/bluetoothd-gattrib.$(OBJEXT)
@@ -2684,94 +3083,41 @@ mostlyclean-compile:
        -rm -f attrib/gatttool.$(OBJEXT)
        -rm -f attrib/interactive.$(OBJEXT)
        -rm -f attrib/utils.$(OBJEXT)
-       -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.$(OBJEXT)
-       -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo
-       -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ipc.$(OBJEXT)
-       -rm -f audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo
-       -rm -f audio/audio_libasound_module_pcm_bluetooth_la-ipc.$(OBJEXT)
-       -rm -f audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo
-       -rm -f audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.$(OBJEXT)
-       -rm -f audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo
-       -rm -f audio/audio_libgstbluetooth_la-gsta2dpsink.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gsta2dpsink.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstavdtpsink.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstavdtpsink.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstbluetooth.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstbluetooth.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstrtpsbcpay.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcdec.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcdec.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcenc.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcenc.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcparse.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcparse.lo
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcutil.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-gstsbcutil.lo
-       -rm -f audio/audio_libgstbluetooth_la-ipc.$(OBJEXT)
-       -rm -f audio/audio_libgstbluetooth_la-ipc.lo
-       -rm -f audio/bluetoothd-a2dp.$(OBJEXT)
-       -rm -f audio/bluetoothd-avctp.$(OBJEXT)
-       -rm -f audio/bluetoothd-avdtp.$(OBJEXT)
-       -rm -f audio/bluetoothd-avrcp.$(OBJEXT)
-       -rm -f audio/bluetoothd-control.$(OBJEXT)
-       -rm -f audio/bluetoothd-device.$(OBJEXT)
-       -rm -f audio/bluetoothd-gateway.$(OBJEXT)
-       -rm -f audio/bluetoothd-headset.$(OBJEXT)
-       -rm -f audio/bluetoothd-ipc.$(OBJEXT)
-       -rm -f audio/bluetoothd-main.$(OBJEXT)
-       -rm -f audio/bluetoothd-manager.$(OBJEXT)
-       -rm -f audio/bluetoothd-media.$(OBJEXT)
-       -rm -f audio/bluetoothd-sink.$(OBJEXT)
-       -rm -f audio/bluetoothd-source.$(OBJEXT)
-       -rm -f audio/bluetoothd-telephony.$(OBJEXT)
-       -rm -f audio/bluetoothd-transport.$(OBJEXT)
-       -rm -f audio/bluetoothd-unix.$(OBJEXT)
-       -rm -f audio/ipc.$(OBJEXT)
-       -rm -f audio/telephony-dummy.$(OBJEXT)
-       -rm -f audio/telephony-maemo5.$(OBJEXT)
-       -rm -f audio/telephony-maemo6.$(OBJEXT)
-       -rm -f audio/telephony-ofono.$(OBJEXT)
        -rm -f btio/bluetoothd-btio.$(OBJEXT)
        -rm -f btio/btio.$(OBJEXT)
-       -rm -f compat/bnep.$(OBJEXT)
-       -rm -f compat/dun.$(OBJEXT)
-       -rm -f compat/dund.$(OBJEXT)
-       -rm -f compat/fakehid.$(OBJEXT)
-       -rm -f compat/hidd.$(OBJEXT)
-       -rm -f compat/msdun.$(OBJEXT)
-       -rm -f compat/pand.$(OBJEXT)
-       -rm -f compat/sdp.$(OBJEXT)
-       -rm -f cups/hcrp.$(OBJEXT)
-       -rm -f cups/main.$(OBJEXT)
-       -rm -f cups/sdp.$(OBJEXT)
-       -rm -f cups/spp.$(OBJEXT)
-       -rm -f deviceinfo/bluetoothd-deviceinfo.$(OBJEXT)
-       -rm -f deviceinfo/bluetoothd-main.$(OBJEXT)
-       -rm -f deviceinfo/bluetoothd-manager.$(OBJEXT)
+       -rm -f btio/obexd-btio.$(OBJEXT)
+       -rm -f client/agent.$(OBJEXT)
+       -rm -f client/display.$(OBJEXT)
+       -rm -f client/main.$(OBJEXT)
+       -rm -f emulator/amp.$(OBJEXT)
+       -rm -f emulator/b1ee.$(OBJEXT)
        -rm -f emulator/btdev.$(OBJEXT)
+       -rm -f emulator/bthost.$(OBJEXT)
        -rm -f emulator/main.$(OBJEXT)
        -rm -f emulator/server.$(OBJEXT)
        -rm -f emulator/vhci.$(OBJEXT)
-       -rm -f gdbus/bluetoothd-mainloop.$(OBJEXT)
-       -rm -f gdbus/bluetoothd-object.$(OBJEXT)
-       -rm -f gdbus/bluetoothd-polkit.$(OBJEXT)
-       -rm -f gdbus/bluetoothd-watch.$(OBJEXT)
+       -rm -f gdbus/client.$(OBJEXT)
+       -rm -f gdbus/client.lo
        -rm -f gdbus/mainloop.$(OBJEXT)
+       -rm -f gdbus/mainloop.lo
        -rm -f gdbus/object.$(OBJEXT)
+       -rm -f gdbus/object.lo
        -rm -f gdbus/polkit.$(OBJEXT)
+       -rm -f gdbus/polkit.lo
        -rm -f gdbus/watch.$(OBJEXT)
-       -rm -f health/bluetoothd-hdp.$(OBJEXT)
-       -rm -f health/bluetoothd-hdp_main.$(OBJEXT)
-       -rm -f health/bluetoothd-hdp_manager.$(OBJEXT)
-       -rm -f health/bluetoothd-hdp_util.$(OBJEXT)
-       -rm -f health/bluetoothd-mcap.$(OBJEXT)
-       -rm -f health/bluetoothd-mcap_sync.$(OBJEXT)
-       -rm -f input/bluetoothd-device.$(OBJEXT)
-       -rm -f input/bluetoothd-fakehid.$(OBJEXT)
-       -rm -f input/bluetoothd-main.$(OBJEXT)
-       -rm -f input/bluetoothd-manager.$(OBJEXT)
-       -rm -f input/bluetoothd-server.$(OBJEXT)
+       -rm -f gdbus/watch.lo
+       -rm -f gobex/gobex-apparam.$(OBJEXT)
+       -rm -f gobex/gobex-defs.$(OBJEXT)
+       -rm -f gobex/gobex-header.$(OBJEXT)
+       -rm -f gobex/gobex-packet.$(OBJEXT)
+       -rm -f gobex/gobex-transfer.$(OBJEXT)
+       -rm -f gobex/gobex.$(OBJEXT)
+       -rm -f gobex/obexd-gobex-apparam.$(OBJEXT)
+       -rm -f gobex/obexd-gobex-defs.$(OBJEXT)
+       -rm -f gobex/obexd-gobex-header.$(OBJEXT)
+       -rm -f gobex/obexd-gobex-packet.$(OBJEXT)
+       -rm -f gobex/obexd-gobex-transfer.$(OBJEXT)
+       -rm -f gobex/obexd-gobex.$(OBJEXT)
        -rm -f lib/bluetooth.$(OBJEXT)
        -rm -f lib/bluetooth.lo
        -rm -f lib/hci.$(OBJEXT)
@@ -2780,64 +3126,111 @@ mostlyclean-compile:
        -rm -f lib/sdp.lo
        -rm -f lib/uuid.$(OBJEXT)
        -rm -f lib/uuid.lo
-       -rm -f mgmt/main.$(OBJEXT)
        -rm -f monitor/btsnoop.$(OBJEXT)
        -rm -f monitor/control.$(OBJEXT)
+       -rm -f monitor/crc.$(OBJEXT)
+       -rm -f monitor/display.$(OBJEXT)
        -rm -f monitor/hcidump.$(OBJEXT)
+       -rm -f monitor/l2cap.$(OBJEXT)
+       -rm -f monitor/ll.$(OBJEXT)
+       -rm -f monitor/lmp.$(OBJEXT)
        -rm -f monitor/main.$(OBJEXT)
        -rm -f monitor/mainloop.$(OBJEXT)
        -rm -f monitor/packet.$(OBJEXT)
-       -rm -f network/bluetoothd-common.$(OBJEXT)
-       -rm -f network/bluetoothd-connection.$(OBJEXT)
-       -rm -f network/bluetoothd-main.$(OBJEXT)
-       -rm -f network/bluetoothd-manager.$(OBJEXT)
-       -rm -f network/bluetoothd-server.$(OBJEXT)
-       -rm -f plugins/bluetoothd-adaptername.$(OBJEXT)
-       -rm -f plugins/bluetoothd-dbusoob.$(OBJEXT)
-       -rm -f plugins/bluetoothd-formfactor.$(OBJEXT)
+       -rm -f monitor/sdp.$(OBJEXT)
+       -rm -f monitor/uuid.$(OBJEXT)
+       -rm -f monitor/vendor.$(OBJEXT)
+       -rm -f obexd/client/obexd-bluetooth.$(OBJEXT)
+       -rm -f obexd/client/obexd-dbus.$(OBJEXT)
+       -rm -f obexd/client/obexd-driver.$(OBJEXT)
+       -rm -f obexd/client/obexd-ftp.$(OBJEXT)
+       -rm -f obexd/client/obexd-manager.$(OBJEXT)
+       -rm -f obexd/client/obexd-map-event.$(OBJEXT)
+       -rm -f obexd/client/obexd-map.$(OBJEXT)
+       -rm -f obexd/client/obexd-mns.$(OBJEXT)
+       -rm -f obexd/client/obexd-opp.$(OBJEXT)
+       -rm -f obexd/client/obexd-pbap.$(OBJEXT)
+       -rm -f obexd/client/obexd-session.$(OBJEXT)
+       -rm -f obexd/client/obexd-sync.$(OBJEXT)
+       -rm -f obexd/client/obexd-transfer.$(OBJEXT)
+       -rm -f obexd/client/obexd-transport.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-bluetooth.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-filesystem.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-ftp.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-irmc.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-mas.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-messages-dummy.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-opp.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-pbap.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-pcsuite.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-phonebook-dummy.$(OBJEXT)
+       -rm -f obexd/plugins/obexd-vcard.$(OBJEXT)
+       -rm -f obexd/src/obexd-log.$(OBJEXT)
+       -rm -f obexd/src/obexd-main.$(OBJEXT)
+       -rm -f obexd/src/obexd-manager.$(OBJEXT)
+       -rm -f obexd/src/obexd-mimetype.$(OBJEXT)
+       -rm -f obexd/src/obexd-obex.$(OBJEXT)
+       -rm -f obexd/src/obexd-plugin.$(OBJEXT)
+       -rm -f obexd/src/obexd-server.$(OBJEXT)
+       -rm -f obexd/src/obexd-service.$(OBJEXT)
+       -rm -f obexd/src/obexd-transport.$(OBJEXT)
+       -rm -f plugins/bluetoothd-autopair.$(OBJEXT)
        -rm -f plugins/bluetoothd-gatt-example.$(OBJEXT)
-       -rm -f plugins/bluetoothd-hal.$(OBJEXT)
-       -rm -f plugins/bluetoothd-hciops.$(OBJEXT)
-       -rm -f plugins/bluetoothd-maemo6.$(OBJEXT)
-       -rm -f plugins/bluetoothd-mgmtops.$(OBJEXT)
-       -rm -f plugins/bluetoothd-pnat.$(OBJEXT)
-       -rm -f plugins/bluetoothd-service.$(OBJEXT)
-       -rm -f plugins/bluetoothd-storage.$(OBJEXT)
+       -rm -f plugins/bluetoothd-hostname.$(OBJEXT)
+       -rm -f plugins/bluetoothd-neard.$(OBJEXT)
+       -rm -f plugins/bluetoothd-policy.$(OBJEXT)
        -rm -f plugins/bluetoothd-wiimote.$(OBJEXT)
        -rm -f plugins/plugins_external_dummy_la-external-dummy.$(OBJEXT)
        -rm -f plugins/plugins_external_dummy_la-external-dummy.lo
-       -rm -f proximity/bluetoothd-immalert.$(OBJEXT)
-       -rm -f proximity/bluetoothd-linkloss.$(OBJEXT)
-       -rm -f proximity/bluetoothd-main.$(OBJEXT)
-       -rm -f proximity/bluetoothd-manager.$(OBJEXT)
-       -rm -f proximity/bluetoothd-monitor.$(OBJEXT)
-       -rm -f proximity/bluetoothd-reporter.$(OBJEXT)
-       -rm -f sap/bluetoothd-main.$(OBJEXT)
-       -rm -f sap/bluetoothd-manager.$(OBJEXT)
-       -rm -f sap/bluetoothd-sap.$(OBJEXT)
-       -rm -f sap/bluetoothd-server.$(OBJEXT)
-       -rm -f sap/sap-dummy.$(OBJEXT)
-       -rm -f sap/sap-u8500.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc.lo
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives.lo
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_armv6.lo
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_mmx.lo
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_neon.$(OBJEXT)
-       -rm -f sbc/sbc_libsbc_la-sbc_primitives_neon.lo
-       -rm -f sbc/sbcdec.$(OBJEXT)
-       -rm -f sbc/sbcenc.$(OBJEXT)
-       -rm -f sbc/sbcinfo.$(OBJEXT)
-       -rm -f sbc/sbctester.$(OBJEXT)
-       -rm -f serial/bluetoothd-main.$(OBJEXT)
-       -rm -f serial/bluetoothd-manager.$(OBJEXT)
-       -rm -f serial/bluetoothd-port.$(OBJEXT)
-       -rm -f serial/bluetoothd-proxy.$(OBJEXT)
+       -rm -f profiles/alert/bluetoothd-server.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-a2dp.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-avctp.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-avdtp.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-avrcp.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-control.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-media.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-player.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-sink.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-source.$(OBJEXT)
+       -rm -f profiles/audio/bluetoothd-transport.$(OBJEXT)
+       -rm -f profiles/cups/hcrp.$(OBJEXT)
+       -rm -f profiles/cups/main.$(OBJEXT)
+       -rm -f profiles/cups/sdp.$(OBJEXT)
+       -rm -f profiles/cups/spp.$(OBJEXT)
+       -rm -f profiles/cyclingspeed/bluetoothd-cyclingspeed.$(OBJEXT)
+       -rm -f profiles/deviceinfo/bluetoothd-deviceinfo.$(OBJEXT)
+       -rm -f profiles/gatt/bluetoothd-gas.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-hdp.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-hdp_main.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-hdp_manager.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-hdp_util.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-mcap.$(OBJEXT)
+       -rm -f profiles/health/bluetoothd-mcap_sync.$(OBJEXT)
+       -rm -f profiles/heartrate/bluetoothd-heartrate.$(OBJEXT)
+       -rm -f profiles/iap/main.$(OBJEXT)
+       -rm -f profiles/input/bluetoothd-device.$(OBJEXT)
+       -rm -f profiles/input/bluetoothd-hog.$(OBJEXT)
+       -rm -f profiles/input/bluetoothd-manager.$(OBJEXT)
+       -rm -f profiles/input/bluetoothd-server.$(OBJEXT)
+       -rm -f profiles/input/bluetoothd-suspend-dummy.$(OBJEXT)
+       -rm -f profiles/network/bluetoothd-common.$(OBJEXT)
+       -rm -f profiles/network/bluetoothd-connection.$(OBJEXT)
+       -rm -f profiles/network/bluetoothd-manager.$(OBJEXT)
+       -rm -f profiles/network/bluetoothd-server.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-immalert.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-linkloss.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-main.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-manager.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-monitor.$(OBJEXT)
+       -rm -f profiles/proximity/bluetoothd-reporter.$(OBJEXT)
+       -rm -f profiles/sap/bluetoothd-main.$(OBJEXT)
+       -rm -f profiles/sap/bluetoothd-manager.$(OBJEXT)
+       -rm -f profiles/sap/bluetoothd-sap-dummy.$(OBJEXT)
+       -rm -f profiles/sap/bluetoothd-server.$(OBJEXT)
+       -rm -f profiles/sap/sap-u8500.$(OBJEXT)
+       -rm -f profiles/scanparam/bluetoothd-scan.$(OBJEXT)
+       -rm -f profiles/thermometer/bluetoothd-thermometer.$(OBJEXT)
+       -rm -f profiles/time/bluetoothd-server.$(OBJEXT)
        -rm -f src/bluetoothd-adapter.$(OBJEXT)
        -rm -f src/bluetoothd-agent.$(OBJEXT)
        -rm -f src/bluetoothd-attrib-server.$(OBJEXT)
@@ -2845,14 +3238,11 @@ mostlyclean-compile:
        -rm -f src/bluetoothd-device.$(OBJEXT)
        -rm -f src/bluetoothd-eir.$(OBJEXT)
        -rm -f src/bluetoothd-error.$(OBJEXT)
-       -rm -f src/bluetoothd-event.$(OBJEXT)
        -rm -f src/bluetoothd-glib-helper.$(OBJEXT)
        -rm -f src/bluetoothd-log.$(OBJEXT)
        -rm -f src/bluetoothd-main.$(OBJEXT)
-       -rm -f src/bluetoothd-manager.$(OBJEXT)
-       -rm -f src/bluetoothd-oob.$(OBJEXT)
-       -rm -f src/bluetoothd-oui.$(OBJEXT)
        -rm -f src/bluetoothd-plugin.$(OBJEXT)
+       -rm -f src/bluetoothd-profile.$(OBJEXT)
        -rm -f src/bluetoothd-rfkill.$(OBJEXT)
        -rm -f src/bluetoothd-sdp-client.$(OBJEXT)
        -rm -f src/bluetoothd-sdp-xml.$(OBJEXT)
@@ -2860,50 +3250,47 @@ mostlyclean-compile:
        -rm -f src/bluetoothd-sdpd-request.$(OBJEXT)
        -rm -f src/bluetoothd-sdpd-server.$(OBJEXT)
        -rm -f src/bluetoothd-sdpd-service.$(OBJEXT)
+       -rm -f src/bluetoothd-service.$(OBJEXT)
        -rm -f src/bluetoothd-storage.$(OBJEXT)
+       -rm -f src/bluetoothd-systemd.$(OBJEXT)
        -rm -f src/bluetoothd-textfile.$(OBJEXT)
+       -rm -f src/eir.$(OBJEXT)
        -rm -f src/glib-helper.$(OBJEXT)
        -rm -f src/log.$(OBJEXT)
        -rm -f src/oui.$(OBJEXT)
        -rm -f src/sdp-xml.$(OBJEXT)
+       -rm -f src/sdpd-database.$(OBJEXT)
+       -rm -f src/sdpd-request.$(OBJEXT)
+       -rm -f src/sdpd-service.$(OBJEXT)
+       -rm -f src/shared/bluetoothd-mgmt.$(OBJEXT)
+       -rm -f src/shared/bluetoothd-util.$(OBJEXT)
+       -rm -f src/shared/btsnoop.$(OBJEXT)
+       -rm -f src/shared/hciemu.$(OBJEXT)
+       -rm -f src/shared/mgmt.$(OBJEXT)
+       -rm -f src/shared/pcap.$(OBJEXT)
+       -rm -f src/shared/tester.$(OBJEXT)
+       -rm -f src/shared/util.$(OBJEXT)
        -rm -f src/textfile.$(OBJEXT)
-       -rm -f src/unit_test_eir-eir.$(OBJEXT)
-       -rm -f src/unit_test_eir-glib-helper.$(OBJEXT)
-       -rm -f test/agent.$(OBJEXT)
-       -rm -f test/attest.$(OBJEXT)
-       -rm -f test/avtest.$(OBJEXT)
-       -rm -f test/bdaddr.$(OBJEXT)
-       -rm -f test/btiotest.$(OBJEXT)
-       -rm -f test/gaptest.$(OBJEXT)
-       -rm -f test/hciemu.$(OBJEXT)
-       -rm -f test/hstest.$(OBJEXT)
-       -rm -f test/ipctest.$(OBJEXT)
-       -rm -f test/l2test.$(OBJEXT)
-       -rm -f test/lmptest.$(OBJEXT)
-       -rm -f test/mpris-player.$(OBJEXT)
-       -rm -f test/rctest.$(OBJEXT)
-       -rm -f test/scotest.$(OBJEXT)
-       -rm -f test/sdptest.$(OBJEXT)
-       -rm -f test/test-textfile.$(OBJEXT)
-       -rm -f test/uuidtest.$(OBJEXT)
-       -rm -f thermometer/bluetoothd-main.$(OBJEXT)
-       -rm -f thermometer/bluetoothd-manager.$(OBJEXT)
-       -rm -f thermometer/bluetoothd-thermometer.$(OBJEXT)
-       -rm -f time/bluetoothd-main.$(OBJEXT)
-       -rm -f time/bluetoothd-server.$(OBJEXT)
-       -rm -f tools/avctrl.$(OBJEXT)
+       -rm -f tools/amptest.$(OBJEXT)
        -rm -f tools/avinfo.$(OBJEXT)
+       -rm -f tools/avtest.$(OBJEXT)
        -rm -f tools/bccmd.$(OBJEXT)
+       -rm -f tools/bdaddr.$(OBJEXT)
+       -rm -f tools/bluetooth-player.$(OBJEXT)
+       -rm -f tools/btattach.$(OBJEXT)
+       -rm -f tools/btinfo.$(OBJEXT)
+       -rm -f tools/btiotest.$(OBJEXT)
+       -rm -f tools/btmgmt.$(OBJEXT)
+       -rm -f tools/btsnoop.$(OBJEXT)
        -rm -f tools/ciptool.$(OBJEXT)
+       -rm -f tools/cltest.$(OBJEXT)
        -rm -f tools/csr.$(OBJEXT)
        -rm -f tools/csr_3wire.$(OBJEXT)
        -rm -f tools/csr_bcsp.$(OBJEXT)
        -rm -f tools/csr_h4.$(OBJEXT)
        -rm -f tools/csr_hci.$(OBJEXT)
        -rm -f tools/csr_usb.$(OBJEXT)
-       -rm -f tools/dfu.$(OBJEXT)
-       -rm -f tools/dfubabel.$(OBJEXT)
-       -rm -f tools/dfutool.$(OBJEXT)
+       -rm -f tools/gap-tester.$(OBJEXT)
        -rm -f tools/hciattach.$(OBJEXT)
        -rm -f tools/hciattach_ath3k.$(OBJEXT)
        -rm -f tools/hciattach_intel.$(OBJEXT)
@@ -2912,28 +3299,71 @@ mostlyclean-compile:
        -rm -f tools/hciattach_ti.$(OBJEXT)
        -rm -f tools/hciattach_tialt.$(OBJEXT)
        -rm -f tools/hciconfig.$(OBJEXT)
+       -rm -f tools/hcidump.$(OBJEXT)
        -rm -f tools/hcieventmask.$(OBJEXT)
        -rm -f tools/hcisecfilter.$(OBJEXT)
        -rm -f tools/hcitool.$(OBJEXT)
        -rm -f tools/hid2hci.$(OBJEXT)
-       -rm -f tools/kword.$(OBJEXT)
+       -rm -f tools/hwdb.$(OBJEXT)
+       -rm -f tools/l2cap-tester.$(OBJEXT)
        -rm -f tools/l2ping.$(OBJEXT)
-       -rm -f tools/lexer.$(OBJEXT)
-       -rm -f tools/parser.$(OBJEXT)
-       -rm -f tools/ppporc.$(OBJEXT)
+       -rm -f tools/l2test.$(OBJEXT)
+       -rm -f tools/mgmt-tester.$(OBJEXT)
+       -rm -f tools/mpris-player.$(OBJEXT)
+       -rm -f tools/obex-client-tool.$(OBJEXT)
+       -rm -f tools/obex-server-tool.$(OBJEXT)
+       -rm -f tools/obexctl.$(OBJEXT)
+       -rm -f tools/parser/amp.$(OBJEXT)
+       -rm -f tools/parser/att.$(OBJEXT)
+       -rm -f tools/parser/avctp.$(OBJEXT)
+       -rm -f tools/parser/avdtp.$(OBJEXT)
+       -rm -f tools/parser/avrcp.$(OBJEXT)
+       -rm -f tools/parser/bnep.$(OBJEXT)
+       -rm -f tools/parser/bpa.$(OBJEXT)
+       -rm -f tools/parser/capi.$(OBJEXT)
+       -rm -f tools/parser/cmtp.$(OBJEXT)
+       -rm -f tools/parser/csr.$(OBJEXT)
+       -rm -f tools/parser/ericsson.$(OBJEXT)
+       -rm -f tools/parser/hci.$(OBJEXT)
+       -rm -f tools/parser/hcrp.$(OBJEXT)
+       -rm -f tools/parser/hidp.$(OBJEXT)
+       -rm -f tools/parser/l2cap.$(OBJEXT)
+       -rm -f tools/parser/lmp.$(OBJEXT)
+       -rm -f tools/parser/obex.$(OBJEXT)
+       -rm -f tools/parser/parser.$(OBJEXT)
+       -rm -f tools/parser/ppp.$(OBJEXT)
+       -rm -f tools/parser/rfcomm.$(OBJEXT)
+       -rm -f tools/parser/sap.$(OBJEXT)
+       -rm -f tools/parser/sdp.$(OBJEXT)
+       -rm -f tools/parser/smp.$(OBJEXT)
+       -rm -f tools/parser/tcpip.$(OBJEXT)
+       -rm -f tools/rctest.$(OBJEXT)
        -rm -f tools/rfcomm.$(OBJEXT)
+       -rm -f tools/sco-tester.$(OBJEXT)
+       -rm -f tools/scotest.$(OBJEXT)
        -rm -f tools/sdptool.$(OBJEXT)
        -rm -f tools/ubcsp.$(OBJEXT)
-       -rm -f unit/unit_test_eir-test-eir.$(OBJEXT)
+       -rm -f unit/test-crc.$(OBJEXT)
+       -rm -f unit/test-eir.$(OBJEXT)
+       -rm -f unit/test-gdbus-client.$(OBJEXT)
+       -rm -f unit/test-gobex-apparam.$(OBJEXT)
+       -rm -f unit/test-gobex-header.$(OBJEXT)
+       -rm -f unit/test-gobex-packet.$(OBJEXT)
+       -rm -f unit/test-gobex-transfer.$(OBJEXT)
+       -rm -f unit/test-gobex.$(OBJEXT)
+       -rm -f unit/test-lib.$(OBJEXT)
+       -rm -f unit/test-mgmt.$(OBJEXT)
+       -rm -f unit/test-sdp.$(OBJEXT)
+       -rm -f unit/test-textfile.$(OBJEXT)
+       -rm -f unit/test-uuid.$(OBJEXT)
+       -rm -f unit/util.$(OBJEXT)
 
 distclean-compile:
        -rm -f *.tab.c
 
-@AMDEP_TRUE@@am__include@ @am__quote@alert/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@alert/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@android/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/att.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-att.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt-service.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gatt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/bluetoothd-gattrib.Po@am__quote@
@@ -2942,136 +3372,144 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/gatttool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/interactive.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@attrib/$(DEPDIR)/utils.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-a2dp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avctp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avdtp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-avrcp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-control.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-device.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-gateway.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-headset.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-ipc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-media.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-sink.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-source.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-telephony.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-transport.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/bluetoothd-unix.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/ipc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-dummy.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-maemo5.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-maemo6.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@audio/$(DEPDIR)/telephony-ofono.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/bluetoothd-btio.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/btio.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/bnep.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/dun.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/dund.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/fakehid.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/hidd.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/msdun.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/pand.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@compat/$(DEPDIR)/sdp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/hcrp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/sdp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@cups/$(DEPDIR)/spp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@deviceinfo/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@btio/$(DEPDIR)/obexd-btio.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/agent.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/display.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@client/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/amp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/b1ee.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/btdev.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/bthost.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/server.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@emulator/$(DEPDIR)/vhci.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-mainloop.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-object.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-polkit.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/bluetoothd-watch.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/mainloop.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-hdp_util.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-mcap.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@health/$(DEPDIR)/bluetoothd-mcap_sync.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-device.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-fakehid.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@input/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/client.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/mainloop.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/object.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/polkit.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gdbus/$(DEPDIR)/watch.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-apparam.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-defs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex-transfer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/gobex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-apparam.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-defs.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex-transfer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@gobex/$(DEPDIR)/obexd-gobex.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/bluetooth.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/hci.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/sdp.Plo@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@lib/$(DEPDIR)/uuid.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@mgmt/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/btsnoop.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/control.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/crc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/display.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/hcidump.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/l2cap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/ll.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/lmp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/main.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/mainloop.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/packet.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-common.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-connection.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@network/$(DEPDIR)/bluetoothd-server.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-adaptername.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-dbusoob.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-formfactor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/uuid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@monitor/$(DEPDIR)/vendor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-bluetooth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-dbus.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-driver.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-ftp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-map-event.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-map.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-mns.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-opp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-pbap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-session.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-sync.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-transfer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/client/$(DEPDIR)/obexd-transport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-filesystem.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-ftp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-irmc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-mas.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-opp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-pbap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/plugins/$(DEPDIR)/obexd-vcard.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-log.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-mimetype.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-obex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-plugin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@obexd/src/$(DEPDIR)/obexd-transport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-autopair.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-gatt-example.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hal.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hciops.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-maemo6.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-mgmtops.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-pnat.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-service.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-storage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-hostname.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-neard.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-policy.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/bluetoothd-wiimote.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-immalert.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-linkloss.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-monitor.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@proximity/$(DEPDIR)/bluetoothd-reporter.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-sap.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/bluetoothd-server.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/sap-dummy.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sap/$(DEPDIR)/sap-u8500.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Plo@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcdec.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcenc.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbcinfo.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@sbc/$(DEPDIR)/sbctester.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-port.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@serial/$(DEPDIR)/bluetoothd-proxy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/alert/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-control.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-media.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-player.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-sink.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-source.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/audio/$(DEPDIR)/bluetoothd-transport.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/hcrp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/cups/$(DEPDIR)/spp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/gatt/$(DEPDIR)/bluetoothd-gas.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-mcap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/iap/$(DEPDIR)/main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-device.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-hog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-common.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-connection.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/network/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-main.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/bluetoothd-server.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/sap/$(DEPDIR)/sap-u8500.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@profiles/time/$(DEPDIR)/bluetoothd-server.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-adapter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-agent.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-attrib-server.Po@am__quote@
@@ -3079,14 +3517,11 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-device.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-eir.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-error.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-event.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-glib-helper.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-oob.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-oui.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-plugin.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-profile.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-rfkill.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-client.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdp-xml.Po@am__quote@
@@ -3094,50 +3529,47 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-request.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-server.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-sdpd-service.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-service.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-storage.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-systemd.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/bluetoothd-textfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/eir.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/glib-helper.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/log.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/oui.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdp-xml.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-database.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-request.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/sdpd-service.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/textfile.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/unit_test_eir-eir.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@src/$(DEPDIR)/unit_test_eir-glib-helper.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/agent.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/attest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/avtest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/bdaddr.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/btiotest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/gaptest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/hciemu.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/hstest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/ipctest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/l2test.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/lmptest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/mpris-player.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/rctest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/scotest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/sdptest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/test-textfile.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@test/$(DEPDIR)/uuidtest.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-manager.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@thermometer/$(DEPDIR)/bluetoothd-thermometer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@time/$(DEPDIR)/bluetoothd-main.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@time/$(DEPDIR)/bluetoothd-server.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avctrl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/bluetoothd-mgmt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/bluetoothd-util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/btsnoop.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/hciemu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/mgmt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/pcap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/tester.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@src/shared/$(DEPDIR)/util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/amptest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/avtest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bccmd.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bdaddr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/bluetooth-player.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btattach.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btinfo.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btiotest.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btmgmt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/btsnoop.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ciptool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/cltest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_3wire.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_bcsp.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_h4.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_hci.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/csr_usb.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfu.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfubabel.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/dfutool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/gap-tester.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ath3k.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_intel.Po@am__quote@
@@ -3146,19 +3578,64 @@ distclean-compile:
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_ti.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciattach_tialt.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hciconfig.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcidump.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcieventmask.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcisecfilter.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hcitool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hid2hci.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/kword.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/hwdb.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2cap-tester.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2ping.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/lexer.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/parser.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ppporc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/l2test.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mgmt-tester.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/mpris-player.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-client-tool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obex-server-tool.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/obexctl.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rctest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/rfcomm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sco-tester.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/scotest.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/sdptool.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@tools/$(DEPDIR)/ubcsp.Po@am__quote@
-@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/unit_test_eir-test-eir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/amp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/att.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avctp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avdtp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/avrcp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/bnep.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/bpa.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/capi.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/cmtp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/csr.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/ericsson.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hci.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hcrp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/hidp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/l2cap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/lmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/obex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/parser.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/ppp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/rfcomm.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/sap.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/smp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@tools/parser/$(DEPDIR)/tcpip.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-crc.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-eir.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gdbus-client.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-apparam.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-header.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-packet.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex-transfer.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-gobex.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-lib.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-mgmt.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-sdp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-textfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/test-uuid.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@unit/$(DEPDIR)/util.Po@am__quote@
 
 .c.o:
 @am__fastdepCC_TRUE@   $(AM_V_CC)depbase=`echo $@ | sed 's|[^/]*$$|$(DEPDIR)/&|;s|\.o$$||'`;\
@@ -3184,1111 +3661,1272 @@ distclean-compile:
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $<
 
-audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo: audio/ctl_bluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo -c -o audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'audio/ctl_bluetooth.c' || echo '$(srcdir)/'`audio/ctl_bluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Tpo audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ctl_bluetooth.c' object='audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+plugins/plugins_external_dummy_la-external-dummy.lo: plugins/external-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -MT plugins/plugins_external_dummy_la-external-dummy.lo -MD -MP -MF plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/external-dummy.c' object='plugins/plugins_external_dummy_la-external-dummy.lo' libtool=yes @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_ctl_bluetooth_la-ctl_bluetooth.lo `test -f 'audio/ctl_bluetooth.c' || echo '$(srcdir)/'`audio/ctl_bluetooth.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
 
-audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo: audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Tpo -c -o audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libasound_module_ctl_bluetooth_la-ipc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+btio/obexd-btio.o: btio/btio.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT btio/obexd-btio.o -MD -MP -MF btio/$(DEPDIR)/obexd-btio.Tpo -c -o btio/obexd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) btio/$(DEPDIR)/obexd-btio.Tpo btio/$(DEPDIR)/obexd-btio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='btio/btio.c' object='btio/obexd-btio.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_ctl_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_ctl_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o btio/obexd-btio.o `test -f 'btio/btio.c' || echo '$(srcdir)/'`btio/btio.c
 
-audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo: audio/pcm_bluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo -c -o audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'audio/pcm_bluetooth.c' || echo '$(srcdir)/'`audio/pcm_bluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Tpo audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/pcm_bluetooth.c' object='audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+btio/obexd-btio.obj: btio/btio.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT btio/obexd-btio.obj -MD -MP -MF btio/$(DEPDIR)/obexd-btio.Tpo -c -o btio/obexd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) btio/$(DEPDIR)/obexd-btio.Tpo btio/$(DEPDIR)/obexd-btio.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='btio/btio.c' object='btio/obexd-btio.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_pcm_bluetooth_la-pcm_bluetooth.lo `test -f 'audio/pcm_bluetooth.c' || echo '$(srcdir)/'`audio/pcm_bluetooth.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o btio/obexd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi`
 
-audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo: audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Tpo -c -o audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libasound_module_pcm_bluetooth_la-ipc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex.o: gobex/gobex.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex.Tpo -c -o gobex/obexd-gobex.o `test -f 'gobex/gobex.c' || echo '$(srcdir)/'`gobex/gobex.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex.Tpo gobex/$(DEPDIR)/obexd-gobex.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex.c' object='gobex/obexd-gobex.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libasound_module_pcm_bluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libasound_module_pcm_bluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex.o `test -f 'gobex/gobex.c' || echo '$(srcdir)/'`gobex/gobex.c
 
-audio/audio_libgstbluetooth_la-gstbluetooth.lo: audio/gstbluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstbluetooth.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Tpo -c -o audio/audio_libgstbluetooth_la-gstbluetooth.lo `test -f 'audio/gstbluetooth.c' || echo '$(srcdir)/'`audio/gstbluetooth.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstbluetooth.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstbluetooth.c' object='audio/audio_libgstbluetooth_la-gstbluetooth.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex.obj: gobex/gobex.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex.Tpo -c -o gobex/obexd-gobex.obj `if test -f 'gobex/gobex.c'; then $(CYGPATH_W) 'gobex/gobex.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex.Tpo gobex/$(DEPDIR)/obexd-gobex.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex.c' object='gobex/obexd-gobex.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstbluetooth.lo `test -f 'audio/gstbluetooth.c' || echo '$(srcdir)/'`audio/gstbluetooth.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex.obj `if test -f 'gobex/gobex.c'; then $(CYGPATH_W) 'gobex/gobex.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex.c'; fi`
 
-audio/audio_libgstbluetooth_la-gstsbcenc.lo: audio/gstsbcenc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcenc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcenc.lo `test -f 'audio/gstsbcenc.c' || echo '$(srcdir)/'`audio/gstsbcenc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcenc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstsbcenc.c' object='audio/audio_libgstbluetooth_la-gstsbcenc.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-defs.o: gobex/gobex-defs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-defs.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-defs.Tpo -c -o gobex/obexd-gobex-defs.o `test -f 'gobex/gobex-defs.c' || echo '$(srcdir)/'`gobex/gobex-defs.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-defs.Tpo gobex/$(DEPDIR)/obexd-gobex-defs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-defs.c' object='gobex/obexd-gobex-defs.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcenc.lo `test -f 'audio/gstsbcenc.c' || echo '$(srcdir)/'`audio/gstsbcenc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-defs.o `test -f 'gobex/gobex-defs.c' || echo '$(srcdir)/'`gobex/gobex-defs.c
 
-audio/audio_libgstbluetooth_la-gstsbcdec.lo: audio/gstsbcdec.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcdec.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcdec.lo `test -f 'audio/gstsbcdec.c' || echo '$(srcdir)/'`audio/gstsbcdec.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcdec.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstsbcdec.c' object='audio/audio_libgstbluetooth_la-gstsbcdec.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-defs.obj: gobex/gobex-defs.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-defs.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-defs.Tpo -c -o gobex/obexd-gobex-defs.obj `if test -f 'gobex/gobex-defs.c'; then $(CYGPATH_W) 'gobex/gobex-defs.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-defs.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-defs.Tpo gobex/$(DEPDIR)/obexd-gobex-defs.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-defs.c' object='gobex/obexd-gobex-defs.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcdec.lo `test -f 'audio/gstsbcdec.c' || echo '$(srcdir)/'`audio/gstsbcdec.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-defs.obj `if test -f 'gobex/gobex-defs.c'; then $(CYGPATH_W) 'gobex/gobex-defs.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-defs.c'; fi`
 
-audio/audio_libgstbluetooth_la-gstsbcparse.lo: audio/gstsbcparse.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcparse.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcparse.lo `test -f 'audio/gstsbcparse.c' || echo '$(srcdir)/'`audio/gstsbcparse.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcparse.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstsbcparse.c' object='audio/audio_libgstbluetooth_la-gstsbcparse.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-packet.o: gobex/gobex-packet.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-packet.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-packet.Tpo -c -o gobex/obexd-gobex-packet.o `test -f 'gobex/gobex-packet.c' || echo '$(srcdir)/'`gobex/gobex-packet.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-packet.Tpo gobex/$(DEPDIR)/obexd-gobex-packet.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-packet.c' object='gobex/obexd-gobex-packet.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcparse.lo `test -f 'audio/gstsbcparse.c' || echo '$(srcdir)/'`audio/gstsbcparse.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-packet.o `test -f 'gobex/gobex-packet.c' || echo '$(srcdir)/'`gobex/gobex-packet.c
 
-audio/audio_libgstbluetooth_la-gstavdtpsink.lo: audio/gstavdtpsink.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstavdtpsink.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Tpo -c -o audio/audio_libgstbluetooth_la-gstavdtpsink.lo `test -f 'audio/gstavdtpsink.c' || echo '$(srcdir)/'`audio/gstavdtpsink.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstavdtpsink.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstavdtpsink.c' object='audio/audio_libgstbluetooth_la-gstavdtpsink.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-packet.obj: gobex/gobex-packet.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-packet.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-packet.Tpo -c -o gobex/obexd-gobex-packet.obj `if test -f 'gobex/gobex-packet.c'; then $(CYGPATH_W) 'gobex/gobex-packet.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-packet.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-packet.Tpo gobex/$(DEPDIR)/obexd-gobex-packet.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-packet.c' object='gobex/obexd-gobex-packet.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstavdtpsink.lo `test -f 'audio/gstavdtpsink.c' || echo '$(srcdir)/'`audio/gstavdtpsink.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-packet.obj `if test -f 'gobex/gobex-packet.c'; then $(CYGPATH_W) 'gobex/gobex-packet.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-packet.c'; fi`
 
-audio/audio_libgstbluetooth_la-gsta2dpsink.lo: audio/gsta2dpsink.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gsta2dpsink.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Tpo -c -o audio/audio_libgstbluetooth_la-gsta2dpsink.lo `test -f 'audio/gsta2dpsink.c' || echo '$(srcdir)/'`audio/gsta2dpsink.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gsta2dpsink.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gsta2dpsink.c' object='audio/audio_libgstbluetooth_la-gsta2dpsink.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-header.o: gobex/gobex-header.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-header.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-header.Tpo -c -o gobex/obexd-gobex-header.o `test -f 'gobex/gobex-header.c' || echo '$(srcdir)/'`gobex/gobex-header.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-header.Tpo gobex/$(DEPDIR)/obexd-gobex-header.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-header.c' object='gobex/obexd-gobex-header.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gsta2dpsink.lo `test -f 'audio/gsta2dpsink.c' || echo '$(srcdir)/'`audio/gsta2dpsink.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-header.o `test -f 'gobex/gobex-header.c' || echo '$(srcdir)/'`gobex/gobex-header.c
 
-audio/audio_libgstbluetooth_la-gstsbcutil.lo: audio/gstsbcutil.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstsbcutil.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Tpo -c -o audio/audio_libgstbluetooth_la-gstsbcutil.lo `test -f 'audio/gstsbcutil.c' || echo '$(srcdir)/'`audio/gstsbcutil.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstsbcutil.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstsbcutil.c' object='audio/audio_libgstbluetooth_la-gstsbcutil.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-header.obj: gobex/gobex-header.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-header.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-header.Tpo -c -o gobex/obexd-gobex-header.obj `if test -f 'gobex/gobex-header.c'; then $(CYGPATH_W) 'gobex/gobex-header.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-header.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-header.Tpo gobex/$(DEPDIR)/obexd-gobex-header.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-header.c' object='gobex/obexd-gobex-header.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstsbcutil.lo `test -f 'audio/gstsbcutil.c' || echo '$(srcdir)/'`audio/gstsbcutil.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-header.obj `if test -f 'gobex/gobex-header.c'; then $(CYGPATH_W) 'gobex/gobex-header.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-header.c'; fi`
 
-audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo: audio/gstrtpsbcpay.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Tpo -c -o audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'audio/gstrtpsbcpay.c' || echo '$(srcdir)/'`audio/gstrtpsbcpay.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-gstrtpsbcpay.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gstrtpsbcpay.c' object='audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-transfer.o: gobex/gobex-transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-transfer.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo -c -o gobex/obexd-gobex-transfer.o `test -f 'gobex/gobex-transfer.c' || echo '$(srcdir)/'`gobex/gobex-transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo gobex/$(DEPDIR)/obexd-gobex-transfer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-transfer.c' object='gobex/obexd-gobex-transfer.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-gstrtpsbcpay.lo `test -f 'audio/gstrtpsbcpay.c' || echo '$(srcdir)/'`audio/gstrtpsbcpay.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-transfer.o `test -f 'gobex/gobex-transfer.c' || echo '$(srcdir)/'`gobex/gobex-transfer.c
 
-audio/audio_libgstbluetooth_la-ipc.lo: audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -MT audio/audio_libgstbluetooth_la-ipc.lo -MD -MP -MF audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Tpo -c -o audio/audio_libgstbluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Tpo audio/$(DEPDIR)/audio_libgstbluetooth_la-ipc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ipc.c' object='audio/audio_libgstbluetooth_la-ipc.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-transfer.obj: gobex/gobex-transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-transfer.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo -c -o gobex/obexd-gobex-transfer.obj `if test -f 'gobex/gobex-transfer.c'; then $(CYGPATH_W) 'gobex/gobex-transfer.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-transfer.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-transfer.Tpo gobex/$(DEPDIR)/obexd-gobex-transfer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-transfer.c' object='gobex/obexd-gobex-transfer.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(audio_libgstbluetooth_la_CFLAGS) $(CFLAGS) -c -o audio/audio_libgstbluetooth_la-ipc.lo `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-transfer.obj `if test -f 'gobex/gobex-transfer.c'; then $(CYGPATH_W) 'gobex/gobex-transfer.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-transfer.c'; fi`
 
-plugins/plugins_external_dummy_la-external-dummy.lo: plugins/external-dummy.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -MT plugins/plugins_external_dummy_la-external-dummy.lo -MD -MP -MF plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Tpo plugins/$(DEPDIR)/plugins_external_dummy_la-external-dummy.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/external-dummy.c' object='plugins/plugins_external_dummy_la-external-dummy.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-apparam.o: gobex/gobex-apparam.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-apparam.o -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo -c -o gobex/obexd-gobex-apparam.o `test -f 'gobex/gobex-apparam.c' || echo '$(srcdir)/'`gobex/gobex-apparam.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo gobex/$(DEPDIR)/obexd-gobex-apparam.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-apparam.c' object='gobex/obexd-gobex-apparam.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(plugins_external_dummy_la_CFLAGS) $(CFLAGS) -c -o plugins/plugins_external_dummy_la-external-dummy.lo `test -f 'plugins/external-dummy.c' || echo '$(srcdir)/'`plugins/external-dummy.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-apparam.o `test -f 'gobex/gobex-apparam.c' || echo '$(srcdir)/'`gobex/gobex-apparam.c
 
-sbc/sbc_libsbc_la-sbc.lo: sbc/sbc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Tpo -c -o sbc/sbc_libsbc_la-sbc.lo `test -f 'sbc/sbc.c' || echo '$(srcdir)/'`sbc/sbc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc.c' object='sbc/sbc_libsbc_la-sbc.lo' libtool=yes @AMDEPBACKSLASH@
+gobex/obexd-gobex-apparam.obj: gobex/gobex-apparam.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT gobex/obexd-gobex-apparam.obj -MD -MP -MF gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo -c -o gobex/obexd-gobex-apparam.obj `if test -f 'gobex/gobex-apparam.c'; then $(CYGPATH_W) 'gobex/gobex-apparam.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-apparam.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gobex/$(DEPDIR)/obexd-gobex-apparam.Tpo gobex/$(DEPDIR)/obexd-gobex-apparam.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gobex/gobex-apparam.c' object='gobex/obexd-gobex-apparam.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc.lo `test -f 'sbc/sbc.c' || echo '$(srcdir)/'`sbc/sbc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o gobex/obexd-gobex-apparam.obj `if test -f 'gobex/gobex-apparam.c'; then $(CYGPATH_W) 'gobex/gobex-apparam.c'; else $(CYGPATH_W) '$(srcdir)/gobex/gobex-apparam.c'; fi`
 
-sbc/sbc_libsbc_la-sbc_primitives.lo: sbc/sbc_primitives.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives.lo `test -f 'sbc/sbc_primitives.c' || echo '$(srcdir)/'`sbc/sbc_primitives.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc_primitives.c' object='sbc/sbc_libsbc_la-sbc_primitives.lo' libtool=yes @AMDEPBACKSLASH@
+obexd/plugins/obexd-filesystem.o: obexd/plugins/filesystem.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-filesystem.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo -c -o obexd/plugins/obexd-filesystem.o `test -f 'obexd/plugins/filesystem.c' || echo '$(srcdir)/'`obexd/plugins/filesystem.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo obexd/plugins/$(DEPDIR)/obexd-filesystem.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/filesystem.c' object='obexd/plugins/obexd-filesystem.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives.lo `test -f 'sbc/sbc_primitives.c' || echo '$(srcdir)/'`sbc/sbc_primitives.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-filesystem.o `test -f 'obexd/plugins/filesystem.c' || echo '$(srcdir)/'`obexd/plugins/filesystem.c
 
-sbc/sbc_libsbc_la-sbc_primitives_mmx.lo: sbc/sbc_primitives_mmx.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_mmx.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_mmx.lo `test -f 'sbc/sbc_primitives_mmx.c' || echo '$(srcdir)/'`sbc/sbc_primitives_mmx.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_mmx.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc_primitives_mmx.c' object='sbc/sbc_libsbc_la-sbc_primitives_mmx.lo' libtool=yes @AMDEPBACKSLASH@
+obexd/plugins/obexd-filesystem.obj: obexd/plugins/filesystem.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-filesystem.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo -c -o obexd/plugins/obexd-filesystem.obj `if test -f 'obexd/plugins/filesystem.c'; then $(CYGPATH_W) 'obexd/plugins/filesystem.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/filesystem.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-filesystem.Tpo obexd/plugins/$(DEPDIR)/obexd-filesystem.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/filesystem.c' object='obexd/plugins/obexd-filesystem.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_mmx.lo `test -f 'sbc/sbc_primitives_mmx.c' || echo '$(srcdir)/'`sbc/sbc_primitives_mmx.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-filesystem.obj `if test -f 'obexd/plugins/filesystem.c'; then $(CYGPATH_W) 'obexd/plugins/filesystem.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/filesystem.c'; fi`
 
-sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo: sbc/sbc_primitives_iwmmxt.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo `test -f 'sbc/sbc_primitives_iwmmxt.c' || echo '$(srcdir)/'`sbc/sbc_primitives_iwmmxt.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_iwmmxt.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc_primitives_iwmmxt.c' object='sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo' libtool=yes @AMDEPBACKSLASH@
+obexd/plugins/obexd-bluetooth.o: obexd/plugins/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-bluetooth.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/plugins/obexd-bluetooth.o `test -f 'obexd/plugins/bluetooth.c' || echo '$(srcdir)/'`obexd/plugins/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/bluetooth.c' object='obexd/plugins/obexd-bluetooth.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_iwmmxt.lo `test -f 'sbc/sbc_primitives_iwmmxt.c' || echo '$(srcdir)/'`sbc/sbc_primitives_iwmmxt.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-bluetooth.o `test -f 'obexd/plugins/bluetooth.c' || echo '$(srcdir)/'`obexd/plugins/bluetooth.c
 
-sbc/sbc_libsbc_la-sbc_primitives_neon.lo: sbc/sbc_primitives_neon.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_neon.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_neon.lo `test -f 'sbc/sbc_primitives_neon.c' || echo '$(srcdir)/'`sbc/sbc_primitives_neon.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_neon.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc_primitives_neon.c' object='sbc/sbc_libsbc_la-sbc_primitives_neon.lo' libtool=yes @AMDEPBACKSLASH@
+obexd/plugins/obexd-bluetooth.obj: obexd/plugins/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-bluetooth.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/plugins/obexd-bluetooth.obj `if test -f 'obexd/plugins/bluetooth.c'; then $(CYGPATH_W) 'obexd/plugins/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/bluetooth.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-bluetooth.Tpo obexd/plugins/$(DEPDIR)/obexd-bluetooth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/bluetooth.c' object='obexd/plugins/obexd-bluetooth.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_neon.lo `test -f 'sbc/sbc_primitives_neon.c' || echo '$(srcdir)/'`sbc/sbc_primitives_neon.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-bluetooth.obj `if test -f 'obexd/plugins/bluetooth.c'; then $(CYGPATH_W) 'obexd/plugins/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/bluetooth.c'; fi`
 
-sbc/sbc_libsbc_la-sbc_primitives_armv6.lo: sbc/sbc_primitives_armv6.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -MT sbc/sbc_libsbc_la-sbc_primitives_armv6.lo -MD -MP -MF sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Tpo sbc/$(DEPDIR)/sbc_libsbc_la-sbc_primitives_armv6.Plo
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sbc/sbc_primitives_armv6.c' object='sbc/sbc_libsbc_la-sbc_primitives_armv6.lo' libtool=yes @AMDEPBACKSLASH@
+obexd/plugins/obexd-pcsuite.o: obexd/plugins/pcsuite.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pcsuite.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo -c -o obexd/plugins/obexd-pcsuite.o `test -f 'obexd/plugins/pcsuite.c' || echo '$(srcdir)/'`obexd/plugins/pcsuite.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/pcsuite.c' object='obexd/plugins/obexd-pcsuite.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(sbc_libsbc_la_CFLAGS) $(CFLAGS) -c -o sbc/sbc_libsbc_la-sbc_primitives_armv6.lo `test -f 'sbc/sbc_primitives_armv6.c' || echo '$(srcdir)/'`sbc/sbc_primitives_armv6.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pcsuite.o `test -f 'obexd/plugins/pcsuite.c' || echo '$(srcdir)/'`obexd/plugins/pcsuite.c
 
-gdbus/bluetoothd-mainloop.o: gdbus/mainloop.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-mainloop.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo -c -o gdbus/bluetoothd-mainloop.o `test -f 'gdbus/mainloop.c' || echo '$(srcdir)/'`gdbus/mainloop.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo gdbus/$(DEPDIR)/bluetoothd-mainloop.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/mainloop.c' object='gdbus/bluetoothd-mainloop.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-pcsuite.obj: obexd/plugins/pcsuite.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pcsuite.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo -c -o obexd/plugins/obexd-pcsuite.obj `if test -f 'obexd/plugins/pcsuite.c'; then $(CYGPATH_W) 'obexd/plugins/pcsuite.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pcsuite.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pcsuite.Tpo obexd/plugins/$(DEPDIR)/obexd-pcsuite.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/pcsuite.c' object='obexd/plugins/obexd-pcsuite.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-mainloop.o `test -f 'gdbus/mainloop.c' || echo '$(srcdir)/'`gdbus/mainloop.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pcsuite.obj `if test -f 'obexd/plugins/pcsuite.c'; then $(CYGPATH_W) 'obexd/plugins/pcsuite.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pcsuite.c'; fi`
 
-gdbus/bluetoothd-mainloop.obj: gdbus/mainloop.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-mainloop.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo -c -o gdbus/bluetoothd-mainloop.obj `if test -f 'gdbus/mainloop.c'; then $(CYGPATH_W) 'gdbus/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/mainloop.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-mainloop.Tpo gdbus/$(DEPDIR)/bluetoothd-mainloop.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/mainloop.c' object='gdbus/bluetoothd-mainloop.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-opp.o: obexd/plugins/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-opp.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/plugins/obexd-opp.o `test -f 'obexd/plugins/opp.c' || echo '$(srcdir)/'`obexd/plugins/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-opp.Tpo obexd/plugins/$(DEPDIR)/obexd-opp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/opp.c' object='obexd/plugins/obexd-opp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-mainloop.obj `if test -f 'gdbus/mainloop.c'; then $(CYGPATH_W) 'gdbus/mainloop.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/mainloop.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-opp.o `test -f 'obexd/plugins/opp.c' || echo '$(srcdir)/'`obexd/plugins/opp.c
 
-gdbus/bluetoothd-watch.o: gdbus/watch.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-watch.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-watch.Tpo -c -o gdbus/bluetoothd-watch.o `test -f 'gdbus/watch.c' || echo '$(srcdir)/'`gdbus/watch.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-watch.Tpo gdbus/$(DEPDIR)/bluetoothd-watch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/watch.c' object='gdbus/bluetoothd-watch.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-opp.obj: obexd/plugins/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-opp.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/plugins/obexd-opp.obj `if test -f 'obexd/plugins/opp.c'; then $(CYGPATH_W) 'obexd/plugins/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/opp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-opp.Tpo obexd/plugins/$(DEPDIR)/obexd-opp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/opp.c' object='obexd/plugins/obexd-opp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-watch.o `test -f 'gdbus/watch.c' || echo '$(srcdir)/'`gdbus/watch.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-opp.obj `if test -f 'obexd/plugins/opp.c'; then $(CYGPATH_W) 'obexd/plugins/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/opp.c'; fi`
 
-gdbus/bluetoothd-watch.obj: gdbus/watch.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-watch.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-watch.Tpo -c -o gdbus/bluetoothd-watch.obj `if test -f 'gdbus/watch.c'; then $(CYGPATH_W) 'gdbus/watch.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/watch.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-watch.Tpo gdbus/$(DEPDIR)/bluetoothd-watch.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/watch.c' object='gdbus/bluetoothd-watch.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-ftp.o: obexd/plugins/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-ftp.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/plugins/obexd-ftp.o `test -f 'obexd/plugins/ftp.c' || echo '$(srcdir)/'`obexd/plugins/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo obexd/plugins/$(DEPDIR)/obexd-ftp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/ftp.c' object='obexd/plugins/obexd-ftp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-watch.obj `if test -f 'gdbus/watch.c'; then $(CYGPATH_W) 'gdbus/watch.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/watch.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-ftp.o `test -f 'obexd/plugins/ftp.c' || echo '$(srcdir)/'`obexd/plugins/ftp.c
 
-gdbus/bluetoothd-object.o: gdbus/object.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-object.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-object.Tpo -c -o gdbus/bluetoothd-object.o `test -f 'gdbus/object.c' || echo '$(srcdir)/'`gdbus/object.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-object.Tpo gdbus/$(DEPDIR)/bluetoothd-object.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/object.c' object='gdbus/bluetoothd-object.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-ftp.obj: obexd/plugins/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-ftp.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/plugins/obexd-ftp.obj `if test -f 'obexd/plugins/ftp.c'; then $(CYGPATH_W) 'obexd/plugins/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/ftp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-ftp.Tpo obexd/plugins/$(DEPDIR)/obexd-ftp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/ftp.c' object='obexd/plugins/obexd-ftp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-object.o `test -f 'gdbus/object.c' || echo '$(srcdir)/'`gdbus/object.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-ftp.obj `if test -f 'obexd/plugins/ftp.c'; then $(CYGPATH_W) 'obexd/plugins/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/ftp.c'; fi`
 
-gdbus/bluetoothd-object.obj: gdbus/object.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-object.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-object.Tpo -c -o gdbus/bluetoothd-object.obj `if test -f 'gdbus/object.c'; then $(CYGPATH_W) 'gdbus/object.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/object.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-object.Tpo gdbus/$(DEPDIR)/bluetoothd-object.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/object.c' object='gdbus/bluetoothd-object.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-irmc.o: obexd/plugins/irmc.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-irmc.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo -c -o obexd/plugins/obexd-irmc.o `test -f 'obexd/plugins/irmc.c' || echo '$(srcdir)/'`obexd/plugins/irmc.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo obexd/plugins/$(DEPDIR)/obexd-irmc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/irmc.c' object='obexd/plugins/obexd-irmc.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-object.obj `if test -f 'gdbus/object.c'; then $(CYGPATH_W) 'gdbus/object.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/object.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-irmc.o `test -f 'obexd/plugins/irmc.c' || echo '$(srcdir)/'`obexd/plugins/irmc.c
 
-gdbus/bluetoothd-polkit.o: gdbus/polkit.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-polkit.o -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo -c -o gdbus/bluetoothd-polkit.o `test -f 'gdbus/polkit.c' || echo '$(srcdir)/'`gdbus/polkit.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo gdbus/$(DEPDIR)/bluetoothd-polkit.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/polkit.c' object='gdbus/bluetoothd-polkit.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-irmc.obj: obexd/plugins/irmc.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-irmc.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo -c -o obexd/plugins/obexd-irmc.obj `if test -f 'obexd/plugins/irmc.c'; then $(CYGPATH_W) 'obexd/plugins/irmc.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/irmc.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-irmc.Tpo obexd/plugins/$(DEPDIR)/obexd-irmc.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/irmc.c' object='obexd/plugins/obexd-irmc.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-polkit.o `test -f 'gdbus/polkit.c' || echo '$(srcdir)/'`gdbus/polkit.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-irmc.obj `if test -f 'obexd/plugins/irmc.c'; then $(CYGPATH_W) 'obexd/plugins/irmc.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/irmc.c'; fi`
 
-gdbus/bluetoothd-polkit.obj: gdbus/polkit.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT gdbus/bluetoothd-polkit.obj -MD -MP -MF gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo -c -o gdbus/bluetoothd-polkit.obj `if test -f 'gdbus/polkit.c'; then $(CYGPATH_W) 'gdbus/polkit.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/polkit.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) gdbus/$(DEPDIR)/bluetoothd-polkit.Tpo gdbus/$(DEPDIR)/bluetoothd-polkit.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='gdbus/polkit.c' object='gdbus/bluetoothd-polkit.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-pbap.o: obexd/plugins/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pbap.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/plugins/obexd-pbap.o `test -f 'obexd/plugins/pbap.c' || echo '$(srcdir)/'`obexd/plugins/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo obexd/plugins/$(DEPDIR)/obexd-pbap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/pbap.c' object='obexd/plugins/obexd-pbap.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o gdbus/bluetoothd-polkit.obj `if test -f 'gdbus/polkit.c'; then $(CYGPATH_W) 'gdbus/polkit.c'; else $(CYGPATH_W) '$(srcdir)/gdbus/polkit.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pbap.o `test -f 'obexd/plugins/pbap.c' || echo '$(srcdir)/'`obexd/plugins/pbap.c
 
-plugins/bluetoothd-pnat.o: plugins/pnat.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-pnat.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-pnat.Tpo -c -o plugins/bluetoothd-pnat.o `test -f 'plugins/pnat.c' || echo '$(srcdir)/'`plugins/pnat.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-pnat.Tpo plugins/$(DEPDIR)/bluetoothd-pnat.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/pnat.c' object='plugins/bluetoothd-pnat.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-pbap.obj: obexd/plugins/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-pbap.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/plugins/obexd-pbap.obj `if test -f 'obexd/plugins/pbap.c'; then $(CYGPATH_W) 'obexd/plugins/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pbap.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-pbap.Tpo obexd/plugins/$(DEPDIR)/obexd-pbap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/pbap.c' object='obexd/plugins/obexd-pbap.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-pnat.o `test -f 'plugins/pnat.c' || echo '$(srcdir)/'`plugins/pnat.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-pbap.obj `if test -f 'obexd/plugins/pbap.c'; then $(CYGPATH_W) 'obexd/plugins/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/pbap.c'; fi`
 
-plugins/bluetoothd-pnat.obj: plugins/pnat.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-pnat.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-pnat.Tpo -c -o plugins/bluetoothd-pnat.obj `if test -f 'plugins/pnat.c'; then $(CYGPATH_W) 'plugins/pnat.c'; else $(CYGPATH_W) '$(srcdir)/plugins/pnat.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-pnat.Tpo plugins/$(DEPDIR)/bluetoothd-pnat.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/pnat.c' object='plugins/bluetoothd-pnat.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-vcard.o: obexd/plugins/vcard.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-vcard.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo -c -o obexd/plugins/obexd-vcard.o `test -f 'obexd/plugins/vcard.c' || echo '$(srcdir)/'`obexd/plugins/vcard.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo obexd/plugins/$(DEPDIR)/obexd-vcard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/vcard.c' object='obexd/plugins/obexd-vcard.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-pnat.obj `if test -f 'plugins/pnat.c'; then $(CYGPATH_W) 'plugins/pnat.c'; else $(CYGPATH_W) '$(srcdir)/plugins/pnat.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-vcard.o `test -f 'obexd/plugins/vcard.c' || echo '$(srcdir)/'`obexd/plugins/vcard.c
 
-audio/bluetoothd-main.o: audio/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-main.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-main.Tpo -c -o audio/bluetoothd-main.o `test -f 'audio/main.c' || echo '$(srcdir)/'`audio/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-main.Tpo audio/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/main.c' object='audio/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-vcard.obj: obexd/plugins/vcard.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-vcard.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo -c -o obexd/plugins/obexd-vcard.obj `if test -f 'obexd/plugins/vcard.c'; then $(CYGPATH_W) 'obexd/plugins/vcard.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/vcard.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-vcard.Tpo obexd/plugins/$(DEPDIR)/obexd-vcard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/vcard.c' object='obexd/plugins/obexd-vcard.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-main.o `test -f 'audio/main.c' || echo '$(srcdir)/'`audio/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-vcard.obj `if test -f 'obexd/plugins/vcard.c'; then $(CYGPATH_W) 'obexd/plugins/vcard.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/vcard.c'; fi`
 
-audio/bluetoothd-main.obj: audio/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-main.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-main.Tpo -c -o audio/bluetoothd-main.obj `if test -f 'audio/main.c'; then $(CYGPATH_W) 'audio/main.c'; else $(CYGPATH_W) '$(srcdir)/audio/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-main.Tpo audio/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/main.c' object='audio/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-phonebook-dummy.o: obexd/plugins/phonebook-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-phonebook-dummy.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Tpo -c -o obexd/plugins/obexd-phonebook-dummy.o `test -f 'obexd/plugins/phonebook-dummy.c' || echo '$(srcdir)/'`obexd/plugins/phonebook-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/phonebook-dummy.c' object='obexd/plugins/obexd-phonebook-dummy.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-main.obj `if test -f 'audio/main.c'; then $(CYGPATH_W) 'audio/main.c'; else $(CYGPATH_W) '$(srcdir)/audio/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-phonebook-dummy.o `test -f 'obexd/plugins/phonebook-dummy.c' || echo '$(srcdir)/'`obexd/plugins/phonebook-dummy.c
 
-audio/bluetoothd-manager.o: audio/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-manager.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-manager.Tpo -c -o audio/bluetoothd-manager.o `test -f 'audio/manager.c' || echo '$(srcdir)/'`audio/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-manager.Tpo audio/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/manager.c' object='audio/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-phonebook-dummy.obj: obexd/plugins/phonebook-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-phonebook-dummy.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Tpo -c -o obexd/plugins/obexd-phonebook-dummy.obj `if test -f 'obexd/plugins/phonebook-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/phonebook-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/phonebook-dummy.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-phonebook-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/phonebook-dummy.c' object='obexd/plugins/obexd-phonebook-dummy.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-manager.o `test -f 'audio/manager.c' || echo '$(srcdir)/'`audio/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-phonebook-dummy.obj `if test -f 'obexd/plugins/phonebook-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/phonebook-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/phonebook-dummy.c'; fi`
 
-audio/bluetoothd-manager.obj: audio/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-manager.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-manager.Tpo -c -o audio/bluetoothd-manager.obj `if test -f 'audio/manager.c'; then $(CYGPATH_W) 'audio/manager.c'; else $(CYGPATH_W) '$(srcdir)/audio/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-manager.Tpo audio/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/manager.c' object='audio/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-mas.o: obexd/plugins/mas.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-mas.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-mas.Tpo -c -o obexd/plugins/obexd-mas.o `test -f 'obexd/plugins/mas.c' || echo '$(srcdir)/'`obexd/plugins/mas.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-mas.Tpo obexd/plugins/$(DEPDIR)/obexd-mas.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/mas.c' object='obexd/plugins/obexd-mas.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-manager.obj `if test -f 'audio/manager.c'; then $(CYGPATH_W) 'audio/manager.c'; else $(CYGPATH_W) '$(srcdir)/audio/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-mas.o `test -f 'obexd/plugins/mas.c' || echo '$(srcdir)/'`obexd/plugins/mas.c
 
-audio/bluetoothd-gateway.o: audio/gateway.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-gateway.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-gateway.Tpo -c -o audio/bluetoothd-gateway.o `test -f 'audio/gateway.c' || echo '$(srcdir)/'`audio/gateway.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-gateway.Tpo audio/$(DEPDIR)/bluetoothd-gateway.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gateway.c' object='audio/bluetoothd-gateway.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-mas.obj: obexd/plugins/mas.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-mas.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-mas.Tpo -c -o obexd/plugins/obexd-mas.obj `if test -f 'obexd/plugins/mas.c'; then $(CYGPATH_W) 'obexd/plugins/mas.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/mas.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-mas.Tpo obexd/plugins/$(DEPDIR)/obexd-mas.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/mas.c' object='obexd/plugins/obexd-mas.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-gateway.o `test -f 'audio/gateway.c' || echo '$(srcdir)/'`audio/gateway.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-mas.obj `if test -f 'obexd/plugins/mas.c'; then $(CYGPATH_W) 'obexd/plugins/mas.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/mas.c'; fi`
 
-audio/bluetoothd-gateway.obj: audio/gateway.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-gateway.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-gateway.Tpo -c -o audio/bluetoothd-gateway.obj `if test -f 'audio/gateway.c'; then $(CYGPATH_W) 'audio/gateway.c'; else $(CYGPATH_W) '$(srcdir)/audio/gateway.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-gateway.Tpo audio/$(DEPDIR)/bluetoothd-gateway.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/gateway.c' object='audio/bluetoothd-gateway.obj' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-messages-dummy.o: obexd/plugins/messages-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-messages-dummy.o -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo -c -o obexd/plugins/obexd-messages-dummy.o `test -f 'obexd/plugins/messages-dummy.c' || echo '$(srcdir)/'`obexd/plugins/messages-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/messages-dummy.c' object='obexd/plugins/obexd-messages-dummy.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-gateway.obj `if test -f 'audio/gateway.c'; then $(CYGPATH_W) 'audio/gateway.c'; else $(CYGPATH_W) '$(srcdir)/audio/gateway.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-messages-dummy.o `test -f 'obexd/plugins/messages-dummy.c' || echo '$(srcdir)/'`obexd/plugins/messages-dummy.c
 
-audio/bluetoothd-headset.o: audio/headset.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-headset.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-headset.Tpo -c -o audio/bluetoothd-headset.o `test -f 'audio/headset.c' || echo '$(srcdir)/'`audio/headset.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-headset.Tpo audio/$(DEPDIR)/bluetoothd-headset.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/headset.c' object='audio/bluetoothd-headset.o' libtool=no @AMDEPBACKSLASH@
+obexd/plugins/obexd-messages-dummy.obj: obexd/plugins/messages-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/plugins/obexd-messages-dummy.obj -MD -MP -MF obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo -c -o obexd/plugins/obexd-messages-dummy.obj `if test -f 'obexd/plugins/messages-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/messages-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/messages-dummy.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Tpo obexd/plugins/$(DEPDIR)/obexd-messages-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/plugins/messages-dummy.c' object='obexd/plugins/obexd-messages-dummy.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-headset.o `test -f 'audio/headset.c' || echo '$(srcdir)/'`audio/headset.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/plugins/obexd-messages-dummy.obj `if test -f 'obexd/plugins/messages-dummy.c'; then $(CYGPATH_W) 'obexd/plugins/messages-dummy.c'; else $(CYGPATH_W) '$(srcdir)/obexd/plugins/messages-dummy.c'; fi`
 
-audio/bluetoothd-headset.obj: audio/headset.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-headset.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-headset.Tpo -c -o audio/bluetoothd-headset.obj `if test -f 'audio/headset.c'; then $(CYGPATH_W) 'audio/headset.c'; else $(CYGPATH_W) '$(srcdir)/audio/headset.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-headset.Tpo audio/$(DEPDIR)/bluetoothd-headset.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/headset.c' object='audio/bluetoothd-headset.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-mns.o: obexd/client/mns.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-mns.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-mns.Tpo -c -o obexd/client/obexd-mns.o `test -f 'obexd/client/mns.c' || echo '$(srcdir)/'`obexd/client/mns.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-mns.Tpo obexd/client/$(DEPDIR)/obexd-mns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/mns.c' object='obexd/client/obexd-mns.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-headset.obj `if test -f 'audio/headset.c'; then $(CYGPATH_W) 'audio/headset.c'; else $(CYGPATH_W) '$(srcdir)/audio/headset.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-mns.o `test -f 'obexd/client/mns.c' || echo '$(srcdir)/'`obexd/client/mns.c
 
-audio/bluetoothd-control.o: audio/control.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-control.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o audio/bluetoothd-control.o `test -f 'audio/control.c' || echo '$(srcdir)/'`audio/control.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-control.Tpo audio/$(DEPDIR)/bluetoothd-control.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/control.c' object='audio/bluetoothd-control.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-mns.obj: obexd/client/mns.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-mns.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-mns.Tpo -c -o obexd/client/obexd-mns.obj `if test -f 'obexd/client/mns.c'; then $(CYGPATH_W) 'obexd/client/mns.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/mns.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-mns.Tpo obexd/client/$(DEPDIR)/obexd-mns.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/mns.c' object='obexd/client/obexd-mns.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-control.o `test -f 'audio/control.c' || echo '$(srcdir)/'`audio/control.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-mns.obj `if test -f 'obexd/client/mns.c'; then $(CYGPATH_W) 'obexd/client/mns.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/mns.c'; fi`
 
-audio/bluetoothd-control.obj: audio/control.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-control.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o audio/bluetoothd-control.obj `if test -f 'audio/control.c'; then $(CYGPATH_W) 'audio/control.c'; else $(CYGPATH_W) '$(srcdir)/audio/control.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-control.Tpo audio/$(DEPDIR)/bluetoothd-control.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/control.c' object='audio/bluetoothd-control.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-main.o: obexd/src/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-main.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-main.Tpo -c -o obexd/src/obexd-main.o `test -f 'obexd/src/main.c' || echo '$(srcdir)/'`obexd/src/main.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-main.Tpo obexd/src/$(DEPDIR)/obexd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/main.c' object='obexd/src/obexd-main.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-control.obj `if test -f 'audio/control.c'; then $(CYGPATH_W) 'audio/control.c'; else $(CYGPATH_W) '$(srcdir)/audio/control.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-main.o `test -f 'obexd/src/main.c' || echo '$(srcdir)/'`obexd/src/main.c
 
-audio/bluetoothd-avctp.o: audio/avctp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avctp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o audio/bluetoothd-avctp.o `test -f 'audio/avctp.c' || echo '$(srcdir)/'`audio/avctp.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avctp.Tpo audio/$(DEPDIR)/bluetoothd-avctp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avctp.c' object='audio/bluetoothd-avctp.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-main.obj: obexd/src/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-main.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-main.Tpo -c -o obexd/src/obexd-main.obj `if test -f 'obexd/src/main.c'; then $(CYGPATH_W) 'obexd/src/main.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/main.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-main.Tpo obexd/src/$(DEPDIR)/obexd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/main.c' object='obexd/src/obexd-main.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avctp.o `test -f 'audio/avctp.c' || echo '$(srcdir)/'`audio/avctp.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-main.obj `if test -f 'obexd/src/main.c'; then $(CYGPATH_W) 'obexd/src/main.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/main.c'; fi`
 
-audio/bluetoothd-avctp.obj: audio/avctp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avctp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o audio/bluetoothd-avctp.obj `if test -f 'audio/avctp.c'; then $(CYGPATH_W) 'audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avctp.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avctp.Tpo audio/$(DEPDIR)/bluetoothd-avctp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avctp.c' object='audio/bluetoothd-avctp.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-plugin.o: obexd/src/plugin.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-plugin.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-plugin.Tpo -c -o obexd/src/obexd-plugin.o `test -f 'obexd/src/plugin.c' || echo '$(srcdir)/'`obexd/src/plugin.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-plugin.Tpo obexd/src/$(DEPDIR)/obexd-plugin.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/plugin.c' object='obexd/src/obexd-plugin.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avctp.obj `if test -f 'audio/avctp.c'; then $(CYGPATH_W) 'audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avctp.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-plugin.o `test -f 'obexd/src/plugin.c' || echo '$(srcdir)/'`obexd/src/plugin.c
 
-audio/bluetoothd-avrcp.o: audio/avrcp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avrcp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o audio/bluetoothd-avrcp.o `test -f 'audio/avrcp.c' || echo '$(srcdir)/'`audio/avrcp.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avrcp.Tpo audio/$(DEPDIR)/bluetoothd-avrcp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avrcp.c' object='audio/bluetoothd-avrcp.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-plugin.obj: obexd/src/plugin.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-plugin.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-plugin.Tpo -c -o obexd/src/obexd-plugin.obj `if test -f 'obexd/src/plugin.c'; then $(CYGPATH_W) 'obexd/src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/plugin.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-plugin.Tpo obexd/src/$(DEPDIR)/obexd-plugin.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/plugin.c' object='obexd/src/obexd-plugin.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avrcp.o `test -f 'audio/avrcp.c' || echo '$(srcdir)/'`audio/avrcp.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-plugin.obj `if test -f 'obexd/src/plugin.c'; then $(CYGPATH_W) 'obexd/src/plugin.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/plugin.c'; fi`
 
-audio/bluetoothd-avrcp.obj: audio/avrcp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avrcp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o audio/bluetoothd-avrcp.obj `if test -f 'audio/avrcp.c'; then $(CYGPATH_W) 'audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avrcp.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avrcp.Tpo audio/$(DEPDIR)/bluetoothd-avrcp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avrcp.c' object='audio/bluetoothd-avrcp.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-log.o: obexd/src/log.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-log.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-log.Tpo -c -o obexd/src/obexd-log.o `test -f 'obexd/src/log.c' || echo '$(srcdir)/'`obexd/src/log.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-log.Tpo obexd/src/$(DEPDIR)/obexd-log.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/log.c' object='obexd/src/obexd-log.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avrcp.obj `if test -f 'audio/avrcp.c'; then $(CYGPATH_W) 'audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avrcp.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-log.o `test -f 'obexd/src/log.c' || echo '$(srcdir)/'`obexd/src/log.c
 
-audio/bluetoothd-device.o: audio/device.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-device.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-device.Tpo -c -o audio/bluetoothd-device.o `test -f 'audio/device.c' || echo '$(srcdir)/'`audio/device.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-device.Tpo audio/$(DEPDIR)/bluetoothd-device.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/device.c' object='audio/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-log.obj: obexd/src/log.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-log.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-log.Tpo -c -o obexd/src/obexd-log.obj `if test -f 'obexd/src/log.c'; then $(CYGPATH_W) 'obexd/src/log.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/log.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-log.Tpo obexd/src/$(DEPDIR)/obexd-log.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/log.c' object='obexd/src/obexd-log.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-device.o `test -f 'audio/device.c' || echo '$(srcdir)/'`audio/device.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-log.obj `if test -f 'obexd/src/log.c'; then $(CYGPATH_W) 'obexd/src/log.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/log.c'; fi`
 
-audio/bluetoothd-device.obj: audio/device.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-device.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-device.Tpo -c -o audio/bluetoothd-device.obj `if test -f 'audio/device.c'; then $(CYGPATH_W) 'audio/device.c'; else $(CYGPATH_W) '$(srcdir)/audio/device.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-device.Tpo audio/$(DEPDIR)/bluetoothd-device.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/device.c' object='audio/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-manager.o: obexd/src/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-manager.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/src/obexd-manager.o `test -f 'obexd/src/manager.c' || echo '$(srcdir)/'`obexd/src/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-manager.Tpo obexd/src/$(DEPDIR)/obexd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/manager.c' object='obexd/src/obexd-manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-device.obj `if test -f 'audio/device.c'; then $(CYGPATH_W) 'audio/device.c'; else $(CYGPATH_W) '$(srcdir)/audio/device.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-manager.o `test -f 'obexd/src/manager.c' || echo '$(srcdir)/'`obexd/src/manager.c
 
-audio/bluetoothd-source.o: audio/source.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-source.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o audio/bluetoothd-source.o `test -f 'audio/source.c' || echo '$(srcdir)/'`audio/source.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-source.Tpo audio/$(DEPDIR)/bluetoothd-source.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/source.c' object='audio/bluetoothd-source.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-manager.obj: obexd/src/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-manager.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/src/obexd-manager.obj `if test -f 'obexd/src/manager.c'; then $(CYGPATH_W) 'obexd/src/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-manager.Tpo obexd/src/$(DEPDIR)/obexd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/manager.c' object='obexd/src/obexd-manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-source.o `test -f 'audio/source.c' || echo '$(srcdir)/'`audio/source.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-manager.obj `if test -f 'obexd/src/manager.c'; then $(CYGPATH_W) 'obexd/src/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/manager.c'; fi`
 
-audio/bluetoothd-source.obj: audio/source.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-source.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o audio/bluetoothd-source.obj `if test -f 'audio/source.c'; then $(CYGPATH_W) 'audio/source.c'; else $(CYGPATH_W) '$(srcdir)/audio/source.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-source.Tpo audio/$(DEPDIR)/bluetoothd-source.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/source.c' object='audio/bluetoothd-source.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-obex.o: obexd/src/obex.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-obex.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-obex.Tpo -c -o obexd/src/obexd-obex.o `test -f 'obexd/src/obex.c' || echo '$(srcdir)/'`obexd/src/obex.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-obex.Tpo obexd/src/$(DEPDIR)/obexd-obex.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/obex.c' object='obexd/src/obexd-obex.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-source.obj `if test -f 'audio/source.c'; then $(CYGPATH_W) 'audio/source.c'; else $(CYGPATH_W) '$(srcdir)/audio/source.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-obex.o `test -f 'obexd/src/obex.c' || echo '$(srcdir)/'`obexd/src/obex.c
 
-audio/bluetoothd-sink.o: audio/sink.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-sink.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o audio/bluetoothd-sink.o `test -f 'audio/sink.c' || echo '$(srcdir)/'`audio/sink.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-sink.Tpo audio/$(DEPDIR)/bluetoothd-sink.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/sink.c' object='audio/bluetoothd-sink.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-obex.obj: obexd/src/obex.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-obex.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-obex.Tpo -c -o obexd/src/obexd-obex.obj `if test -f 'obexd/src/obex.c'; then $(CYGPATH_W) 'obexd/src/obex.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/obex.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-obex.Tpo obexd/src/$(DEPDIR)/obexd-obex.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/obex.c' object='obexd/src/obexd-obex.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-sink.o `test -f 'audio/sink.c' || echo '$(srcdir)/'`audio/sink.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-obex.obj `if test -f 'obexd/src/obex.c'; then $(CYGPATH_W) 'obexd/src/obex.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/obex.c'; fi`
 
-audio/bluetoothd-sink.obj: audio/sink.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-sink.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o audio/bluetoothd-sink.obj `if test -f 'audio/sink.c'; then $(CYGPATH_W) 'audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/audio/sink.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-sink.Tpo audio/$(DEPDIR)/bluetoothd-sink.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/sink.c' object='audio/bluetoothd-sink.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-mimetype.o: obexd/src/mimetype.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-mimetype.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-mimetype.Tpo -c -o obexd/src/obexd-mimetype.o `test -f 'obexd/src/mimetype.c' || echo '$(srcdir)/'`obexd/src/mimetype.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-mimetype.Tpo obexd/src/$(DEPDIR)/obexd-mimetype.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/mimetype.c' object='obexd/src/obexd-mimetype.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-sink.obj `if test -f 'audio/sink.c'; then $(CYGPATH_W) 'audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/audio/sink.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-mimetype.o `test -f 'obexd/src/mimetype.c' || echo '$(srcdir)/'`obexd/src/mimetype.c
 
-audio/bluetoothd-a2dp.o: audio/a2dp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-a2dp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o audio/bluetoothd-a2dp.o `test -f 'audio/a2dp.c' || echo '$(srcdir)/'`audio/a2dp.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-a2dp.Tpo audio/$(DEPDIR)/bluetoothd-a2dp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/a2dp.c' object='audio/bluetoothd-a2dp.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-mimetype.obj: obexd/src/mimetype.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-mimetype.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-mimetype.Tpo -c -o obexd/src/obexd-mimetype.obj `if test -f 'obexd/src/mimetype.c'; then $(CYGPATH_W) 'obexd/src/mimetype.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/mimetype.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-mimetype.Tpo obexd/src/$(DEPDIR)/obexd-mimetype.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/mimetype.c' object='obexd/src/obexd-mimetype.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-a2dp.o `test -f 'audio/a2dp.c' || echo '$(srcdir)/'`audio/a2dp.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-mimetype.obj `if test -f 'obexd/src/mimetype.c'; then $(CYGPATH_W) 'obexd/src/mimetype.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/mimetype.c'; fi`
 
-audio/bluetoothd-a2dp.obj: audio/a2dp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-a2dp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o audio/bluetoothd-a2dp.obj `if test -f 'audio/a2dp.c'; then $(CYGPATH_W) 'audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/audio/a2dp.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-a2dp.Tpo audio/$(DEPDIR)/bluetoothd-a2dp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/a2dp.c' object='audio/bluetoothd-a2dp.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-service.o: obexd/src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-service.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-service.Tpo -c -o obexd/src/obexd-service.o `test -f 'obexd/src/service.c' || echo '$(srcdir)/'`obexd/src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-service.Tpo obexd/src/$(DEPDIR)/obexd-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/service.c' object='obexd/src/obexd-service.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-a2dp.obj `if test -f 'audio/a2dp.c'; then $(CYGPATH_W) 'audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/audio/a2dp.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-service.o `test -f 'obexd/src/service.c' || echo '$(srcdir)/'`obexd/src/service.c
 
-audio/bluetoothd-avdtp.o: audio/avdtp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avdtp.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o audio/bluetoothd-avdtp.o `test -f 'audio/avdtp.c' || echo '$(srcdir)/'`audio/avdtp.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avdtp.Tpo audio/$(DEPDIR)/bluetoothd-avdtp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avdtp.c' object='audio/bluetoothd-avdtp.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-service.obj: obexd/src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-service.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-service.Tpo -c -o obexd/src/obexd-service.obj `if test -f 'obexd/src/service.c'; then $(CYGPATH_W) 'obexd/src/service.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/service.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-service.Tpo obexd/src/$(DEPDIR)/obexd-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/service.c' object='obexd/src/obexd-service.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avdtp.o `test -f 'audio/avdtp.c' || echo '$(srcdir)/'`audio/avdtp.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-service.obj `if test -f 'obexd/src/service.c'; then $(CYGPATH_W) 'obexd/src/service.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/service.c'; fi`
 
-audio/bluetoothd-avdtp.obj: audio/avdtp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-avdtp.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o audio/bluetoothd-avdtp.obj `if test -f 'audio/avdtp.c'; then $(CYGPATH_W) 'audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avdtp.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-avdtp.Tpo audio/$(DEPDIR)/bluetoothd-avdtp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/avdtp.c' object='audio/bluetoothd-avdtp.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-transport.o: obexd/src/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-transport.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/src/obexd-transport.o `test -f 'obexd/src/transport.c' || echo '$(srcdir)/'`obexd/src/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-transport.Tpo obexd/src/$(DEPDIR)/obexd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/transport.c' object='obexd/src/obexd-transport.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-avdtp.obj `if test -f 'audio/avdtp.c'; then $(CYGPATH_W) 'audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/audio/avdtp.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-transport.o `test -f 'obexd/src/transport.c' || echo '$(srcdir)/'`obexd/src/transport.c
 
-audio/bluetoothd-ipc.o: audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-ipc.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-ipc.Tpo -c -o audio/bluetoothd-ipc.o `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-ipc.Tpo audio/$(DEPDIR)/bluetoothd-ipc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ipc.c' object='audio/bluetoothd-ipc.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-transport.obj: obexd/src/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-transport.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/src/obexd-transport.obj `if test -f 'obexd/src/transport.c'; then $(CYGPATH_W) 'obexd/src/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/transport.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-transport.Tpo obexd/src/$(DEPDIR)/obexd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/transport.c' object='obexd/src/obexd-transport.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-ipc.o `test -f 'audio/ipc.c' || echo '$(srcdir)/'`audio/ipc.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-transport.obj `if test -f 'obexd/src/transport.c'; then $(CYGPATH_W) 'obexd/src/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/transport.c'; fi`
 
-audio/bluetoothd-ipc.obj: audio/ipc.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-ipc.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-ipc.Tpo -c -o audio/bluetoothd-ipc.obj `if test -f 'audio/ipc.c'; then $(CYGPATH_W) 'audio/ipc.c'; else $(CYGPATH_W) '$(srcdir)/audio/ipc.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-ipc.Tpo audio/$(DEPDIR)/bluetoothd-ipc.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/ipc.c' object='audio/bluetoothd-ipc.obj' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-server.o: obexd/src/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-server.o -MD -MP -MF obexd/src/$(DEPDIR)/obexd-server.Tpo -c -o obexd/src/obexd-server.o `test -f 'obexd/src/server.c' || echo '$(srcdir)/'`obexd/src/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-server.Tpo obexd/src/$(DEPDIR)/obexd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/server.c' object='obexd/src/obexd-server.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-ipc.obj `if test -f 'audio/ipc.c'; then $(CYGPATH_W) 'audio/ipc.c'; else $(CYGPATH_W) '$(srcdir)/audio/ipc.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-server.o `test -f 'obexd/src/server.c' || echo '$(srcdir)/'`obexd/src/server.c
 
-audio/bluetoothd-unix.o: audio/unix.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-unix.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-unix.Tpo -c -o audio/bluetoothd-unix.o `test -f 'audio/unix.c' || echo '$(srcdir)/'`audio/unix.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-unix.Tpo audio/$(DEPDIR)/bluetoothd-unix.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/unix.c' object='audio/bluetoothd-unix.o' libtool=no @AMDEPBACKSLASH@
+obexd/src/obexd-server.obj: obexd/src/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/src/obexd-server.obj -MD -MP -MF obexd/src/$(DEPDIR)/obexd-server.Tpo -c -o obexd/src/obexd-server.obj `if test -f 'obexd/src/server.c'; then $(CYGPATH_W) 'obexd/src/server.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/src/$(DEPDIR)/obexd-server.Tpo obexd/src/$(DEPDIR)/obexd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/src/server.c' object='obexd/src/obexd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-unix.o `test -f 'audio/unix.c' || echo '$(srcdir)/'`audio/unix.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/src/obexd-server.obj `if test -f 'obexd/src/server.c'; then $(CYGPATH_W) 'obexd/src/server.c'; else $(CYGPATH_W) '$(srcdir)/obexd/src/server.c'; fi`
 
-audio/bluetoothd-unix.obj: audio/unix.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-unix.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-unix.Tpo -c -o audio/bluetoothd-unix.obj `if test -f 'audio/unix.c'; then $(CYGPATH_W) 'audio/unix.c'; else $(CYGPATH_W) '$(srcdir)/audio/unix.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-unix.Tpo audio/$(DEPDIR)/bluetoothd-unix.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/unix.c' object='audio/bluetoothd-unix.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-manager.o: obexd/client/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-manager.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/client/obexd-manager.o `test -f 'obexd/client/manager.c' || echo '$(srcdir)/'`obexd/client/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-manager.Tpo obexd/client/$(DEPDIR)/obexd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/manager.c' object='obexd/client/obexd-manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-unix.obj `if test -f 'audio/unix.c'; then $(CYGPATH_W) 'audio/unix.c'; else $(CYGPATH_W) '$(srcdir)/audio/unix.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-manager.o `test -f 'obexd/client/manager.c' || echo '$(srcdir)/'`obexd/client/manager.c
 
-audio/bluetoothd-media.o: audio/media.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-media.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o audio/bluetoothd-media.o `test -f 'audio/media.c' || echo '$(srcdir)/'`audio/media.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-media.Tpo audio/$(DEPDIR)/bluetoothd-media.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/media.c' object='audio/bluetoothd-media.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-manager.obj: obexd/client/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-manager.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-manager.Tpo -c -o obexd/client/obexd-manager.obj `if test -f 'obexd/client/manager.c'; then $(CYGPATH_W) 'obexd/client/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-manager.Tpo obexd/client/$(DEPDIR)/obexd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/manager.c' object='obexd/client/obexd-manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-media.o `test -f 'audio/media.c' || echo '$(srcdir)/'`audio/media.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-manager.obj `if test -f 'obexd/client/manager.c'; then $(CYGPATH_W) 'obexd/client/manager.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/manager.c'; fi`
 
-audio/bluetoothd-media.obj: audio/media.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-media.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o audio/bluetoothd-media.obj `if test -f 'audio/media.c'; then $(CYGPATH_W) 'audio/media.c'; else $(CYGPATH_W) '$(srcdir)/audio/media.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-media.Tpo audio/$(DEPDIR)/bluetoothd-media.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/media.c' object='audio/bluetoothd-media.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-session.o: obexd/client/session.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-session.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-session.Tpo -c -o obexd/client/obexd-session.o `test -f 'obexd/client/session.c' || echo '$(srcdir)/'`obexd/client/session.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-session.Tpo obexd/client/$(DEPDIR)/obexd-session.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/session.c' object='obexd/client/obexd-session.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-media.obj `if test -f 'audio/media.c'; then $(CYGPATH_W) 'audio/media.c'; else $(CYGPATH_W) '$(srcdir)/audio/media.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-session.o `test -f 'obexd/client/session.c' || echo '$(srcdir)/'`obexd/client/session.c
 
-audio/bluetoothd-transport.o: audio/transport.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-transport.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o audio/bluetoothd-transport.o `test -f 'audio/transport.c' || echo '$(srcdir)/'`audio/transport.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-transport.Tpo audio/$(DEPDIR)/bluetoothd-transport.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/transport.c' object='audio/bluetoothd-transport.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-session.obj: obexd/client/session.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-session.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-session.Tpo -c -o obexd/client/obexd-session.obj `if test -f 'obexd/client/session.c'; then $(CYGPATH_W) 'obexd/client/session.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/session.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-session.Tpo obexd/client/$(DEPDIR)/obexd-session.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/session.c' object='obexd/client/obexd-session.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-transport.o `test -f 'audio/transport.c' || echo '$(srcdir)/'`audio/transport.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-session.obj `if test -f 'obexd/client/session.c'; then $(CYGPATH_W) 'obexd/client/session.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/session.c'; fi`
 
-audio/bluetoothd-transport.obj: audio/transport.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-transport.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o audio/bluetoothd-transport.obj `if test -f 'audio/transport.c'; then $(CYGPATH_W) 'audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/audio/transport.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-transport.Tpo audio/$(DEPDIR)/bluetoothd-transport.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/transport.c' object='audio/bluetoothd-transport.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-bluetooth.o: obexd/client/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bluetooth.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/client/obexd-bluetooth.o `test -f 'obexd/client/bluetooth.c' || echo '$(srcdir)/'`obexd/client/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo obexd/client/$(DEPDIR)/obexd-bluetooth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/bluetooth.c' object='obexd/client/obexd-bluetooth.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-transport.obj `if test -f 'audio/transport.c'; then $(CYGPATH_W) 'audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/audio/transport.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bluetooth.o `test -f 'obexd/client/bluetooth.c' || echo '$(srcdir)/'`obexd/client/bluetooth.c
 
-sap/bluetoothd-main.o: sap/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-main.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o sap/bluetoothd-main.o `test -f 'sap/main.c' || echo '$(srcdir)/'`sap/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-main.Tpo sap/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/main.c' object='sap/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-bluetooth.obj: obexd/client/bluetooth.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-bluetooth.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo -c -o obexd/client/obexd-bluetooth.obj `if test -f 'obexd/client/bluetooth.c'; then $(CYGPATH_W) 'obexd/client/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bluetooth.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-bluetooth.Tpo obexd/client/$(DEPDIR)/obexd-bluetooth.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/bluetooth.c' object='obexd/client/obexd-bluetooth.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-main.o `test -f 'sap/main.c' || echo '$(srcdir)/'`sap/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-bluetooth.obj `if test -f 'obexd/client/bluetooth.c'; then $(CYGPATH_W) 'obexd/client/bluetooth.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/bluetooth.c'; fi`
 
-sap/bluetoothd-main.obj: sap/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-main.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o sap/bluetoothd-main.obj `if test -f 'sap/main.c'; then $(CYGPATH_W) 'sap/main.c'; else $(CYGPATH_W) '$(srcdir)/sap/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-main.Tpo sap/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/main.c' object='sap/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-sync.o: obexd/client/sync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-sync.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-sync.Tpo -c -o obexd/client/obexd-sync.o `test -f 'obexd/client/sync.c' || echo '$(srcdir)/'`obexd/client/sync.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-sync.Tpo obexd/client/$(DEPDIR)/obexd-sync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/sync.c' object='obexd/client/obexd-sync.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-main.obj `if test -f 'sap/main.c'; then $(CYGPATH_W) 'sap/main.c'; else $(CYGPATH_W) '$(srcdir)/sap/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-sync.o `test -f 'obexd/client/sync.c' || echo '$(srcdir)/'`obexd/client/sync.c
 
-sap/bluetoothd-manager.o: sap/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-manager.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o sap/bluetoothd-manager.o `test -f 'sap/manager.c' || echo '$(srcdir)/'`sap/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-manager.Tpo sap/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/manager.c' object='sap/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-sync.obj: obexd/client/sync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-sync.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-sync.Tpo -c -o obexd/client/obexd-sync.obj `if test -f 'obexd/client/sync.c'; then $(CYGPATH_W) 'obexd/client/sync.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/sync.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-sync.Tpo obexd/client/$(DEPDIR)/obexd-sync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/sync.c' object='obexd/client/obexd-sync.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-manager.o `test -f 'sap/manager.c' || echo '$(srcdir)/'`sap/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-sync.obj `if test -f 'obexd/client/sync.c'; then $(CYGPATH_W) 'obexd/client/sync.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/sync.c'; fi`
 
-sap/bluetoothd-manager.obj: sap/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-manager.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o sap/bluetoothd-manager.obj `if test -f 'sap/manager.c'; then $(CYGPATH_W) 'sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/sap/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-manager.Tpo sap/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/manager.c' object='sap/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-pbap.o: obexd/client/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-pbap.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/client/obexd-pbap.o `test -f 'obexd/client/pbap.c' || echo '$(srcdir)/'`obexd/client/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-pbap.Tpo obexd/client/$(DEPDIR)/obexd-pbap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/pbap.c' object='obexd/client/obexd-pbap.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-manager.obj `if test -f 'sap/manager.c'; then $(CYGPATH_W) 'sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/sap/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-pbap.o `test -f 'obexd/client/pbap.c' || echo '$(srcdir)/'`obexd/client/pbap.c
 
-sap/bluetoothd-server.o: sap/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-server.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o sap/bluetoothd-server.o `test -f 'sap/server.c' || echo '$(srcdir)/'`sap/server.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-server.Tpo sap/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/server.c' object='sap/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-pbap.obj: obexd/client/pbap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-pbap.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-pbap.Tpo -c -o obexd/client/obexd-pbap.obj `if test -f 'obexd/client/pbap.c'; then $(CYGPATH_W) 'obexd/client/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/pbap.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-pbap.Tpo obexd/client/$(DEPDIR)/obexd-pbap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/pbap.c' object='obexd/client/obexd-pbap.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-server.o `test -f 'sap/server.c' || echo '$(srcdir)/'`sap/server.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-pbap.obj `if test -f 'obexd/client/pbap.c'; then $(CYGPATH_W) 'obexd/client/pbap.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/pbap.c'; fi`
 
-sap/bluetoothd-server.obj: sap/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-server.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o sap/bluetoothd-server.obj `if test -f 'sap/server.c'; then $(CYGPATH_W) 'sap/server.c'; else $(CYGPATH_W) '$(srcdir)/sap/server.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-server.Tpo sap/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/server.c' object='sap/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-ftp.o: obexd/client/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-ftp.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/client/obexd-ftp.o `test -f 'obexd/client/ftp.c' || echo '$(srcdir)/'`obexd/client/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-ftp.Tpo obexd/client/$(DEPDIR)/obexd-ftp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/ftp.c' object='obexd/client/obexd-ftp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-server.obj `if test -f 'sap/server.c'; then $(CYGPATH_W) 'sap/server.c'; else $(CYGPATH_W) '$(srcdir)/sap/server.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-ftp.o `test -f 'obexd/client/ftp.c' || echo '$(srcdir)/'`obexd/client/ftp.c
 
-input/bluetoothd-main.o: input/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-main.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-main.Tpo -c -o input/bluetoothd-main.o `test -f 'input/main.c' || echo '$(srcdir)/'`input/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-main.Tpo input/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/main.c' object='input/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-ftp.obj: obexd/client/ftp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-ftp.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-ftp.Tpo -c -o obexd/client/obexd-ftp.obj `if test -f 'obexd/client/ftp.c'; then $(CYGPATH_W) 'obexd/client/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/ftp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-ftp.Tpo obexd/client/$(DEPDIR)/obexd-ftp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/ftp.c' object='obexd/client/obexd-ftp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-main.o `test -f 'input/main.c' || echo '$(srcdir)/'`input/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-ftp.obj `if test -f 'obexd/client/ftp.c'; then $(CYGPATH_W) 'obexd/client/ftp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/ftp.c'; fi`
 
-input/bluetoothd-main.obj: input/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-main.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-main.Tpo -c -o input/bluetoothd-main.obj `if test -f 'input/main.c'; then $(CYGPATH_W) 'input/main.c'; else $(CYGPATH_W) '$(srcdir)/input/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-main.Tpo input/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/main.c' object='input/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-opp.o: obexd/client/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-opp.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/client/obexd-opp.o `test -f 'obexd/client/opp.c' || echo '$(srcdir)/'`obexd/client/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-opp.Tpo obexd/client/$(DEPDIR)/obexd-opp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/opp.c' object='obexd/client/obexd-opp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-main.obj `if test -f 'input/main.c'; then $(CYGPATH_W) 'input/main.c'; else $(CYGPATH_W) '$(srcdir)/input/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-opp.o `test -f 'obexd/client/opp.c' || echo '$(srcdir)/'`obexd/client/opp.c
 
-input/bluetoothd-manager.o: input/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-manager.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o input/bluetoothd-manager.o `test -f 'input/manager.c' || echo '$(srcdir)/'`input/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-manager.Tpo input/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/manager.c' object='input/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-opp.obj: obexd/client/opp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-opp.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-opp.Tpo -c -o obexd/client/obexd-opp.obj `if test -f 'obexd/client/opp.c'; then $(CYGPATH_W) 'obexd/client/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/opp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-opp.Tpo obexd/client/$(DEPDIR)/obexd-opp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/opp.c' object='obexd/client/obexd-opp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-manager.o `test -f 'input/manager.c' || echo '$(srcdir)/'`input/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-opp.obj `if test -f 'obexd/client/opp.c'; then $(CYGPATH_W) 'obexd/client/opp.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/opp.c'; fi`
 
-input/bluetoothd-manager.obj: input/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-manager.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o input/bluetoothd-manager.obj `if test -f 'input/manager.c'; then $(CYGPATH_W) 'input/manager.c'; else $(CYGPATH_W) '$(srcdir)/input/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-manager.Tpo input/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/manager.c' object='input/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-map.o: obexd/client/map.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map.Tpo -c -o obexd/client/obexd-map.o `test -f 'obexd/client/map.c' || echo '$(srcdir)/'`obexd/client/map.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map.Tpo obexd/client/$(DEPDIR)/obexd-map.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/map.c' object='obexd/client/obexd-map.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-manager.obj `if test -f 'input/manager.c'; then $(CYGPATH_W) 'input/manager.c'; else $(CYGPATH_W) '$(srcdir)/input/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map.o `test -f 'obexd/client/map.c' || echo '$(srcdir)/'`obexd/client/map.c
 
-input/bluetoothd-server.o: input/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-server.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-server.Tpo -c -o input/bluetoothd-server.o `test -f 'input/server.c' || echo '$(srcdir)/'`input/server.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-server.Tpo input/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/server.c' object='input/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-map.obj: obexd/client/map.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map.Tpo -c -o obexd/client/obexd-map.obj `if test -f 'obexd/client/map.c'; then $(CYGPATH_W) 'obexd/client/map.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map.Tpo obexd/client/$(DEPDIR)/obexd-map.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/map.c' object='obexd/client/obexd-map.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-server.o `test -f 'input/server.c' || echo '$(srcdir)/'`input/server.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map.obj `if test -f 'obexd/client/map.c'; then $(CYGPATH_W) 'obexd/client/map.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map.c'; fi`
 
-input/bluetoothd-server.obj: input/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-server.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-server.Tpo -c -o input/bluetoothd-server.obj `if test -f 'input/server.c'; then $(CYGPATH_W) 'input/server.c'; else $(CYGPATH_W) '$(srcdir)/input/server.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-server.Tpo input/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/server.c' object='input/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-map-event.o: obexd/client/map-event.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map-event.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map-event.Tpo -c -o obexd/client/obexd-map-event.o `test -f 'obexd/client/map-event.c' || echo '$(srcdir)/'`obexd/client/map-event.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map-event.Tpo obexd/client/$(DEPDIR)/obexd-map-event.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/map-event.c' object='obexd/client/obexd-map-event.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-server.obj `if test -f 'input/server.c'; then $(CYGPATH_W) 'input/server.c'; else $(CYGPATH_W) '$(srcdir)/input/server.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map-event.o `test -f 'obexd/client/map-event.c' || echo '$(srcdir)/'`obexd/client/map-event.c
 
-input/bluetoothd-device.o: input/device.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-device.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-device.Tpo -c -o input/bluetoothd-device.o `test -f 'input/device.c' || echo '$(srcdir)/'`input/device.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-device.Tpo input/$(DEPDIR)/bluetoothd-device.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/device.c' object='input/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-map-event.obj: obexd/client/map-event.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-map-event.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-map-event.Tpo -c -o obexd/client/obexd-map-event.obj `if test -f 'obexd/client/map-event.c'; then $(CYGPATH_W) 'obexd/client/map-event.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map-event.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-map-event.Tpo obexd/client/$(DEPDIR)/obexd-map-event.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/map-event.c' object='obexd/client/obexd-map-event.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-device.o `test -f 'input/device.c' || echo '$(srcdir)/'`input/device.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-map-event.obj `if test -f 'obexd/client/map-event.c'; then $(CYGPATH_W) 'obexd/client/map-event.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/map-event.c'; fi`
 
-input/bluetoothd-device.obj: input/device.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-device.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-device.Tpo -c -o input/bluetoothd-device.obj `if test -f 'input/device.c'; then $(CYGPATH_W) 'input/device.c'; else $(CYGPATH_W) '$(srcdir)/input/device.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-device.Tpo input/$(DEPDIR)/bluetoothd-device.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/device.c' object='input/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-transfer.o: obexd/client/transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transfer.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transfer.Tpo -c -o obexd/client/obexd-transfer.o `test -f 'obexd/client/transfer.c' || echo '$(srcdir)/'`obexd/client/transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transfer.Tpo obexd/client/$(DEPDIR)/obexd-transfer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/transfer.c' object='obexd/client/obexd-transfer.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-device.obj `if test -f 'input/device.c'; then $(CYGPATH_W) 'input/device.c'; else $(CYGPATH_W) '$(srcdir)/input/device.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transfer.o `test -f 'obexd/client/transfer.c' || echo '$(srcdir)/'`obexd/client/transfer.c
 
-input/bluetoothd-fakehid.o: input/fakehid.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-fakehid.o -MD -MP -MF input/$(DEPDIR)/bluetoothd-fakehid.Tpo -c -o input/bluetoothd-fakehid.o `test -f 'input/fakehid.c' || echo '$(srcdir)/'`input/fakehid.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-fakehid.Tpo input/$(DEPDIR)/bluetoothd-fakehid.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/fakehid.c' object='input/bluetoothd-fakehid.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-transfer.obj: obexd/client/transfer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transfer.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transfer.Tpo -c -o obexd/client/obexd-transfer.obj `if test -f 'obexd/client/transfer.c'; then $(CYGPATH_W) 'obexd/client/transfer.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transfer.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transfer.Tpo obexd/client/$(DEPDIR)/obexd-transfer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/transfer.c' object='obexd/client/obexd-transfer.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-fakehid.o `test -f 'input/fakehid.c' || echo '$(srcdir)/'`input/fakehid.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transfer.obj `if test -f 'obexd/client/transfer.c'; then $(CYGPATH_W) 'obexd/client/transfer.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transfer.c'; fi`
 
-input/bluetoothd-fakehid.obj: input/fakehid.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT input/bluetoothd-fakehid.obj -MD -MP -MF input/$(DEPDIR)/bluetoothd-fakehid.Tpo -c -o input/bluetoothd-fakehid.obj `if test -f 'input/fakehid.c'; then $(CYGPATH_W) 'input/fakehid.c'; else $(CYGPATH_W) '$(srcdir)/input/fakehid.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) input/$(DEPDIR)/bluetoothd-fakehid.Tpo input/$(DEPDIR)/bluetoothd-fakehid.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='input/fakehid.c' object='input/bluetoothd-fakehid.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-transport.o: obexd/client/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transport.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/client/obexd-transport.o `test -f 'obexd/client/transport.c' || echo '$(srcdir)/'`obexd/client/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transport.Tpo obexd/client/$(DEPDIR)/obexd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/transport.c' object='obexd/client/obexd-transport.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o input/bluetoothd-fakehid.obj `if test -f 'input/fakehid.c'; then $(CYGPATH_W) 'input/fakehid.c'; else $(CYGPATH_W) '$(srcdir)/input/fakehid.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transport.o `test -f 'obexd/client/transport.c' || echo '$(srcdir)/'`obexd/client/transport.c
 
-serial/bluetoothd-main.o: serial/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-main.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-main.Tpo -c -o serial/bluetoothd-main.o `test -f 'serial/main.c' || echo '$(srcdir)/'`serial/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-main.Tpo serial/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/main.c' object='serial/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-transport.obj: obexd/client/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-transport.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-transport.Tpo -c -o obexd/client/obexd-transport.obj `if test -f 'obexd/client/transport.c'; then $(CYGPATH_W) 'obexd/client/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transport.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-transport.Tpo obexd/client/$(DEPDIR)/obexd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/transport.c' object='obexd/client/obexd-transport.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-main.o `test -f 'serial/main.c' || echo '$(srcdir)/'`serial/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-transport.obj `if test -f 'obexd/client/transport.c'; then $(CYGPATH_W) 'obexd/client/transport.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/transport.c'; fi`
 
-serial/bluetoothd-main.obj: serial/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-main.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-main.Tpo -c -o serial/bluetoothd-main.obj `if test -f 'serial/main.c'; then $(CYGPATH_W) 'serial/main.c'; else $(CYGPATH_W) '$(srcdir)/serial/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-main.Tpo serial/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/main.c' object='serial/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-dbus.o: obexd/client/dbus.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-dbus.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-dbus.Tpo -c -o obexd/client/obexd-dbus.o `test -f 'obexd/client/dbus.c' || echo '$(srcdir)/'`obexd/client/dbus.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-dbus.Tpo obexd/client/$(DEPDIR)/obexd-dbus.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/dbus.c' object='obexd/client/obexd-dbus.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-main.obj `if test -f 'serial/main.c'; then $(CYGPATH_W) 'serial/main.c'; else $(CYGPATH_W) '$(srcdir)/serial/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-dbus.o `test -f 'obexd/client/dbus.c' || echo '$(srcdir)/'`obexd/client/dbus.c
 
-serial/bluetoothd-manager.o: serial/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-manager.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-manager.Tpo -c -o serial/bluetoothd-manager.o `test -f 'serial/manager.c' || echo '$(srcdir)/'`serial/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-manager.Tpo serial/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/manager.c' object='serial/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-dbus.obj: obexd/client/dbus.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-dbus.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-dbus.Tpo -c -o obexd/client/obexd-dbus.obj `if test -f 'obexd/client/dbus.c'; then $(CYGPATH_W) 'obexd/client/dbus.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/dbus.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-dbus.Tpo obexd/client/$(DEPDIR)/obexd-dbus.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/dbus.c' object='obexd/client/obexd-dbus.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-manager.o `test -f 'serial/manager.c' || echo '$(srcdir)/'`serial/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-dbus.obj `if test -f 'obexd/client/dbus.c'; then $(CYGPATH_W) 'obexd/client/dbus.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/dbus.c'; fi`
 
-serial/bluetoothd-manager.obj: serial/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-manager.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-manager.Tpo -c -o serial/bluetoothd-manager.obj `if test -f 'serial/manager.c'; then $(CYGPATH_W) 'serial/manager.c'; else $(CYGPATH_W) '$(srcdir)/serial/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-manager.Tpo serial/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/manager.c' object='serial/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-driver.o: obexd/client/driver.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-driver.o -MD -MP -MF obexd/client/$(DEPDIR)/obexd-driver.Tpo -c -o obexd/client/obexd-driver.o `test -f 'obexd/client/driver.c' || echo '$(srcdir)/'`obexd/client/driver.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-driver.Tpo obexd/client/$(DEPDIR)/obexd-driver.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/driver.c' object='obexd/client/obexd-driver.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-manager.obj `if test -f 'serial/manager.c'; then $(CYGPATH_W) 'serial/manager.c'; else $(CYGPATH_W) '$(srcdir)/serial/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-driver.o `test -f 'obexd/client/driver.c' || echo '$(srcdir)/'`obexd/client/driver.c
 
-serial/bluetoothd-proxy.o: serial/proxy.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-proxy.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-proxy.Tpo -c -o serial/bluetoothd-proxy.o `test -f 'serial/proxy.c' || echo '$(srcdir)/'`serial/proxy.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-proxy.Tpo serial/$(DEPDIR)/bluetoothd-proxy.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/proxy.c' object='serial/bluetoothd-proxy.o' libtool=no @AMDEPBACKSLASH@
+obexd/client/obexd-driver.obj: obexd/client/driver.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -MT obexd/client/obexd-driver.obj -MD -MP -MF obexd/client/$(DEPDIR)/obexd-driver.Tpo -c -o obexd/client/obexd-driver.obj `if test -f 'obexd/client/driver.c'; then $(CYGPATH_W) 'obexd/client/driver.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/driver.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) obexd/client/$(DEPDIR)/obexd-driver.Tpo obexd/client/$(DEPDIR)/obexd-driver.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='obexd/client/driver.c' object='obexd/client/obexd-driver.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-proxy.o `test -f 'serial/proxy.c' || echo '$(srcdir)/'`serial/proxy.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(obexd_src_obexd_CPPFLAGS) $(CPPFLAGS) $(obexd_src_obexd_CFLAGS) $(CFLAGS) -c -o obexd/client/obexd-driver.obj `if test -f 'obexd/client/driver.c'; then $(CYGPATH_W) 'obexd/client/driver.c'; else $(CYGPATH_W) '$(srcdir)/obexd/client/driver.c'; fi`
 
-serial/bluetoothd-proxy.obj: serial/proxy.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-proxy.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-proxy.Tpo -c -o serial/bluetoothd-proxy.obj `if test -f 'serial/proxy.c'; then $(CYGPATH_W) 'serial/proxy.c'; else $(CYGPATH_W) '$(srcdir)/serial/proxy.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-proxy.Tpo serial/$(DEPDIR)/bluetoothd-proxy.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/proxy.c' object='serial/bluetoothd-proxy.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-hostname.o: plugins/hostname.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hostname.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hostname.Tpo -c -o plugins/bluetoothd-hostname.o `test -f 'plugins/hostname.c' || echo '$(srcdir)/'`plugins/hostname.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hostname.Tpo plugins/$(DEPDIR)/bluetoothd-hostname.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hostname.c' object='plugins/bluetoothd-hostname.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-proxy.obj `if test -f 'serial/proxy.c'; then $(CYGPATH_W) 'serial/proxy.c'; else $(CYGPATH_W) '$(srcdir)/serial/proxy.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hostname.o `test -f 'plugins/hostname.c' || echo '$(srcdir)/'`plugins/hostname.c
 
-serial/bluetoothd-port.o: serial/port.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-port.o -MD -MP -MF serial/$(DEPDIR)/bluetoothd-port.Tpo -c -o serial/bluetoothd-port.o `test -f 'serial/port.c' || echo '$(srcdir)/'`serial/port.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-port.Tpo serial/$(DEPDIR)/bluetoothd-port.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/port.c' object='serial/bluetoothd-port.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-hostname.obj: plugins/hostname.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hostname.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hostname.Tpo -c -o plugins/bluetoothd-hostname.obj `if test -f 'plugins/hostname.c'; then $(CYGPATH_W) 'plugins/hostname.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hostname.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hostname.Tpo plugins/$(DEPDIR)/bluetoothd-hostname.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hostname.c' object='plugins/bluetoothd-hostname.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-port.o `test -f 'serial/port.c' || echo '$(srcdir)/'`serial/port.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hostname.obj `if test -f 'plugins/hostname.c'; then $(CYGPATH_W) 'plugins/hostname.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hostname.c'; fi`
 
-serial/bluetoothd-port.obj: serial/port.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT serial/bluetoothd-port.obj -MD -MP -MF serial/$(DEPDIR)/bluetoothd-port.Tpo -c -o serial/bluetoothd-port.obj `if test -f 'serial/port.c'; then $(CYGPATH_W) 'serial/port.c'; else $(CYGPATH_W) '$(srcdir)/serial/port.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) serial/$(DEPDIR)/bluetoothd-port.Tpo serial/$(DEPDIR)/bluetoothd-port.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='serial/port.c' object='serial/bluetoothd-port.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-wiimote.o: plugins/wiimote.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o serial/bluetoothd-port.obj `if test -f 'serial/port.c'; then $(CYGPATH_W) 'serial/port.c'; else $(CYGPATH_W) '$(srcdir)/serial/port.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c
 
-network/bluetoothd-main.o: network/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-main.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-main.Tpo -c -o network/bluetoothd-main.o `test -f 'network/main.c' || echo '$(srcdir)/'`network/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-main.Tpo network/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/main.c' object='network/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-wiimote.obj: plugins/wiimote.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-main.o `test -f 'network/main.c' || echo '$(srcdir)/'`network/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi`
 
-network/bluetoothd-main.obj: network/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-main.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-main.Tpo -c -o network/bluetoothd-main.obj `if test -f 'network/main.c'; then $(CYGPATH_W) 'network/main.c'; else $(CYGPATH_W) '$(srcdir)/network/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-main.Tpo network/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/main.c' object='network/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-autopair.o: plugins/autopair.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-autopair.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-autopair.Tpo -c -o plugins/bluetoothd-autopair.o `test -f 'plugins/autopair.c' || echo '$(srcdir)/'`plugins/autopair.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-autopair.Tpo plugins/$(DEPDIR)/bluetoothd-autopair.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/autopair.c' object='plugins/bluetoothd-autopair.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-main.obj `if test -f 'network/main.c'; then $(CYGPATH_W) 'network/main.c'; else $(CYGPATH_W) '$(srcdir)/network/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-autopair.o `test -f 'plugins/autopair.c' || echo '$(srcdir)/'`plugins/autopair.c
 
-network/bluetoothd-manager.o: network/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-manager.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o network/bluetoothd-manager.o `test -f 'network/manager.c' || echo '$(srcdir)/'`network/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-manager.Tpo network/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/manager.c' object='network/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-autopair.obj: plugins/autopair.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-autopair.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-autopair.Tpo -c -o plugins/bluetoothd-autopair.obj `if test -f 'plugins/autopair.c'; then $(CYGPATH_W) 'plugins/autopair.c'; else $(CYGPATH_W) '$(srcdir)/plugins/autopair.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-autopair.Tpo plugins/$(DEPDIR)/bluetoothd-autopair.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/autopair.c' object='plugins/bluetoothd-autopair.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-manager.o `test -f 'network/manager.c' || echo '$(srcdir)/'`network/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-autopair.obj `if test -f 'plugins/autopair.c'; then $(CYGPATH_W) 'plugins/autopair.c'; else $(CYGPATH_W) '$(srcdir)/plugins/autopair.c'; fi`
 
-network/bluetoothd-manager.obj: network/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-manager.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o network/bluetoothd-manager.obj `if test -f 'network/manager.c'; then $(CYGPATH_W) 'network/manager.c'; else $(CYGPATH_W) '$(srcdir)/network/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-manager.Tpo network/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/manager.c' object='network/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-policy.o: plugins/policy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-policy.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-policy.Tpo -c -o plugins/bluetoothd-policy.o `test -f 'plugins/policy.c' || echo '$(srcdir)/'`plugins/policy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-policy.Tpo plugins/$(DEPDIR)/bluetoothd-policy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/policy.c' object='plugins/bluetoothd-policy.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-manager.obj `if test -f 'network/manager.c'; then $(CYGPATH_W) 'network/manager.c'; else $(CYGPATH_W) '$(srcdir)/network/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-policy.o `test -f 'plugins/policy.c' || echo '$(srcdir)/'`plugins/policy.c
 
-network/bluetoothd-common.o: network/common.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-common.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-common.Tpo -c -o network/bluetoothd-common.o `test -f 'network/common.c' || echo '$(srcdir)/'`network/common.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-common.Tpo network/$(DEPDIR)/bluetoothd-common.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/common.c' object='network/bluetoothd-common.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-policy.obj: plugins/policy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-policy.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-policy.Tpo -c -o plugins/bluetoothd-policy.obj `if test -f 'plugins/policy.c'; then $(CYGPATH_W) 'plugins/policy.c'; else $(CYGPATH_W) '$(srcdir)/plugins/policy.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-policy.Tpo plugins/$(DEPDIR)/bluetoothd-policy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/policy.c' object='plugins/bluetoothd-policy.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-common.o `test -f 'network/common.c' || echo '$(srcdir)/'`network/common.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-policy.obj `if test -f 'plugins/policy.c'; then $(CYGPATH_W) 'plugins/policy.c'; else $(CYGPATH_W) '$(srcdir)/plugins/policy.c'; fi`
 
-network/bluetoothd-common.obj: network/common.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-common.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-common.Tpo -c -o network/bluetoothd-common.obj `if test -f 'network/common.c'; then $(CYGPATH_W) 'network/common.c'; else $(CYGPATH_W) '$(srcdir)/network/common.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-common.Tpo network/$(DEPDIR)/bluetoothd-common.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/common.c' object='network/bluetoothd-common.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-gatt-example.o: plugins/gatt-example.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-common.obj `if test -f 'network/common.c'; then $(CYGPATH_W) 'network/common.c'; else $(CYGPATH_W) '$(srcdir)/network/common.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c
 
-network/bluetoothd-server.o: network/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-server.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-server.Tpo -c -o network/bluetoothd-server.o `test -f 'network/server.c' || echo '$(srcdir)/'`network/server.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-server.Tpo network/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/server.c' object='network/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-gatt-example.obj: plugins/gatt-example.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-server.o `test -f 'network/server.c' || echo '$(srcdir)/'`network/server.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi`
 
-network/bluetoothd-server.obj: network/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-server.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-server.Tpo -c -o network/bluetoothd-server.obj `if test -f 'network/server.c'; then $(CYGPATH_W) 'network/server.c'; else $(CYGPATH_W) '$(srcdir)/network/server.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-server.Tpo network/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/server.c' object='network/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-neard.o: plugins/neard.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-neard.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-neard.Tpo -c -o plugins/bluetoothd-neard.o `test -f 'plugins/neard.c' || echo '$(srcdir)/'`plugins/neard.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-neard.Tpo plugins/$(DEPDIR)/bluetoothd-neard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/neard.c' object='plugins/bluetoothd-neard.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-server.obj `if test -f 'network/server.c'; then $(CYGPATH_W) 'network/server.c'; else $(CYGPATH_W) '$(srcdir)/network/server.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-neard.o `test -f 'plugins/neard.c' || echo '$(srcdir)/'`plugins/neard.c
 
-network/bluetoothd-connection.o: network/connection.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-connection.o -MD -MP -MF network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o network/bluetoothd-connection.o `test -f 'network/connection.c' || echo '$(srcdir)/'`network/connection.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-connection.Tpo network/$(DEPDIR)/bluetoothd-connection.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/connection.c' object='network/bluetoothd-connection.o' libtool=no @AMDEPBACKSLASH@
+plugins/bluetoothd-neard.obj: plugins/neard.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-neard.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-neard.Tpo -c -o plugins/bluetoothd-neard.obj `if test -f 'plugins/neard.c'; then $(CYGPATH_W) 'plugins/neard.c'; else $(CYGPATH_W) '$(srcdir)/plugins/neard.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-neard.Tpo plugins/$(DEPDIR)/bluetoothd-neard.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/neard.c' object='plugins/bluetoothd-neard.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-connection.o `test -f 'network/connection.c' || echo '$(srcdir)/'`network/connection.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-neard.obj `if test -f 'plugins/neard.c'; then $(CYGPATH_W) 'plugins/neard.c'; else $(CYGPATH_W) '$(srcdir)/plugins/neard.c'; fi`
 
-network/bluetoothd-connection.obj: network/connection.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT network/bluetoothd-connection.obj -MD -MP -MF network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o network/bluetoothd-connection.obj `if test -f 'network/connection.c'; then $(CYGPATH_W) 'network/connection.c'; else $(CYGPATH_W) '$(srcdir)/network/connection.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) network/$(DEPDIR)/bluetoothd-connection.Tpo network/$(DEPDIR)/bluetoothd-connection.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='network/connection.c' object='network/bluetoothd-connection.obj' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-main.o: profiles/sap/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-main.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/sap/bluetoothd-main.o `test -f 'profiles/sap/main.c' || echo '$(srcdir)/'`profiles/sap/main.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo profiles/sap/$(DEPDIR)/bluetoothd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/main.c' object='profiles/sap/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o network/bluetoothd-connection.obj `if test -f 'network/connection.c'; then $(CYGPATH_W) 'network/connection.c'; else $(CYGPATH_W) '$(srcdir)/network/connection.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-main.o `test -f 'profiles/sap/main.c' || echo '$(srcdir)/'`profiles/sap/main.c
 
-plugins/bluetoothd-service.o: plugins/service.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-service.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-service.Tpo -c -o plugins/bluetoothd-service.o `test -f 'plugins/service.c' || echo '$(srcdir)/'`plugins/service.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-service.Tpo plugins/$(DEPDIR)/bluetoothd-service.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/service.c' object='plugins/bluetoothd-service.o' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-main.obj: profiles/sap/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-main.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/sap/bluetoothd-main.obj `if test -f 'profiles/sap/main.c'; then $(CYGPATH_W) 'profiles/sap/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/main.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-main.Tpo profiles/sap/$(DEPDIR)/bluetoothd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/main.c' object='profiles/sap/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-service.o `test -f 'plugins/service.c' || echo '$(srcdir)/'`plugins/service.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-main.obj `if test -f 'profiles/sap/main.c'; then $(CYGPATH_W) 'profiles/sap/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/main.c'; fi`
 
-plugins/bluetoothd-service.obj: plugins/service.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-service.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-service.Tpo -c -o plugins/bluetoothd-service.obj `if test -f 'plugins/service.c'; then $(CYGPATH_W) 'plugins/service.c'; else $(CYGPATH_W) '$(srcdir)/plugins/service.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-service.Tpo plugins/$(DEPDIR)/bluetoothd-service.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/service.c' object='plugins/bluetoothd-service.obj' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-manager.o: profiles/sap/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-manager.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/sap/bluetoothd-manager.o `test -f 'profiles/sap/manager.c' || echo '$(srcdir)/'`profiles/sap/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo profiles/sap/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/manager.c' object='profiles/sap/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-service.obj `if test -f 'plugins/service.c'; then $(CYGPATH_W) 'plugins/service.c'; else $(CYGPATH_W) '$(srcdir)/plugins/service.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-manager.o `test -f 'profiles/sap/manager.c' || echo '$(srcdir)/'`profiles/sap/manager.c
 
-health/bluetoothd-hdp_main.o: health/hdp_main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_main.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o health/bluetoothd-hdp_main.o `test -f 'health/hdp_main.c' || echo '$(srcdir)/'`health/hdp_main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_main.Tpo health/$(DEPDIR)/bluetoothd-hdp_main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_main.c' object='health/bluetoothd-hdp_main.o' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-manager.obj: profiles/sap/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-manager.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/sap/bluetoothd-manager.obj `if test -f 'profiles/sap/manager.c'; then $(CYGPATH_W) 'profiles/sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-manager.Tpo profiles/sap/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/manager.c' object='profiles/sap/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_main.o `test -f 'health/hdp_main.c' || echo '$(srcdir)/'`health/hdp_main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-manager.obj `if test -f 'profiles/sap/manager.c'; then $(CYGPATH_W) 'profiles/sap/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/manager.c'; fi`
 
-health/bluetoothd-hdp_main.obj: health/hdp_main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_main.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o health/bluetoothd-hdp_main.obj `if test -f 'health/hdp_main.c'; then $(CYGPATH_W) 'health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_main.Tpo health/$(DEPDIR)/bluetoothd-hdp_main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_main.c' object='health/bluetoothd-hdp_main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-server.o: profiles/sap/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-server.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/sap/bluetoothd-server.o `test -f 'profiles/sap/server.c' || echo '$(srcdir)/'`profiles/sap/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo profiles/sap/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/server.c' object='profiles/sap/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_main.obj `if test -f 'health/hdp_main.c'; then $(CYGPATH_W) 'health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-server.o `test -f 'profiles/sap/server.c' || echo '$(srcdir)/'`profiles/sap/server.c
 
-health/bluetoothd-hdp_manager.o: health/hdp_manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_manager.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o health/bluetoothd-hdp_manager.o `test -f 'health/hdp_manager.c' || echo '$(srcdir)/'`health/hdp_manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo health/$(DEPDIR)/bluetoothd-hdp_manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_manager.c' object='health/bluetoothd-hdp_manager.o' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-server.obj: profiles/sap/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-server.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/sap/bluetoothd-server.obj `if test -f 'profiles/sap/server.c'; then $(CYGPATH_W) 'profiles/sap/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-server.Tpo profiles/sap/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/server.c' object='profiles/sap/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_manager.o `test -f 'health/hdp_manager.c' || echo '$(srcdir)/'`health/hdp_manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-server.obj `if test -f 'profiles/sap/server.c'; then $(CYGPATH_W) 'profiles/sap/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/server.c'; fi`
 
-health/bluetoothd-hdp_manager.obj: health/hdp_manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_manager.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o health/bluetoothd-hdp_manager.obj `if test -f 'health/hdp_manager.c'; then $(CYGPATH_W) 'health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo health/$(DEPDIR)/bluetoothd-hdp_manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_manager.c' object='health/bluetoothd-hdp_manager.obj' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-sap-dummy.o: profiles/sap/sap-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-sap-dummy.o -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo -c -o profiles/sap/bluetoothd-sap-dummy.o `test -f 'profiles/sap/sap-dummy.c' || echo '$(srcdir)/'`profiles/sap/sap-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/sap-dummy.c' object='profiles/sap/bluetoothd-sap-dummy.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_manager.obj `if test -f 'health/hdp_manager.c'; then $(CYGPATH_W) 'health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-sap-dummy.o `test -f 'profiles/sap/sap-dummy.c' || echo '$(srcdir)/'`profiles/sap/sap-dummy.c
 
-health/bluetoothd-hdp.o: health/hdp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o health/bluetoothd-hdp.o `test -f 'health/hdp.c' || echo '$(srcdir)/'`health/hdp.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp.Tpo health/$(DEPDIR)/bluetoothd-hdp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp.c' object='health/bluetoothd-hdp.o' libtool=no @AMDEPBACKSLASH@
+profiles/sap/bluetoothd-sap-dummy.obj: profiles/sap/sap-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/sap/bluetoothd-sap-dummy.obj -MD -MP -MF profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo -c -o profiles/sap/bluetoothd-sap-dummy.obj `if test -f 'profiles/sap/sap-dummy.c'; then $(CYGPATH_W) 'profiles/sap/sap-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/sap-dummy.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Tpo profiles/sap/$(DEPDIR)/bluetoothd-sap-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/sap/sap-dummy.c' object='profiles/sap/bluetoothd-sap-dummy.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp.o `test -f 'health/hdp.c' || echo '$(srcdir)/'`health/hdp.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/sap/bluetoothd-sap-dummy.obj `if test -f 'profiles/sap/sap-dummy.c'; then $(CYGPATH_W) 'profiles/sap/sap-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/sap/sap-dummy.c'; fi`
 
-health/bluetoothd-hdp.obj: health/hdp.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o health/bluetoothd-hdp.obj `if test -f 'health/hdp.c'; then $(CYGPATH_W) 'health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp.Tpo health/$(DEPDIR)/bluetoothd-hdp.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp.c' object='health/bluetoothd-hdp.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-source.o: profiles/audio/source.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-source.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o profiles/audio/bluetoothd-source.o `test -f 'profiles/audio/source.c' || echo '$(srcdir)/'`profiles/audio/source.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo profiles/audio/$(DEPDIR)/bluetoothd-source.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/source.c' object='profiles/audio/bluetoothd-source.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp.obj `if test -f 'health/hdp.c'; then $(CYGPATH_W) 'health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-source.o `test -f 'profiles/audio/source.c' || echo '$(srcdir)/'`profiles/audio/source.c
 
-health/bluetoothd-hdp_util.o: health/hdp_util.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_util.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o health/bluetoothd-hdp_util.o `test -f 'health/hdp_util.c' || echo '$(srcdir)/'`health/hdp_util.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_util.Tpo health/$(DEPDIR)/bluetoothd-hdp_util.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_util.c' object='health/bluetoothd-hdp_util.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-source.obj: profiles/audio/source.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-source.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo -c -o profiles/audio/bluetoothd-source.obj `if test -f 'profiles/audio/source.c'; then $(CYGPATH_W) 'profiles/audio/source.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/source.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-source.Tpo profiles/audio/$(DEPDIR)/bluetoothd-source.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/source.c' object='profiles/audio/bluetoothd-source.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_util.o `test -f 'health/hdp_util.c' || echo '$(srcdir)/'`health/hdp_util.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-source.obj `if test -f 'profiles/audio/source.c'; then $(CYGPATH_W) 'profiles/audio/source.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/source.c'; fi`
 
-health/bluetoothd-hdp_util.obj: health/hdp_util.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-hdp_util.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o health/bluetoothd-hdp_util.obj `if test -f 'health/hdp_util.c'; then $(CYGPATH_W) 'health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_util.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-hdp_util.Tpo health/$(DEPDIR)/bluetoothd-hdp_util.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/hdp_util.c' object='health/bluetoothd-hdp_util.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-sink.o: profiles/audio/sink.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-sink.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o profiles/audio/bluetoothd-sink.o `test -f 'profiles/audio/sink.c' || echo '$(srcdir)/'`profiles/audio/sink.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo profiles/audio/$(DEPDIR)/bluetoothd-sink.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/sink.c' object='profiles/audio/bluetoothd-sink.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-hdp_util.obj `if test -f 'health/hdp_util.c'; then $(CYGPATH_W) 'health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/health/hdp_util.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-sink.o `test -f 'profiles/audio/sink.c' || echo '$(srcdir)/'`profiles/audio/sink.c
 
-thermometer/bluetoothd-main.o: thermometer/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-main.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-main.Tpo -c -o thermometer/bluetoothd-main.o `test -f 'thermometer/main.c' || echo '$(srcdir)/'`thermometer/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-main.Tpo thermometer/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/main.c' object='thermometer/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-sink.obj: profiles/audio/sink.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-sink.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo -c -o profiles/audio/bluetoothd-sink.obj `if test -f 'profiles/audio/sink.c'; then $(CYGPATH_W) 'profiles/audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/sink.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-sink.Tpo profiles/audio/$(DEPDIR)/bluetoothd-sink.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/sink.c' object='profiles/audio/bluetoothd-sink.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-main.o `test -f 'thermometer/main.c' || echo '$(srcdir)/'`thermometer/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-sink.obj `if test -f 'profiles/audio/sink.c'; then $(CYGPATH_W) 'profiles/audio/sink.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/sink.c'; fi`
 
-thermometer/bluetoothd-main.obj: thermometer/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-main.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-main.Tpo -c -o thermometer/bluetoothd-main.obj `if test -f 'thermometer/main.c'; then $(CYGPATH_W) 'thermometer/main.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-main.Tpo thermometer/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/main.c' object='thermometer/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-a2dp.o: profiles/audio/a2dp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-a2dp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o profiles/audio/bluetoothd-a2dp.o `test -f 'profiles/audio/a2dp.c' || echo '$(srcdir)/'`profiles/audio/a2dp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/a2dp.c' object='profiles/audio/bluetoothd-a2dp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-main.obj `if test -f 'thermometer/main.c'; then $(CYGPATH_W) 'thermometer/main.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-a2dp.o `test -f 'profiles/audio/a2dp.c' || echo '$(srcdir)/'`profiles/audio/a2dp.c
 
-thermometer/bluetoothd-manager.o: thermometer/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-manager.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-manager.Tpo -c -o thermometer/bluetoothd-manager.o `test -f 'thermometer/manager.c' || echo '$(srcdir)/'`thermometer/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-manager.Tpo thermometer/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/manager.c' object='thermometer/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-a2dp.obj: profiles/audio/a2dp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-a2dp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo -c -o profiles/audio/bluetoothd-a2dp.obj `if test -f 'profiles/audio/a2dp.c'; then $(CYGPATH_W) 'profiles/audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/a2dp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-a2dp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/a2dp.c' object='profiles/audio/bluetoothd-a2dp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-manager.o `test -f 'thermometer/manager.c' || echo '$(srcdir)/'`thermometer/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-a2dp.obj `if test -f 'profiles/audio/a2dp.c'; then $(CYGPATH_W) 'profiles/audio/a2dp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/a2dp.c'; fi`
 
-thermometer/bluetoothd-manager.obj: thermometer/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-manager.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-manager.Tpo -c -o thermometer/bluetoothd-manager.obj `if test -f 'thermometer/manager.c'; then $(CYGPATH_W) 'thermometer/manager.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-manager.Tpo thermometer/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/manager.c' object='thermometer/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avdtp.o: profiles/audio/avdtp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avdtp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o profiles/audio/bluetoothd-avdtp.o `test -f 'profiles/audio/avdtp.c' || echo '$(srcdir)/'`profiles/audio/avdtp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avdtp.c' object='profiles/audio/bluetoothd-avdtp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-manager.obj `if test -f 'thermometer/manager.c'; then $(CYGPATH_W) 'thermometer/manager.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avdtp.o `test -f 'profiles/audio/avdtp.c' || echo '$(srcdir)/'`profiles/audio/avdtp.c
 
-thermometer/bluetoothd-thermometer.o: thermometer/thermometer.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-thermometer.o -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o thermometer/bluetoothd-thermometer.o `test -f 'thermometer/thermometer.c' || echo '$(srcdir)/'`thermometer/thermometer.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo thermometer/$(DEPDIR)/bluetoothd-thermometer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/thermometer.c' object='thermometer/bluetoothd-thermometer.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avdtp.obj: profiles/audio/avdtp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avdtp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo -c -o profiles/audio/bluetoothd-avdtp.obj `if test -f 'profiles/audio/avdtp.c'; then $(CYGPATH_W) 'profiles/audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avdtp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avdtp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avdtp.c' object='profiles/audio/bluetoothd-avdtp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-thermometer.o `test -f 'thermometer/thermometer.c' || echo '$(srcdir)/'`thermometer/thermometer.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avdtp.obj `if test -f 'profiles/audio/avdtp.c'; then $(CYGPATH_W) 'profiles/audio/avdtp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avdtp.c'; fi`
 
-thermometer/bluetoothd-thermometer.obj: thermometer/thermometer.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT thermometer/bluetoothd-thermometer.obj -MD -MP -MF thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o thermometer/bluetoothd-thermometer.obj `if test -f 'thermometer/thermometer.c'; then $(CYGPATH_W) 'thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/thermometer.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo thermometer/$(DEPDIR)/bluetoothd-thermometer.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='thermometer/thermometer.c' object='thermometer/bluetoothd-thermometer.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-media.o: profiles/audio/media.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-media.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o profiles/audio/bluetoothd-media.o `test -f 'profiles/audio/media.c' || echo '$(srcdir)/'`profiles/audio/media.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo profiles/audio/$(DEPDIR)/bluetoothd-media.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/media.c' object='profiles/audio/bluetoothd-media.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o thermometer/bluetoothd-thermometer.obj `if test -f 'thermometer/thermometer.c'; then $(CYGPATH_W) 'thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/thermometer/thermometer.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-media.o `test -f 'profiles/audio/media.c' || echo '$(srcdir)/'`profiles/audio/media.c
 
-alert/bluetoothd-main.o: alert/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-main.o -MD -MP -MF alert/$(DEPDIR)/bluetoothd-main.Tpo -c -o alert/bluetoothd-main.o `test -f 'alert/main.c' || echo '$(srcdir)/'`alert/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-main.Tpo alert/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='alert/main.c' object='alert/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-media.obj: profiles/audio/media.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-media.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo -c -o profiles/audio/bluetoothd-media.obj `if test -f 'profiles/audio/media.c'; then $(CYGPATH_W) 'profiles/audio/media.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/media.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-media.Tpo profiles/audio/$(DEPDIR)/bluetoothd-media.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/media.c' object='profiles/audio/bluetoothd-media.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-main.o `test -f 'alert/main.c' || echo '$(srcdir)/'`alert/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-media.obj `if test -f 'profiles/audio/media.c'; then $(CYGPATH_W) 'profiles/audio/media.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/media.c'; fi`
 
-alert/bluetoothd-main.obj: alert/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-main.obj -MD -MP -MF alert/$(DEPDIR)/bluetoothd-main.Tpo -c -o alert/bluetoothd-main.obj `if test -f 'alert/main.c'; then $(CYGPATH_W) 'alert/main.c'; else $(CYGPATH_W) '$(srcdir)/alert/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-main.Tpo alert/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='alert/main.c' object='alert/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-transport.o: profiles/audio/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-transport.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o profiles/audio/bluetoothd-transport.o `test -f 'profiles/audio/transport.c' || echo '$(srcdir)/'`profiles/audio/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo profiles/audio/$(DEPDIR)/bluetoothd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/transport.c' object='profiles/audio/bluetoothd-transport.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-main.obj `if test -f 'alert/main.c'; then $(CYGPATH_W) 'alert/main.c'; else $(CYGPATH_W) '$(srcdir)/alert/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-transport.o `test -f 'profiles/audio/transport.c' || echo '$(srcdir)/'`profiles/audio/transport.c
 
-alert/bluetoothd-server.o: alert/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-server.o -MD -MP -MF alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o alert/bluetoothd-server.o `test -f 'alert/server.c' || echo '$(srcdir)/'`alert/server.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-server.Tpo alert/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='alert/server.c' object='alert/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-transport.obj: profiles/audio/transport.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-transport.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo -c -o profiles/audio/bluetoothd-transport.obj `if test -f 'profiles/audio/transport.c'; then $(CYGPATH_W) 'profiles/audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/transport.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-transport.Tpo profiles/audio/$(DEPDIR)/bluetoothd-transport.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/transport.c' object='profiles/audio/bluetoothd-transport.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-server.o `test -f 'alert/server.c' || echo '$(srcdir)/'`alert/server.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-transport.obj `if test -f 'profiles/audio/transport.c'; then $(CYGPATH_W) 'profiles/audio/transport.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/transport.c'; fi`
 
-alert/bluetoothd-server.obj: alert/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT alert/bluetoothd-server.obj -MD -MP -MF alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o alert/bluetoothd-server.obj `if test -f 'alert/server.c'; then $(CYGPATH_W) 'alert/server.c'; else $(CYGPATH_W) '$(srcdir)/alert/server.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) alert/$(DEPDIR)/bluetoothd-server.Tpo alert/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='alert/server.c' object='alert/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-control.o: profiles/audio/control.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-control.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o profiles/audio/bluetoothd-control.o `test -f 'profiles/audio/control.c' || echo '$(srcdir)/'`profiles/audio/control.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo profiles/audio/$(DEPDIR)/bluetoothd-control.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/control.c' object='profiles/audio/bluetoothd-control.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o alert/bluetoothd-server.obj `if test -f 'alert/server.c'; then $(CYGPATH_W) 'alert/server.c'; else $(CYGPATH_W) '$(srcdir)/alert/server.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-control.o `test -f 'profiles/audio/control.c' || echo '$(srcdir)/'`profiles/audio/control.c
 
-time/bluetoothd-main.o: time/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-main.o -MD -MP -MF time/$(DEPDIR)/bluetoothd-main.Tpo -c -o time/bluetoothd-main.o `test -f 'time/main.c' || echo '$(srcdir)/'`time/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-main.Tpo time/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='time/main.c' object='time/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-control.obj: profiles/audio/control.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-control.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo -c -o profiles/audio/bluetoothd-control.obj `if test -f 'profiles/audio/control.c'; then $(CYGPATH_W) 'profiles/audio/control.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/control.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-control.Tpo profiles/audio/$(DEPDIR)/bluetoothd-control.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/control.c' object='profiles/audio/bluetoothd-control.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-main.o `test -f 'time/main.c' || echo '$(srcdir)/'`time/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-control.obj `if test -f 'profiles/audio/control.c'; then $(CYGPATH_W) 'profiles/audio/control.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/control.c'; fi`
 
-time/bluetoothd-main.obj: time/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-main.obj -MD -MP -MF time/$(DEPDIR)/bluetoothd-main.Tpo -c -o time/bluetoothd-main.obj `if test -f 'time/main.c'; then $(CYGPATH_W) 'time/main.c'; else $(CYGPATH_W) '$(srcdir)/time/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-main.Tpo time/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='time/main.c' object='time/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avctp.o: profiles/audio/avctp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avctp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o profiles/audio/bluetoothd-avctp.o `test -f 'profiles/audio/avctp.c' || echo '$(srcdir)/'`profiles/audio/avctp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avctp.c' object='profiles/audio/bluetoothd-avctp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-main.obj `if test -f 'time/main.c'; then $(CYGPATH_W) 'time/main.c'; else $(CYGPATH_W) '$(srcdir)/time/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avctp.o `test -f 'profiles/audio/avctp.c' || echo '$(srcdir)/'`profiles/audio/avctp.c
 
-time/bluetoothd-server.o: time/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-server.o -MD -MP -MF time/$(DEPDIR)/bluetoothd-server.Tpo -c -o time/bluetoothd-server.o `test -f 'time/server.c' || echo '$(srcdir)/'`time/server.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-server.Tpo time/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='time/server.c' object='time/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avctp.obj: profiles/audio/avctp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avctp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo -c -o profiles/audio/bluetoothd-avctp.obj `if test -f 'profiles/audio/avctp.c'; then $(CYGPATH_W) 'profiles/audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avctp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avctp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avctp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avctp.c' object='profiles/audio/bluetoothd-avctp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-server.o `test -f 'time/server.c' || echo '$(srcdir)/'`time/server.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avctp.obj `if test -f 'profiles/audio/avctp.c'; then $(CYGPATH_W) 'profiles/audio/avctp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avctp.c'; fi`
 
-time/bluetoothd-server.obj: time/server.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT time/bluetoothd-server.obj -MD -MP -MF time/$(DEPDIR)/bluetoothd-server.Tpo -c -o time/bluetoothd-server.obj `if test -f 'time/server.c'; then $(CYGPATH_W) 'time/server.c'; else $(CYGPATH_W) '$(srcdir)/time/server.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) time/$(DEPDIR)/bluetoothd-server.Tpo time/$(DEPDIR)/bluetoothd-server.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='time/server.c' object='time/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avrcp.o: profiles/audio/avrcp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avrcp.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o profiles/audio/bluetoothd-avrcp.o `test -f 'profiles/audio/avrcp.c' || echo '$(srcdir)/'`profiles/audio/avrcp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avrcp.c' object='profiles/audio/bluetoothd-avrcp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o time/bluetoothd-server.obj `if test -f 'time/server.c'; then $(CYGPATH_W) 'time/server.c'; else $(CYGPATH_W) '$(srcdir)/time/server.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avrcp.o `test -f 'profiles/audio/avrcp.c' || echo '$(srcdir)/'`profiles/audio/avrcp.c
 
-plugins/bluetoothd-gatt-example.o: plugins/gatt-example.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-avrcp.obj: profiles/audio/avrcp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-avrcp.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo -c -o profiles/audio/bluetoothd-avrcp.obj `if test -f 'profiles/audio/avrcp.c'; then $(CYGPATH_W) 'profiles/audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avrcp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Tpo profiles/audio/$(DEPDIR)/bluetoothd-avrcp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/avrcp.c' object='profiles/audio/bluetoothd-avrcp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.o `test -f 'plugins/gatt-example.c' || echo '$(srcdir)/'`plugins/gatt-example.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-avrcp.obj `if test -f 'profiles/audio/avrcp.c'; then $(CYGPATH_W) 'profiles/audio/avrcp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/avrcp.c'; fi`
 
-plugins/bluetoothd-gatt-example.obj: plugins/gatt-example.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-gatt-example.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-gatt-example.Tpo plugins/$(DEPDIR)/bluetoothd-gatt-example.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/gatt-example.c' object='plugins/bluetoothd-gatt-example.obj' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-player.o: profiles/audio/player.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-player.o -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo -c -o profiles/audio/bluetoothd-player.o `test -f 'profiles/audio/player.c' || echo '$(srcdir)/'`profiles/audio/player.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo profiles/audio/$(DEPDIR)/bluetoothd-player.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/player.c' object='profiles/audio/bluetoothd-player.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-gatt-example.obj `if test -f 'plugins/gatt-example.c'; then $(CYGPATH_W) 'plugins/gatt-example.c'; else $(CYGPATH_W) '$(srcdir)/plugins/gatt-example.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-player.o `test -f 'profiles/audio/player.c' || echo '$(srcdir)/'`profiles/audio/player.c
 
-proximity/bluetoothd-main.o: proximity/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-main.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o proximity/bluetoothd-main.o `test -f 'proximity/main.c' || echo '$(srcdir)/'`proximity/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-main.Tpo proximity/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/main.c' object='proximity/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+profiles/audio/bluetoothd-player.obj: profiles/audio/player.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/audio/bluetoothd-player.obj -MD -MP -MF profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo -c -o profiles/audio/bluetoothd-player.obj `if test -f 'profiles/audio/player.c'; then $(CYGPATH_W) 'profiles/audio/player.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/player.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/audio/$(DEPDIR)/bluetoothd-player.Tpo profiles/audio/$(DEPDIR)/bluetoothd-player.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/audio/player.c' object='profiles/audio/bluetoothd-player.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-main.o `test -f 'proximity/main.c' || echo '$(srcdir)/'`proximity/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/audio/bluetoothd-player.obj `if test -f 'profiles/audio/player.c'; then $(CYGPATH_W) 'profiles/audio/player.c'; else $(CYGPATH_W) '$(srcdir)/profiles/audio/player.c'; fi`
 
-proximity/bluetoothd-main.obj: proximity/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-main.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o proximity/bluetoothd-main.obj `if test -f 'proximity/main.c'; then $(CYGPATH_W) 'proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/proximity/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-main.Tpo proximity/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/main.c' object='proximity/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-manager.o: profiles/network/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-manager.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/network/bluetoothd-manager.o `test -f 'profiles/network/manager.c' || echo '$(srcdir)/'`profiles/network/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo profiles/network/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/manager.c' object='profiles/network/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-main.obj `if test -f 'proximity/main.c'; then $(CYGPATH_W) 'proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/proximity/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-manager.o `test -f 'profiles/network/manager.c' || echo '$(srcdir)/'`profiles/network/manager.c
 
-proximity/bluetoothd-manager.o: proximity/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-manager.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o proximity/bluetoothd-manager.o `test -f 'proximity/manager.c' || echo '$(srcdir)/'`proximity/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-manager.Tpo proximity/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/manager.c' object='proximity/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-manager.obj: profiles/network/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-manager.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/network/bluetoothd-manager.obj `if test -f 'profiles/network/manager.c'; then $(CYGPATH_W) 'profiles/network/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-manager.Tpo profiles/network/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/manager.c' object='profiles/network/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-manager.o `test -f 'proximity/manager.c' || echo '$(srcdir)/'`proximity/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-manager.obj `if test -f 'profiles/network/manager.c'; then $(CYGPATH_W) 'profiles/network/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/manager.c'; fi`
 
-proximity/bluetoothd-manager.obj: proximity/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-manager.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o proximity/bluetoothd-manager.obj `if test -f 'proximity/manager.c'; then $(CYGPATH_W) 'proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/proximity/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-manager.Tpo proximity/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/manager.c' object='proximity/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-common.o: profiles/network/common.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-common.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-common.Tpo -c -o profiles/network/bluetoothd-common.o `test -f 'profiles/network/common.c' || echo '$(srcdir)/'`profiles/network/common.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-common.Tpo profiles/network/$(DEPDIR)/bluetoothd-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/common.c' object='profiles/network/bluetoothd-common.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-manager.obj `if test -f 'proximity/manager.c'; then $(CYGPATH_W) 'proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/proximity/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-common.o `test -f 'profiles/network/common.c' || echo '$(srcdir)/'`profiles/network/common.c
 
-proximity/bluetoothd-monitor.o: proximity/monitor.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-monitor.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o proximity/bluetoothd-monitor.o `test -f 'proximity/monitor.c' || echo '$(srcdir)/'`proximity/monitor.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-monitor.Tpo proximity/$(DEPDIR)/bluetoothd-monitor.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/monitor.c' object='proximity/bluetoothd-monitor.o' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-common.obj: profiles/network/common.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-common.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-common.Tpo -c -o profiles/network/bluetoothd-common.obj `if test -f 'profiles/network/common.c'; then $(CYGPATH_W) 'profiles/network/common.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/common.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-common.Tpo profiles/network/$(DEPDIR)/bluetoothd-common.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/common.c' object='profiles/network/bluetoothd-common.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-monitor.o `test -f 'proximity/monitor.c' || echo '$(srcdir)/'`proximity/monitor.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-common.obj `if test -f 'profiles/network/common.c'; then $(CYGPATH_W) 'profiles/network/common.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/common.c'; fi`
 
-proximity/bluetoothd-monitor.obj: proximity/monitor.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-monitor.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o proximity/bluetoothd-monitor.obj `if test -f 'proximity/monitor.c'; then $(CYGPATH_W) 'proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/proximity/monitor.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-monitor.Tpo proximity/$(DEPDIR)/bluetoothd-monitor.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/monitor.c' object='proximity/bluetoothd-monitor.obj' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-server.o: profiles/network/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-server.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/network/bluetoothd-server.o `test -f 'profiles/network/server.c' || echo '$(srcdir)/'`profiles/network/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-server.Tpo profiles/network/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/server.c' object='profiles/network/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-monitor.obj `if test -f 'proximity/monitor.c'; then $(CYGPATH_W) 'proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/proximity/monitor.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-server.o `test -f 'profiles/network/server.c' || echo '$(srcdir)/'`profiles/network/server.c
 
-proximity/bluetoothd-reporter.o: proximity/reporter.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-reporter.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o proximity/bluetoothd-reporter.o `test -f 'proximity/reporter.c' || echo '$(srcdir)/'`proximity/reporter.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-reporter.Tpo proximity/$(DEPDIR)/bluetoothd-reporter.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/reporter.c' object='proximity/bluetoothd-reporter.o' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-server.obj: profiles/network/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-server.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/network/bluetoothd-server.obj `if test -f 'profiles/network/server.c'; then $(CYGPATH_W) 'profiles/network/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-server.Tpo profiles/network/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/server.c' object='profiles/network/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-reporter.o `test -f 'proximity/reporter.c' || echo '$(srcdir)/'`proximity/reporter.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-server.obj `if test -f 'profiles/network/server.c'; then $(CYGPATH_W) 'profiles/network/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/server.c'; fi`
 
-proximity/bluetoothd-reporter.obj: proximity/reporter.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-reporter.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o proximity/bluetoothd-reporter.obj `if test -f 'proximity/reporter.c'; then $(CYGPATH_W) 'proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/proximity/reporter.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-reporter.Tpo proximity/$(DEPDIR)/bluetoothd-reporter.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/reporter.c' object='proximity/bluetoothd-reporter.obj' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-connection.o: profiles/network/connection.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-connection.o -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o profiles/network/bluetoothd-connection.o `test -f 'profiles/network/connection.c' || echo '$(srcdir)/'`profiles/network/connection.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo profiles/network/$(DEPDIR)/bluetoothd-connection.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/connection.c' object='profiles/network/bluetoothd-connection.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-reporter.obj `if test -f 'proximity/reporter.c'; then $(CYGPATH_W) 'proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/proximity/reporter.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-connection.o `test -f 'profiles/network/connection.c' || echo '$(srcdir)/'`profiles/network/connection.c
 
-proximity/bluetoothd-linkloss.o: proximity/linkloss.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-linkloss.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o proximity/bluetoothd-linkloss.o `test -f 'proximity/linkloss.c' || echo '$(srcdir)/'`proximity/linkloss.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo proximity/$(DEPDIR)/bluetoothd-linkloss.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/linkloss.c' object='proximity/bluetoothd-linkloss.o' libtool=no @AMDEPBACKSLASH@
+profiles/network/bluetoothd-connection.obj: profiles/network/connection.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/network/bluetoothd-connection.obj -MD -MP -MF profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo -c -o profiles/network/bluetoothd-connection.obj `if test -f 'profiles/network/connection.c'; then $(CYGPATH_W) 'profiles/network/connection.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/connection.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/network/$(DEPDIR)/bluetoothd-connection.Tpo profiles/network/$(DEPDIR)/bluetoothd-connection.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/network/connection.c' object='profiles/network/bluetoothd-connection.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-linkloss.o `test -f 'proximity/linkloss.c' || echo '$(srcdir)/'`proximity/linkloss.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/network/bluetoothd-connection.obj `if test -f 'profiles/network/connection.c'; then $(CYGPATH_W) 'profiles/network/connection.c'; else $(CYGPATH_W) '$(srcdir)/profiles/network/connection.c'; fi`
 
-proximity/bluetoothd-linkloss.obj: proximity/linkloss.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-linkloss.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o proximity/bluetoothd-linkloss.obj `if test -f 'proximity/linkloss.c'; then $(CYGPATH_W) 'proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/proximity/linkloss.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo proximity/$(DEPDIR)/bluetoothd-linkloss.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/linkloss.c' object='proximity/bluetoothd-linkloss.obj' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-manager.o: profiles/input/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-manager.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/input/bluetoothd-manager.o `test -f 'profiles/input/manager.c' || echo '$(srcdir)/'`profiles/input/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo profiles/input/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/manager.c' object='profiles/input/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-linkloss.obj `if test -f 'proximity/linkloss.c'; then $(CYGPATH_W) 'proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/proximity/linkloss.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-manager.o `test -f 'profiles/input/manager.c' || echo '$(srcdir)/'`profiles/input/manager.c
 
-proximity/bluetoothd-immalert.o: proximity/immalert.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-immalert.o -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o proximity/bluetoothd-immalert.o `test -f 'proximity/immalert.c' || echo '$(srcdir)/'`proximity/immalert.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-immalert.Tpo proximity/$(DEPDIR)/bluetoothd-immalert.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/immalert.c' object='proximity/bluetoothd-immalert.o' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-manager.obj: profiles/input/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-manager.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/input/bluetoothd-manager.obj `if test -f 'profiles/input/manager.c'; then $(CYGPATH_W) 'profiles/input/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-manager.Tpo profiles/input/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/manager.c' object='profiles/input/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-immalert.o `test -f 'proximity/immalert.c' || echo '$(srcdir)/'`proximity/immalert.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-manager.obj `if test -f 'profiles/input/manager.c'; then $(CYGPATH_W) 'profiles/input/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/manager.c'; fi`
 
-proximity/bluetoothd-immalert.obj: proximity/immalert.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT proximity/bluetoothd-immalert.obj -MD -MP -MF proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o proximity/bluetoothd-immalert.obj `if test -f 'proximity/immalert.c'; then $(CYGPATH_W) 'proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/proximity/immalert.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) proximity/$(DEPDIR)/bluetoothd-immalert.Tpo proximity/$(DEPDIR)/bluetoothd-immalert.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='proximity/immalert.c' object='proximity/bluetoothd-immalert.obj' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-server.o: profiles/input/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-server.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/input/bluetoothd-server.o `test -f 'profiles/input/server.c' || echo '$(srcdir)/'`profiles/input/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-server.Tpo profiles/input/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/server.c' object='profiles/input/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o proximity/bluetoothd-immalert.obj `if test -f 'proximity/immalert.c'; then $(CYGPATH_W) 'proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/proximity/immalert.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-server.o `test -f 'profiles/input/server.c' || echo '$(srcdir)/'`profiles/input/server.c
 
-deviceinfo/bluetoothd-main.o: deviceinfo/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-main.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo -c -o deviceinfo/bluetoothd-main.o `test -f 'deviceinfo/main.c' || echo '$(srcdir)/'`deviceinfo/main.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo deviceinfo/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/main.c' object='deviceinfo/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-server.obj: profiles/input/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-server.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/input/bluetoothd-server.obj `if test -f 'profiles/input/server.c'; then $(CYGPATH_W) 'profiles/input/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-server.Tpo profiles/input/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/server.c' object='profiles/input/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-main.o `test -f 'deviceinfo/main.c' || echo '$(srcdir)/'`deviceinfo/main.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-server.obj `if test -f 'profiles/input/server.c'; then $(CYGPATH_W) 'profiles/input/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/server.c'; fi`
 
-deviceinfo/bluetoothd-main.obj: deviceinfo/main.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-main.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo -c -o deviceinfo/bluetoothd-main.obj `if test -f 'deviceinfo/main.c'; then $(CYGPATH_W) 'deviceinfo/main.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/main.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-main.Tpo deviceinfo/$(DEPDIR)/bluetoothd-main.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/main.c' object='deviceinfo/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-device.o: profiles/input/device.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-device.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-device.Tpo -c -o profiles/input/bluetoothd-device.o `test -f 'profiles/input/device.c' || echo '$(srcdir)/'`profiles/input/device.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-device.Tpo profiles/input/$(DEPDIR)/bluetoothd-device.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/device.c' object='profiles/input/bluetoothd-device.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-main.obj `if test -f 'deviceinfo/main.c'; then $(CYGPATH_W) 'deviceinfo/main.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/main.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-device.o `test -f 'profiles/input/device.c' || echo '$(srcdir)/'`profiles/input/device.c
 
-deviceinfo/bluetoothd-manager.o: deviceinfo/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-manager.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo -c -o deviceinfo/bluetoothd-manager.o `test -f 'deviceinfo/manager.c' || echo '$(srcdir)/'`deviceinfo/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo deviceinfo/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/manager.c' object='deviceinfo/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-device.obj: profiles/input/device.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-device.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-device.Tpo -c -o profiles/input/bluetoothd-device.obj `if test -f 'profiles/input/device.c'; then $(CYGPATH_W) 'profiles/input/device.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/device.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-device.Tpo profiles/input/$(DEPDIR)/bluetoothd-device.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/device.c' object='profiles/input/bluetoothd-device.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-manager.o `test -f 'deviceinfo/manager.c' || echo '$(srcdir)/'`deviceinfo/manager.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-device.obj `if test -f 'profiles/input/device.c'; then $(CYGPATH_W) 'profiles/input/device.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/device.c'; fi`
 
-deviceinfo/bluetoothd-manager.obj: deviceinfo/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-manager.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo -c -o deviceinfo/bluetoothd-manager.obj `if test -f 'deviceinfo/manager.c'; then $(CYGPATH_W) 'deviceinfo/manager.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-manager.Tpo deviceinfo/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/manager.c' object='deviceinfo/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-hog.o: profiles/input/hog.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo -c -o profiles/input/bluetoothd-hog.o `test -f 'profiles/input/hog.c' || echo '$(srcdir)/'`profiles/input/hog.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/hog.c' object='profiles/input/bluetoothd-hog.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-manager.obj `if test -f 'deviceinfo/manager.c'; then $(CYGPATH_W) 'deviceinfo/manager.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/manager.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog.o `test -f 'profiles/input/hog.c' || echo '$(srcdir)/'`profiles/input/hog.c
 
-deviceinfo/bluetoothd-deviceinfo.o: deviceinfo/deviceinfo.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-deviceinfo.o -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o deviceinfo/bluetoothd-deviceinfo.o `test -f 'deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`deviceinfo/deviceinfo.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/deviceinfo.c' object='deviceinfo/bluetoothd-deviceinfo.o' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-hog.obj: profiles/input/hog.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-hog.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo -c -o profiles/input/bluetoothd-hog.obj `if test -f 'profiles/input/hog.c'; then $(CYGPATH_W) 'profiles/input/hog.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-hog.Tpo profiles/input/$(DEPDIR)/bluetoothd-hog.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/hog.c' object='profiles/input/bluetoothd-hog.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-deviceinfo.o `test -f 'deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`deviceinfo/deviceinfo.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-hog.obj `if test -f 'profiles/input/hog.c'; then $(CYGPATH_W) 'profiles/input/hog.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/hog.c'; fi`
 
-deviceinfo/bluetoothd-deviceinfo.obj: deviceinfo/deviceinfo.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT deviceinfo/bluetoothd-deviceinfo.obj -MD -MP -MF deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/deviceinfo.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='deviceinfo/deviceinfo.c' object='deviceinfo/bluetoothd-deviceinfo.obj' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-suspend-dummy.o: profiles/input/suspend-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-suspend-dummy.o -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Tpo -c -o profiles/input/bluetoothd-suspend-dummy.o `test -f 'profiles/input/suspend-dummy.c' || echo '$(srcdir)/'`profiles/input/suspend-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Tpo profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/suspend-dummy.c' object='profiles/input/bluetoothd-suspend-dummy.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/deviceinfo/deviceinfo.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-suspend-dummy.o `test -f 'profiles/input/suspend-dummy.c' || echo '$(srcdir)/'`profiles/input/suspend-dummy.c
 
-plugins/bluetoothd-hciops.o: plugins/hciops.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hciops.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hciops.Tpo -c -o plugins/bluetoothd-hciops.o `test -f 'plugins/hciops.c' || echo '$(srcdir)/'`plugins/hciops.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hciops.Tpo plugins/$(DEPDIR)/bluetoothd-hciops.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hciops.c' object='plugins/bluetoothd-hciops.o' libtool=no @AMDEPBACKSLASH@
+profiles/input/bluetoothd-suspend-dummy.obj: profiles/input/suspend-dummy.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/input/bluetoothd-suspend-dummy.obj -MD -MP -MF profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Tpo -c -o profiles/input/bluetoothd-suspend-dummy.obj `if test -f 'profiles/input/suspend-dummy.c'; then $(CYGPATH_W) 'profiles/input/suspend-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/suspend-dummy.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Tpo profiles/input/$(DEPDIR)/bluetoothd-suspend-dummy.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/input/suspend-dummy.c' object='profiles/input/bluetoothd-suspend-dummy.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hciops.o `test -f 'plugins/hciops.c' || echo '$(srcdir)/'`plugins/hciops.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/input/bluetoothd-suspend-dummy.obj `if test -f 'profiles/input/suspend-dummy.c'; then $(CYGPATH_W) 'profiles/input/suspend-dummy.c'; else $(CYGPATH_W) '$(srcdir)/profiles/input/suspend-dummy.c'; fi`
 
-plugins/bluetoothd-hciops.obj: plugins/hciops.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hciops.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hciops.Tpo -c -o plugins/bluetoothd-hciops.obj `if test -f 'plugins/hciops.c'; then $(CYGPATH_W) 'plugins/hciops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hciops.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hciops.Tpo plugins/$(DEPDIR)/bluetoothd-hciops.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hciops.c' object='plugins/bluetoothd-hciops.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-mcap.o: profiles/health/mcap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o profiles/health/bluetoothd-mcap.o `test -f 'profiles/health/mcap.c' || echo '$(srcdir)/'`profiles/health/mcap.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/mcap.c' object='profiles/health/bluetoothd-mcap.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hciops.obj `if test -f 'plugins/hciops.c'; then $(CYGPATH_W) 'plugins/hciops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hciops.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap.o `test -f 'profiles/health/mcap.c' || echo '$(srcdir)/'`profiles/health/mcap.c
 
-plugins/bluetoothd-mgmtops.o: plugins/mgmtops.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-mgmtops.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo -c -o plugins/bluetoothd-mgmtops.o `test -f 'plugins/mgmtops.c' || echo '$(srcdir)/'`plugins/mgmtops.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo plugins/$(DEPDIR)/bluetoothd-mgmtops.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/mgmtops.c' object='plugins/bluetoothd-mgmtops.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-mcap.obj: profiles/health/mcap.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o profiles/health/bluetoothd-mcap.obj `if test -f 'profiles/health/mcap.c'; then $(CYGPATH_W) 'profiles/health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/mcap.c' object='profiles/health/bluetoothd-mcap.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-mgmtops.o `test -f 'plugins/mgmtops.c' || echo '$(srcdir)/'`plugins/mgmtops.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap.obj `if test -f 'profiles/health/mcap.c'; then $(CYGPATH_W) 'profiles/health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap.c'; fi`
 
-plugins/bluetoothd-mgmtops.obj: plugins/mgmtops.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-mgmtops.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo -c -o plugins/bluetoothd-mgmtops.obj `if test -f 'plugins/mgmtops.c'; then $(CYGPATH_W) 'plugins/mgmtops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/mgmtops.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-mgmtops.Tpo plugins/$(DEPDIR)/bluetoothd-mgmtops.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/mgmtops.c' object='plugins/bluetoothd-mgmtops.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-mcap_sync.o: profiles/health/mcap_sync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap_sync.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o profiles/health/bluetoothd-mcap_sync.o `test -f 'profiles/health/mcap_sync.c' || echo '$(srcdir)/'`profiles/health/mcap_sync.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/mcap_sync.c' object='profiles/health/bluetoothd-mcap_sync.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-mgmtops.obj `if test -f 'plugins/mgmtops.c'; then $(CYGPATH_W) 'plugins/mgmtops.c'; else $(CYGPATH_W) '$(srcdir)/plugins/mgmtops.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap_sync.o `test -f 'profiles/health/mcap_sync.c' || echo '$(srcdir)/'`profiles/health/mcap_sync.c
 
-plugins/bluetoothd-hal.o: plugins/hal.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hal.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hal.Tpo -c -o plugins/bluetoothd-hal.o `test -f 'plugins/hal.c' || echo '$(srcdir)/'`plugins/hal.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hal.Tpo plugins/$(DEPDIR)/bluetoothd-hal.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hal.c' object='plugins/bluetoothd-hal.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-mcap_sync.obj: profiles/health/mcap_sync.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-mcap_sync.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o profiles/health/bluetoothd-mcap_sync.obj `if test -f 'profiles/health/mcap_sync.c'; then $(CYGPATH_W) 'profiles/health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap_sync.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo profiles/health/$(DEPDIR)/bluetoothd-mcap_sync.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/mcap_sync.c' object='profiles/health/bluetoothd-mcap_sync.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hal.o `test -f 'plugins/hal.c' || echo '$(srcdir)/'`plugins/hal.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-mcap_sync.obj `if test -f 'profiles/health/mcap_sync.c'; then $(CYGPATH_W) 'profiles/health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/mcap_sync.c'; fi`
 
-plugins/bluetoothd-hal.obj: plugins/hal.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-hal.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-hal.Tpo -c -o plugins/bluetoothd-hal.obj `if test -f 'plugins/hal.c'; then $(CYGPATH_W) 'plugins/hal.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hal.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-hal.Tpo plugins/$(DEPDIR)/bluetoothd-hal.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/hal.c' object='plugins/bluetoothd-hal.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_main.o: profiles/health/hdp_main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_main.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o profiles/health/bluetoothd-hdp_main.o `test -f 'profiles/health/hdp_main.c' || echo '$(srcdir)/'`profiles/health/hdp_main.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_main.c' object='profiles/health/bluetoothd-hdp_main.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-hal.obj `if test -f 'plugins/hal.c'; then $(CYGPATH_W) 'plugins/hal.c'; else $(CYGPATH_W) '$(srcdir)/plugins/hal.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_main.o `test -f 'profiles/health/hdp_main.c' || echo '$(srcdir)/'`profiles/health/hdp_main.c
 
-plugins/bluetoothd-formfactor.o: plugins/formfactor.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-formfactor.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo -c -o plugins/bluetoothd-formfactor.o `test -f 'plugins/formfactor.c' || echo '$(srcdir)/'`plugins/formfactor.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo plugins/$(DEPDIR)/bluetoothd-formfactor.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/formfactor.c' object='plugins/bluetoothd-formfactor.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_main.obj: profiles/health/hdp_main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_main.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo -c -o profiles/health/bluetoothd-hdp_main.obj `if test -f 'profiles/health/hdp_main.c'; then $(CYGPATH_W) 'profiles/health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_main.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_main.c' object='profiles/health/bluetoothd-hdp_main.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-formfactor.o `test -f 'plugins/formfactor.c' || echo '$(srcdir)/'`plugins/formfactor.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_main.obj `if test -f 'profiles/health/hdp_main.c'; then $(CYGPATH_W) 'profiles/health/hdp_main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_main.c'; fi`
 
-plugins/bluetoothd-formfactor.obj: plugins/formfactor.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-formfactor.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo -c -o plugins/bluetoothd-formfactor.obj `if test -f 'plugins/formfactor.c'; then $(CYGPATH_W) 'plugins/formfactor.c'; else $(CYGPATH_W) '$(srcdir)/plugins/formfactor.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-formfactor.Tpo plugins/$(DEPDIR)/bluetoothd-formfactor.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/formfactor.c' object='plugins/bluetoothd-formfactor.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_manager.o: profiles/health/hdp_manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_manager.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o profiles/health/bluetoothd-hdp_manager.o `test -f 'profiles/health/hdp_manager.c' || echo '$(srcdir)/'`profiles/health/hdp_manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_manager.c' object='profiles/health/bluetoothd-hdp_manager.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-formfactor.obj `if test -f 'plugins/formfactor.c'; then $(CYGPATH_W) 'plugins/formfactor.c'; else $(CYGPATH_W) '$(srcdir)/plugins/formfactor.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_manager.o `test -f 'profiles/health/hdp_manager.c' || echo '$(srcdir)/'`profiles/health/hdp_manager.c
 
-plugins/bluetoothd-storage.o: plugins/storage.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-storage.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-storage.Tpo -c -o plugins/bluetoothd-storage.o `test -f 'plugins/storage.c' || echo '$(srcdir)/'`plugins/storage.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-storage.Tpo plugins/$(DEPDIR)/bluetoothd-storage.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/storage.c' object='plugins/bluetoothd-storage.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_manager.obj: profiles/health/hdp_manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_manager.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo -c -o profiles/health/bluetoothd-hdp_manager.obj `if test -f 'profiles/health/hdp_manager.c'; then $(CYGPATH_W) 'profiles/health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_manager.c' object='profiles/health/bluetoothd-hdp_manager.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-storage.o `test -f 'plugins/storage.c' || echo '$(srcdir)/'`plugins/storage.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_manager.obj `if test -f 'profiles/health/hdp_manager.c'; then $(CYGPATH_W) 'profiles/health/hdp_manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_manager.c'; fi`
 
-plugins/bluetoothd-storage.obj: plugins/storage.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-storage.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-storage.Tpo -c -o plugins/bluetoothd-storage.obj `if test -f 'plugins/storage.c'; then $(CYGPATH_W) 'plugins/storage.c'; else $(CYGPATH_W) '$(srcdir)/plugins/storage.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-storage.Tpo plugins/$(DEPDIR)/bluetoothd-storage.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/storage.c' object='plugins/bluetoothd-storage.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp.o: profiles/health/hdp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o profiles/health/bluetoothd-hdp.o `test -f 'profiles/health/hdp.c' || echo '$(srcdir)/'`profiles/health/hdp.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp.c' object='profiles/health/bluetoothd-hdp.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-storage.obj `if test -f 'plugins/storage.c'; then $(CYGPATH_W) 'plugins/storage.c'; else $(CYGPATH_W) '$(srcdir)/plugins/storage.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp.o `test -f 'profiles/health/hdp.c' || echo '$(srcdir)/'`profiles/health/hdp.c
 
-plugins/bluetoothd-adaptername.o: plugins/adaptername.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-adaptername.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo -c -o plugins/bluetoothd-adaptername.o `test -f 'plugins/adaptername.c' || echo '$(srcdir)/'`plugins/adaptername.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo plugins/$(DEPDIR)/bluetoothd-adaptername.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/adaptername.c' object='plugins/bluetoothd-adaptername.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp.obj: profiles/health/hdp.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo -c -o profiles/health/bluetoothd-hdp.obj `if test -f 'profiles/health/hdp.c'; then $(CYGPATH_W) 'profiles/health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp.c' object='profiles/health/bluetoothd-hdp.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-adaptername.o `test -f 'plugins/adaptername.c' || echo '$(srcdir)/'`plugins/adaptername.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp.obj `if test -f 'profiles/health/hdp.c'; then $(CYGPATH_W) 'profiles/health/hdp.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp.c'; fi`
 
-plugins/bluetoothd-adaptername.obj: plugins/adaptername.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-adaptername.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo -c -o plugins/bluetoothd-adaptername.obj `if test -f 'plugins/adaptername.c'; then $(CYGPATH_W) 'plugins/adaptername.c'; else $(CYGPATH_W) '$(srcdir)/plugins/adaptername.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-adaptername.Tpo plugins/$(DEPDIR)/bluetoothd-adaptername.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/adaptername.c' object='plugins/bluetoothd-adaptername.obj' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_util.o: profiles/health/hdp_util.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_util.o -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o profiles/health/bluetoothd-hdp_util.o `test -f 'profiles/health/hdp_util.c' || echo '$(srcdir)/'`profiles/health/hdp_util.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_util.c' object='profiles/health/bluetoothd-hdp_util.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-adaptername.obj `if test -f 'plugins/adaptername.c'; then $(CYGPATH_W) 'plugins/adaptername.c'; else $(CYGPATH_W) '$(srcdir)/plugins/adaptername.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_util.o `test -f 'profiles/health/hdp_util.c' || echo '$(srcdir)/'`profiles/health/hdp_util.c
 
-plugins/bluetoothd-wiimote.o: plugins/wiimote.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.o' libtool=no @AMDEPBACKSLASH@
+profiles/health/bluetoothd-hdp_util.obj: profiles/health/hdp_util.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/health/bluetoothd-hdp_util.obj -MD -MP -MF profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo -c -o profiles/health/bluetoothd-hdp_util.obj `if test -f 'profiles/health/hdp_util.c'; then $(CYGPATH_W) 'profiles/health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_util.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Tpo profiles/health/$(DEPDIR)/bluetoothd-hdp_util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/health/hdp_util.c' object='profiles/health/bluetoothd-hdp_util.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.o `test -f 'plugins/wiimote.c' || echo '$(srcdir)/'`plugins/wiimote.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/health/bluetoothd-hdp_util.obj `if test -f 'profiles/health/hdp_util.c'; then $(CYGPATH_W) 'profiles/health/hdp_util.c'; else $(CYGPATH_W) '$(srcdir)/profiles/health/hdp_util.c'; fi`
 
-plugins/bluetoothd-wiimote.obj: plugins/wiimote.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-wiimote.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-wiimote.Tpo plugins/$(DEPDIR)/bluetoothd-wiimote.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/wiimote.c' object='plugins/bluetoothd-wiimote.obj' libtool=no @AMDEPBACKSLASH@
+profiles/gatt/bluetoothd-gas.o: profiles/gatt/gas.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/gatt/bluetoothd-gas.o -MD -MP -MF profiles/gatt/$(DEPDIR)/bluetoothd-gas.Tpo -c -o profiles/gatt/bluetoothd-gas.o `test -f 'profiles/gatt/gas.c' || echo '$(srcdir)/'`profiles/gatt/gas.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/gatt/$(DEPDIR)/bluetoothd-gas.Tpo profiles/gatt/$(DEPDIR)/bluetoothd-gas.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/gatt/gas.c' object='profiles/gatt/bluetoothd-gas.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-wiimote.obj `if test -f 'plugins/wiimote.c'; then $(CYGPATH_W) 'plugins/wiimote.c'; else $(CYGPATH_W) '$(srcdir)/plugins/wiimote.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/gatt/bluetoothd-gas.o `test -f 'profiles/gatt/gas.c' || echo '$(srcdir)/'`profiles/gatt/gas.c
+
+profiles/gatt/bluetoothd-gas.obj: profiles/gatt/gas.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/gatt/bluetoothd-gas.obj -MD -MP -MF profiles/gatt/$(DEPDIR)/bluetoothd-gas.Tpo -c -o profiles/gatt/bluetoothd-gas.obj `if test -f 'profiles/gatt/gas.c'; then $(CYGPATH_W) 'profiles/gatt/gas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/gatt/gas.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/gatt/$(DEPDIR)/bluetoothd-gas.Tpo profiles/gatt/$(DEPDIR)/bluetoothd-gas.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/gatt/gas.c' object='profiles/gatt/bluetoothd-gas.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/gatt/bluetoothd-gas.obj `if test -f 'profiles/gatt/gas.c'; then $(CYGPATH_W) 'profiles/gatt/gas.c'; else $(CYGPATH_W) '$(srcdir)/profiles/gatt/gas.c'; fi`
+
+profiles/scanparam/bluetoothd-scan.o: profiles/scanparam/scan.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scan.o -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo -c -o profiles/scanparam/bluetoothd-scan.o `test -f 'profiles/scanparam/scan.c' || echo '$(srcdir)/'`profiles/scanparam/scan.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/scanparam/scan.c' object='profiles/scanparam/bluetoothd-scan.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scan.o `test -f 'profiles/scanparam/scan.c' || echo '$(srcdir)/'`profiles/scanparam/scan.c
+
+profiles/scanparam/bluetoothd-scan.obj: profiles/scanparam/scan.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/scanparam/bluetoothd-scan.obj -MD -MP -MF profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo -c -o profiles/scanparam/bluetoothd-scan.obj `if test -f 'profiles/scanparam/scan.c'; then $(CYGPATH_W) 'profiles/scanparam/scan.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scan.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Tpo profiles/scanparam/$(DEPDIR)/bluetoothd-scan.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/scanparam/scan.c' object='profiles/scanparam/bluetoothd-scan.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/scanparam/bluetoothd-scan.obj `if test -f 'profiles/scanparam/scan.c'; then $(CYGPATH_W) 'profiles/scanparam/scan.c'; else $(CYGPATH_W) '$(srcdir)/profiles/scanparam/scan.c'; fi`
+
+profiles/deviceinfo/bluetoothd-deviceinfo.o: profiles/deviceinfo/deviceinfo.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-deviceinfo.o -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o profiles/deviceinfo/bluetoothd-deviceinfo.o `test -f 'profiles/deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`profiles/deviceinfo/deviceinfo.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/deviceinfo/deviceinfo.c' object='profiles/deviceinfo/bluetoothd-deviceinfo.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-deviceinfo.o `test -f 'profiles/deviceinfo/deviceinfo.c' || echo '$(srcdir)/'`profiles/deviceinfo/deviceinfo.c
+
+profiles/deviceinfo/bluetoothd-deviceinfo.obj: profiles/deviceinfo/deviceinfo.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/deviceinfo/bluetoothd-deviceinfo.obj -MD -MP -MF profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo -c -o profiles/deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'profiles/deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'profiles/deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/deviceinfo.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Tpo profiles/deviceinfo/$(DEPDIR)/bluetoothd-deviceinfo.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/deviceinfo/deviceinfo.c' object='profiles/deviceinfo/bluetoothd-deviceinfo.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/deviceinfo/bluetoothd-deviceinfo.obj `if test -f 'profiles/deviceinfo/deviceinfo.c'; then $(CYGPATH_W) 'profiles/deviceinfo/deviceinfo.c'; else $(CYGPATH_W) '$(srcdir)/profiles/deviceinfo/deviceinfo.c'; fi`
+
+profiles/alert/bluetoothd-server.o: profiles/alert/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/alert/bluetoothd-server.o -MD -MP -MF profiles/alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/alert/bluetoothd-server.o `test -f 'profiles/alert/server.c' || echo '$(srcdir)/'`profiles/alert/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/alert/$(DEPDIR)/bluetoothd-server.Tpo profiles/alert/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/alert/server.c' object='profiles/alert/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/alert/bluetoothd-server.o `test -f 'profiles/alert/server.c' || echo '$(srcdir)/'`profiles/alert/server.c
 
-plugins/bluetoothd-maemo6.o: plugins/maemo6.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-maemo6.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo -c -o plugins/bluetoothd-maemo6.o `test -f 'plugins/maemo6.c' || echo '$(srcdir)/'`plugins/maemo6.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo plugins/$(DEPDIR)/bluetoothd-maemo6.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/maemo6.c' object='plugins/bluetoothd-maemo6.o' libtool=no @AMDEPBACKSLASH@
+profiles/alert/bluetoothd-server.obj: profiles/alert/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/alert/bluetoothd-server.obj -MD -MP -MF profiles/alert/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/alert/bluetoothd-server.obj `if test -f 'profiles/alert/server.c'; then $(CYGPATH_W) 'profiles/alert/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/alert/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/alert/$(DEPDIR)/bluetoothd-server.Tpo profiles/alert/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/alert/server.c' object='profiles/alert/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-maemo6.o `test -f 'plugins/maemo6.c' || echo '$(srcdir)/'`plugins/maemo6.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/alert/bluetoothd-server.obj `if test -f 'profiles/alert/server.c'; then $(CYGPATH_W) 'profiles/alert/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/alert/server.c'; fi`
 
-plugins/bluetoothd-maemo6.obj: plugins/maemo6.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-maemo6.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo -c -o plugins/bluetoothd-maemo6.obj `if test -f 'plugins/maemo6.c'; then $(CYGPATH_W) 'plugins/maemo6.c'; else $(CYGPATH_W) '$(srcdir)/plugins/maemo6.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-maemo6.Tpo plugins/$(DEPDIR)/bluetoothd-maemo6.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/maemo6.c' object='plugins/bluetoothd-maemo6.obj' libtool=no @AMDEPBACKSLASH@
+profiles/time/bluetoothd-server.o: profiles/time/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/time/bluetoothd-server.o -MD -MP -MF profiles/time/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/time/bluetoothd-server.o `test -f 'profiles/time/server.c' || echo '$(srcdir)/'`profiles/time/server.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/time/$(DEPDIR)/bluetoothd-server.Tpo profiles/time/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/time/server.c' object='profiles/time/bluetoothd-server.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-maemo6.obj `if test -f 'plugins/maemo6.c'; then $(CYGPATH_W) 'plugins/maemo6.c'; else $(CYGPATH_W) '$(srcdir)/plugins/maemo6.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/time/bluetoothd-server.o `test -f 'profiles/time/server.c' || echo '$(srcdir)/'`profiles/time/server.c
 
-plugins/bluetoothd-dbusoob.o: plugins/dbusoob.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-dbusoob.o -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo -c -o plugins/bluetoothd-dbusoob.o `test -f 'plugins/dbusoob.c' || echo '$(srcdir)/'`plugins/dbusoob.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo plugins/$(DEPDIR)/bluetoothd-dbusoob.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/dbusoob.c' object='plugins/bluetoothd-dbusoob.o' libtool=no @AMDEPBACKSLASH@
+profiles/time/bluetoothd-server.obj: profiles/time/server.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/time/bluetoothd-server.obj -MD -MP -MF profiles/time/$(DEPDIR)/bluetoothd-server.Tpo -c -o profiles/time/bluetoothd-server.obj `if test -f 'profiles/time/server.c'; then $(CYGPATH_W) 'profiles/time/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/time/server.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/time/$(DEPDIR)/bluetoothd-server.Tpo profiles/time/$(DEPDIR)/bluetoothd-server.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/time/server.c' object='profiles/time/bluetoothd-server.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-dbusoob.o `test -f 'plugins/dbusoob.c' || echo '$(srcdir)/'`plugins/dbusoob.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/time/bluetoothd-server.obj `if test -f 'profiles/time/server.c'; then $(CYGPATH_W) 'profiles/time/server.c'; else $(CYGPATH_W) '$(srcdir)/profiles/time/server.c'; fi`
 
-plugins/bluetoothd-dbusoob.obj: plugins/dbusoob.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT plugins/bluetoothd-dbusoob.obj -MD -MP -MF plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo -c -o plugins/bluetoothd-dbusoob.obj `if test -f 'plugins/dbusoob.c'; then $(CYGPATH_W) 'plugins/dbusoob.c'; else $(CYGPATH_W) '$(srcdir)/plugins/dbusoob.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) plugins/$(DEPDIR)/bluetoothd-dbusoob.Tpo plugins/$(DEPDIR)/bluetoothd-dbusoob.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='plugins/dbusoob.c' object='plugins/bluetoothd-dbusoob.obj' libtool=no @AMDEPBACKSLASH@
+profiles/proximity/bluetoothd-main.o: profiles/proximity/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-main.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/proximity/bluetoothd-main.o `test -f 'profiles/proximity/main.c' || echo '$(srcdir)/'`profiles/proximity/main.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-main.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/main.c' object='profiles/proximity/bluetoothd-main.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o plugins/bluetoothd-dbusoob.obj `if test -f 'plugins/dbusoob.c'; then $(CYGPATH_W) 'plugins/dbusoob.c'; else $(CYGPATH_W) '$(srcdir)/plugins/dbusoob.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-main.o `test -f 'profiles/proximity/main.c' || echo '$(srcdir)/'`profiles/proximity/main.c
+
+profiles/proximity/bluetoothd-main.obj: profiles/proximity/main.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-main.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-main.Tpo -c -o profiles/proximity/bluetoothd-main.obj `if test -f 'profiles/proximity/main.c'; then $(CYGPATH_W) 'profiles/proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/main.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-main.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-main.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/main.c' object='profiles/proximity/bluetoothd-main.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-main.obj `if test -f 'profiles/proximity/main.c'; then $(CYGPATH_W) 'profiles/proximity/main.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/main.c'; fi`
+
+profiles/proximity/bluetoothd-manager.o: profiles/proximity/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-manager.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/proximity/bluetoothd-manager.o `test -f 'profiles/proximity/manager.c' || echo '$(srcdir)/'`profiles/proximity/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-manager.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/manager.c' object='profiles/proximity/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-manager.o `test -f 'profiles/proximity/manager.c' || echo '$(srcdir)/'`profiles/proximity/manager.c
+
+profiles/proximity/bluetoothd-manager.obj: profiles/proximity/manager.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-manager.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-manager.Tpo -c -o profiles/proximity/bluetoothd-manager.obj `if test -f 'profiles/proximity/manager.c'; then $(CYGPATH_W) 'profiles/proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/manager.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-manager.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-manager.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/manager.c' object='profiles/proximity/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-manager.obj `if test -f 'profiles/proximity/manager.c'; then $(CYGPATH_W) 'profiles/proximity/manager.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/manager.c'; fi`
+
+profiles/proximity/bluetoothd-monitor.o: profiles/proximity/monitor.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-monitor.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o profiles/proximity/bluetoothd-monitor.o `test -f 'profiles/proximity/monitor.c' || echo '$(srcdir)/'`profiles/proximity/monitor.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/monitor.c' object='profiles/proximity/bluetoothd-monitor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-monitor.o `test -f 'profiles/proximity/monitor.c' || echo '$(srcdir)/'`profiles/proximity/monitor.c
+
+profiles/proximity/bluetoothd-monitor.obj: profiles/proximity/monitor.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-monitor.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Tpo -c -o profiles/proximity/bluetoothd-monitor.obj `if test -f 'profiles/proximity/monitor.c'; then $(CYGPATH_W) 'profiles/proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/monitor.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-monitor.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/monitor.c' object='profiles/proximity/bluetoothd-monitor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-monitor.obj `if test -f 'profiles/proximity/monitor.c'; then $(CYGPATH_W) 'profiles/proximity/monitor.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/monitor.c'; fi`
+
+profiles/proximity/bluetoothd-reporter.o: profiles/proximity/reporter.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-reporter.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o profiles/proximity/bluetoothd-reporter.o `test -f 'profiles/proximity/reporter.c' || echo '$(srcdir)/'`profiles/proximity/reporter.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/reporter.c' object='profiles/proximity/bluetoothd-reporter.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-reporter.o `test -f 'profiles/proximity/reporter.c' || echo '$(srcdir)/'`profiles/proximity/reporter.c
+
+profiles/proximity/bluetoothd-reporter.obj: profiles/proximity/reporter.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-reporter.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Tpo -c -o profiles/proximity/bluetoothd-reporter.obj `if test -f 'profiles/proximity/reporter.c'; then $(CYGPATH_W) 'profiles/proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/reporter.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-reporter.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/reporter.c' object='profiles/proximity/bluetoothd-reporter.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-reporter.obj `if test -f 'profiles/proximity/reporter.c'; then $(CYGPATH_W) 'profiles/proximity/reporter.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/reporter.c'; fi`
+
+profiles/proximity/bluetoothd-linkloss.o: profiles/proximity/linkloss.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-linkloss.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o profiles/proximity/bluetoothd-linkloss.o `test -f 'profiles/proximity/linkloss.c' || echo '$(srcdir)/'`profiles/proximity/linkloss.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/linkloss.c' object='profiles/proximity/bluetoothd-linkloss.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-linkloss.o `test -f 'profiles/proximity/linkloss.c' || echo '$(srcdir)/'`profiles/proximity/linkloss.c
+
+profiles/proximity/bluetoothd-linkloss.obj: profiles/proximity/linkloss.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-linkloss.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo -c -o profiles/proximity/bluetoothd-linkloss.obj `if test -f 'profiles/proximity/linkloss.c'; then $(CYGPATH_W) 'profiles/proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/linkloss.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-linkloss.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/linkloss.c' object='profiles/proximity/bluetoothd-linkloss.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-linkloss.obj `if test -f 'profiles/proximity/linkloss.c'; then $(CYGPATH_W) 'profiles/proximity/linkloss.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/linkloss.c'; fi`
+
+profiles/proximity/bluetoothd-immalert.o: profiles/proximity/immalert.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-immalert.o -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o profiles/proximity/bluetoothd-immalert.o `test -f 'profiles/proximity/immalert.c' || echo '$(srcdir)/'`profiles/proximity/immalert.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/immalert.c' object='profiles/proximity/bluetoothd-immalert.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-immalert.o `test -f 'profiles/proximity/immalert.c' || echo '$(srcdir)/'`profiles/proximity/immalert.c
+
+profiles/proximity/bluetoothd-immalert.obj: profiles/proximity/immalert.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/proximity/bluetoothd-immalert.obj -MD -MP -MF profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Tpo -c -o profiles/proximity/bluetoothd-immalert.obj `if test -f 'profiles/proximity/immalert.c'; then $(CYGPATH_W) 'profiles/proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/immalert.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Tpo profiles/proximity/$(DEPDIR)/bluetoothd-immalert.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/proximity/immalert.c' object='profiles/proximity/bluetoothd-immalert.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/proximity/bluetoothd-immalert.obj `if test -f 'profiles/proximity/immalert.c'; then $(CYGPATH_W) 'profiles/proximity/immalert.c'; else $(CYGPATH_W) '$(srcdir)/profiles/proximity/immalert.c'; fi`
+
+profiles/thermometer/bluetoothd-thermometer.o: profiles/thermometer/thermometer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/thermometer/bluetoothd-thermometer.o -MD -MP -MF profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o profiles/thermometer/bluetoothd-thermometer.o `test -f 'profiles/thermometer/thermometer.c' || echo '$(srcdir)/'`profiles/thermometer/thermometer.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/thermometer/thermometer.c' object='profiles/thermometer/bluetoothd-thermometer.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/thermometer/bluetoothd-thermometer.o `test -f 'profiles/thermometer/thermometer.c' || echo '$(srcdir)/'`profiles/thermometer/thermometer.c
+
+profiles/thermometer/bluetoothd-thermometer.obj: profiles/thermometer/thermometer.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/thermometer/bluetoothd-thermometer.obj -MD -MP -MF profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo -c -o profiles/thermometer/bluetoothd-thermometer.obj `if test -f 'profiles/thermometer/thermometer.c'; then $(CYGPATH_W) 'profiles/thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/profiles/thermometer/thermometer.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Tpo profiles/thermometer/$(DEPDIR)/bluetoothd-thermometer.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/thermometer/thermometer.c' object='profiles/thermometer/bluetoothd-thermometer.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/thermometer/bluetoothd-thermometer.obj `if test -f 'profiles/thermometer/thermometer.c'; then $(CYGPATH_W) 'profiles/thermometer/thermometer.c'; else $(CYGPATH_W) '$(srcdir)/profiles/thermometer/thermometer.c'; fi`
+
+profiles/heartrate/bluetoothd-heartrate.o: profiles/heartrate/heartrate.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/heartrate/bluetoothd-heartrate.o -MD -MP -MF profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Tpo -c -o profiles/heartrate/bluetoothd-heartrate.o `test -f 'profiles/heartrate/heartrate.c' || echo '$(srcdir)/'`profiles/heartrate/heartrate.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Tpo profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/heartrate/heartrate.c' object='profiles/heartrate/bluetoothd-heartrate.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/heartrate/bluetoothd-heartrate.o `test -f 'profiles/heartrate/heartrate.c' || echo '$(srcdir)/'`profiles/heartrate/heartrate.c
+
+profiles/heartrate/bluetoothd-heartrate.obj: profiles/heartrate/heartrate.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/heartrate/bluetoothd-heartrate.obj -MD -MP -MF profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Tpo -c -o profiles/heartrate/bluetoothd-heartrate.obj `if test -f 'profiles/heartrate/heartrate.c'; then $(CYGPATH_W) 'profiles/heartrate/heartrate.c'; else $(CYGPATH_W) '$(srcdir)/profiles/heartrate/heartrate.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Tpo profiles/heartrate/$(DEPDIR)/bluetoothd-heartrate.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/heartrate/heartrate.c' object='profiles/heartrate/bluetoothd-heartrate.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/heartrate/bluetoothd-heartrate.obj `if test -f 'profiles/heartrate/heartrate.c'; then $(CYGPATH_W) 'profiles/heartrate/heartrate.c'; else $(CYGPATH_W) '$(srcdir)/profiles/heartrate/heartrate.c'; fi`
+
+profiles/cyclingspeed/bluetoothd-cyclingspeed.o: profiles/cyclingspeed/cyclingspeed.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/cyclingspeed/bluetoothd-cyclingspeed.o -MD -MP -MF profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Tpo -c -o profiles/cyclingspeed/bluetoothd-cyclingspeed.o `test -f 'profiles/cyclingspeed/cyclingspeed.c' || echo '$(srcdir)/'`profiles/cyclingspeed/cyclingspeed.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Tpo profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/cyclingspeed/cyclingspeed.c' object='profiles/cyclingspeed/bluetoothd-cyclingspeed.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/cyclingspeed/bluetoothd-cyclingspeed.o `test -f 'profiles/cyclingspeed/cyclingspeed.c' || echo '$(srcdir)/'`profiles/cyclingspeed/cyclingspeed.c
+
+profiles/cyclingspeed/bluetoothd-cyclingspeed.obj: profiles/cyclingspeed/cyclingspeed.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT profiles/cyclingspeed/bluetoothd-cyclingspeed.obj -MD -MP -MF profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Tpo -c -o profiles/cyclingspeed/bluetoothd-cyclingspeed.obj `if test -f 'profiles/cyclingspeed/cyclingspeed.c'; then $(CYGPATH_W) 'profiles/cyclingspeed/cyclingspeed.c'; else $(CYGPATH_W) '$(srcdir)/profiles/cyclingspeed/cyclingspeed.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Tpo profiles/cyclingspeed/$(DEPDIR)/bluetoothd-cyclingspeed.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='profiles/cyclingspeed/cyclingspeed.c' object='profiles/cyclingspeed/bluetoothd-cyclingspeed.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o profiles/cyclingspeed/bluetoothd-cyclingspeed.obj `if test -f 'profiles/cyclingspeed/cyclingspeed.c'; then $(CYGPATH_W) 'profiles/cyclingspeed/cyclingspeed.c'; else $(CYGPATH_W) '$(srcdir)/profiles/cyclingspeed/cyclingspeed.c'; fi`
 
 attrib/bluetoothd-att.o: attrib/att.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-att.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-att.Tpo -c -o attrib/bluetoothd-att.o `test -f 'attrib/att.c' || echo '$(srcdir)/'`attrib/att.c
@@ -4332,20 +4970,6 @@ attrib/bluetoothd-gattrib.obj: attrib/gattrib.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-gattrib.obj `if test -f 'attrib/gattrib.c'; then $(CYGPATH_W) 'attrib/gattrib.c'; else $(CYGPATH_W) '$(srcdir)/attrib/gattrib.c'; fi`
 
-attrib/bluetoothd-client.o: attrib/client.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-client.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-client.Tpo -c -o attrib/bluetoothd-client.o `test -f 'attrib/client.c' || echo '$(srcdir)/'`attrib/client.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-client.Tpo attrib/$(DEPDIR)/bluetoothd-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='attrib/client.c' object='attrib/bluetoothd-client.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-client.o `test -f 'attrib/client.c' || echo '$(srcdir)/'`attrib/client.c
-
-attrib/bluetoothd-client.obj: attrib/client.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-client.obj -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-client.Tpo -c -o attrib/bluetoothd-client.obj `if test -f 'attrib/client.c'; then $(CYGPATH_W) 'attrib/client.c'; else $(CYGPATH_W) '$(srcdir)/attrib/client.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-client.Tpo attrib/$(DEPDIR)/bluetoothd-client.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='attrib/client.c' object='attrib/bluetoothd-client.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o attrib/bluetoothd-client.obj `if test -f 'attrib/client.c'; then $(CYGPATH_W) 'attrib/client.c'; else $(CYGPATH_W) '$(srcdir)/attrib/client.c'; fi`
-
 attrib/bluetoothd-gatt-service.o: attrib/gatt-service.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT attrib/bluetoothd-gatt-service.o -MD -MP -MF attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo -c -o attrib/bluetoothd-gatt-service.o `test -f 'attrib/gatt-service.c' || echo '$(srcdir)/'`attrib/gatt-service.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) attrib/$(DEPDIR)/bluetoothd-gatt-service.Tpo attrib/$(DEPDIR)/bluetoothd-gatt-service.Po
@@ -4374,34 +4998,6 @@ btio/bluetoothd-btio.obj: btio/btio.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o btio/bluetoothd-btio.obj `if test -f 'btio/btio.c'; then $(CYGPATH_W) 'btio/btio.c'; else $(CYGPATH_W) '$(srcdir)/btio/btio.c'; fi`
 
-health/bluetoothd-mcap.o: health/mcap.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o health/bluetoothd-mcap.o `test -f 'health/mcap.c' || echo '$(srcdir)/'`health/mcap.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap.Tpo health/$(DEPDIR)/bluetoothd-mcap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/mcap.c' object='health/bluetoothd-mcap.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap.o `test -f 'health/mcap.c' || echo '$(srcdir)/'`health/mcap.c
-
-health/bluetoothd-mcap.obj: health/mcap.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap.Tpo -c -o health/bluetoothd-mcap.obj `if test -f 'health/mcap.c'; then $(CYGPATH_W) 'health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap.Tpo health/$(DEPDIR)/bluetoothd-mcap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/mcap.c' object='health/bluetoothd-mcap.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap.obj `if test -f 'health/mcap.c'; then $(CYGPATH_W) 'health/mcap.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap.c'; fi`
-
-health/bluetoothd-mcap_sync.o: health/mcap_sync.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap_sync.o -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o health/bluetoothd-mcap_sync.o `test -f 'health/mcap_sync.c' || echo '$(srcdir)/'`health/mcap_sync.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo health/$(DEPDIR)/bluetoothd-mcap_sync.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/mcap_sync.c' object='health/bluetoothd-mcap_sync.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap_sync.o `test -f 'health/mcap_sync.c' || echo '$(srcdir)/'`health/mcap_sync.c
-
-health/bluetoothd-mcap_sync.obj: health/mcap_sync.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT health/bluetoothd-mcap_sync.obj -MD -MP -MF health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo -c -o health/bluetoothd-mcap_sync.obj `if test -f 'health/mcap_sync.c'; then $(CYGPATH_W) 'health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap_sync.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) health/$(DEPDIR)/bluetoothd-mcap_sync.Tpo health/$(DEPDIR)/bluetoothd-mcap_sync.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='health/mcap_sync.c' object='health/bluetoothd-mcap_sync.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o health/bluetoothd-mcap_sync.obj `if test -f 'health/mcap_sync.c'; then $(CYGPATH_W) 'health/mcap_sync.c'; else $(CYGPATH_W) '$(srcdir)/health/mcap_sync.c'; fi`
-
 src/bluetoothd-main.o: src/main.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-main.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-main.Tpo -c -o src/bluetoothd-main.o `test -f 'src/main.c' || echo '$(srcdir)/'`src/main.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-main.Tpo src/$(DEPDIR)/bluetoothd-main.Po
@@ -4430,6 +5026,20 @@ src/bluetoothd-log.obj: src/log.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-log.obj `if test -f 'src/log.c'; then $(CYGPATH_W) 'src/log.c'; else $(CYGPATH_W) '$(srcdir)/src/log.c'; fi`
 
+src/bluetoothd-systemd.o: src/systemd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-systemd.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-systemd.Tpo -c -o src/bluetoothd-systemd.o `test -f 'src/systemd.c' || echo '$(srcdir)/'`src/systemd.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-systemd.Tpo src/$(DEPDIR)/bluetoothd-systemd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/systemd.c' object='src/bluetoothd-systemd.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-systemd.o `test -f 'src/systemd.c' || echo '$(srcdir)/'`src/systemd.c
+
+src/bluetoothd-systemd.obj: src/systemd.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-systemd.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-systemd.Tpo -c -o src/bluetoothd-systemd.obj `if test -f 'src/systemd.c'; then $(CYGPATH_W) 'src/systemd.c'; else $(CYGPATH_W) '$(srcdir)/src/systemd.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-systemd.Tpo src/$(DEPDIR)/bluetoothd-systemd.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/systemd.c' object='src/bluetoothd-systemd.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-systemd.obj `if test -f 'src/systemd.c'; then $(CYGPATH_W) 'src/systemd.c'; else $(CYGPATH_W) '$(srcdir)/src/systemd.c'; fi`
+
 src/bluetoothd-rfkill.o: src/rfkill.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-rfkill.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-rfkill.Tpo -c -o src/bluetoothd-rfkill.o `test -f 'src/rfkill.c' || echo '$(srcdir)/'`src/rfkill.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-rfkill.Tpo src/$(DEPDIR)/bluetoothd-rfkill.Po
@@ -4570,20 +5180,6 @@ src/bluetoothd-glib-helper.obj: src/glib-helper.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi`
 
-src/bluetoothd-oui.o: src/oui.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oui.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-oui.Tpo -c -o src/bluetoothd-oui.o `test -f 'src/oui.c' || echo '$(srcdir)/'`src/oui.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oui.Tpo src/$(DEPDIR)/bluetoothd-oui.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/oui.c' object='src/bluetoothd-oui.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oui.o `test -f 'src/oui.c' || echo '$(srcdir)/'`src/oui.c
-
-src/bluetoothd-oui.obj: src/oui.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oui.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-oui.Tpo -c -o src/bluetoothd-oui.obj `if test -f 'src/oui.c'; then $(CYGPATH_W) 'src/oui.c'; else $(CYGPATH_W) '$(srcdir)/src/oui.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oui.Tpo src/$(DEPDIR)/bluetoothd-oui.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/oui.c' object='src/bluetoothd-oui.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oui.obj `if test -f 'src/oui.c'; then $(CYGPATH_W) 'src/oui.c'; else $(CYGPATH_W) '$(srcdir)/src/oui.c'; fi`
-
 src/bluetoothd-plugin.o: src/plugin.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-plugin.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-plugin.Tpo -c -o src/bluetoothd-plugin.o `test -f 'src/plugin.c' || echo '$(srcdir)/'`src/plugin.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-plugin.Tpo src/$(DEPDIR)/bluetoothd-plugin.Po
@@ -4640,20 +5236,6 @@ src/bluetoothd-error.obj: src/error.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-error.obj `if test -f 'src/error.c'; then $(CYGPATH_W) 'src/error.c'; else $(CYGPATH_W) '$(srcdir)/src/error.c'; fi`
 
-src/bluetoothd-manager.o: src/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-manager.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-manager.Tpo -c -o src/bluetoothd-manager.o `test -f 'src/manager.c' || echo '$(srcdir)/'`src/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-manager.Tpo src/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/manager.c' object='src/bluetoothd-manager.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-manager.o `test -f 'src/manager.c' || echo '$(srcdir)/'`src/manager.c
-
-src/bluetoothd-manager.obj: src/manager.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-manager.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-manager.Tpo -c -o src/bluetoothd-manager.obj `if test -f 'src/manager.c'; then $(CYGPATH_W) 'src/manager.c'; else $(CYGPATH_W) '$(srcdir)/src/manager.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-manager.Tpo src/$(DEPDIR)/bluetoothd-manager.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/manager.c' object='src/bluetoothd-manager.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-manager.obj `if test -f 'src/manager.c'; then $(CYGPATH_W) 'src/manager.c'; else $(CYGPATH_W) '$(srcdir)/src/manager.c'; fi`
-
 src/bluetoothd-adapter.o: src/adapter.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-adapter.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-adapter.Tpo -c -o src/bluetoothd-adapter.o `test -f 'src/adapter.c' || echo '$(srcdir)/'`src/adapter.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-adapter.Tpo src/$(DEPDIR)/bluetoothd-adapter.Po
@@ -4668,6 +5250,34 @@ src/bluetoothd-adapter.obj: src/adapter.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-adapter.obj `if test -f 'src/adapter.c'; then $(CYGPATH_W) 'src/adapter.c'; else $(CYGPATH_W) '$(srcdir)/src/adapter.c'; fi`
 
+src/bluetoothd-profile.o: src/profile.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-profile.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-profile.Tpo -c -o src/bluetoothd-profile.o `test -f 'src/profile.c' || echo '$(srcdir)/'`src/profile.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-profile.Tpo src/$(DEPDIR)/bluetoothd-profile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/profile.c' object='src/bluetoothd-profile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-profile.o `test -f 'src/profile.c' || echo '$(srcdir)/'`src/profile.c
+
+src/bluetoothd-profile.obj: src/profile.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-profile.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-profile.Tpo -c -o src/bluetoothd-profile.obj `if test -f 'src/profile.c'; then $(CYGPATH_W) 'src/profile.c'; else $(CYGPATH_W) '$(srcdir)/src/profile.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-profile.Tpo src/$(DEPDIR)/bluetoothd-profile.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/profile.c' object='src/bluetoothd-profile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-profile.obj `if test -f 'src/profile.c'; then $(CYGPATH_W) 'src/profile.c'; else $(CYGPATH_W) '$(srcdir)/src/profile.c'; fi`
+
+src/bluetoothd-service.o: src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-service.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-service.Tpo -c -o src/bluetoothd-service.o `test -f 'src/service.c' || echo '$(srcdir)/'`src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-service.Tpo src/$(DEPDIR)/bluetoothd-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/service.c' object='src/bluetoothd-service.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-service.o `test -f 'src/service.c' || echo '$(srcdir)/'`src/service.c
+
+src/bluetoothd-service.obj: src/service.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-service.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-service.Tpo -c -o src/bluetoothd-service.obj `if test -f 'src/service.c'; then $(CYGPATH_W) 'src/service.c'; else $(CYGPATH_W) '$(srcdir)/src/service.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-service.Tpo src/$(DEPDIR)/bluetoothd-service.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/service.c' object='src/bluetoothd-service.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-service.obj `if test -f 'src/service.c'; then $(CYGPATH_W) 'src/service.c'; else $(CYGPATH_W) '$(srcdir)/src/service.c'; fi`
+
 src/bluetoothd-device.o: src/device.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-device.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-device.Tpo -c -o src/bluetoothd-device.o `test -f 'src/device.c' || echo '$(srcdir)/'`src/device.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-device.Tpo src/$(DEPDIR)/bluetoothd-device.Po
@@ -4696,34 +5306,6 @@ src/bluetoothd-dbus-common.obj: src/dbus-common.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-dbus-common.obj `if test -f 'src/dbus-common.c'; then $(CYGPATH_W) 'src/dbus-common.c'; else $(CYGPATH_W) '$(srcdir)/src/dbus-common.c'; fi`
 
-src/bluetoothd-event.o: src/event.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-event.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-event.Tpo -c -o src/bluetoothd-event.o `test -f 'src/event.c' || echo '$(srcdir)/'`src/event.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-event.Tpo src/$(DEPDIR)/bluetoothd-event.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/event.c' object='src/bluetoothd-event.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-event.o `test -f 'src/event.c' || echo '$(srcdir)/'`src/event.c
-
-src/bluetoothd-event.obj: src/event.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-event.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-event.Tpo -c -o src/bluetoothd-event.obj `if test -f 'src/event.c'; then $(CYGPATH_W) 'src/event.c'; else $(CYGPATH_W) '$(srcdir)/src/event.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-event.Tpo src/$(DEPDIR)/bluetoothd-event.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/event.c' object='src/bluetoothd-event.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-event.obj `if test -f 'src/event.c'; then $(CYGPATH_W) 'src/event.c'; else $(CYGPATH_W) '$(srcdir)/src/event.c'; fi`
-
-src/bluetoothd-oob.o: src/oob.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oob.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-oob.Tpo -c -o src/bluetoothd-oob.o `test -f 'src/oob.c' || echo '$(srcdir)/'`src/oob.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oob.Tpo src/$(DEPDIR)/bluetoothd-oob.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/oob.c' object='src/bluetoothd-oob.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oob.o `test -f 'src/oob.c' || echo '$(srcdir)/'`src/oob.c
-
-src/bluetoothd-oob.obj: src/oob.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-oob.obj -MD -MP -MF src/$(DEPDIR)/bluetoothd-oob.Tpo -c -o src/bluetoothd-oob.obj `if test -f 'src/oob.c'; then $(CYGPATH_W) 'src/oob.c'; else $(CYGPATH_W) '$(srcdir)/src/oob.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-oob.Tpo src/$(DEPDIR)/bluetoothd-oob.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/oob.c' object='src/bluetoothd-oob.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-oob.obj `if test -f 'src/oob.c'; then $(CYGPATH_W) 'src/oob.c'; else $(CYGPATH_W) '$(srcdir)/src/oob.c'; fi`
-
 src/bluetoothd-eir.o: src/eir.c
 @am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/bluetoothd-eir.o -MD -MP -MF src/$(DEPDIR)/bluetoothd-eir.Tpo -c -o src/bluetoothd-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c
 @am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/bluetoothd-eir.Tpo src/$(DEPDIR)/bluetoothd-eir.Po
@@ -4738,99 +5320,51 @@ src/bluetoothd-eir.obj: src/eir.c
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
 @am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/bluetoothd-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi`
 
-audio/bluetoothd-telephony.o: audio/telephony.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-telephony.o -MD -MP -MF audio/$(DEPDIR)/bluetoothd-telephony.Tpo -c -o audio/bluetoothd-telephony.o `test -f 'audio/telephony.c' || echo '$(srcdir)/'`audio/telephony.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-telephony.Tpo audio/$(DEPDIR)/bluetoothd-telephony.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/telephony.c' object='audio/bluetoothd-telephony.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-telephony.o `test -f 'audio/telephony.c' || echo '$(srcdir)/'`audio/telephony.c
-
-audio/bluetoothd-telephony.obj: audio/telephony.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT audio/bluetoothd-telephony.obj -MD -MP -MF audio/$(DEPDIR)/bluetoothd-telephony.Tpo -c -o audio/bluetoothd-telephony.obj `if test -f 'audio/telephony.c'; then $(CYGPATH_W) 'audio/telephony.c'; else $(CYGPATH_W) '$(srcdir)/audio/telephony.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) audio/$(DEPDIR)/bluetoothd-telephony.Tpo audio/$(DEPDIR)/bluetoothd-telephony.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='audio/telephony.c' object='audio/bluetoothd-telephony.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o audio/bluetoothd-telephony.obj `if test -f 'audio/telephony.c'; then $(CYGPATH_W) 'audio/telephony.c'; else $(CYGPATH_W) '$(srcdir)/audio/telephony.c'; fi`
-
-sap/bluetoothd-sap.o: sap/sap.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-sap.o -MD -MP -MF sap/$(DEPDIR)/bluetoothd-sap.Tpo -c -o sap/bluetoothd-sap.o `test -f 'sap/sap.c' || echo '$(srcdir)/'`sap/sap.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-sap.Tpo sap/$(DEPDIR)/bluetoothd-sap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/sap.c' object='sap/bluetoothd-sap.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-sap.o `test -f 'sap/sap.c' || echo '$(srcdir)/'`sap/sap.c
-
-sap/bluetoothd-sap.obj: sap/sap.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT sap/bluetoothd-sap.obj -MD -MP -MF sap/$(DEPDIR)/bluetoothd-sap.Tpo -c -o sap/bluetoothd-sap.obj `if test -f 'sap/sap.c'; then $(CYGPATH_W) 'sap/sap.c'; else $(CYGPATH_W) '$(srcdir)/sap/sap.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) sap/$(DEPDIR)/bluetoothd-sap.Tpo sap/$(DEPDIR)/bluetoothd-sap.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='sap/sap.c' object='sap/bluetoothd-sap.obj' libtool=no @AMDEPBACKSLASH@
+src/shared/bluetoothd-util.o: src/shared/util.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/shared/bluetoothd-util.o -MD -MP -MF src/shared/$(DEPDIR)/bluetoothd-util.Tpo -c -o src/shared/bluetoothd-util.o `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/bluetoothd-util.Tpo src/shared/$(DEPDIR)/bluetoothd-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/shared/util.c' object='src/shared/bluetoothd-util.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o sap/bluetoothd-sap.obj `if test -f 'sap/sap.c'; then $(CYGPATH_W) 'sap/sap.c'; else $(CYGPATH_W) '$(srcdir)/sap/sap.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/shared/bluetoothd-util.o `test -f 'src/shared/util.c' || echo '$(srcdir)/'`src/shared/util.c
 
-unit/unit_test_eir-test-eir.o: unit/test-eir.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT unit/unit_test_eir-test-eir.o -MD -MP -MF unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo -c -o unit/unit_test_eir-test-eir.o `test -f 'unit/test-eir.c' || echo '$(srcdir)/'`unit/test-eir.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo unit/$(DEPDIR)/unit_test_eir-test-eir.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='unit/test-eir.c' object='unit/unit_test_eir-test-eir.o' libtool=no @AMDEPBACKSLASH@
+src/shared/bluetoothd-util.obj: src/shared/util.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/shared/bluetoothd-util.obj -MD -MP -MF src/shared/$(DEPDIR)/bluetoothd-util.Tpo -c -o src/shared/bluetoothd-util.obj `if test -f 'src/shared/util.c'; then $(CYGPATH_W) 'src/shared/util.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/util.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/bluetoothd-util.Tpo src/shared/$(DEPDIR)/bluetoothd-util.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/shared/util.c' object='src/shared/bluetoothd-util.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o unit/unit_test_eir-test-eir.o `test -f 'unit/test-eir.c' || echo '$(srcdir)/'`unit/test-eir.c
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/shared/bluetoothd-util.obj `if test -f 'src/shared/util.c'; then $(CYGPATH_W) 'src/shared/util.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/util.c'; fi`
 
-unit/unit_test_eir-test-eir.obj: unit/test-eir.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT unit/unit_test_eir-test-eir.obj -MD -MP -MF unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo -c -o unit/unit_test_eir-test-eir.obj `if test -f 'unit/test-eir.c'; then $(CYGPATH_W) 'unit/test-eir.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-eir.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) unit/$(DEPDIR)/unit_test_eir-test-eir.Tpo unit/$(DEPDIR)/unit_test_eir-test-eir.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='unit/test-eir.c' object='unit/unit_test_eir-test-eir.obj' libtool=no @AMDEPBACKSLASH@
+src/shared/bluetoothd-mgmt.o: src/shared/mgmt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/shared/bluetoothd-mgmt.o -MD -MP -MF src/shared/$(DEPDIR)/bluetoothd-mgmt.Tpo -c -o src/shared/bluetoothd-mgmt.o `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/bluetoothd-mgmt.Tpo src/shared/$(DEPDIR)/bluetoothd-mgmt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/shared/mgmt.c' object='src/shared/bluetoothd-mgmt.o' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o unit/unit_test_eir-test-eir.obj `if test -f 'unit/test-eir.c'; then $(CYGPATH_W) 'unit/test-eir.c'; else $(CYGPATH_W) '$(srcdir)/unit/test-eir.c'; fi`
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/shared/bluetoothd-mgmt.o `test -f 'src/shared/mgmt.c' || echo '$(srcdir)/'`src/shared/mgmt.c
 
-src/unit_test_eir-eir.o: src/eir.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-eir.o -MD -MP -MF src/$(DEPDIR)/unit_test_eir-eir.Tpo -c -o src/unit_test_eir-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-eir.Tpo src/$(DEPDIR)/unit_test_eir-eir.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/eir.c' object='src/unit_test_eir-eir.o' libtool=no @AMDEPBACKSLASH@
+src/shared/bluetoothd-mgmt.obj: src/shared/mgmt.c
+@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -MT src/shared/bluetoothd-mgmt.obj -MD -MP -MF src/shared/$(DEPDIR)/bluetoothd-mgmt.Tpo -c -o src/shared/bluetoothd-mgmt.obj `if test -f 'src/shared/mgmt.c'; then $(CYGPATH_W) 'src/shared/mgmt.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/mgmt.c'; fi`
+@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/shared/$(DEPDIR)/bluetoothd-mgmt.Tpo src/shared/$(DEPDIR)/bluetoothd-mgmt.Po
+@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/shared/mgmt.c' object='src/shared/bluetoothd-mgmt.obj' libtool=no @AMDEPBACKSLASH@
 @AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-eir.o `test -f 'src/eir.c' || echo '$(srcdir)/'`src/eir.c
-
-src/unit_test_eir-eir.obj: src/eir.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-eir.obj -MD -MP -MF src/$(DEPDIR)/unit_test_eir-eir.Tpo -c -o src/unit_test_eir-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-eir.Tpo src/$(DEPDIR)/unit_test_eir-eir.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/eir.c' object='src/unit_test_eir-eir.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-eir.obj `if test -f 'src/eir.c'; then $(CYGPATH_W) 'src/eir.c'; else $(CYGPATH_W) '$(srcdir)/src/eir.c'; fi`
-
-src/unit_test_eir-glib-helper.o: src/glib-helper.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-glib-helper.o -MD -MP -MF src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo -c -o src/unit_test_eir-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo src/$(DEPDIR)/unit_test_eir-glib-helper.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/glib-helper.c' object='src/unit_test_eir-glib-helper.o' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-glib-helper.o `test -f 'src/glib-helper.c' || echo '$(srcdir)/'`src/glib-helper.c
-
-src/unit_test_eir-glib-helper.obj: src/glib-helper.c
-@am__fastdepCC_TRUE@   $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -MT src/unit_test_eir-glib-helper.obj -MD -MP -MF src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo -c -o src/unit_test_eir-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi`
-@am__fastdepCC_TRUE@   $(AM_V_at)$(am__mv) src/$(DEPDIR)/unit_test_eir-glib-helper.Tpo src/$(DEPDIR)/unit_test_eir-glib-helper.Po
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      $(AM_V_CC)source='src/glib-helper.c' object='src/unit_test_eir-glib-helper.obj' libtool=no @AMDEPBACKSLASH@
-@AMDEP_TRUE@@am__fastdepCC_FALSE@      DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
-@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(unit_test_eir_CFLAGS) $(CFLAGS) -c -o src/unit_test_eir-glib-helper.obj `if test -f 'src/glib-helper.c'; then $(CYGPATH_W) 'src/glib-helper.c'; else $(CYGPATH_W) '$(srcdir)/src/glib-helper.c'; fi`
-
-.l.c:
-       $(AM_V_LEX)$(am__skiplex) $(SHELL) $(YLWRAP) $< $(LEX_OUTPUT_ROOT).c $@ -- $(LEXCOMPILE)
-
-.y.c:
-       $(AM_V_YACC)$(am__skipyacc) $(SHELL) $(YLWRAP) $< y.tab.c $@ y.tab.h $*.h y.output $*.output -- $(YACCCOMPILE)
+@am__fastdepCC_FALSE@  $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(src_bluetoothd_CFLAGS) $(CFLAGS) -c -o src/shared/bluetoothd-mgmt.obj `if test -f 'src/shared/mgmt.c'; then $(CYGPATH_W) 'src/shared/mgmt.c'; else $(CYGPATH_W) '$(srcdir)/src/shared/mgmt.c'; fi`
 
 mostlyclean-libtool:
        -rm -f *.lo
 
 clean-libtool:
        -rm -rf .libs _libs
+       -rm -rf android/.libs android/_libs
        -rm -rf attrib/.libs attrib/_libs
-       -rm -rf audio/.libs audio/_libs
-       -rm -rf compat/.libs compat/_libs
-       -rm -rf cups/.libs cups/_libs
+       -rm -rf client/.libs client/_libs
        -rm -rf emulator/.libs emulator/_libs
+       -rm -rf gdbus/.libs gdbus/_libs
        -rm -rf lib/.libs lib/_libs
-       -rm -rf mgmt/.libs mgmt/_libs
        -rm -rf monitor/.libs monitor/_libs
+       -rm -rf obexd/src/.libs obexd/src/_libs
        -rm -rf plugins/.libs plugins/_libs
-       -rm -rf sbc/.libs sbc/_libs
+       -rm -rf profiles/cups/.libs profiles/cups/_libs
+       -rm -rf profiles/iap/.libs profiles/iap/_libs
        -rm -rf src/.libs src/_libs
-       -rm -rf test/.libs test/_libs
        -rm -rf tools/.libs tools/_libs
        -rm -rf unit/.libs unit/_libs
 
@@ -4838,11 +5372,18 @@ distclean-libtool:
        -rm -f libtool config.lt
 install-man1: $(dist_man_MANS) $(man_MANS)
        @$(NORMAL_INSTALL)
-       test -z "$(man1dir)" || $(MKDIR_P) "$(DESTDIR)$(man1dir)"
-       @list=''; test -n "$(man1dir)" || exit 0; \
-       { for i in $$list; do echo "$$i"; done; \
-       l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
-         sed -n '/\.1[a-z]*$$/p'; \
+       @list1=''; \
+       list2='$(dist_man_MANS) $(man_MANS)'; \
+       test -n "$(man1dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man1dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man1dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.1[a-z]*$$/p'; \
+       fi; \
        } | while read p; do \
          if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; echo "$$p"; \
@@ -4874,11 +5415,18 @@ uninstall-man1:
        dir='$(DESTDIR)$(man1dir)'; $(am__uninstall_files_from_dir)
 install-man8: $(dist_man_MANS) $(man_MANS)
        @$(NORMAL_INSTALL)
-       test -z "$(man8dir)" || $(MKDIR_P) "$(DESTDIR)$(man8dir)"
-       @list=''; test -n "$(man8dir)" || exit 0; \
-       { for i in $$list; do echo "$$i"; done; \
-       l2='$(dist_man_MANS) $(man_MANS)'; for i in $$l2; do echo "$$i"; done | \
-         sed -n '/\.8[a-z]*$$/p'; \
+       @list1=''; \
+       list2='$(dist_man_MANS) $(man_MANS)'; \
+       test -n "$(man8dir)" \
+         && test -n "`echo $$list1$$list2`" \
+         || exit 0; \
+       echo " $(MKDIR_P) '$(DESTDIR)$(man8dir)'"; \
+       $(MKDIR_P) "$(DESTDIR)$(man8dir)" || exit 1; \
+       { for i in $$list1; do echo "$$i"; done;  \
+       if test -n "$$list2"; then \
+         for i in $$list2; do echo "$$i"; done \
+           | sed -n '/\.8[a-z]*$$/p'; \
+       fi; \
        } | while read p; do \
          if test -f $$p; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; echo "$$p"; \
@@ -4908,28 +5456,13 @@ uninstall-man8:
        } | sed -e 's,.*/,,;h;s,.*\.,,;s,^[^8][0-9a-z]*$$,8,;x' \
              -e 's,\.[0-9a-z]*$$,,;$(transform);G;s,\n,.,'`; \
        dir='$(DESTDIR)$(man8dir)'; $(am__uninstall_files_from_dir)
-install-alsaconfDATA: $(alsaconf_DATA)
-       @$(NORMAL_INSTALL)
-       test -z "$(alsaconfdir)" || $(MKDIR_P) "$(DESTDIR)$(alsaconfdir)"
-       @list='$(alsaconf_DATA)'; test -n "$(alsaconfdir)" || list=; \
-       for p in $$list; do \
-         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
-         echo "$$d$$p"; \
-       done | $(am__base_list) | \
-       while read files; do \
-         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(alsaconfdir)'"; \
-         $(INSTALL_DATA) $$files "$(DESTDIR)$(alsaconfdir)" || exit $$?; \
-       done
-
-uninstall-alsaconfDATA:
-       @$(NORMAL_UNINSTALL)
-       @list='$(alsaconf_DATA)'; test -n "$(alsaconfdir)" || list=; \
-       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(alsaconfdir)'; $(am__uninstall_files_from_dir)
 install-confDATA: $(conf_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(confdir)" || $(MKDIR_P) "$(DESTDIR)$(confdir)"
        @list='$(conf_DATA)'; test -n "$(confdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(confdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(confdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -4946,8 +5479,11 @@ uninstall-confDATA:
        dir='$(DESTDIR)$(confdir)'; $(am__uninstall_files_from_dir)
 install-dbusDATA: $(dbus_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(dbusdir)" || $(MKDIR_P) "$(DESTDIR)$(dbusdir)"
        @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(dbusdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(dbusdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -4962,28 +5498,55 @@ uninstall-dbusDATA:
        @list='$(dbus_DATA)'; test -n "$(dbusdir)" || list=; \
        files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
        dir='$(DESTDIR)$(dbusdir)'; $(am__uninstall_files_from_dir)
-install-dbusserviceDATA: $(dbusservice_DATA)
+install-dbussessionbusDATA: $(dbussessionbus_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(dbusservicedir)" || $(MKDIR_P) "$(DESTDIR)$(dbusservicedir)"
-       @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \
+       @list='$(dbussessionbus_DATA)'; test -n "$(dbussessionbusdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(dbussessionbusdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(dbussessionbusdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
        done | $(am__base_list) | \
        while read files; do \
-         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusservicedir)'"; \
-         $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusservicedir)" || exit $$?; \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbussessionbusdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(dbussessionbusdir)" || exit $$?; \
        done
 
-uninstall-dbusserviceDATA:
+uninstall-dbussessionbusDATA:
        @$(NORMAL_UNINSTALL)
-       @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \
+       @list='$(dbussessionbus_DATA)'; test -n "$(dbussessionbusdir)" || list=; \
        files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(dbusservicedir)'; $(am__uninstall_files_from_dir)
+       dir='$(DESTDIR)$(dbussessionbusdir)'; $(am__uninstall_files_from_dir)
+install-dbussystembusDATA: $(dbussystembus_DATA)
+       @$(NORMAL_INSTALL)
+       @list='$(dbussystembus_DATA)'; test -n "$(dbussystembusdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(dbussystembusdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(dbussystembusdir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbussystembusdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(dbussystembusdir)" || exit $$?; \
+       done
+
+uninstall-dbussystembusDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(dbussystembus_DATA)'; test -n "$(dbussystembusdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(dbussystembusdir)'; $(am__uninstall_files_from_dir)
 install-pkgconfigDATA: $(pkgconfig_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(pkgconfigdir)" || $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)"
        @list='$(pkgconfig_DATA)'; test -n "$(pkgconfigdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(pkgconfigdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(pkgconfigdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -5000,8 +5563,11 @@ uninstall-pkgconfigDATA:
        dir='$(DESTDIR)$(pkgconfigdir)'; $(am__uninstall_files_from_dir)
 install-rulesDATA: $(rules_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(rulesdir)" || $(MKDIR_P) "$(DESTDIR)$(rulesdir)"
        @list='$(rules_DATA)'; test -n "$(rulesdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(rulesdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(rulesdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -5018,8 +5584,11 @@ uninstall-rulesDATA:
        dir='$(DESTDIR)$(rulesdir)'; $(am__uninstall_files_from_dir)
 install-stateDATA: $(state_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(statedir)" || $(MKDIR_P) "$(DESTDIR)$(statedir)"
        @list='$(state_DATA)'; test -n "$(statedir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(statedir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(statedir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -5034,28 +5603,55 @@ uninstall-stateDATA:
        @list='$(state_DATA)'; test -n "$(statedir)" || list=; \
        files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
        dir='$(DESTDIR)$(statedir)'; $(am__uninstall_files_from_dir)
-install-systemdunitDATA: $(systemdunit_DATA)
+install-systemdsystemunitDATA: $(systemdsystemunit_DATA)
        @$(NORMAL_INSTALL)
-       test -z "$(systemdunitdir)" || $(MKDIR_P) "$(DESTDIR)$(systemdunitdir)"
-       @list='$(systemdunit_DATA)'; test -n "$(systemdunitdir)" || list=; \
+       @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(systemdsystemunitdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(systemdsystemunitdir)" || exit 1; \
+       fi; \
+       for p in $$list; do \
+         if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
+         echo "$$d$$p"; \
+       done | $(am__base_list) | \
+       while read files; do \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdsystemunitdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdsystemunitdir)" || exit $$?; \
+       done
+
+uninstall-systemdsystemunitDATA:
+       @$(NORMAL_UNINSTALL)
+       @list='$(systemdsystemunit_DATA)'; test -n "$(systemdsystemunitdir)" || list=; \
+       files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+       dir='$(DESTDIR)$(systemdsystemunitdir)'; $(am__uninstall_files_from_dir)
+install-systemduserunitDATA: $(systemduserunit_DATA)
+       @$(NORMAL_INSTALL)
+       @list='$(systemduserunit_DATA)'; test -n "$(systemduserunitdir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(systemduserunitdir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(systemduserunitdir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
        done | $(am__base_list) | \
        while read files; do \
-         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemdunitdir)'"; \
-         $(INSTALL_DATA) $$files "$(DESTDIR)$(systemdunitdir)" || exit $$?; \
+         echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemduserunitdir)'"; \
+         $(INSTALL_DATA) $$files "$(DESTDIR)$(systemduserunitdir)" || exit $$?; \
        done
 
-uninstall-systemdunitDATA:
+uninstall-systemduserunitDATA:
        @$(NORMAL_UNINSTALL)
-       @list='$(systemdunit_DATA)'; test -n "$(systemdunitdir)" || list=; \
+       @list='$(systemduserunit_DATA)'; test -n "$(systemduserunitdir)" || list=; \
        files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
-       dir='$(DESTDIR)$(systemdunitdir)'; $(am__uninstall_files_from_dir)
+       dir='$(DESTDIR)$(systemduserunitdir)'; $(am__uninstall_files_from_dir)
 install-includeHEADERS: $(include_HEADERS)
        @$(NORMAL_INSTALL)
-       test -z "$(includedir)" || $(MKDIR_P) "$(DESTDIR)$(includedir)"
        @list='$(include_HEADERS)'; test -n "$(includedir)" || list=; \
+       if test -n "$$list"; then \
+         echo " $(MKDIR_P) '$(DESTDIR)$(includedir)'"; \
+         $(MKDIR_P) "$(DESTDIR)$(includedir)" || exit 1; \
+       fi; \
        for p in $$list; do \
          if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \
          echo "$$d$$p"; \
@@ -5283,7 +5879,6 @@ dist-lzip: distdir
 dist-lzma: distdir
        tardir=$(distdir) && $(am__tar) | lzma -9 -c >$(distdir).tar.lzma
        $(am__remove_distdir)
-
 dist-xz: distdir
        tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
        $(am__remove_distdir)
@@ -5302,7 +5897,7 @@ dist-zip: distdir
        $(am__remove_distdir)
 
 dist dist-all: distdir
-       tardir=$(distdir) && $(am__tar) | GZIP=$(GZIP_ENV) gzip -c >$(distdir).tar.gz
+       tardir=$(distdir) && $(am__tar) | XZ_OPT=$${XZ_OPT--e} xz -c >$(distdir).tar.xz
        $(am__remove_distdir)
 
 # This target untars the dist file and tries a VPATH configuration.  Then
@@ -5327,7 +5922,7 @@ distcheck: dist
        *.zip*) \
          unzip $(distdir).zip ;;\
        esac
-       chmod -R a-w $(distdir); chmod a+w $(distdir)
+       chmod -R a-w $(distdir); chmod u+w $(distdir)
        mkdir $(distdir)/_build
        mkdir $(distdir)/_inst
        chmod a-w $(distdir)
@@ -5400,7 +5995,7 @@ all-am: Makefile $(LIBRARIES) $(LTLIBRARIES) $(PROGRAMS) $(SCRIPTS) \
 install-binPROGRAMS: install-libLTLIBRARIES
 
 installdirs:
-       for dir in "$(DESTDIR)$(alsadir)" "$(DESTDIR)$(gstreamerdir)" "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" "$(DESTDIR)$(sbindir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(alsaconfdir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" "$(DESTDIR)$(systemdunitdir)" "$(DESTDIR)$(includedir)"; do \
+       for dir in "$(DESTDIR)$(libdir)" "$(DESTDIR)$(plugindir)" "$(DESTDIR)$(bindir)" "$(DESTDIR)$(cupsdir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(udevdir)" "$(DESTDIR)$(testdir)" "$(DESTDIR)$(man1dir)" "$(DESTDIR)$(man8dir)" "$(DESTDIR)$(confdir)" "$(DESTDIR)$(dbusdir)" "$(DESTDIR)$(dbussessionbusdir)" "$(DESTDIR)$(dbussystembusdir)" "$(DESTDIR)$(pkgconfigdir)" "$(DESTDIR)$(rulesdir)" "$(DESTDIR)$(statedir)" "$(DESTDIR)$(systemdsystemunitdir)" "$(DESTDIR)$(systemduserunitdir)" "$(DESTDIR)$(includedir)"; do \
          test -z "$$dir" || $(MKDIR_P) "$$dir"; \
        done
 install: $(BUILT_SOURCES)
@@ -5431,56 +6026,72 @@ clean-generic:
 distclean-generic:
        -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES)
        -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES)
-       -rm -f alert/$(DEPDIR)/$(am__dirstamp)
-       -rm -f alert/$(am__dirstamp)
+       -rm -f android/$(DEPDIR)/$(am__dirstamp)
+       -rm -f android/$(am__dirstamp)
        -rm -f attrib/$(DEPDIR)/$(am__dirstamp)
        -rm -f attrib/$(am__dirstamp)
-       -rm -f audio/$(DEPDIR)/$(am__dirstamp)
-       -rm -f audio/$(am__dirstamp)
        -rm -f btio/$(DEPDIR)/$(am__dirstamp)
        -rm -f btio/$(am__dirstamp)
-       -rm -f compat/$(DEPDIR)/$(am__dirstamp)
-       -rm -f compat/$(am__dirstamp)
-       -rm -f cups/$(DEPDIR)/$(am__dirstamp)
-       -rm -f cups/$(am__dirstamp)
-       -rm -f deviceinfo/$(DEPDIR)/$(am__dirstamp)
-       -rm -f deviceinfo/$(am__dirstamp)
+       -rm -f client/$(DEPDIR)/$(am__dirstamp)
+       -rm -f client/$(am__dirstamp)
        -rm -f emulator/$(DEPDIR)/$(am__dirstamp)
        -rm -f emulator/$(am__dirstamp)
        -rm -f gdbus/$(DEPDIR)/$(am__dirstamp)
        -rm -f gdbus/$(am__dirstamp)
-       -rm -f health/$(DEPDIR)/$(am__dirstamp)
-       -rm -f health/$(am__dirstamp)
-       -rm -f input/$(DEPDIR)/$(am__dirstamp)
-       -rm -f input/$(am__dirstamp)
+       -rm -f gobex/$(DEPDIR)/$(am__dirstamp)
+       -rm -f gobex/$(am__dirstamp)
        -rm -f lib/$(DEPDIR)/$(am__dirstamp)
        -rm -f lib/$(am__dirstamp)
-       -rm -f mgmt/$(DEPDIR)/$(am__dirstamp)
-       -rm -f mgmt/$(am__dirstamp)
        -rm -f monitor/$(DEPDIR)/$(am__dirstamp)
        -rm -f monitor/$(am__dirstamp)
-       -rm -f network/$(DEPDIR)/$(am__dirstamp)
-       -rm -f network/$(am__dirstamp)
+       -rm -f obexd/client/$(DEPDIR)/$(am__dirstamp)
+       -rm -f obexd/client/$(am__dirstamp)
+       -rm -f obexd/plugins/$(DEPDIR)/$(am__dirstamp)
+       -rm -f obexd/plugins/$(am__dirstamp)
+       -rm -f obexd/src/$(DEPDIR)/$(am__dirstamp)
+       -rm -f obexd/src/$(am__dirstamp)
        -rm -f plugins/$(DEPDIR)/$(am__dirstamp)
        -rm -f plugins/$(am__dirstamp)
-       -rm -f proximity/$(DEPDIR)/$(am__dirstamp)
-       -rm -f proximity/$(am__dirstamp)
-       -rm -f sap/$(DEPDIR)/$(am__dirstamp)
-       -rm -f sap/$(am__dirstamp)
-       -rm -f sbc/$(DEPDIR)/$(am__dirstamp)
-       -rm -f sbc/$(am__dirstamp)
-       -rm -f serial/$(DEPDIR)/$(am__dirstamp)
-       -rm -f serial/$(am__dirstamp)
+       -rm -f profiles/alert/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/alert/$(am__dirstamp)
+       -rm -f profiles/audio/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/audio/$(am__dirstamp)
+       -rm -f profiles/cups/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/cups/$(am__dirstamp)
+       -rm -f profiles/cyclingspeed/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/cyclingspeed/$(am__dirstamp)
+       -rm -f profiles/deviceinfo/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/deviceinfo/$(am__dirstamp)
+       -rm -f profiles/gatt/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/gatt/$(am__dirstamp)
+       -rm -f profiles/health/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/health/$(am__dirstamp)
+       -rm -f profiles/heartrate/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/heartrate/$(am__dirstamp)
+       -rm -f profiles/iap/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/iap/$(am__dirstamp)
+       -rm -f profiles/input/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/input/$(am__dirstamp)
+       -rm -f profiles/network/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/network/$(am__dirstamp)
+       -rm -f profiles/proximity/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/proximity/$(am__dirstamp)
+       -rm -f profiles/sap/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/sap/$(am__dirstamp)
+       -rm -f profiles/scanparam/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/scanparam/$(am__dirstamp)
+       -rm -f profiles/thermometer/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/thermometer/$(am__dirstamp)
+       -rm -f profiles/time/$(DEPDIR)/$(am__dirstamp)
+       -rm -f profiles/time/$(am__dirstamp)
        -rm -f src/$(DEPDIR)/$(am__dirstamp)
        -rm -f src/$(am__dirstamp)
-       -rm -f test/$(DEPDIR)/$(am__dirstamp)
-       -rm -f test/$(am__dirstamp)
-       -rm -f thermometer/$(DEPDIR)/$(am__dirstamp)
-       -rm -f thermometer/$(am__dirstamp)
-       -rm -f time/$(DEPDIR)/$(am__dirstamp)
-       -rm -f time/$(am__dirstamp)
+       -rm -f src/shared/$(DEPDIR)/$(am__dirstamp)
+       -rm -f src/shared/$(am__dirstamp)
        -rm -f tools/$(DEPDIR)/$(am__dirstamp)
        -rm -f tools/$(am__dirstamp)
+       -rm -f tools/parser/$(DEPDIR)/$(am__dirstamp)
+       -rm -f tools/parser/$(am__dirstamp)
        -rm -f unit/$(DEPDIR)/$(am__dirstamp)
        -rm -f unit/$(am__dirstamp)
        -test -z "$(DISTCLEANFILES)" || rm -f $(DISTCLEANFILES)
@@ -5488,23 +6099,19 @@ distclean-generic:
 maintainer-clean-generic:
        @echo "This command is intended for maintainers to use"
        @echo "it deletes files that may require special tools to rebuild."
-       -rm -f tools/lexer.c
-       -rm -f tools/parser.c
-       -rm -f tools/parser.h
        -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES)
        -test -z "$(MAINTAINERCLEANFILES)" || rm -f $(MAINTAINERCLEANFILES)
 clean: clean-am
 
-clean-am: clean-alsaLTLIBRARIES clean-binPROGRAMS clean-cupsPROGRAMS \
-       clean-generic clean-gstreamerLTLIBRARIES clean-libLTLIBRARIES \
-       clean-libtool clean-local clean-noinstLIBRARIES \
-       clean-noinstLTLIBRARIES clean-noinstPROGRAMS \
-       clean-pluginLTLIBRARIES clean-sbinPROGRAMS clean-udevPROGRAMS \
-       mostlyclean-am
+clean-am: clean-binPROGRAMS clean-cupsPROGRAMS clean-generic \
+       clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \
+       clean-local clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
+       clean-noinstPROGRAMS clean-pluginLTLIBRARIES \
+       clean-udevPROGRAMS mostlyclean-am
 
 distclean: distclean-am
        -rm -f $(am__CONFIG_DISTCLEAN_FILES)
-       -rm -rf alert/$(DEPDIR) attrib/$(DEPDIR) audio/$(DEPDIR) btio/$(DEPDIR) compat/$(DEPDIR) cups/$(DEPDIR) deviceinfo/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) health/$(DEPDIR) input/$(DEPDIR) lib/$(DEPDIR) mgmt/$(DEPDIR) monitor/$(DEPDIR) network/$(DEPDIR) plugins/$(DEPDIR) proximity/$(DEPDIR) sap/$(DEPDIR) sbc/$(DEPDIR) serial/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) thermometer/$(DEPDIR) time/$(DEPDIR) tools/$(DEPDIR) unit/$(DEPDIR)
+       -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
        -rm -f Makefile
 distclean-am: clean-am distclean-compile distclean-generic \
        distclean-hdr distclean-libtool distclean-tags
@@ -5521,20 +6128,20 @@ info: info-am
 
 info-am:
 
-install-data-am: install-alsaLTLIBRARIES install-alsaconfDATA \
-       install-confDATA install-cupsPROGRAMS install-dbusDATA \
-       install-dbusserviceDATA install-dist_udevSCRIPTS \
-       install-gstreamerLTLIBRARIES install-includeHEADERS \
-       install-man install-pkgconfigDATA install-pluginLTLIBRARIES \
-       install-rulesDATA install-stateDATA install-systemdunitDATA \
-       install-udevPROGRAMS
+install-data-am: install-confDATA install-cupsPROGRAMS \
+       install-dbusDATA install-dbussessionbusDATA \
+       install-dbussystembusDATA install-includeHEADERS install-man \
+       install-pkgconfigDATA install-pluginLTLIBRARIES \
+       install-rulesDATA install-stateDATA \
+       install-systemdsystemunitDATA install-systemduserunitDATA \
+       install-testSCRIPTS install-udevPROGRAMS
 
 install-dvi: install-dvi-am
 
 install-dvi-am:
 
 install-exec-am: install-binPROGRAMS install-libLTLIBRARIES \
-       install-sbinPROGRAMS
+       install-libexecPROGRAMS
 
 install-html: install-html-am
 
@@ -5559,7 +6166,7 @@ installcheck-am:
 maintainer-clean: maintainer-clean-am
        -rm -f $(am__CONFIG_DISTCLEAN_FILES)
        -rm -rf $(top_srcdir)/autom4te.cache
-       -rm -rf alert/$(DEPDIR) attrib/$(DEPDIR) audio/$(DEPDIR) btio/$(DEPDIR) compat/$(DEPDIR) cups/$(DEPDIR) deviceinfo/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) health/$(DEPDIR) input/$(DEPDIR) lib/$(DEPDIR) mgmt/$(DEPDIR) monitor/$(DEPDIR) network/$(DEPDIR) plugins/$(DEPDIR) proximity/$(DEPDIR) sap/$(DEPDIR) sbc/$(DEPDIR) serial/$(DEPDIR) src/$(DEPDIR) test/$(DEPDIR) thermometer/$(DEPDIR) time/$(DEPDIR) tools/$(DEPDIR) unit/$(DEPDIR)
+       -rm -rf android/$(DEPDIR) attrib/$(DEPDIR) btio/$(DEPDIR) client/$(DEPDIR) emulator/$(DEPDIR) gdbus/$(DEPDIR) gobex/$(DEPDIR) lib/$(DEPDIR) monitor/$(DEPDIR) obexd/client/$(DEPDIR) obexd/plugins/$(DEPDIR) obexd/src/$(DEPDIR) plugins/$(DEPDIR) profiles/alert/$(DEPDIR) profiles/audio/$(DEPDIR) profiles/cups/$(DEPDIR) profiles/cyclingspeed/$(DEPDIR) profiles/deviceinfo/$(DEPDIR) profiles/gatt/$(DEPDIR) profiles/health/$(DEPDIR) profiles/heartrate/$(DEPDIR) profiles/iap/$(DEPDIR) profiles/input/$(DEPDIR) profiles/network/$(DEPDIR) profiles/proximity/$(DEPDIR) profiles/sap/$(DEPDIR) profiles/scanparam/$(DEPDIR) profiles/thermometer/$(DEPDIR) profiles/time/$(DEPDIR) src/$(DEPDIR) src/shared/$(DEPDIR) tools/$(DEPDIR) tools/parser/$(DEPDIR) unit/$(DEPDIR)
        -rm -f Makefile
 maintainer-clean-am: distclean-am maintainer-clean-generic
 
@@ -5576,78 +6183,77 @@ ps: ps-am
 
 ps-am:
 
-uninstall-am: uninstall-alsaLTLIBRARIES uninstall-alsaconfDATA \
-       uninstall-binPROGRAMS uninstall-confDATA \
+uninstall-am: uninstall-binPROGRAMS uninstall-confDATA \
        uninstall-cupsPROGRAMS uninstall-dbusDATA \
-       uninstall-dbusserviceDATA uninstall-dist_udevSCRIPTS \
-       uninstall-gstreamerLTLIBRARIES uninstall-includeHEADERS \
-       uninstall-libLTLIBRARIES uninstall-man uninstall-pkgconfigDATA \
-       uninstall-pluginLTLIBRARIES uninstall-rulesDATA \
-       uninstall-sbinPROGRAMS uninstall-stateDATA \
-       uninstall-systemdunitDATA uninstall-udevPROGRAMS
+       uninstall-dbussessionbusDATA uninstall-dbussystembusDATA \
+       uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+       uninstall-libexecPROGRAMS uninstall-man \
+       uninstall-pkgconfigDATA uninstall-pluginLTLIBRARIES \
+       uninstall-rulesDATA uninstall-stateDATA \
+       uninstall-systemdsystemunitDATA uninstall-systemduserunitDATA \
+       uninstall-testSCRIPTS uninstall-udevPROGRAMS
 
 uninstall-man: uninstall-man1 uninstall-man8
 
 .MAKE: all check check-am install install-am install-strip
 
 .PHONY: CTAGS GTAGS all all-am am--refresh check check-TESTS check-am \
-       clean clean-alsaLTLIBRARIES clean-binPROGRAMS \
-       clean-cupsPROGRAMS clean-generic clean-gstreamerLTLIBRARIES \
-       clean-libLTLIBRARIES clean-libtool clean-local \
-       clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
+       clean clean-binPROGRAMS clean-cupsPROGRAMS clean-generic \
+       clean-libLTLIBRARIES clean-libexecPROGRAMS clean-libtool \
+       clean-local clean-noinstLIBRARIES clean-noinstLTLIBRARIES \
        clean-noinstPROGRAMS clean-pluginLTLIBRARIES \
-       clean-sbinPROGRAMS clean-udevPROGRAMS ctags dist dist-all \
-       dist-bzip2 dist-gzip dist-lzip dist-lzma dist-shar dist-tarZ \
-       dist-xz dist-zip distcheck distclean distclean-compile \
-       distclean-generic distclean-hdr distclean-libtool \
-       distclean-tags distcleancheck distdir distuninstallcheck dvi \
-       dvi-am html html-am info info-am install \
-       install-alsaLTLIBRARIES install-alsaconfDATA install-am \
-       install-binPROGRAMS install-confDATA install-cupsPROGRAMS \
-       install-data install-data-am install-dbusDATA \
-       install-dbusserviceDATA install-dist_udevSCRIPTS install-dvi \
-       install-dvi-am install-exec install-exec-am \
-       install-gstreamerLTLIBRARIES install-html install-html-am \
+       clean-udevPROGRAMS ctags dist dist-all dist-bzip2 dist-gzip \
+       dist-lzip dist-lzma dist-shar dist-tarZ dist-xz dist-zip \
+       distcheck distclean distclean-compile distclean-generic \
+       distclean-hdr distclean-libtool distclean-tags distcleancheck \
+       distdir distuninstallcheck dvi dvi-am html html-am info \
+       info-am install install-am install-binPROGRAMS \
+       install-confDATA install-cupsPROGRAMS install-data \
+       install-data-am install-dbusDATA install-dbussessionbusDATA \
+       install-dbussystembusDATA install-dvi install-dvi-am \
+       install-exec install-exec-am install-html install-html-am \
        install-includeHEADERS install-info install-info-am \
-       install-libLTLIBRARIES install-man install-man1 install-man8 \
-       install-pdf install-pdf-am install-pkgconfigDATA \
-       install-pluginLTLIBRARIES install-ps install-ps-am \
-       install-rulesDATA install-sbinPROGRAMS install-stateDATA \
-       install-strip install-systemdunitDATA install-udevPROGRAMS \
-       installcheck installcheck-am installdirs maintainer-clean \
-       maintainer-clean-generic mostlyclean mostlyclean-compile \
-       mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \
-       tags uninstall uninstall-alsaLTLIBRARIES \
-       uninstall-alsaconfDATA uninstall-am uninstall-binPROGRAMS \
-       uninstall-confDATA uninstall-cupsPROGRAMS uninstall-dbusDATA \
-       uninstall-dbusserviceDATA uninstall-dist_udevSCRIPTS \
-       uninstall-gstreamerLTLIBRARIES uninstall-includeHEADERS \
-       uninstall-libLTLIBRARIES uninstall-man uninstall-man1 \
+       install-libLTLIBRARIES install-libexecPROGRAMS install-man \
+       install-man1 install-man8 install-pdf install-pdf-am \
+       install-pkgconfigDATA install-pluginLTLIBRARIES install-ps \
+       install-ps-am install-rulesDATA install-stateDATA \
+       install-strip install-systemdsystemunitDATA \
+       install-systemduserunitDATA install-testSCRIPTS \
+       install-udevPROGRAMS installcheck installcheck-am installdirs \
+       maintainer-clean maintainer-clean-generic mostlyclean \
+       mostlyclean-compile mostlyclean-generic mostlyclean-libtool \
+       pdf pdf-am ps ps-am tags uninstall uninstall-am \
+       uninstall-binPROGRAMS uninstall-confDATA \
+       uninstall-cupsPROGRAMS uninstall-dbusDATA \
+       uninstall-dbussessionbusDATA uninstall-dbussystembusDATA \
+       uninstall-includeHEADERS uninstall-libLTLIBRARIES \
+       uninstall-libexecPROGRAMS uninstall-man uninstall-man1 \
        uninstall-man8 uninstall-pkgconfigDATA \
        uninstall-pluginLTLIBRARIES uninstall-rulesDATA \
-       uninstall-sbinPROGRAMS uninstall-stateDATA \
-       uninstall-systemdunitDATA uninstall-udevPROGRAMS
+       uninstall-stateDATA uninstall-systemdsystemunitDATA \
+       uninstall-systemduserunitDATA uninstall-testSCRIPTS \
+       uninstall-udevPROGRAMS
 
 
-@TOOLS_TRUE@tools/kword.c: tools/parser.h
+obexd/src/plugin.$(OBJEXT): obexd/src/builtin.h
 
-src/builtin.h: src/genbuiltin $(builtin_sources)
-       $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
+obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources)
+       $(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@
 
-audio/telephony.c: audio/@TELEPHONY_DRIVER@
-       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
+%.service: %.service.in Makefile
+       $(SED_PROCESS)
 
-sap/sap.c: sap/@SAP_DRIVER@
-       $(AM_V_GEN)$(LN_S) $(abs_top_srcdir)/$< $@
+src/builtin.h: src/genbuiltin $(builtin_sources)
+       $(AM_V_GEN)$(srcdir)/src/genbuiltin $(builtin_modules) > $@
 
-scripts/%.rules:
-       $(AM_V_GEN)cp $(subst 97-,,$@) $@
+tools/%.rules:
+       $(AM_V_GEN)cp $(srcdir)/$(subst 97-,,$@) $@
 
 $(lib_libbluetooth_la_OBJECTS): $(local_headers)
 
 lib/bluetooth/%.h: lib/%.h
        $(AM_V_at)$(MKDIR_P) lib/bluetooth
-       $(AM_V_GEN)$(LN_S) $(abs_top_builddir)/$< $@
+       $(AM_V_GEN)$(LN_S) -f $(abs_top_builddir)/$< $@
 
 clean-local:
        $(RM) -r lib/bluetooth
diff --git a/Makefile.obexd b/Makefile.obexd
new file mode 100644 (file)
index 0000000..3760867
--- /dev/null
@@ -0,0 +1,112 @@
+
+if SYSTEMD
+systemduserunitdir = @SYSTEMD_USERUNITDIR@
+systemduserunit_DATA = obexd/src/obex.service
+
+dbussessionbusdir = @DBUS_SESSIONBUSDIR@
+dbussessionbus_DATA = obexd/src/org.bluez.obex.service
+endif
+
+EXTRA_DIST += obexd/src/obex.service.in obexd/src/org.bluez.obex.service
+
+obex_plugindir = $(libdir)/obex/plugins
+
+obexd_builtin_modules =
+obexd_builtin_sources =
+obexd_builtin_nodist =
+
+obexd_builtin_modules += filesystem
+obexd_builtin_sources += obexd/plugins/filesystem.c obexd/plugins/filesystem.h
+
+obexd_builtin_modules += bluetooth
+obexd_builtin_sources += obexd/plugins/bluetooth.c
+
+if EXPERIMENTAL
+obexd_builtin_modules += pcsuite
+obexd_builtin_sources += obexd/plugins/pcsuite.c
+endif
+
+obexd_builtin_modules += opp
+obexd_builtin_sources += obexd/plugins/opp.c
+
+obexd_builtin_modules += ftp
+obexd_builtin_sources += obexd/plugins/ftp.c obexd/plugins/ftp.h
+
+if OBEX
+obexd_builtin_modules += irmc
+obexd_builtin_sources += obexd/plugins/irmc.c
+
+obexd_builtin_modules += pbap
+obexd_builtin_sources += obexd/plugins/pbap.c \
+                               obexd/plugins/vcard.h obexd/plugins/vcard.c \
+                               obexd/plugins/phonebook.h \
+                               obexd/plugins/phonebook-dummy.c
+endif
+
+obexd_builtin_modules += mas
+obexd_builtin_sources += obexd/plugins/mas.c obexd/src/map_ap.h \
+                               obexd/plugins/messages.h \
+                               obexd/plugins/messages-dummy.c
+
+obexd_builtin_modules += mns
+obexd_builtin_sources += obexd/client/mns.c obexd/src/map_ap.h \
+                               obexd/client/map-event.h
+
+libexec_PROGRAMS += obexd/src/obexd
+
+obexd_src_obexd_SOURCES = $(btio_sources) $(gobex_sources) \
+                       $(obexd_builtin_sources) \
+                       obexd/src/main.c obexd/src/obexd.h \
+                       obexd/src/plugin.h obexd/src/plugin.c \
+                       obexd/src/log.h obexd/src/log.c \
+                       obexd/src/manager.h obexd/src/manager.c \
+                       obexd/src/obex.h obexd/src/obex.c obexd/src/obex-priv.h \
+                       obexd/src/mimetype.h obexd/src/mimetype.c \
+                       obexd/src/service.h obexd/src/service.c \
+                       obexd/src/transport.h obexd/src/transport.c \
+                       obexd/src/server.h obexd/src/server.c \
+                       obexd/client/manager.h obexd/client/manager.c \
+                       obexd/client/session.h obexd/client/session.c \
+                       obexd/client/bluetooth.h obexd/client/bluetooth.c \
+                       obexd/client/sync.h obexd/client/sync.c \
+                       obexd/client/pbap.h obexd/client/pbap.c \
+                       obexd/client/ftp.h obexd/client/ftp.c \
+                       obexd/client/opp.h obexd/client/opp.c \
+                       obexd/client/map.h obexd/client/map.c \
+                       obexd/client/map-event.h obexd/client/map-event.c \
+                       obexd/client/transfer.h obexd/client/transfer.c \
+                       obexd/client/transport.h obexd/client/transport.c \
+                       obexd/client/dbus.h obexd/client/dbus.c \
+                       obexd/client/driver.h obexd/client/driver.c \
+                       obexd/src/map_ap.h
+obexd_src_obexd_LDADD = lib/libbluetooth-internal.la \
+                       gdbus/libgdbus-internal.la \
+                       @ICAL_LIBS@ @DBUS_LIBS@ @GLIB_LIBS@ -ldl
+
+obexd_src_obexd_LDFLAGS = -Wl,--export-dynamic
+
+obexd_src_obexd_CFLAGS = $(AM_CFLAGS) @GLIB_CFLAGS@ @DBUS_CFLAGS@ \
+                               @ICAL_CFLAGS@ -DOBEX_PLUGIN_BUILTIN \
+                               -DPLUGINDIR=\""$(obex_plugindir)"\" \
+                               -fPIC -D_FILE_OFFSET_BITS=64
+
+obexd_src_obexd_CPPFLAGS = -I$(builddir)/lib -I$(builddir)/obexd/src  \
+                               -I$(srcdir)/obexd/src -I$(srcdir)/btio \
+                               -I$(srcdir)/gobex -I$(srcdir)/gdbus
+
+obexd_src_obexd_SHORTNAME = obexd
+
+obexd_builtin_files = obexd/src/builtin.h $(obexd_builtin_nodist)
+
+nodist_obexd_src_obexd_SOURCES = $(obexd_builtin_files)
+
+BUILT_SOURCES += obexd/src/builtin.h
+
+obexd/src/plugin.$(OBJEXT): obexd/src/builtin.h
+
+obexd/src/builtin.h: obexd/src/genbuiltin $(obexd_builtin_sources)
+       $(AM_V_GEN)$(srcdir)/obexd/src/genbuiltin $(obexd_builtin_modules) > $@
+
+CLEANFILES += obexd/src/builtin.h $(builtin_files) obexd/src/obex.service
+
+EXTRA_DIST += obexd/src/genbuiltin
diff --git a/Makefile.plugins b/Makefile.plugins
new file mode 100644 (file)
index 0000000..7c5f71d
--- /dev/null
@@ -0,0 +1,112 @@
+
+builtin_modules += hostname
+builtin_sources += plugins/hostname.c
+
+builtin_modules += wiimote
+builtin_sources += plugins/wiimote.c
+
+builtin_modules += autopair
+builtin_sources += plugins/autopair.c
+
+builtin_modules += policy
+builtin_sources += plugins/policy.c
+
+if MAINTAINER_MODE
+builtin_modules += gatt_example
+builtin_sources += plugins/gatt-example.c
+endif
+
+if EXPERIMENTAL
+builtin_modules += neard
+builtin_sources += plugins/neard.c
+
+builtin_modules += sap
+builtin_sources += profiles/sap/main.c profiles/sap/manager.h \
+                       profiles/sap/manager.c profiles/sap/server.h \
+                       profiles/sap/server.c profiles/sap/sap.h \
+                       profiles/sap/sap-dummy.c
+
+noinst_LIBRARIES += profiles/sap/libsap.a
+profiles_sap_libsap_a_SOURCES = profiles/sap/sap.h profiles/sap/sap-u8500.c
+endif
+
+builtin_modules += a2dp
+builtin_sources += profiles/audio/source.h profiles/audio/source.c \
+                       profiles/audio/sink.h profiles/audio/sink.c \
+                       profiles/audio/a2dp.h profiles/audio/a2dp.c \
+                       profiles/audio/avdtp.h profiles/audio/avdtp.c \
+                       profiles/audio/media.h profiles/audio/media.c \
+                       profiles/audio/transport.h profiles/audio/transport.c \
+                       profiles/audio/a2dp-codecs.h
+
+builtin_modules += avrcp
+builtin_sources += profiles/audio/control.h profiles/audio/control.c \
+                       profiles/audio/avctp.h profiles/audio/avctp.c \
+                       profiles/audio/avrcp.h profiles/audio/avrcp.c \
+                       profiles/audio/player.h profiles/audio/player.c
+
+builtin_modules += network
+builtin_sources += profiles/network/manager.c \
+                       profiles/network/common.h profiles/network/common.c \
+                       profiles/network/server.h profiles/network/server.c \
+                       profiles/network/connection.h \
+                       profiles/network/connection.c
+
+builtin_modules += input
+builtin_sources += profiles/input/manager.c \
+                       profiles/input/server.h profiles/input/server.c \
+                       profiles/input/device.h profiles/input/device.c
+
+builtin_modules += hog
+builtin_sources += profiles/input/hog.c profiles/input/uhid_copy.h \
+                       profiles/input/suspend.h profiles/input/suspend-dummy.c
+
+if EXPERIMENTAL
+builtin_modules += health
+builtin_sources += profiles/health/mcap_lib.h profiles/health/mcap_internal.h \
+                       profiles/health/mcap.h profiles/health/mcap.c \
+                       profiles/health/mcap_sync.c \
+                       profiles/health/hdp_main.c profiles/health/hdp_types.h \
+                       profiles/health/hdp_manager.h \
+                       profiles/health/hdp_manager.c \
+                       profiles/health/hdp.h profiles/health/hdp.c \
+                       profiles/health/hdp_util.h profiles/health/hdp_util.c
+endif
+
+builtin_modules += gatt
+builtin_sources += profiles/gatt/gas.c
+
+builtin_modules += scanparam
+builtin_sources += profiles/scanparam/scan.c
+
+builtin_modules += deviceinfo
+builtin_sources += profiles/deviceinfo/deviceinfo.c
+
+if EXPERIMENTAL
+builtin_modules += alert
+builtin_sources += profiles/alert/server.c
+
+builtin_modules += time
+builtin_sources += profiles/time/server.c
+
+builtin_modules += proximity
+builtin_sources += profiles/proximity/main.c profiles/proximity/manager.h \
+                       profiles/proximity/manager.c \
+                       profiles/proximity/monitor.h \
+                       profiles/proximity/monitor.c \
+                       profiles/proximity/reporter.h \
+                       profiles/proximity/reporter.c \
+                       profiles/proximity/linkloss.h \
+                       profiles/proximity/linkloss.c \
+                       profiles/proximity/immalert.h \
+                       profiles/proximity/immalert.c
+
+builtin_modules += thermometer
+builtin_sources += profiles/thermometer/thermometer.c
+
+builtin_modules += heartrate
+builtin_sources += profiles/heartrate/heartrate.c
+
+builtin_modules += cyclingspeed
+builtin_sources += profiles/cyclingspeed/cyclingspeed.c
+endif
index 5b1efb8..840b95c 100644 (file)
 
-if TOOLS
-if DATAFILES
-conf_DATA += tools/rfcomm.conf
+if CLIENT
+bin_PROGRAMS += client/bluetoothctl
+
+client_bluetoothctl_SOURCES = client/main.c \
+                                       client/display.h client/display.c \
+                                       client/agent.h client/agent.c \
+                                       monitor/uuid.h monitor/uuid.c
+client_bluetoothctl_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@ \
+                               -lreadline
 endif
 
-bin_PROGRAMS += tools/rfcomm tools/l2ping \
-                               tools/hcitool tools/sdptool tools/ciptool
-
-sbin_PROGRAMS += tools/hciattach tools/hciconfig
-
-noinst_PROGRAMS += tools/avinfo tools/ppporc \
-                               tools/hcieventmask tools/hcisecfilter
-
-tools/kword.c: tools/parser.h
-
-tools_rfcomm_SOURCES = tools/rfcomm.c tools/parser.y tools/lexer.l \
-                                       tools/kword.h tools/kword.c
-EXTRA_tools_rfcomm_SOURCES = tools/parser.h tools/parser.c \
-                                                       tools/lexer.c
-tools_rfcomm_LDADD = lib/libbluetooth-private.la
-
-tools_l2ping_LDADD = lib/libbluetooth-private.la
-
-tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
-                                               tools/hciattach_st.c \
-                                               tools/hciattach_ti.c \
-                                               tools/hciattach_tialt.c \
-                                               tools/hciattach_ath3k.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 \
-                                               src/textfile.h src/textfile.c
-tools_hciconfig_LDADD = lib/libbluetooth-private.la
-
-tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c \
-                                               src/textfile.h src/textfile.c
-tools_hcitool_LDADD = lib/libbluetooth-private.la
-
-tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
-tools_sdptool_LDADD = lib/libbluetooth-private.la
-
-tools_ciptool_LDADD = lib/libbluetooth-private.la
-
-tools_avinfo_LDADD = lib/libbluetooth-private.la
-
-tools_ppporc_LDADD = lib/libbluetooth-private.la
-
-tools_hcieventmask_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@
+if MONITOR
+bin_PROGRAMS += monitor/btmon
 
 monitor_btmon_SOURCES = monitor/main.c monitor/bt.h \
                                        monitor/mainloop.h monitor/mainloop.c \
+                                       monitor/display.h monitor/display.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
+                                       monitor/packet.h monitor/packet.c \
+                                       monitor/vendor.h monitor/vendor.c \
+                                       monitor/lmp.h monitor/lmp.c \
+                                       monitor/l2cap.h monitor/l2cap.c \
+                                       monitor/uuid.h monitor/uuid.c \
+                                       monitor/sdp.h monitor/sdp.c \
+                                       monitor/crc.h monitor/crc.c \
+                                       monitor/ll.h monitor/ll.c
+monitor_btmon_LDADD = lib/libbluetooth-internal.la
+endif
+
+if EXPERIMENTAL
+noinst_PROGRAMS += emulator/btvirt emulator/b1ee \
+                                       tools/mgmt-tester tools/gap-tester \
+                                       tools/l2cap-tester tools/sco-tester
 
 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
-
-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 src/log.c
-attrib_gatttool_LDADD = lib/libbluetooth-private.la @GLIB_LIBS@ @READLINE_LIBS@
+                                       emulator/btdev.h emulator/btdev.c \
+                                       emulator/bthost.h emulator/bthost.c \
+                                       emulator/amp.h emulator/amp.c
+
+emulator_b1ee_SOURCES = emulator/b1ee.c monitor/mainloop.h monitor/mainloop.c
+
+tools_mgmt_tester_SOURCES = tools/mgmt-tester.c monitor/bt.h \
+                               emulator/btdev.h emulator/btdev.c \
+                               emulator/bthost.h emulator/bthost.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c \
+                               src/shared/hciemu.h src/shared/hciemu.c \
+                               src/shared/tester.h src/shared/tester.c
+tools_mgmt_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_l2cap_tester_SOURCES = tools/l2cap-tester.c monitor/bt.h \
+                               emulator/btdev.h emulator/btdev.c \
+                               emulator/bthost.h emulator/bthost.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c \
+                               src/shared/hciemu.h src/shared/hciemu.c \
+                               src/shared/tester.h src/shared/tester.c
+tools_l2cap_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_gap_tester_SOURCES = tools/gap-tester.c monitor/bt.h \
+                               emulator/btdev.h emulator/btdev.c \
+                               emulator/bthost.h emulator/bthost.c \
+                               src/shared/hciemu.h src/shared/hciemu.c \
+                               src/shared/tester.h src/shared/tester.c
+tools_gap_tester_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+
+tools_sco_tester_SOURCES = tools/sco-tester.c monitor/bt.h \
+                               emulator/btdev.h emulator/btdev.c \
+                               emulator/bthost.h emulator/bthost.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c \
+                               src/shared/hciemu.h src/shared/hciemu.c \
+                               src/shared/tester.h src/shared/tester.c
+tools_sco_tester_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 endif
 
-dist_man_MANS += tools/rfcomm.1 tools/l2ping.8 \
-                       tools/hciattach.8 tools/hciconfig.8 \
-                       tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
-else
-EXTRA_DIST += tools/rfcomm.1 tools/l2ping.8 \
-                       tools/hciattach.8 tools/hciconfig.8 \
-                       tools/hcitool.1 tools/sdptool.1 tools/ciptool.1
-endif
+if TOOLS
+bin_PROGRAMS += tools/hciattach tools/hciconfig tools/hcitool tools/hcidump \
+                       tools/rfcomm tools/rctest tools/l2test tools/l2ping \
+                       tools/sdptool tools/ciptool tools/bccmd
 
-CLEANFILES += tools/lexer.c tools/parser.c tools/parser.h
+tools_hciattach_SOURCES = tools/hciattach.c tools/hciattach.h \
+                                               tools/hciattach_st.c \
+                                               tools/hciattach_ti.c \
+                                               tools/hciattach_tialt.c \
+                                               tools/hciattach_ath3k.c \
+                                               tools/hciattach_qualcomm.c \
+                                               tools/hciattach_intel.c
+tools_hciattach_LDADD = lib/libbluetooth-internal.la
+
+tools_hciconfig_SOURCES = tools/hciconfig.c tools/csr.h tools/csr.c
+tools_hciconfig_LDADD = lib/libbluetooth-internal.la
+
+tools_hcitool_SOURCES = tools/hcitool.c src/oui.h src/oui.c
+tools_hcitool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ @UDEV_LIBS@
+
+tools_hcidump_SOURCES = tools/hcidump.c \
+                               tools/parser/parser.h tools/parser/parser.c \
+                               tools/parser/lmp.c \
+                               tools/parser/hci.c \
+                               tools/parser/l2cap.h tools/parser/l2cap.c \
+                               tools/parser/amp.c \
+                               tools/parser/smp.c \
+                               tools/parser/att.c \
+                               tools/parser/sdp.h tools/parser/sdp.c \
+                               tools/parser/rfcomm.h tools/parser/rfcomm.c \
+                               tools/parser/bnep.c \
+                               tools/parser/cmtp.c \
+                               tools/parser/hidp.c \
+                               tools/parser/hcrp.c \
+                               tools/parser/avdtp.c \
+                               tools/parser/avctp.c \
+                               tools/parser/avrcp.c \
+                               tools/parser/sap.c \
+                               tools/parser/obex.c \
+                               tools/parser/capi.c \
+                               tools/parser/ppp.c \
+                               tools/parser/tcpip.c \
+                               tools/parser/ericsson.c \
+                               tools/parser/csr.c \
+                               tools/parser/bpa.c
+tools_hcidump_LDADD = lib/libbluetooth-internal.la
+
+tools_rfcomm_LDADD = lib/libbluetooth-internal.la
+
+tools_rctest_LDADD = lib/libbluetooth-internal.la
+
+tools_l2test_LDADD = lib/libbluetooth-internal.la
+
+tools_l2ping_LDADD = lib/libbluetooth-internal.la
 
-EXTRA_DIST += tools/rfcomm.conf
+tools_sdptool_SOURCES = tools/sdptool.c src/sdp-xml.h src/sdp-xml.c
+tools_sdptool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-if BCCMD
-sbin_PROGRAMS += tools/bccmd
+tools_ciptool_LDADD = lib/libbluetooth-internal.la
 
 tools_bccmd_SOURCES = tools/bccmd.c tools/csr.h tools/csr.c \
-                       tools/csr_hci.c tools/csr_h4.c tools/csr_3wire.c \
+                       tools/csr_hci.c tools/csr_usb.c \
+                       tools/csr_h4.c tools/csr_3wire.c \
                        tools/csr_bcsp.c tools/ubcsp.h tools/ubcsp.c
-tools_bccmd_LDADD = lib/libbluetooth-private.la
+tools_bccmd_LDADD = lib/libbluetooth-internal.la
 
-if USB
-tools_bccmd_SOURCES += tools/csr_usb.c
-tools_bccmd_LDADD += @USB_LIBS@
-endif
-
-dist_man_MANS += tools/bccmd.8
+dist_man_MANS += tools/hciattach.1 tools/hciconfig.1 \
+                       tools/hcitool.1 tools/hcidump.1 \
+                       tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+                       tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
 else
-EXTRA_DIST += tools/bccmd.8
+EXTRA_DIST += tools/hciattach.1 tools/hciconfig.1 \
+                       tools/hcitool.1 tools/hcidump.1 \
+                       tools/rfcomm.1 tools/rctest.1 tools/l2ping.1 \
+                       tools/sdptool.1 tools/ciptool.1 tools/bccmd.1
 endif
 
 if HID2HCI
@@ -115,153 +162,123 @@ udevdir = @UDEV_DIR@
 
 udev_PROGRAMS = tools/hid2hci
 
-tools_hid2hci_LDADD = @USB_LIBS@ @UDEV_LIBS@
+tools_hid2hci_LDADD = @UDEV_LIBS@
 
-dist_man_MANS += tools/hid2hci.8
+dist_man_MANS += tools/hid2hci.1
 else
-EXTRA_DIST += tools/hid2hci.8
-endif
-
-if DFUTOOL
-bin_PROGRAMS += tools/dfutool
-
-tools_dfutool_SOURCES = tools/dfutool.c tools/dfu.h tools/dfu.c
-tools_dfutool_LDADD = @USB_LIBS@
-
-dist_man_MANS += tools/dfutool.1
-else
-EXTRA_DIST += tools/dfutool.1
-endif
-
-
-if USB
-noinst_PROGRAMS += tools/dfubabel tools/avctrl
-
-tools_dfubabel_LDADD = @USB_LIBS@
-
-tools_avctrl_LDADD = @USB_LIBS@
+EXTRA_DIST += tools/hid2hci.1
 endif
 
-EXTRA_DIST += tools/dfubabel.1 tools/avctrl.8
-
-
-if CUPS
-cupsdir = $(libdir)/cups/backend
+if EXPERIMENTAL
+noinst_PROGRAMS += tools/bdaddr tools/avinfo tools/avtest \
+                       tools/scotest tools/amptest tools/hwdb \
+                       tools/hcieventmask tools/hcisecfilter \
+                       tools/btmgmt tools/btinfo tools/btattach \
+                       tools/btsnoop tools/btiotest tools/cltest \
+                       tools/mpris-player
 
-cups_PROGRAMS = cups/bluetooth
+tools_bdaddr_SOURCES = tools/bdaddr.c src/oui.h src/oui.c
+tools_bdaddr_LDADD = lib/libbluetooth-internal.la @UDEV_LIBS@
 
-cups_bluetooth_SOURCES = $(gdbus_sources) cups/main.c cups/cups.h \
-                                       cups/sdp.c cups/spp.c cups/hcrp.c
+tools_avinfo_LDADD = lib/libbluetooth-internal.la
 
-cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ lib/libbluetooth-private.la
-endif
+tools_avtest_LDADD = lib/libbluetooth-internal.la
 
+tools_scotest_LDADD = lib/libbluetooth-internal.la
 
-if TEST
-sbin_PROGRAMS += test/hciemu
+tools_amptest_LDADD = lib/libbluetooth-internal.la
 
-bin_PROGRAMS += test/l2test test/rctest
+tools_hwdb_LDADD = lib/libbluetooth-internal.la
 
-noinst_PROGRAMS += test/gaptest test/sdptest test/scotest \
-                       test/attest test/hstest test/avtest test/ipctest \
-                                       test/lmptest test/bdaddr test/agent \
-                                       test/btiotest test/test-textfile \
-                                       test/uuidtest test/mpris-player
+tools_hcieventmask_LDADD = lib/libbluetooth-internal.la
 
-test_hciemu_LDADD = lib/libbluetooth-private.la
+tools_btmgmt_SOURCES = tools/btmgmt.c src/glib-helper.c src/eir.c \
+                               src/shared/util.h src/shared/util.c \
+                               src/shared/mgmt.h src/shared/mgmt.c
+tools_btmgmt_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-test_l2test_LDADD = lib/libbluetooth-private.la
+tools_btinfo_SOURCES = tools/btinfo.c
 
-test_rctest_LDADD = lib/libbluetooth-private.la
+tools_btsnoop_SOURCES = tools/btsnoop.c \
+                               src/shared/pcap.h src/shared/pcap.c \
+                               src/shared/btsnoop.h src/shared/btsnoop.c
 
-test_gaptest_LDADD = @DBUS_LIBS@
+tools_btiotest_SOURCES = tools/btiotest.c btio/btio.h btio/btio.c
+tools_btiotest_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
 
-test_sdptest_LDADD = lib/libbluetooth-private.la
+tools_mpris_player_SOURCES = tools/mpris-player.c
+tools_mpris_player_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
 
-test_scotest_LDADD = lib/libbluetooth-private.la
+tools_cltest_SOURCES = tools/cltest.c monitor/mainloop.h monitor/mainloop.c
+tools_cltest_LDADD = lib/libbluetooth-internal.la
 
-test_attest_LDADD = lib/libbluetooth-private.la
-
-test_hstest_LDADD = lib/libbluetooth-private.la
-
-test_avtest_LDADD = lib/libbluetooth-private.la
-
-test_lmptest_LDADD = lib/libbluetooth-private.la
-
-test_ipctest_SOURCES = test/ipctest.c audio/ipc.h audio/ipc.c
-test_ipctest_LDADD= @GLIB_LIBS@ sbc/libsbc.la
+EXTRA_DIST += tools/bdaddr.1
+endif
 
-test_bdaddr_SOURCES = test/bdaddr.c src/oui.h src/oui.c
-test_bdaddr_LDADD = lib/libbluetooth-private.la
+if READLINE
+noinst_PROGRAMS += attrib/gatttool \
+                       tools/obex-client-tool tools/obex-server-tool \
+                       tools/bluetooth-player tools/obexctl
 
-test_agent_LDADD = @DBUS_LIBS@
+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 src/log.c client/display.c \
+                               client/display.h
+attrib_gatttool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@ -lreadline
+
+tools_obex_client_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+                                               tools/obex-client-tool.c
+tools_obex_client_tool_LDADD = lib/libbluetooth-internal.la \
+                                               @GLIB_LIBS@ -lreadline
+
+tools_obex_server_tool_SOURCES = $(gobex_sources) $(btio_sources) \
+                                               tools/obex-server-tool.c
+tools_obex_server_tool_LDADD = lib/libbluetooth-internal.la @GLIB_LIBS@
+
+tools_bluetooth_player_SOURCES = tools/bluetooth-player.c \
+                               client/display.h client/display.c
+tools_bluetooth_player_LDADD = gdbus/libgdbus-internal.la \
+                               @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+
+tools_obexctl_SOURCES = tools/obexctl.c \
+                               client/display.h client/display.c
+tools_obexctl_LDADD = gdbus/libgdbus-internal.la \
+                               @GLIB_LIBS@ @DBUS_LIBS@ -lreadline
+endif
 
-test_btiotest_SOURCES = test/btiotest.c btio/btio.h btio/btio.c
-test_btiotest_LDADD = @GLIB_LIBS@ lib/libbluetooth-private.la
+if EXPERIMENTAL
+noinst_PROGRAMS += profiles/iap/iapd
 
-test_uuidtest_SOURCES = test/uuidtest.c
-test_uuidtest_LDADD = lib/libbluetooth-private.la
+profiles_iap_iapd_SOURCES = profiles/iap/main.c
+profiles_iap_iapd_LDADD = gdbus/libgdbus-internal.la @GLIB_LIBS@ @DBUS_LIBS@
+endif
 
-test_mpris_player_SOURCES = test/mpris-player.c
-test_mpris_player_LDADD = @DBUS_LIBS@ @GLIB_LIBS@
+if CUPS
+cupsdir = $(libdir)/cups/backend
 
-test_test_textfile_SOURCES = test/test-textfile.c src/textfile.h src/textfile.c
+cups_PROGRAMS = profiles/cups/bluetooth
 
-dist_man_MANS += test/rctest.1 test/hciemu.1
+profiles_cups_bluetooth_SOURCES = profiles/cups/main.c \
+                                       profiles/cups/cups.h \
+                                       profiles/cups/sdp.c \
+                                       profiles/cups/spp.c \
+                                       profiles/cups/hcrp.c
 
-EXTRA_DIST += test/bdaddr.8
-else
-EXTRA_DIST += test/rctest.1 test/hciemu.1 test/bdaddr.8
+profiles_cups_bluetooth_LDADD = @GLIB_LIBS@ @DBUS_LIBS@ \
+                               lib/libbluetooth-internal.la \
+                               gdbus/libgdbus-internal.la
 endif
 
-EXTRA_DIST += test/sap-client test/hsplay test/hsmicro \
+test_scripts += test/sap_client.py test/bluezutils.py \
                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-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/simple-player test/test-nap
-
-if HIDD
-bin_PROGRAMS += compat/hidd
-
-compat_hidd_SOURCES = compat/hidd.c compat/hidd.h src/uinput.h \
-                               compat/sdp.h compat/sdp.c compat/fakehid.c \
-                                               src/textfile.h src/textfile.c
-compat_hidd_LDADD = -lm lib/libbluetooth-private.la
-
-dist_man_MANS += compat/hidd.1
-else
-EXTRA_DIST += compat/hidd.1
-endif
-
-if PAND
-bin_PROGRAMS += compat/pand
-
-compat_pand_SOURCES = compat/pand.c compat/pand.h \
-                               compat/bnep.c compat/sdp.h compat/sdp.c \
-                                               src/textfile.h src/textfile.c
-compat_pand_LDADD = lib/libbluetooth-private.la
-
-dist_man_MANS += compat/pand.1
-else
-EXTRA_DIST += compat/pand.1
-endif
-
-if DUND
-bin_PROGRAMS += compat/dund
-
-compat_dund_SOURCES = compat/dund.c compat/dund.h compat/lib.h \
-                       compat/sdp.h compat/sdp.c compat/dun.c compat/msdun.c \
-                                               src/textfile.h src/textfile.c
-compat_dund_LDADD = lib/libbluetooth-private.la
-
-dist_man_MANS += compat/dund.1
-else
-EXTRA_DIST += compat/dund.1
-endif
+               test/test-device test/simple-agent \
+               test/simple-service test/simple-endpoint test/test-sap-server \
+               test/test-proximity test/test-network \
+               test/test-thermometer test/test-profile 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/simple-player test/test-nap \
+               test/test-heartrate test/test-alert test/test-hfp \
+               test/test-cyclingspeed
diff --git a/README b/README
index 77778e0..c991ab0 100644 (file)
--- a/README
+++ b/README
@@ -10,17 +10,15 @@ Compilation and installation
 ============================
 
 In order to compile Bluetooth utilities you need following software packages:
-       - Linux Bluetooth protocol stack (BlueZ)
        - GCC compiler
-       - D-Bus library
        - GLib library
-       - USB library (optional)
-       - Lexical Analyzer (flex, lex)
-       - YACC (yacc, bison, byacc)
+       - D-Bus library
+       - udev library (optional)
+       - readline (command line clients)
 
 To configure run:
        ./configure --prefix=/usr --mandir=/usr/share/man \
-               --sysconfdir=/etc --localstatedir=/var --libexecdir=/lib
+                               --sysconfdir=/etc --localstatedir=/var
 
 Configure automatically searches for all required components and packages.
 
@@ -28,6 +26,97 @@ To compile and install run:
        make && make install
 
 
+Configuration and options
+=========================
+
+For a working system, certain configuration options need to be enabled:
+
+       --enable-library
+
+               Enable installation of Bluetooth library
+
+               By default the Bluetooth library is no longer installed.
+
+               The user interfaces or command line utilities do not
+               require an installed Bluetooth library anymore. This
+               option is provided for legacy third party applications
+               that still depend on the library.
+
+               When the library installation is enabled, it is a good
+               idea to use a separate bluez-library or libbluetooth
+               package for it.
+
+       --disable-tools
+
+               Disable support for Bluetooth utilities
+
+               By default the Bluetooth utilities are built and also
+               installed. For production systems the tools are not
+               needed and this option allows to disable them to save
+               build time and disk space.
+
+               When the tools are selected, it is a good idea to
+               use a separate bluez-tools package for them.
+
+       --disable-cups
+
+               Disable support for CUPS printer backend
+
+               By default the printer backend for CUPS is build and
+               also installed. For systems that do not require printing
+               over Bluetooth, this options allows to disable it.
+
+               When the CUPS backend is selected, it is a good idea to
+               use a separate bluez-cups package for it.
+
+       --disable-monitor
+
+               Disable support for the Bluetooth monitor utility
+
+               By default the monitor utility is enabled. It provides
+               support for HCI level tracing and debugging. For systems
+               that don't require any kind of tracing or debugging
+               capabilities, this options allows to disable it.
+
+               The monitor utility should be placed in the main package
+               along with the daemons. It is universally useful.
+
+       --disable-client
+
+               Disable support for the command line client
+
+               By default the command line client is enabled and uses the
+               readline library. For specific systems where BlueZ is
+               configured by other means, the command line client can be
+               disabled and the dependency on readline is removed.
+
+               The client should be placed in the main package along
+               with the daemons. It is universally useful.
+
+       --disable-systemd
+
+               Disable integration with systemd
+
+               By default the integration with systemd is enabled and
+               installed. This gives the best integration into all
+               distributions based on systemd.
+
+               This option is provided for distributions that do not
+               support systemd. In that case all integration with the
+               init system is up to the package.
+
+       --enable-experimental
+
+               Enable experimental plugins
+
+               By default all plugins that are still in development
+               are disabled. This option can be used to enable them.
+
+               It is not recommended to enable this option for production
+               systems. The APIs or behavior of the experimental plugins
+               is unstable and might still change.
+
+
 Information
 ===========
 
diff --git a/TODO b/TODO
index 17e9848..7bb100b 100644 (file)
--- a/TODO
+++ b/TODO
@@ -24,12 +24,36 @@ General
   Priority: high
   Complexity: C4
 
-- Rename glib-helper file to a more convenient name. The ideia is try to keep
+- Rename glib-helper file to a more convenient name. The idea is try to keep
   only sdp helpers functions. bt_* prefix shall be also changed.
 
   Priority: Low
   Complexity: C1
 
+- Function in src/adapter.c to convert old storage files to new ini-file format
+  should be removed 6-8 months after first BlueZ 5 release.
+
+  Priority: Low
+  Complexity: C1
+
+- Remove usage of symlinks for drivers, such as profiles/input/suspend.c and
+  profiles/sap/sap.c. Instead, select drivers at runtime by using config
+  options or probing for running D-Bus services (using e.g.
+  g_dbus_add_service_watch()). Idea first mentioned on
+  http://thread.gmane.org/gmane.linux.bluez.kernel/30175/focus=30190.
+
+- Reuse connection handling code of src/profile.c also for built-in profiles
+  so plugins would only need to register their btd_profile and the core takes
+  care of the rest including listen to the right channel and manages the sdp
+  record. Once btd_profile manages the connection it can also notify about
+  their state, this probably remove the need of having callbacks to
+  .connect/.disconnect since their state can be tracked, it also enables any
+  plugin to track any profile state change which can be useful for e.g.
+  a connection policy plugin in case one is needed.
+
+  Priority: Low
+  Complexity: C2
+
 Low Energy
 ==========
 
@@ -86,7 +110,7 @@ Low Energy
   Complexity: C1
 
 - Static random address setup and storage. Once this address is written
-  in the a given remote, the address can not be changed anymore.
+  in a given remote, the address can not be changed anymore.
 
   Priority: Low
   Complexity: C1
@@ -101,7 +125,7 @@ Low Energy
 
 - Device Name Characteristic is a GAP characteristic for Low Energy. This
   characteristic shall be integrated/used in the discovery procedure. The
-  ideia is to report the value of this characteristic using DeviceFound signals.
+  idea is to report the value of this characteristic using DeviceFound signals.
   Discussion with the community is needed before to start this task. Other GAP
   characteristics for LE needs to follow a similar approach. It is not clear
   if all GAP characteristics can be exposed using properties instead of a primary
@@ -191,7 +215,7 @@ ATT/GATT
   Priority: Low
   Complecity: C1
 
-- Add sdp discovery support to gattool with BR (--sdp, default is 0x1f)
+- Add sdp discovery support to gatttool with BR (--sdp, default is 0x1f)
 
   Priority: Low
   Complexity: C1
index 1d6d736..5bfa29d 100644 (file)
@@ -22,380 +22,33 @@ AC_DEFUN([COMPILER_FLAGS], [
                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], [
-       AC_CHECK_FUNC(ppoll, dummy=yes, AC_DEFINE(NEED_PPOLL, 1,
-                       [Define to 1 if you need the ppoll() function.]))
-])
-
-AC_DEFUN([AC_INIT_BLUEZ], [
-       AC_PREFIX_DEFAULT(/usr/local)
-
-       if (test "${prefix}" = "NONE"); then
-               dnl no prefix and no sysconfdir, so default to /etc
-               if (test "$sysconfdir" = '${prefix}/etc'); then
-                       AC_SUBST([sysconfdir], ['/etc'])
-               fi
-
-               dnl no prefix and no localstatedir, so default to /var
-               if (test "$localstatedir" = '${prefix}/var'); then
-                       AC_SUBST([localstatedir], ['/var'])
-               fi
-
-               dnl no prefix and no libexecdir, so default to /lib
-               if (test "$libexecdir" = '${exec_prefix}/libexec'); then
-                       AC_SUBST([libexecdir], ['/lib'])
-               fi
-
-               dnl no prefix and no mandir, so use ${prefix}/share/man as default
-               if (test "$mandir" = '${prefix}/man'); then
-                       AC_SUBST([mandir], ['${prefix}/share/man'])
+AC_DEFUN([MISC_FLAGS], [
+       misc_cflags=""
+       misc_ldflags=""
+       AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization],
+                       [disable code optimization through compiler]), [
+               if (test "${enableval}" = "no"); then
+                       misc_cflags="$misc_cflags -O0"
                fi
-
-               prefix="${ac_default_prefix}"
-       fi
-
-       if (test "${libdir}" = '${exec_prefix}/lib'); then
-               libdir="${prefix}/lib"
-       fi
-
-       plugindir="${libdir}/bluetooth/plugins"
-
-       if (test "$sysconfdir" = '${prefix}/etc'); then
-               configdir="${prefix}/etc/bluetooth"
-       else
-               configdir="${sysconfdir}/bluetooth"
-       fi
-
-       if (test "$localstatedir" = '${prefix}/var'); then
-               storagedir="${prefix}/var/lib/bluetooth"
-       else
-               storagedir="${localstatedir}/lib/bluetooth"
-       fi
-
-       AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
-                               [Directory for the configuration files])
-       AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
-                               [Directory for the storage files])
-
-       AC_SUBST(CONFIGDIR, "${configdir}")
-       AC_SUBST(STORAGEDIR, "${storagedir}")
-
-       UDEV_DIR="`$PKG_CONFIG --variable=udevdir udev`"
-       if (test -z "${UDEV_DIR}"); then
-               UDEV_DIR="/lib/udev"
-       fi
-       AC_SUBST(UDEV_DIR)
-])
-
-AC_DEFUN([AC_PATH_DBUS], [
-       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.28, dummy=yes,
-                               AC_MSG_ERROR(GLib >= 2.28 is required))
-       AC_SUBST(GLIB_CFLAGS)
-       AC_SUBST(GLIB_LIBS)
-])
-
-AC_DEFUN([AC_PATH_GSTREAMER], [
-       PKG_CHECK_MODULES(GSTREAMER, gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10, gstreamer_found=yes,
-                               AC_MSG_WARN(GStreamer library version 0.10.30 or later is required);gstreamer_found=no)
-       AC_SUBST(GSTREAMER_CFLAGS)
-       AC_SUBST(GSTREAMER_LIBS)
-       GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
-       AC_SUBST(GSTREAMER_PLUGINSDIR)
-])
-
-AC_DEFUN([AC_PATH_ALSA], [
-       PKG_CHECK_MODULES(ALSA, alsa, alsa_found=yes, alsa_found=no)
-       AC_CHECK_LIB(rt, clock_gettime, ALSA_LIBS="$ALSA_LIBS -lrt", alsa_found=no)
-       AC_SUBST(ALSA_CFLAGS)
-       AC_SUBST(ALSA_LIBS)
-])
-
-AC_DEFUN([AC_PATH_USB], [
-       PKG_CHECK_MODULES(USB, libusb, usb_found=yes, usb_found=no)
-       AC_SUBST(USB_CFLAGS)
-       AC_SUBST(USB_LIBS)
-       AC_CHECK_LIB(usb, usb_get_busses, dummy=yes,
-               AC_DEFINE(NEED_USB_GET_BUSSES, 1,
-                       [Define to 1 if you need the usb_get_busses() function.]))
-       AC_CHECK_LIB(usb, usb_interrupt_read, dummy=yes,
-               AC_DEFINE(NEED_USB_INTERRUPT_READ, 1,
-                       [Define to 1 if you need the usb_interrupt_read() function.]))
-])
-
-AC_DEFUN([AC_PATH_UDEV], [
-       PKG_CHECK_MODULES(UDEV, libudev, udev_found=yes, udev_found=no)
-       AC_SUBST(UDEV_CFLAGS)
-       AC_SUBST(UDEV_LIBS)
-])
-
-AC_DEFUN([AC_PATH_SNDFILE], [
-       PKG_CHECK_MODULES(SNDFILE, sndfile, sndfile_found=yes, sndfile_found=no)
-       AC_SUBST(SNDFILE_CFLAGS)
-       AC_SUBST(SNDFILE_LIBS)
-])
-
-AC_DEFUN([AC_PATH_READLINE], [
-       AC_CHECK_HEADER(readline/readline.h,
-               AC_CHECK_LIB(readline, main,
-                       [ readline_found=yes
-                       AC_SUBST(READLINE_LIBS, "-lreadline")
-                       ], readline_found=no),
-               [])
-])
-
-AC_DEFUN([AC_PATH_CHECK], [
-       PKG_CHECK_MODULES(CHECK, check >= 0.9.6, check_found=yes, check_found=no)
-       AC_SUBST(CHECK_CFLAGS)
-       AC_SUBST(CHECK_LIBS)
-])
-
-AC_DEFUN([AC_PATH_OUI], [
-       AC_ARG_WITH(ouifile,
-                   AS_HELP_STRING([--with-ouifile=PATH],[Path to the oui.txt file @<:@auto@:>@]),
-                   [ac_with_ouifile=$withval],
-                   [ac_with_ouifile="/var/lib/misc/oui.txt"])
-       AC_DEFINE_UNQUOTED(OUIFILE, ["$ac_with_ouifile"], [Define the OUI file path])
-])
-
-AC_DEFUN([AC_ARG_BLUEZ], [
-       debug_enable=no
-       optimization_enable=yes
-       fortify_enable=yes
-       pie_enable=yes
-       sndfile_enable=${sndfile_found}
-       hal_enable=no
-       usb_enable=${usb_found}
-       alsa_enable=${alsa_found}
-       gstreamer_enable=${gstreamer_found}
-       audio_enable=yes
-       input_enable=yes
-       serial_enable=yes
-       network_enable=yes
-       sap_enable=no
-       service_enable=yes
-       health_enable=no
-       pnat_enable=no
-       tools_enable=yes
-       hidd_enable=no
-       pand_enable=no
-       dund_enable=no
-       cups_enable=no
-       test_enable=no
-       bccmd_enable=no
-       pcmcia_enable=no
-       hid2hci_enable=no
-       dfutool_enable=no
-       datafiles_enable=yes
-       telephony_driver=dummy
-       maemo6_enable=no
-       sap_driver=dummy
-       dbusoob_enable=no
-       wiimote_enable=no
-       gatt_enable=no
-
-       AC_ARG_ENABLE(optimization, AC_HELP_STRING([--disable-optimization], [disable code optimization]), [
-               optimization_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(fortify, AC_HELP_STRING([--disable-fortify], [disable compile time buffer checks]), [
-               fortify_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(pie, AC_HELP_STRING([--disable-pie], [disable position independent executables flag]), [
-               pie_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(network, AC_HELP_STRING([--disable-network], [disable network plugin]), [
-               network_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(sap, AC_HELP_STRING([--enable-sap], [enable sap plugin]), [
-               sap_enable=${enableval}
-       ])
-
-       AC_ARG_WITH(sap, AC_HELP_STRING([--with-sap=DRIVER], [select SAP driver]), [
-               sap_driver=${withval}
-       ])
-       AC_SUBST([SAP_DRIVER], [sap-${sap_driver}.c])
-
-       AC_ARG_ENABLE(serial, AC_HELP_STRING([--disable-serial], [disable serial plugin]), [
-               serial_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(input, AC_HELP_STRING([--disable-input], [disable input plugin]), [
-               input_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(audio, AC_HELP_STRING([--disable-audio], [disable audio plugin]), [
-               audio_enable=${enableval}
        ])
-
-       AC_ARG_ENABLE(service, AC_HELP_STRING([--disable-service], [disable service plugin]), [
-               service_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(health, AC_HELP_STRING([--enable-health], [enable health plugin]), [
-               health_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(pnat, AC_HELP_STRING([--enable-pnat], [enable pnat plugin]), [
-               pnat_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(gstreamer, AC_HELP_STRING([--enable-gstreamer], [enable GStreamer support]), [
-               gstreamer_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(alsa, AC_HELP_STRING([--enable-alsa], [enable ALSA support]), [
-               alsa_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(usb, AC_HELP_STRING([--enable-usb], [enable USB support]), [
-               usb_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(tools, AC_HELP_STRING([--enable-tools], [install Bluetooth utilities]), [
-               tools_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(bccmd, AC_HELP_STRING([--enable-bccmd], [install BCCMD interface utility]), [
-               bccmd_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(pcmcia, AC_HELP_STRING([--enable-pcmcia], [install PCMCIA serial script]), [
-               pcmcia_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(hid2hci, AC_HELP_STRING([--enable-hid2hci], [install HID mode switching utility]), [
-               hid2hci_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(dfutool, AC_HELP_STRING([--enable-dfutool], [install DFU firmware upgrade utility]), [
-               dfutool_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(hidd, AC_HELP_STRING([--enable-hidd], [install HID daemon]), [
-               hidd_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(pand, AC_HELP_STRING([--enable-pand], [install PAN daemon]), [
-               pand_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(dund, AC_HELP_STRING([--enable-dund], [install DUN daemon]), [
-               dund_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(cups, AC_HELP_STRING([--enable-cups], [install CUPS backend support]), [
-               cups_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test], [install test programs]), [
-               test_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--enable-datafiles], [install Bluetooth configuration and data files]), [
-               datafiles_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug], [enable compiling with debugging information]), [
-               debug_enable=${enableval}
-       ])
-
-       AC_ARG_WITH(telephony, AC_HELP_STRING([--with-telephony=DRIVER], [select telephony driver]), [
-               telephony_driver=${withval}
-       ])
-
-       AC_SUBST([TELEPHONY_DRIVER], [telephony-${telephony_driver}.c])
-
-       AC_ARG_ENABLE(maemo6, AC_HELP_STRING([--enable-maemo6], [compile with maemo6 plugin]), [
-               maemo6_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(dbusoob, AC_HELP_STRING([--enable-dbusoob], [compile with D-Bus OOB plugin]), [
-               dbusoob_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(wiimote, AC_HELP_STRING([--enable-wiimote], [compile with Wii Remote plugin]), [
-               wiimote_enable=${enableval}
-       ])
-
-       AC_ARG_ENABLE(hal, AC_HELP_STRING([--enable-hal], [Use HAL to determine adapter class]), [
-               hal_enable=${enableval}
+       AC_ARG_ENABLE(debug, AC_HELP_STRING([--enable-debug],
+                       [enable compiling with debugging information]), [
+               if (test "${enableval}" = "yes" &&
+                               test "${ac_cv_prog_cc_g}" = "yes"); then
+                       misc_cflags="$misc_cflags -g"
+               fi
        ])
-
-       AC_ARG_ENABLE(gatt, AC_HELP_STRING([--enable-gatt], [enable gatt module]), [
-               gatt_enable=${enableval}
+       AC_ARG_ENABLE(pie, AC_HELP_STRING([--enable-pie],
+                       [enable position independent executables flag]), [
+               if (test "${enableval}" = "yes" &&
+                               test "${ac_cv_prog_cc_pie}" = "yes"); then
+                       misc_cflags="$misc_cflags -fPIC"
+                       misc_ldflags="$misc_ldflags -pie"
+               fi
        ])
-
-       misc_cflags=""
-       misc_ldflags=""
-
-       if (test "${fortify_enable}" = "yes"); then
-               misc_cflags="$misc_cflags -D_FORTIFY_SOURCE=2"
-       fi
-
-       if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then
-               misc_cflags="$misc_cflags -fPIC"
-               misc_ldflags="$misc_ldflags -pie"
-       fi
-
-       if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then
-               misc_cflags="$misc_cflags -g"
-       fi
-
-       if (test "${optimization_enable}" = "no"); then
-               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
-
-       AM_CONDITIONAL(SNDFILE, test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes")
-       AM_CONDITIONAL(USB, test "${usb_enable}" = "yes" && test "${usb_found}" = "yes")
-       AM_CONDITIONAL(SBC, test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" ||
-                                                                       test "${test_enable}" = "yes")
-       AM_CONDITIONAL(ALSA, test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes")
-       AM_CONDITIONAL(GSTREAMER, test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes")
-       AM_CONDITIONAL(AUDIOPLUGIN, test "${audio_enable}" = "yes")
-       AM_CONDITIONAL(INPUTPLUGIN, test "${input_enable}" = "yes")
-       AM_CONDITIONAL(SERIALPLUGIN, test "${serial_enable}" = "yes")
-       AM_CONDITIONAL(NETWORKPLUGIN, test "${network_enable}" = "yes")
-       AM_CONDITIONAL(SAPPLUGIN, test "${sap_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(PNATPLUGIN, test "${pnat_enable}" = "yes")
-       AM_CONDITIONAL(HIDD, test "${hidd_enable}" = "yes")
-       AM_CONDITIONAL(PAND, test "${pand_enable}" = "yes")
-       AM_CONDITIONAL(DUND, test "${dund_enable}" = "yes")
-       AM_CONDITIONAL(CUPS, test "${cups_enable}" = "yes")
-       AM_CONDITIONAL(TEST, test "${test_enable}" = "yes" && test "${check_found}" = "yes")
-       AM_CONDITIONAL(TOOLS, test "${tools_enable}" = "yes")
-       AM_CONDITIONAL(BCCMD, test "${bccmd_enable}" = "yes")
-       AM_CONDITIONAL(PCMCIA, test "${pcmcia_enable}" = "yes")
-       AM_CONDITIONAL(HID2HCI, test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes" && test "${udev_found}" = "yes")
-       AM_CONDITIONAL(DFUTOOL, test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes")
-       AM_CONDITIONAL(DATAFILES, test "${datafiles_enable}" = "yes")
-       AM_CONDITIONAL(MAEMO6PLUGIN, test "${maemo6_enable}" = "yes")
-       AM_CONDITIONAL(DBUSOOBPLUGIN, test "${dbusoob_enable}" = "yes")
-       AM_CONDITIONAL(WIIMOTEPLUGIN, test "${wiimote_enable}" = "yes")
-       AM_CONDITIONAL(GATTMODULES, test "${gatt_enable}" = "yes")
 ])
index 7e1ecb9..2d0480e 100644 (file)
@@ -1,4 +1,4 @@
-# generated automatically by aclocal 1.11.3 -*- Autoconf -*-
+# generated automatically by aclocal 1.11.6 -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
 # 2005, 2006, 2007, 2008, 2009, 2010, 2011 Free Software Foundation,
@@ -2526,17 +2526,6 @@ freebsd* | dragonfly*)
   esac
   ;;
 
-gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
 haiku*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
@@ -2653,7 +2642,7 @@ linux*oldld* | linux*aout* | linux*coff*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
@@ -3269,10 +3258,6 @@ freebsd* | dragonfly*)
   fi
   ;;
 
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
 haiku*)
   lt_cv_deplibs_check_method=pass_all
   ;;
@@ -3311,7 +3296,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
@@ -4063,7 +4048,7 @@ m4_if([$1], [CXX], [
            ;;
        esac
        ;;
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
        case $cc_basename in
          KCC*)
            # KAI C++ Compiler
@@ -4362,7 +4347,7 @@ m4_if([$1], [CXX], [
       _LT_TAGVAR(lt_prog_compiler_static, $1)='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -6251,9 +6236,6 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(ld_shlibs, $1)=yes
         ;;
 
-      gnu*)
-        ;;
-
       haiku*)
         _LT_TAGVAR(archive_cmds, $1)='$CC -shared $libobjs $deplibs $compiler_flags ${wl}-soname $wl$soname -o $lib'
         _LT_TAGVAR(link_all_deplibs, $1)=yes
@@ -6415,7 +6397,7 @@ if test "$_lt_caught_CXX_error" != yes; then
         _LT_TAGVAR(inherit_rpath, $1)=yes
         ;;
 
-      linux* | k*bsd*-gnu | kopensolaris*-gnu)
+      linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
         case $cc_basename in
           KCC*)
            # Kuck and Associates, Inc. (KAI) C++ Compiler
@@ -8804,7 +8786,7 @@ AC_DEFUN([AM_AUTOMAKE_VERSION],
 [am__api_version='1.11'
 dnl Some users find AM_AUTOMAKE_VERSION and mistake it for a way to
 dnl require some minimum version.  Point them to the right macro.
-m4_if([$1], [1.11.3], [],
+m4_if([$1], [1.11.6], [],
       [AC_FATAL([Do not call $0, use AM_INIT_AUTOMAKE([$1]).])])dnl
 ])
 
@@ -8820,7 +8802,7 @@ m4_define([_AM_AUTOCONF_VERSION], [])
 # Call AM_AUTOMAKE_VERSION and AM_AUTOMAKE_VERSION so they can be traced.
 # This function is AC_REQUIREd by AM_INIT_AUTOMAKE.
 AC_DEFUN([AM_SET_CURRENT_AUTOMAKE_VERSION],
-[AM_AUTOMAKE_VERSION([1.11.3])dnl
+[AM_AUTOMAKE_VERSION([1.11.6])dnl
 m4_ifndef([AC_AUTOCONF_VERSION],
   [m4_copy([m4_PACKAGE_VERSION], [AC_AUTOCONF_VERSION])])dnl
 _AM_AUTOCONF_VERSION(m4_defn([AC_AUTOCONF_VERSION]))])
@@ -9182,18 +9164,6 @@ AC_DEFUN([AM_OUTPUT_DEPENDENCY_COMMANDS],
      [AMDEP_TRUE="$AMDEP_TRUE" ac_aux_dir="$ac_aux_dir"])
 ])
 
-# Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# serial 8
-
-# AM_CONFIG_HEADER is obsolete.  It has been replaced by AC_CONFIG_HEADERS.
-AU_DEFUN([AM_CONFIG_HEADER], [AC_CONFIG_HEADERS($@)])
-
 # Do all the work for Automake.                             -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 1998, 1999, 2000, 2001, 2002, 2003, 2004,
@@ -9378,27 +9348,6 @@ fi
 rmdir .tst 2>/dev/null
 AC_SUBST([am__leading_dot])])
 
-# Copyright (C) 1998, 1999, 2000, 2001, 2002, 2003, 2005
-# Free Software Foundation, Inc.
-#
-# This file is free software; the Free Software Foundation
-# gives unlimited permission to copy and/or distribute it,
-# with or without modifications, as long as this notice is preserved.
-
-# serial 5
-
-# AM_PROG_LEX
-# -----------
-# Autoconf leaves LEX=: if lex or flex can't be found.  Change that to a
-# "missing" invocation, for better error output.
-AC_DEFUN([AM_PROG_LEX],
-[AC_PREREQ(2.50)dnl
-AC_REQUIRE([AM_MISSING_HAS_RUN])dnl
-AC_REQUIRE([AC_PROG_LEX])dnl
-if test "$LEX" = :; then
-  LEX=${am_missing_run}flex
-fi])
-
 # Add --enable-maintainer-mode option to configure.         -*- Autoconf -*-
 # From Jim Meyering
 
@@ -9632,6 +9581,25 @@ AC_DEFUN([_AM_SET_OPTIONS],
 AC_DEFUN([_AM_IF_OPTION],
 [m4_ifset(_AM_MANGLE_OPTION([$1]), [$2], [$3])])
 
+# Copyright (C) 2001, 2003, 2005, 2011 Free Software Foundation, Inc.
+#
+# This file is free software; the Free Software Foundation
+# gives unlimited permission to copy and/or distribute it,
+# with or without modifications, as long as this notice is preserved.
+
+# serial 1
+
+# AM_RUN_LOG(COMMAND)
+# -------------------
+# Run COMMAND, save the exit status in ac_status, and log it.
+# (This has been adapted from Autoconf's _AC_RUN_LOG macro.)
+AC_DEFUN([AM_RUN_LOG],
+[{ echo "$as_me:$LINENO: $1" >&AS_MESSAGE_LOG_FD
+   ($1) >&AS_MESSAGE_LOG_FD 2>&AS_MESSAGE_LOG_FD
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&AS_MESSAGE_LOG_FD
+   (exit $ac_status); }])
+
 # Check to make sure that the build environment is sane.    -*- Autoconf -*-
 
 # Copyright (C) 1996, 1997, 2000, 2001, 2003, 2005, 2008
diff --git a/android/Android.mk b/android/Android.mk
new file mode 100644 (file)
index 0000000..0e025ac
--- /dev/null
@@ -0,0 +1,51 @@
+LOCAL_PATH := $(call my-dir)
+
+# Retrieve BlueZ version from configure.ac file
+BLUEZ_VERSION := $(shell grep ^AC_INIT $(LOCAL_PATH)/../configure.ac | cpp -P -D'AC_INIT(_,v)=v')
+
+# Specify pathmap for glib
+pathmap_INCL += glib:external/bluetooth/glib
+
+#
+# Android BlueZ daemon (bluetoothd)
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       main.c \
+       log.c \
+
+LOCAL_C_INCLUDES := \
+       $(call include-path-for, glib) \
+       $(call include-path-for, glib)/glib \
+       $(LOCAL_PATH)/../src \
+
+LOCAL_CFLAGS := -DVERSION=\"$(BLUEZ_VERSION)\"
+
+LOCAL_SHARED_LIBRARIES := \
+       libglib \
+
+LOCAL_MODULE := bluetoothd
+
+include $(BUILD_EXECUTABLE)
+
+#
+# bluetooth.default.so HAL
+#
+
+include $(CLEAR_VARS)
+
+LOCAL_SRC_FILES := \
+       hal_bluetooth.c \
+       hal_bt_sock.c \
+
+LOCAL_SHARED_LIBRARIES := \
+       libcutils \
+
+LOCAL_MODULE := bluetooth.default
+LOCAL_MODULE_PATH := $(TARGET_OUT_SHARED_LIBRARIES)/hw
+LOCAL_MODULE_TAGS := optional
+LOCAL_MODULE_CLASS := SHARED_LIBRARIES
+
+include $(BUILD_SHARED_LIBRARY)
diff --git a/android/hal-ipc-api.txt b/android/hal-ipc-api.txt
new file mode 100644 (file)
index 0000000..9a8b770
--- /dev/null
@@ -0,0 +1,1247 @@
+Android HAL protocol for Bluetooth
+==================================
+
+The Android HAL daemon for Bluetooth functionality implements the Unix socket
+server protocol around /run/bluetooth/daemon (tentative location) or Linux
+abstract sockets (tentative name).
+
+The daemon is single threaded and uses a mainloop for scheduling and general
+operation.
+
+The protocol is SOCK_SEQPACKET based and follows a strict PDU specification
+with a generic header and initial registration exchange. The communication
+is driven from the HAL with command/response exchanges. The daemon will use
+notification to signal events. The protocol is single PDU exchanged based,
+meaning every command requires a response. Notification does not require
+any confirmation. Not handling this PDU exchange leads to a disconnection of
+the socket.
+
+Command/response and notification use separate sockets. First connected socket
+is used for command/response, second for notification.  All services are
+multi-plexed over same pair of sockets. Separation is done to ease
+implementation of simple HAL library with dedicated thread for handling
+notification.
+
+This strict protocol requirement is done to match C based callbacks and
+callout functions that are running in a thread inside the HAL and might
+block.
+
+       .--Android--.                             .--Android--.
+       |  daemon   |                             |  HAL      |
+       |           |          Command            |           |
+       |           | <-------------------------- |           |
+       |           |                             |           |
+       |           | --------------------------> |           |
+       |           |          Response           |           |
+       |           |                             |           |
+       |           |                             |           |
+       |           |        Notification         |           |
+       |           | --------------------------> |           |
+       |           |                             |           |
+       '-----------'                             '-----------'
+
+Every packet will follow the basic header to support simple multi-plexing
+over the same socket. It will also support a basic control channel with service
+id 0.
+
+       0              8              16             24            31
+       +--------------+--------------+--------------+--------------+
+       | Service ID   | Opcode       | Data Length                 |
+       +--------------+--------------+-----------------------------+
+       |                                                           |
+
+The unique service ID is assigned by this specification for each HAL.
+
+As general rule of thumb, the opcode for command matches the opcode for a
+response. Or the opcode 0x00 for an error is returned.
+
+Notification opcodes start from 0x80.
+
+All command/response opcodes have the least significant bit not set. And all
+notifications have the least significant bit set.
+
+The HAL modules only have the job to map the callback and event functions
+to the protocol. They do not need to do anything else. Below is an example
+of a sample transaction for the Bluetooth Core HAL and enabling of an
+adapter.
+
+       HAL                                Daemon
+       ----------------------------------------------------
+
+       call enable()                  --> command 0x01
+       return enable()                <-- response 0x01
+
+       call adapter_state_changed()   <-- notification 0x81
+       return adapter_state_changed()
+
+When the Android hardware framework calls into the Bluetooth Core HAL
+and executes the enable() callback, the HAL module sends the enable
+command with opcode 0x01 to the daemon. As soon as the daemon responds,
+the callback will return with the appropriate result.
+
+After the daemon switched on the adapter, it will send a notification
+with opcode 0x81 to the HAL module.
+
+The Bluetooth Core HAL and Bluetooth Socket HAL are guaranteed to be
+available from the daemon. All other HAL modules are optional.
+
+When the Bluetooth Core HAL init() function is called, it should open
+the socket and register both "bluetooth" and "socket" service modules. It is
+required to register "socket" service at the same time since the HAL module
+does not have its own init() function.
+
+When new profiles are initiated, the get_profile_interface() callback
+will load the profile and during init() of the profile, it should register the
+specific service.
+
+       Bluetooth main thread       Daemon
+       -------------------------------------------------------
+
+       init()                  --> open command socket
+                               --> open notification socket
+                               --> register module "bluetooth"
+                               --> register module "socket"
+
+       get_profile_interface() --> return profile struct
+                               --> continue on Handsfree thread
+
+
+       Handsfree thread            Daemon
+       --------------------------------------------------------
+
+       init()                  --> register module handsfree
+
+
+Core Service (ID 0)
+===================
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Error (1 octet)
+
+       Opcode 0x01 - Register module command/response
+
+               Command parameters: Service id (1 octet)
+               Response parameters: <none>
+
+               In case a command is sent for an undeclared service ID, it will
+               be rejected. Also there will be no notifications for undeclared
+               service ID.
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Unregister module command/response
+
+               Command parameters: Service id (1 octet)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+
+Bluetooth Core HAL (ID 1)
+=========================
+
+Android HAL name: "bluetooth" (BT_HARDWARE_MODULE_ID)
+
+Commands and responses:
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+       Opcode 0x01 - Enable command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Disable command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x03 - Get Adapter Properties command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x04 - Get Adapter Property command/response
+
+               Command parameters: Property type (1 octet)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x05 - Set Adapter Property command/response
+
+               Command parameters: Property type (1 octet)
+                                   Property length (2 octets)
+                                   Property value (variable)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x06 - Get Remote Device Properties command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x07 - Get Remote Device Property command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Property type (1 octet)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x08 - Set Remote Device Property command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Property type (1 octet)
+                                   Property length (2 octets)
+                                   Property value (variable)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x09 - Get Remote Service Record command/response
+
+               Command parameters: Remote address (6 octets)
+                                   UUID (16 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0a - Get Remote Services command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0b - Start Discovery command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0c - Cancel Discovery command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0d - Create Bond command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0e - Remove Bond command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0f - Cancel Bond command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x10 - PIN Reply command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Accept (1 octet)
+                                   PIN length (1 octet)
+                                   PIN code (16 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x11 - SSP Reply command/response
+
+               Command parameters: Remote address (6 octets)
+                                   SSP variant (1 octet)
+                                   Accept (1 octet)
+                                   Passkey (4 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x12 - DUT Mode Configure command/response
+
+               Command parameters: Enable (1 octet)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x13 - DUT Mode Send command/response
+
+               Command parameters: Opcode (2 octets)
+                                   Length (1 octet)
+                                   Data (variable)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x14 - LE Test Mode command/response
+
+               Command parameters: Opcode (2 octets)
+                                   Length (1 octet)
+                                   Data (variable)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Adapter State Changed notification
+
+               Notifications parameters: State (1 octect)
+
+       Opcode 0x82 - Adapter Properties Changed notification
+
+               Notification parameters: Status (1 octect)
+                                        Num properties (1 octet)
+                                        Type[i] (1 octect)
+                                        Length[i] (2 octets)
+                                        Value[i] (variable)
+
+       Opcode 0x83 - Remote Device Properties notification
+
+               Notification parameters: Status (1 octect)
+                                        Remote address (6 octets)
+                                        Num properties (1 octet)
+                                        Type[i] (1 octect)
+                                        Length[i] (2 octets)
+                                        Value[i] (variable)
+
+       Opcode 0x84 - Device Found notification
+
+               Notification parameters: Num properties (1 octet)
+                                        Type[i] (1 octect)
+                                        Length[i] (2 octets)
+                                        Value[i] (variable)
+
+       Opcode 0x85 - Discovery State Changed notification
+
+               Notifications parameters: State (1 octect)
+
+       Opcode 0x86 - PIN Request notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Remote name (249 octets)
+                                        Class of device (3 octets)
+
+       Opcode 0x87 - SSP Request notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Remote name (249 octets)
+                                        Class of device (3 octets)
+                                        Pairing variant (1 octet)
+                                        Passkey (4 octets)
+
+       Opcode 0x88 - Bond State Changed notification
+
+               Notification parameters: Status (1 octect)
+                                        Remote address (6 octets)
+                                        Bond state (1 octet)
+
+       Opcode 0x89 - ACL State Changed notification
+
+               Notification parameters: Status (1 octect)
+                                        Remote address (6 octets)
+                                        ACL state (1 octet)
+
+       Opcode 0x8a - DUT Mode Receive notification
+
+               Notification parameters: Opcode (2 octects)
+                                        Length  (1 octet)
+                                        Data (variable)
+
+       Opcode 0x8b - LE Test Mode notification
+
+               Notification parameters: Status (1 octect)
+                                        Num packets (2 octets)
+
+
+Bluetooth Socket HAL (ID 2)
+===========================
+
+Android HAL name:: "socket" (BT_PROFILE_SOCKETS_ID)
+
+Commands and responses:
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Listen command/response
+
+               Command parameters: Socket type (1 octet)
+                                   Service name (256 octets)
+                                   Service UUID (16 octets)
+                                   Channel (2 octets)
+                                   Socket flags (1 octet)
+               Response parameters: File descriptor (inline)
+
+               Valid socket types: 0x01 = RFCOMM
+                                   0x02 = SCO
+                                   0x03 = L2CAP
+
+               Valid socket flags: 0x01 = Encrypt
+                                   0x02 = Auth
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Connect command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Socket type (1 octet)
+                                   Service UUID (16 octets)
+                                   Channel (2 octets)
+                                   Socket flags (1 octet)
+               Response parameters: File descriptor (inline)
+
+               Valid socket types: 0x01 = RFCOMM
+                                   0x02 = SCO
+                                   0x03 = L2CAP
+
+               Valid socket flags: 0x01 = Encrypt
+                                   0x02 = Auth
+
+               In case of an error, the error response will be returned.
+
+
+Bluetooth HID Host HAL (ID 3)
+============================
+
+Android HAL name: "hidhost" (BT_PROFILE_HIDHOST_ID)
+
+Commands and responses:
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Connect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Disconnect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x03 - Virtual Unplug command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x04 - Set Info command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Attribute mask (2 octets)
+                                   Subclass (1 octet)
+                                   Application ID (1 octet)
+                                   Vendor ID (2 octets)
+                                   Product ID (2 octets)
+                                   Version (2 octets)
+                                   Country code (1 octet)
+                                   Descriptor length (2 octet)
+                                   Descriptor value (884 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x05 - Get Protocol command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Protocol mode (1 octet)
+               Response parameters: <none>
+
+               Valid protocol modes: 0x00 = Report
+                                     0x01 = Boot
+                                     0xff = Unsupported
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x06 - Set Protocol command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Protocol mode (1 octet)
+               Response parameters: <none>
+
+               Valid protocol modes: 0x00 = Report
+                                     0x01 = Boot
+                                     0xff = Unsupported
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x07 - Get Report command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Report type (1 octet)
+                                   Report ID (1 octet)
+                                   Buffer size (2 octet)
+               Response parameters: <none>
+
+               Valid report types: 0x01 = Input
+                                   0x02 = Output
+                                   0x03 = Feature
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x08 - Set Report command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Report type (1 octet)
+                                   ...
+               Response parameters: <none>
+
+               Valid report types: 0x01 = Input
+                                   0x02 = Output
+                                   0x03 = Feature
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x09 - Send Data command/response
+
+               Command parameters: Remote address (6 octets)
+                                   ...
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Connection State notification
+
+               Notification parameters: Remote address (6 octets)
+
+               Valid connection states: 0x00 = Connected
+                                        0x01 = Connecting
+                                        0x02 = Disconnected
+                                        0x03 = Disconnecting
+                                        0x04 = Failed - Mouse from host
+                                        0x05 = Failed - Keyboard from host
+                                        0x06 = Failed - Too many devices
+                                        0x07 = Failed - No HID driver
+                                        0x08 = Failed - generic
+                                        0x09 = Unknown
+
+       Opcode 0x82 - HID Info notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Attribute mask (2 octets)
+                                        Subclass (1 octet)
+                                        Application ID (1 octet)
+                                        Vendor ID (2 octets)
+                                        Product ID (2 octets)
+                                        Version (2 octets)
+                                        Country code (1 octet)
+                                        Descriptor length (2 octet)
+                                        Descriptor value (884 octets)
+
+       Opcode 0x83 - Protocol Mode notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Status (1 octet)
+                                        Protocol mode (1 octet)
+
+               Valid protocol modes: 0x00 = Report
+                                     0x01 = Boot
+                                     0xff = Unsupported
+
+       Opcode 0x84 - Idle Time notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Status (1 octet)
+                                        Idle time (2 octets)
+
+       Opcode 0x85 - Get Report notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Status (1 octet)
+                                        Report length (2 octets)
+                                        Report data (variable)
+
+       Opcode 0x86 - Virtual Unplug notification
+
+               Notification parameters: Remote address (6 octets)
+                                        Status (1 octet)
+
+               Valid status values: 0x00 = Ok
+                                    0x01 = Handshake - Device not ready
+                                    0x02 = Handshake - Invalid report ID
+                                    0x03 = Handshake - Transaction not SPT
+                                    0x04 = Handshake - Invalid parameter
+                                    0x05 = Handshake - Generic error
+                                    0x06 = General error
+                                    0x07 = SDP error
+                                    0x08 = Set protocol error
+                                    0x09 = Device database full
+                                    0x0a = Device type not supported
+                                    0x0b = No resources
+                                    0x0c = Authentication failed
+                                    0x0d = HDL
+
+
+Bluetooth PAN HAL (ID 4)
+========================
+
+Android HAL name: "pan" (BT_PROFILE_PAN_ID)
+
+Commands and responses:
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Enable command/response
+
+               Command parameters: Local role (1 octet)
+               Response parameters: <none>
+
+               Valid role values: 0x00 = None
+                                  0x01 = NAP
+                                  0x02 = PANU
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Get Local Role command/response
+
+               Command parameters: <none>
+               Response parameters: Local role (1 octet)
+
+               Valid role values: 0x00 = None
+                                  0x01 = NAP
+                                  0x02 = PANU
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x03 - Connect command/response
+
+               Command parameters: Remote address (6 octets)
+                                   Local role (1 octet)
+                                   Remote role (1 octet)
+               Response parameters: <none>
+
+               Valid role values: 0x01 = NAP
+                                  0x02 = PANU
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x04 - Disconnect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Control State notification
+
+               Notification parameters: Control state (1 octect)
+                                        Status (1 octet)
+                                        Local role (1 octet)
+                                        Interface name (17 octet)
+
+               Valid control states: 0x00 = Enabled
+                                     0x01 = Disabled
+
+               Valid role values: 0x00 = None
+                                  0x01 = NAP
+                                  0x02 = PANU
+
+       Opcode 0x82 - Connection State notification
+
+               Notification parameters: Connection state (1 octect)
+                                        Status (1 octet)
+                                        Remote address (6 octets)
+                                        Local role (1 octet)
+                                        Remote role (1 octet)
+
+               Valid connection states: 0x00 = Connected
+                                        0x01 = Connecting
+                                        0x02 = Disconnected
+                                        0x03 = Disconnecting
+
+               Valid role values: 0x01 = NAP
+                                  0x02 = PANU
+
+
+Bluetooth Handsfree HAL (ID 5)
+==============================
+
+Android HAL name: "handsfree" (BT_PROFILE_HANDSFREE_ID)
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Connect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Disconnect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x03 - Connect Audio command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x04 - Disconnect Audio command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x05 - Start Voice Recognition command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x06 - Stop Voice Recognition command/response
+
+               Command parameters: <none>
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x07 - Volume Control command/response
+
+               Command parameters: Volume type (1 octet)
+                                   Volume (1 octet)
+               Response parameters: <none>
+
+               Valid volume types: 0x00 = Speaker
+                                   0x01 = Microphone
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x08 - Device Status Notification command/response
+
+               Command parameters: Network state (1 octet)
+                                   Service type (1 octet)
+                                   Signal strength (1 octet)
+                                   Battery level (1 octet)
+               Response parameters: <none>
+
+               Valid network states: 0x00 = Not available
+                                     0x01 = Available
+
+               Valid service types: 0x00 = Home network
+                                    0x01 = Roaming network
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x09 - COPS Response command/response
+
+               Command parameters: COPS command response (string)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0a - CIND Response command/response
+
+               Command parameters: Service (1 octet)
+                                   Number of active calls (1 octet)
+                                   Number of held calls (1 octet)
+                                   Call setup state (1 octet)
+                                   Signal strength (1 octet)
+                                   Roaming indicator (1 octet)
+                                   Battery level (1 octet)
+               Response parameters: <none>
+
+               Valid call setup states: 0x00 = Active
+                                        0x01 = Held
+                                        0x02 = Dialing
+                                        0x03 = Alerting
+                                        0x04 = Incoming
+                                        0x05 = Waiting
+                                        0x06 = Idle
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0b - Formatted AT Response command/response
+
+               Command parameters: Pre-formatted AT response (string)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0c - AT Response command/response
+
+               Command parameters: Response code (1 octet)
+                                   Error code (1 octet)
+               Response parameters: <none>
+
+               Valid response codes: 0x00 = ERROR
+                                     0x01 = OK
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0d - CLCC Response command/response
+
+               Command parameters: Call index (1 octet)
+                                   Call direction (1 octet)
+                                   Call state (1 octet)
+                                   Call mode (1 octet)
+                                   Call multiparty type (1 octet)
+                                   Call number type (1 octet)
+                                   Call number (variable)
+               Response parameters: <none>
+
+               Valid call directions: 0x00 = Outgoing
+                                      0x01 = Incoming
+
+               Valid call states: 0x00 = Active
+                                  0x01 = Held
+                                  0x02 = Dialing
+                                  0x03 = Alerting
+                                  0x04 = Incoming
+                                  0x05 = Waiting
+                                  0x06 = Idle
+
+               Valid call modes: 0x00 = Voice
+                                 0x01 = Data
+                                 0x02 = Fax
+
+               Valid multiparty types: 0x00 = Single call
+                                       0x01 = Multiparty call
+
+               Valid number types: 0x81 = Unknown
+                                   0x91 = International
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x0e - Phone Status Change command/response
+
+               Command parameters: Number of active calls (1 octet)
+                                   Number of held calls (1 octet)
+                                   Call setup state (1 octet)
+                                   Call number type (1 octet)
+                                   Call number (variable)
+               Response parameters: <none>
+
+               Valid call setup states: 0x00 = Active
+                                        0x01 = Held
+                                        0x02 = Dialing
+                                        0x03 = Alerting
+                                        0x04 = Incoming
+                                        0x05 = Waiting
+                                        0x06 = Idle
+
+               Valid number types: 0x81 = Unknown
+                                   0x91 = International
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Connection State notification
+
+               Notification parameters: Connection state (1 octect)
+                                        Remote address (6 octets)
+
+               Valid connection states: 0x00 = Disconnected
+                                        0x01 = Connecting
+                                        0x02 = Connected
+                                        0x03 = SLC connected
+                                        0x04 = Disconnecting
+
+       Opcode 0x82 - Audio State notification
+
+               Notification parameters: Audio state (1 octect)
+                                        Remote address (6 octets)
+
+               Valid audio states: 0x00 = Disconnected
+                                   0x01 = Connecting
+                                   0x02 = Connected
+                                   0x03 = Disconnecting
+
+       Opcode 0x83 - Voice Recognition Command notification
+
+               Notification parameters: Voice recognition state (1 octet)
+
+               Valid voice recognition states: 0x00 = Stopped
+                                               0x01 = Started
+
+       Opcode 0x84 - Answer Call Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x85 - Hangup Call Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x86 - Volume Command notification
+
+               Notification parameters: Volume type (1 octet)
+
+               Valid volume types: 0x00 = Speaker
+                                   0x01 = Microphone
+
+       Opcode 0x87 - Dial Call Command notification
+
+               Notification parameters: Number (string)
+
+       Opcode 0x88 - DTMF Command notification
+
+               Notification parameters: Tone (1 octet)
+
+       Opcode 0x89 - NREC Command notification
+
+               Notification parameters: NREC types (1 octet)
+
+               Valid NREC types: 0x00 = Stop
+                                 0x01 = Start
+
+       Opcode 0x8a - CHLD Command notification
+
+               Notification parameters: NREC types (1 octet)
+
+               Valid CHLD types: 0x00 = Release and hold
+                                 0x01 = Release active and accept held
+                                 0x02 = Hold active and accept held
+                                 0x03 = Add held call to conference
+
+       Opcode 0x8b - CNUM Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x8c - CIND Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x8d - COPS Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x8e - CLCC Command notification
+
+               Notification parameters: <none>
+
+       Opcode 0x8f - Unknown AT Command notification
+
+               Notification parameters: AT command (string)
+
+       Opcode 0x90 - Key Pressed Command notification
+
+               Notification parameters: <none>
+
+
+Bluetooth Advanced Audio HAL (ID 6)
+===================================
+
+Android HAL name: "ad2p" (BT_PROFILE_ADVANCED_AUDIO_ID)
+
+Commands and responses:
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Connect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Disconnect command/response
+
+               Command parameters: Remote address (6 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Connection State notification
+
+               Notification parameters: Connection state (1 octect)
+                                        Remote address (6 octets)
+
+               Valid connection states: 0x00 = Disconnected
+                                        0x01 = Connecting
+                                        0x02 = Connected
+                                        0x03 = Disconnecting
+
+       Opcode 0x82 - Audio State notification
+
+               Notification parameters: Audio state (1 octect)
+                                        Remote address (6 octets)
+
+               Valid connection states: 0x00 = Remote suspend
+                                        0x01 = Stopped
+                                        0x02 = Started
+
+
+Bluetooth Health HAL (ID 7)
+===========================
+
+Android HAL name: "health" (BT_PROFILE_HEALTH_ID)
+
+       Opcode 0x00 - Error response
+
+               Response parameters: Status (1 octet)
+
+               Valid status values: 0x01 = Fail
+                                    0x02 = Not ready
+                                    0x03 = No memory
+                                    0x04 = Busy
+                                    0x05 = Done (already completed)
+                                    0x06 = Unsupported
+                                    0x07 = Parameter invalid
+                                    0x08 = Unhandled
+                                    0x09 = Authentication failure
+                                    0x0a = Remote device down
+
+       Opcode 0x01 - Register Application command/response
+
+               Command parameters: Application name (string)
+                                   Provider name (string)
+                                   Service name (string)
+                                   Service description (string)
+                                   Number of MDEP (1 octet)
+                                   MDEP Role[i] (1 octet)
+                                   Data type[i] (1 octet)
+                                   Channel type[i] (1 octet)
+                                   MDEP description (string)
+               Response parameters: Application ID (2 octets)
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x02 - Unregister Application command/response
+
+               Command parameters: Application ID (2 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x03 - Connect Channel command/response
+
+               Command parameters: Application ID (2 octets)
+                                   Remote address (6 octets)
+                                   MDEP index (1 octet)
+               Response parameters: Channel ID (2 octets)
+
+               In case of an error, the error response will be returned.
+
+       Opcode 0x04 - Destroy Channel command/response
+
+               Command parameters: Channel ID (2 octets)
+               Response parameters: <none>
+
+               In case of an error, the error response will be returned.
+
+Notifications:
+
+       Opcode 0x81 - Application Registration State notification
+
+               Notification parameters: Application ID (2 octects)
+                                        Application state (1 octet)
+
+               Valid application states: 0x00 = Registration success
+                                         0x01 = Registration failed
+                                         0x02 = Deregistration success
+                                         0x03 = Deregistration failed
+
+       Opcode 0x82 - Channel State notification
+
+               Notification parameters: Application ID (2 octects)
+                                        Remote address (6 octets)
+                                        MDEP index (1 octet)
+                                        Channel ID (2 octets)
+                                        Channel state (1 octet)
+                                        File descriptor (inline)
+
+               Valid channel states: 0x00 = Connecting
+                                     0x01 = Connected
+                                     0x02 = Disconnecting
+                                     0x03 = Disconnected
+                                     0x04 = Destroyed
+
+
+Bluetooth Remote Control HAL (ID 8)
+===================================
+
+Android HAL name: "avrcp" (BT_PROFILE_AV_RC_ID)
+
+       Opcode 0x00 - Error response
+       Opcode 0x01 - Get Play Status command/response
+       Opcode 0x02 - List Player Application Attributes command/response
+       Opcode 0x03 - List Player Application Values command/response
+       Opcode 0x04 - Get Player Application Values command/response
+       Opcode 0x05 - Get Player Application Attributes Text command/response
+       Opcode 0x06 - Get Player Application Values Text command/response
+       Opcode 0x07 - Get Element Attributes Text command/response
+       Opcode 0x08 - Set Player Attributes Value command/response
+       Opcode 0x09 - Register Notification command/response
+
+       Opcode 0x81 - Get Play Status notification
+       Opcode 0x82 - List Player Application Attributes notification
+       ...
+
+
+Bluetooth GATT HAL (ID 9)
+=========================
+
+Android HAL name: "gatt" (BT_PROFILE_GATT_ID)
+
+       Opcode 0x00 - Error response
+       Opcode 0x01 - Register Client command/response
+       Opcode 0x02 - Unregister Client command/response
+       Opcode 0x03 - Scan command/response
+       Opcode 0x04 - Connect Device command/response
+       Opcode 0x05 - Disconnect Device command/response
+       Opcode 0x06 - Refresh command/response
+       Opcode 0x07 - Search Service command/response
+       Opcode 0x08 - Get Included Service command/response
+       Opcode 0x09 - Get Characteristic command/response
+       Opcode 0x0a - Get Descriptor command/response
+       Opcode 0x0b - Read Characteristic command/response
+       Opcode 0x0c - Write Characteristic command/response
+       Opcode 0x0d - Read Descriptor command/response
+       Opcode 0x0e - Write Descriptor command/response
+       Opcode 0x0f - Execute Write command/response
+       Opcode 0x10 - Register For Notification command/response
+       Opcode 0x11 - Deregister For Notification command/response
+       Opcode 0x12 - Read Remote RSSI command/response
+       Opcode 0x13 - Get Device Type command/response
+       Opcode 0x14 - Test Command command/response
+       Opcode 0x15 - Register Server command/response
+       Opcode 0x16 - Unregister Server command/response
+       Opcode 0x17 - Connect Peripheral command/response
+       Opcode 0x18 - Disconnect Peripheral command/response
+       Opcode 0x19 - Add Service command/response
+       Opcode 0x1a - Add Included Service command/response
+       Opcode 0x1b - Add Characteristic command/response
+       Opcode 0x1c - Add Descriptor command/response
+       Opcode 0x1d - Start Service command/response
+       Opcode 0x1e - Stop Service command/response
+       Opcode 0x1f - Delete Service command/response
+       Opcode 0x20 - Send Indication command/response
+       Opcode 0x21 - Send Response command/response
+
+       Opcode 0x81 - Register Client notification
+       Opcode 0x82 - Scan Result notification
+       Opcode 0x83 - Connect Device notification
+       Opcode 0x84 - Disconnect Device notification
+       Opcode 0x85 - Search Complete notification
+       Opcode 0x86 - Search Result notification
+       Opcode 0x87 - Get Characteristic notification
+       Opcode 0x88 - Get Descriptor notification
+       Opcode 0x89 - Get Included Service notification
+       Opcode 0x8a - Register For Notification notification
+       Opcode 0x8b - Notify notification
+       Opcode 0x8c - Read Characteristic notification
+       Opcode 0x8d - Write Characteristic notification
+       Opcode 0x8e - Execute Write notification
+       Opcode 0x8f - Read Descriptor notification
+       Opcode 0x90 - Write Descriptor notification
+       Opcode 0x91 - Read Remote RSSI notification
+       Opcode 0x92 - Register Server notification
+       Opcode 0x93 - Connection notification
+       Opcode 0x94 - Service Added notification
+       Opcode 0x95 - Included Service Added notification
+       Opcode 0x96 - Characteristic Added notification
+       Opcode 0x97 - Descriptor Added notification
+       Opcode 0x98 - Service Started notification
+       Opcode 0x99 - Service Stopped notification
+       Opcode 0x9a - Service Deleted notification
+       Opcode 0x9b - Request Read notification
+       Opcode 0x9c - Request Write notification
+       Opcode 0x9d - Request Execute Write notification
+       Opcode 0x9e - Response Confirmation notification
similarity index 54%
rename from alert/main.c
rename to android/log.c
index ec4ab6d..ce07b82 100644 (file)
@@ -2,8 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
 #include <config.h>
 #endif
 
-#include <stdint.h>
+#include <fcntl.h>
+#include <stdio.h>
+#include <stdarg.h>
+#include <unistd.h>
+#include <sys/uio.h>
+
 #include <glib.h>
-#include <errno.h>
 
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
+void info(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vfprintf(stdout, format, ap);
+       fprintf(stdout, "\n");
 
-static int alert_init(void)
+       va_end(ap);
+}
+
+void warn(const char *format, ...)
 {
-       if (!main_opts.gatt_enabled) {
-               DBG("GATT is disabled");
-               return -ENOTSUP;
-       }
+       va_list ap;
+
+       va_start(ap, format);
+
+       vfprintf(stderr, format, ap);
+       fprintf(stderr, "\n");
 
-       return alert_server_init();
+       va_end(ap);
 }
 
-static void alert_exit(void)
+void error(const char *format, ...)
 {
-       if (!main_opts.gatt_enabled)
-               return;
+       va_list ap;
 
-       alert_server_exit();
+       va_start(ap, format);
+
+       vfprintf(stderr, format, ap);
+       fprintf(stderr, "\n");
+
+       va_end(ap);
 }
 
-BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                       alert_init, alert_exit)
+void btd_debug(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vfprintf(stdout, format, ap);
+       fprintf(stdout, "\n");
+
+       va_end(ap);
+}
diff --git a/android/main.c b/android/main.c
new file mode 100644 (file)
index 0000000..f75b0a8
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  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 <signal.h>
+#include <stdint.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#define SHUTDOWN_GRACE_SECONDS 10
+
+static GMainLoop *event_loop;
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+       g_main_loop_quit(event_loop);
+
+       return FALSE;
+}
+
+static void sig_term(int sig)
+{
+       static bool __terminated = false;
+
+       if (!__terminated) {
+               g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+                                               quit_eventloop, NULL);
+       }
+
+       __terminated = true;
+}
+
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit", NULL },
+       { NULL }
+};
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *err = NULL;
+       struct sigaction sa;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &err) == FALSE) {
+               if (err != NULL) {
+                       g_printerr("%s\n", err->message);
+                       g_error_free(err);
+               } else
+                       g_printerr("An unknown error occurred\n");
+
+               exit(EXIT_FAILURE);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               printf("%s\n", VERSION);
+               exit(EXIT_SUCCESS);
+       }
+
+       event_loop = g_main_loop_new(NULL, FALSE);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = sig_term;
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
+
+       DBG("Entering main loop");
+
+       g_main_loop_run(event_loop);
+
+       g_main_loop_unref(event_loop);
+
+       info("Exit");
+
+       return EXIT_SUCCESS;
+}
index 3e854aa..48c50e3 100644 (file)
@@ -31,13 +31,13 @@ enum {
 struct attribute {
        uint16_t handle;
        bt_uuid_t uuid;
-       int read_reqs;
-       int write_reqs;
+       int read_req;           /* Read requirement */
+       int write_req;          /* Write requirement */
        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;
+       size_t len;
        uint8_t *data;
 };
index c8e2e1d..753c753 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <errno.h>
 #include <stdint.h>
 #include <stdlib.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
+#include "lib/uuid.h"
 #include "att.h"
 
 const char *att_ecode2str(uint8_t status)
@@ -101,6 +105,9 @@ struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len)
        struct att_data_list *list;
        int i;
 
+       if (len > UINT8_MAX)
+               return NULL;
+
        list = g_new0(struct att_data_list, 1);
        list->len = len;
        list->num = num;
@@ -114,9 +121,9 @@ struct att_data_list *att_data_list_alloc(uint16_t num, uint16_t len)
 }
 
 uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                                                       uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
-       const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
+       uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
        uint16_t length;
 
        if (!uuid)
@@ -141,10 +148,10 @@ uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
        return min_len + length;
 }
 
-uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
+uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start,
                                                uint16_t *end, bt_uuid_t *uuid)
 {
-       const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
+       const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
 
        if (pdu == NULL)
                return 0;
@@ -169,7 +176,7 @@ uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
 }
 
 uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
-                                                               int len)
+                                                               size_t len)
 {
        int i;
        uint16_t w;
@@ -178,7 +185,7 @@ uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
        if (list == NULL)
                return 0;
 
-       if (len < list->len + 2)
+       if (len < list->len + sizeof(uint8_t) * 2)
                return 0;
 
        pdu[0] = ATT_OP_READ_BY_GROUP_RESP;
@@ -195,7 +202,7 @@ uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
        return w;
 }
 
-struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
+struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len)
 {
        struct att_data_list *list;
        const uint8_t *ptr;
@@ -208,6 +215,8 @@ struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
        elen = pdu[1];
        num = (len - 2) / elen;
        list = att_data_list_alloc(num, elen);
+       if (list == NULL)
+               return NULL;
 
        ptr = &pdu[2];
 
@@ -220,7 +229,8 @@ struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len)
 }
 
 uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                       const uint8_t *value, int vlen, uint8_t *pdu, int len)
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len)
 {
        uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end) +
                                                        sizeof(uint16_t);
@@ -253,10 +263,11 @@ uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
        return min_len;
 }
 
-uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
-               uint16_t *end, bt_uuid_t *uuid, uint8_t *value, int *vlen)
+uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
+                                               uint16_t *end, bt_uuid_t *uuid,
+                                               uint8_t *value, size_t *vlen)
 {
-       int valuelen;
+       size_t valuelen;
        uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) +
                                                sizeof(*end) + sizeof(uint16_t);
 
@@ -293,7 +304,7 @@ uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
        return len;
 }
 
-uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
+uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, size_t len)
 {
        GSList *l;
        uint16_t offset;
@@ -303,8 +314,9 @@ uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
 
        pdu[0] = ATT_OP_FIND_BY_TYPE_RESP;
 
-       for (l = matches, offset = 1; l && len >= (offset + 4);
-                                       l = l->next, offset += 4) {
+       for (l = matches, offset = 1;
+                               l && len >= (offset + sizeof(uint16_t) * 2);
+                               l = l->next, offset += sizeof(uint16_t) * 2) {
                struct att_range *range = l->data;
 
                att_put_u16(range->start, &pdu[offset]);
@@ -314,11 +326,11 @@ uint16_t enc_find_by_type_resp(GSList *matches, uint8_t *pdu, int len)
        return offset;
 }
 
-GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
+GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len)
 {
        struct att_range *range;
        GSList *matches;
-       int offset;
+       off_t offset;
 
        if (pdu == NULL || len < 5)
                return NULL;
@@ -326,7 +338,9 @@ GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
        if (pdu[0] != ATT_OP_FIND_BY_TYPE_RESP)
                return NULL;
 
-       for (offset = 1, matches = NULL; len >= (offset + 4); offset += 4) {
+       for (offset = 1, matches = NULL;
+                               len >= (offset + sizeof(uint16_t) * 2);
+                               offset += sizeof(uint16_t) * 2) {
                range = g_new0(struct att_range, 1);
                range->start = att_get_u16(&pdu[offset]);
                range->end = att_get_u16(&pdu[offset + 2]);
@@ -338,9 +352,9 @@ GSList *dec_find_by_type_resp(const uint8_t *pdu, int len)
 }
 
 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                                                       uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
-       const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
+       uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
        uint16_t length;
 
        if (!uuid)
@@ -365,10 +379,10 @@ uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
        return min_len + length;
 }
 
-uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
+uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
                                                uint16_t *end, bt_uuid_t *uuid)
 {
-       const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
+       const size_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
 
        if (pdu == NULL)
                return 0;
@@ -393,10 +407,11 @@ uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
        return len;
 }
 
-uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len)
+uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu,
+                                                               size_t len)
 {
        uint8_t *ptr;
-       int i, w, l;
+       size_t i, w, l;
 
        if (list == NULL)
                return 0;
@@ -419,7 +434,7 @@ uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu, int len
        return w;
 }
 
-struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
+struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len)
 {
        struct att_data_list *list;
        const uint8_t *ptr;
@@ -432,6 +447,8 @@ struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
        elen = pdu[1];
        num = (len - 2) / elen;
        list = att_data_list_alloc(num, elen);
+       if (list == NULL)
+               return NULL;
 
        ptr = &pdu[2];
 
@@ -443,8 +460,8 @@ struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len)
        return list;
 }
 
-uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
-                                                       uint8_t *pdu, int len)
+uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
@@ -468,8 +485,8 @@ uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
        return min_len;
 }
 
-uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int *vlen)
+uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t *vlen)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
@@ -492,8 +509,8 @@ uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
        return len;
 }
 
-uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
-                                                       uint8_t *pdu, int len)
+uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
@@ -517,8 +534,8 @@ uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
        return min_len;
 }
 
-uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int *vlen)
+uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t *vlen)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
@@ -542,7 +559,7 @@ uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
        return len;
 }
 
-uint16_t enc_write_resp(uint8_t *pdu, int len)
+uint16_t enc_write_resp(uint8_t *pdu)
 {
        if (pdu == NULL)
                return 0;
@@ -552,7 +569,7 @@ uint16_t enc_write_resp(uint8_t *pdu, int len)
        return sizeof(pdu[0]);
 }
 
-uint16_t dec_write_resp(const uint8_t *pdu, int len)
+uint16_t dec_write_resp(const uint8_t *pdu, size_t len)
 {
        if (pdu == NULL)
                return 0;
@@ -563,7 +580,7 @@ uint16_t dec_write_resp(const uint8_t *pdu, int len)
        return len;
 }
 
-uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
+uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle);
 
@@ -580,7 +597,7 @@ uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len)
 }
 
 uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
-                                                                       int len)
+                                                               size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) +
                                                        sizeof(offset);
@@ -598,7 +615,7 @@ uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
        return min_len;
 }
 
-uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
+uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle);
 
@@ -619,7 +636,7 @@ uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle)
        return min_len;
 }
 
-uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle,
+uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle,
                                                        uint16_t *offset)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
@@ -646,7 +663,7 @@ uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle,
        return min_len;
 }
 
-uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
+uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len)
 {
        if (pdu == NULL)
                return 0;
@@ -664,8 +681,8 @@ uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len)
        return vlen + 1;
 }
 
-uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset,
-                                                       uint8_t *pdu, int len)
+uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset,
+                                               uint8_t *pdu, size_t len)
 {
        if (pdu == NULL)
                return 0;
@@ -681,26 +698,28 @@ uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset,
        return vlen + 1;
 }
 
-uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen)
+ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value,
+                                                               size_t vlen)
 {
        if (pdu == NULL)
-               return 0;
-
-       if (value == NULL || vlen == NULL)
-               return 0;
+               return -EINVAL;
 
        if (pdu[0] != ATT_OP_READ_RESP)
-               return 0;
+               return -EINVAL;
 
-       memcpy(value, pdu + 1, len - 1);
+       if (value == NULL)
+               return len - 1;
 
-       *vlen = len - 1;
+       if (vlen < (len - 1))
+               return -ENOBUFS;
 
-       return len;
+       memcpy(value, pdu + 1, len - 1);
+
+       return len - 1;
 }
 
 uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
-                                                       uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(opcode) +
                                                sizeof(handle) + sizeof(status);
@@ -718,7 +737,8 @@ uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
        return min_len;
 }
 
-uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
+uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu,
+                                                               size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(start) + sizeof(end);
 
@@ -735,7 +755,7 @@ uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len)
        return min_len;
 }
 
-uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
+uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start,
                                                                uint16_t *end)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*start) + sizeof(*end);
@@ -759,10 +779,10 @@ uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
 }
 
 uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
-                                                       uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        uint8_t *ptr;
-       int i, w;
+       size_t i, w;
 
        if (pdu == NULL)
                return 0;
@@ -770,7 +790,7 @@ uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
        if (list == NULL)
                return 0;
 
-       if (len < list->len + 2)
+       if (len < list->len + sizeof(uint8_t) * 2)
                return 0;
 
        pdu[0] = ATT_OP_FIND_INFO_RESP;
@@ -786,7 +806,7 @@ uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
        return w;
 }
 
-struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
+struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len,
                                                        uint8_t *format)
 {
        struct att_data_list *list;
@@ -815,6 +835,8 @@ struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
        ptr = (void *) &pdu[2];
 
        list = att_data_list_alloc(num, elen);
+       if (list == NULL)
+               return NULL;
 
        for (i = 0; i < num; i++) {
                memcpy(list->data[i], ptr, list->len);
@@ -824,8 +846,8 @@ struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
        return list;
 }
 
-uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen,
-                                               uint8_t *pdu, int len)
+uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
@@ -842,8 +864,8 @@ uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen,
        return vlen + min_len;
 }
 
-uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen,
-                                               uint8_t *pdu, int len)
+uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
 
@@ -860,8 +882,8 @@ uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen,
        return vlen + min_len;
 }
 
-uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int vlen)
+uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t vlen)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(uint16_t);
        uint16_t dlen;
@@ -885,7 +907,7 @@ uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle,
        return dlen;
 }
 
-uint16_t enc_confirmation(uint8_t *pdu, int len)
+uint16_t enc_confirmation(uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]);
 
@@ -900,7 +922,7 @@ uint16_t enc_confirmation(uint8_t *pdu, int len)
        return min_len;
 }
 
-uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
+uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
 
@@ -916,7 +938,7 @@ uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len)
        return min_len;
 }
 
-uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
+uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
 
@@ -937,7 +959,7 @@ uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu)
        return min_len;
 }
 
-uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
+uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(mtu);
 
@@ -953,7 +975,7 @@ uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len)
        return min_len;
 }
 
-uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
+uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu)
 {
        const uint16_t min_len = sizeof(pdu[0]) + sizeof(*mtu);
 
@@ -973,3 +995,180 @@ uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu)
 
        return min_len;
 }
+
+uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset,
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) +
+                                                               sizeof(offset);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (vlen > len - min_len)
+               vlen = len - min_len;
+
+       pdu[0] = ATT_OP_PREP_WRITE_REQ;
+       att_put_u16(handle, &pdu[1]);
+       att_put_u16(offset, &pdu[3]);
+
+       if (vlen > 0) {
+               memcpy(&pdu[5], value, vlen);
+               return min_len + vlen;
+       }
+
+       return min_len;
+}
+
+uint16_t dec_prep_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
+                               uint16_t *offset, uint8_t *value, size_t *vlen)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
+                                                       sizeof(*offset);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (handle == NULL || offset == NULL || value == NULL || vlen == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (pdu[0] != ATT_OP_PREP_WRITE_REQ)
+               return 0;
+
+       *handle = att_get_u16(&pdu[1]);
+       *offset = att_get_u16(&pdu[3]);
+
+       *vlen = len - min_len;
+       if (*vlen > 0)
+               memcpy(value, pdu + min_len, *vlen);
+
+       return len;
+}
+
+uint16_t enc_prep_write_resp(uint16_t handle, uint16_t offset,
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(handle) +
+                                                               sizeof(offset);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (vlen > len - min_len)
+               vlen = len - min_len;
+
+       pdu[0] = ATT_OP_PREP_WRITE_RESP;
+       att_put_u16(handle, &pdu[1]);
+       att_put_u16(offset, &pdu[3]);
+
+       if (vlen > 0) {
+               memcpy(&pdu[5], value, vlen);
+               return min_len + vlen;
+       }
+
+       return min_len;
+}
+
+uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle,
+                               uint16_t *offset, uint8_t *value, size_t *vlen)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(*handle) +
+                                                               sizeof(*offset);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (handle == NULL || offset == NULL || value == NULL || vlen == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (pdu[0] != ATT_OP_PREP_WRITE_REQ)
+               return 0;
+
+       *handle = att_get_u16(&pdu[1]);
+       *offset = att_get_u16(&pdu[3]);
+       *vlen = len - min_len;
+       if (*vlen > 0)
+               memcpy(value, pdu + min_len, *vlen);
+
+       return len;
+}
+
+uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(flags);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (flags > 1)
+               return 0;
+
+       pdu[0] = ATT_OP_EXEC_WRITE_REQ;
+       pdu[1] = flags;
+
+       return min_len;
+}
+
+uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags)
+{
+       const uint16_t min_len = sizeof(pdu[0]) + sizeof(*flags);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (flags == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (pdu[0] != ATT_OP_EXEC_WRITE_REQ)
+               return 0;
+
+       *flags = pdu[1];
+
+       return min_len;
+}
+
+uint16_t enc_exec_write_resp(uint8_t *pdu)
+{
+       if (pdu == NULL)
+               return 0;
+
+       pdu[0] = ATT_OP_EXEC_WRITE_RESP;
+
+       return sizeof(pdu[0]);
+}
+
+uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len)
+{
+       const uint16_t min_len = sizeof(pdu[0]);
+
+       if (pdu == NULL)
+               return 0;
+
+       if (len < min_len)
+               return 0;
+
+       if (pdu[0] != ATT_OP_EXEC_WRITE_RESP)
+               return 0;
+
+       return len;
+}
index 144513f..28bc944 100644 (file)
 #define ATT_CHAR_PROPER_AUTH                   0x40
 #define ATT_CHAR_PROPER_EXT_PROPER             0x80
 
-#define ATT_MAX_MTU                            256
+#define ATT_MAX_VALUE_LEN                      512
 #define ATT_DEFAULT_L2CAP_MTU                  48
 #define ATT_DEFAULT_LE_MTU                     23
 
 #define ATT_CID                                        4
 #define ATT_PSM                                        31
 
+/* Flags for Execute Write Request Operation */
+#define ATT_CANCEL_ALL_PREP_WRITES              0x00
+#define ATT_WRITE_ALL_PREP_WRITES               0x01
+
+/* Find Information Response Formats */
+#define ATT_FIND_INFO_RESP_FMT_16BIT           0x01
+#define ATT_FIND_INFO_RESP_FMT_128BIT          0x02
+
 struct att_data_list {
        uint16_t num;
        uint16_t len;
@@ -197,62 +205,82 @@ void att_data_list_free(struct att_data_list *list);
 
 const char *att_ecode2str(uint8_t status);
 uint16_t enc_read_by_grp_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                                                       uint8_t *pdu, int len);
-uint16_t dec_read_by_grp_req(const uint8_t *pdu, int len, uint16_t *start,
-                                               uint16_t *end, bt_uuid_t *uuid);
-uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu, int len);
+                                               uint8_t *pdu, size_t len);
+uint16_t dec_read_by_grp_req(const uint8_t *pdu, size_t len, uint16_t *start,
+                                       uint16_t *end, bt_uuid_t *uuid);
+uint16_t enc_read_by_grp_resp(struct att_data_list *list, uint8_t *pdu,
+                                                               size_t len);
 uint16_t enc_find_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                       const uint8_t *value, int vlen, uint8_t *pdu, int len);
-uint16_t dec_find_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
-               uint16_t *end, bt_uuid_t *uuid, uint8_t *value, int *vlen);
-uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, int len);
-GSList *dec_find_by_type_resp(const uint8_t *pdu, int len);
-struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, int len);
+                               const uint8_t *value, size_t vlen, uint8_t *pdu,
+                               size_t len);
+uint16_t dec_find_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
+               uint16_t *end, bt_uuid_t *uuid, uint8_t *value, size_t *vlen);
+uint16_t enc_find_by_type_resp(GSList *ranges, uint8_t *pdu, size_t len);
+GSList *dec_find_by_type_resp(const uint8_t *pdu, size_t len);
+struct att_data_list *dec_read_by_grp_resp(const uint8_t *pdu, size_t len);
 uint16_t enc_read_by_type_req(uint16_t start, uint16_t end, bt_uuid_t *uuid,
-                                                       uint8_t *pdu, int len);
-uint16_t dec_read_by_type_req(const uint8_t *pdu, int len, uint16_t *start,
-                                               uint16_t *end, bt_uuid_t *uuid);
+                                               uint8_t *pdu, size_t len);
+uint16_t dec_read_by_type_req(const uint8_t *pdu, size_t len, uint16_t *start,
+                                       uint16_t *end, bt_uuid_t *uuid);
 uint16_t enc_read_by_type_resp(struct att_data_list *list, uint8_t *pdu,
-                                                               int len);
-uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, int vlen,
-                                                       uint8_t *pdu, int len);
-uint16_t dec_write_cmd(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int *vlen);
-struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, int len);
-uint16_t enc_write_req(uint16_t handle, const uint8_t *value, int vlen,
-                                                       uint8_t *pdu, int len);
-uint16_t dec_write_req(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int *vlen);
-uint16_t enc_write_resp(uint8_t *pdu, int len);
-uint16_t dec_write_resp(const uint8_t *pdu, int len);
-uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, int len);
+                                                               size_t len);
+uint16_t enc_write_cmd(uint16_t handle, const uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len);
+uint16_t dec_write_cmd(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t *vlen);
+struct att_data_list *dec_read_by_type_resp(const uint8_t *pdu, size_t len);
+uint16_t enc_write_req(uint16_t handle, const uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len);
+uint16_t dec_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t *vlen);
+uint16_t enc_write_resp(uint8_t *pdu);
+uint16_t dec_write_resp(const uint8_t *pdu, size_t len);
+uint16_t enc_read_req(uint16_t handle, uint8_t *pdu, size_t len);
 uint16_t enc_read_blob_req(uint16_t handle, uint16_t offset, uint8_t *pdu,
-                                                               int len);
-uint16_t dec_read_req(const uint8_t *pdu, int len, uint16_t *handle);
-uint16_t dec_read_blob_req(const uint8_t *pdu, int len, uint16_t *handle,
+                                                               size_t len);
+uint16_t dec_read_req(const uint8_t *pdu, size_t len, uint16_t *handle);
+uint16_t dec_read_blob_req(const uint8_t *pdu, size_t len, uint16_t *handle,
                                                        uint16_t *offset);
-uint16_t enc_read_resp(uint8_t *value, int vlen, uint8_t *pdu, int len);
-uint16_t enc_read_blob_resp(uint8_t *value, int vlen, uint16_t offset,
-                                                       uint8_t *pdu, int len);
-uint16_t dec_read_resp(const uint8_t *pdu, int len, uint8_t *value, int *vlen);
+uint16_t enc_read_resp(uint8_t *value, size_t vlen, uint8_t *pdu, size_t len);
+uint16_t enc_read_blob_resp(uint8_t *value, size_t vlen, uint16_t offset,
+                                               uint8_t *pdu, size_t len);
+ssize_t dec_read_resp(const uint8_t *pdu, size_t len, uint8_t *value,
+                                                               size_t vlen);
 uint16_t enc_error_resp(uint8_t opcode, uint16_t handle, uint8_t status,
-                                                       uint8_t *pdu, int len);
-uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu, int len);
-uint16_t dec_find_info_req(const uint8_t *pdu, int len, uint16_t *start,
+                                               uint8_t *pdu, size_t len);
+uint16_t enc_find_info_req(uint16_t start, uint16_t end, uint8_t *pdu,
+                                                               size_t len);
+uint16_t dec_find_info_req(const uint8_t *pdu, size_t len, uint16_t *start,
                                                                uint16_t *end);
 uint16_t enc_find_info_resp(uint8_t format, struct att_data_list *list,
-                                                       uint8_t *pdu, int len);
-struct att_data_list *dec_find_info_resp(const uint8_t *pdu, int len,
+                                               uint8_t *pdu, size_t len);
+struct att_data_list *dec_find_info_resp(const uint8_t *pdu, size_t len,
                                                        uint8_t *format);
-uint16_t enc_notification(uint16_t handle, uint8_t *value, int vlen,
-                                               uint8_t *pdu, int len);
-uint16_t enc_indication(uint16_t handle, uint8_t *value, int vlen,
-                                               uint8_t *pdu, int len);
-uint16_t dec_indication(const uint8_t *pdu, int len, uint16_t *handle,
-                                               uint8_t *value, int vlen);
-uint16_t enc_confirmation(uint8_t *pdu, int len);
-
-uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, int len);
-uint16_t dec_mtu_req(const uint8_t *pdu, int len, uint16_t *mtu);
-uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, int len);
-uint16_t dec_mtu_resp(const uint8_t *pdu, int len, uint16_t *mtu);
+uint16_t enc_notification(uint16_t handle, uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len);
+uint16_t enc_indication(uint16_t handle, uint8_t *value, size_t vlen,
+                                               uint8_t *pdu, size_t len);
+uint16_t dec_indication(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint8_t *value, size_t vlen);
+uint16_t enc_confirmation(uint8_t *pdu, size_t len);
+
+uint16_t enc_mtu_req(uint16_t mtu, uint8_t *pdu, size_t len);
+uint16_t dec_mtu_req(const uint8_t *pdu, size_t len, uint16_t *mtu);
+uint16_t enc_mtu_resp(uint16_t mtu, uint8_t *pdu, size_t len);
+uint16_t dec_mtu_resp(const uint8_t *pdu, size_t len, uint16_t *mtu);
+
+uint16_t enc_prep_write_req(uint16_t handle, uint16_t offset,
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len);
+uint16_t dec_prep_write_req(const uint8_t *pdu, size_t len, uint16_t *handle,
+                               uint16_t *offset, uint8_t *value, size_t *vlen);
+uint16_t enc_prep_write_resp(uint16_t handle, uint16_t offset,
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len);
+uint16_t dec_prep_write_resp(const uint8_t *pdu, size_t len, uint16_t *handle,
+                                               uint16_t *offset, uint8_t *value,
+                                               size_t *vlen);
+uint16_t enc_exec_write_req(uint8_t flags, uint8_t *pdu, size_t len);
+uint16_t dec_exec_write_req(const uint8_t *pdu, size_t len, uint8_t *flags);
+uint16_t enc_exec_write_resp(uint8_t *pdu);
+uint16_t dec_exec_write_resp(const uint8_t *pdu, size_t len);
diff --git a/attrib/client.c b/attrib/client.c
deleted file mode 100644 (file)
index 8d119df..0000000
+++ /dev/null
@@ -1,1144 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <glib.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "log.h"
-#include "gdbus.h"
-#include "error.h"
-#include "dbus-common.h"
-#include "btio.h"
-#include "storage.h"
-
-#include "att.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "gatt.h"
-#include "client.h"
-
-#define CHAR_INTERFACE "org.bluez.Characteristic"
-
-struct format {
-       guint8 format;
-       guint8 exponent;
-       guint16 unit;
-       guint8 namespace;
-       guint16 desc;
-} __attribute__ ((packed));
-
-struct query {
-       DBusMessage *msg;
-       GSList *list;
-};
-
-struct gatt_service {
-       struct btd_device *dev;
-       struct gatt_primary *prim;
-       DBusConnection *conn;
-       GAttrib *attrib;
-       guint attioid;
-       int psm;
-       char *path;
-       GSList *chars;
-       GSList *offline_chars;
-       GSList *watchers;
-       struct query *query;
-};
-
-struct characteristic {
-       struct gatt_service *gatt;
-       char *path;
-       uint16_t handle;
-       uint16_t end;
-       uint8_t perm;
-       char type[MAX_LEN_UUID_STR + 1];
-       char *name;
-       char *desc;
-       struct format *format;
-       uint8_t *value;
-       size_t vlen;
-};
-
-struct query_data {
-       struct gatt_service *gatt;
-       struct characteristic *chr;
-       uint16_t handle;
-};
-
-struct watcher {
-       guint id;
-       char *name;
-       char *path;
-       struct gatt_service *gatt;
-};
-
-static GSList *gatt_services = NULL;
-
-static void characteristic_free(void *user_data)
-{
-       struct characteristic *chr = user_data;
-
-       g_free(chr->path);
-       g_free(chr->desc);
-       g_free(chr->format);
-       g_free(chr->value);
-       g_free(chr->name);
-       g_free(chr);
-}
-
-static void watcher_free(void *user_data)
-{
-       struct watcher *watcher = user_data;
-
-       g_free(watcher->path);
-       g_free(watcher->name);
-       g_free(watcher);
-}
-
-static void gatt_service_free(struct gatt_service *gatt)
-{
-       g_slist_free_full(gatt->watchers, watcher_free);
-       g_slist_free_full(gatt->chars, characteristic_free);
-       g_slist_free(gatt->offline_chars);
-       g_free(gatt->path);
-       btd_device_unref(gatt->dev);
-       dbus_connection_unref(gatt->conn);
-       g_free(gatt);
-}
-
-static void remove_attio(struct gatt_service *gatt)
-{
-       if (gatt->offline_chars || gatt->watchers || gatt->query)
-               return;
-
-       if (gatt->attioid) {
-               btd_device_remove_attio_callback(gatt->dev, gatt->attioid);
-               gatt->attioid = 0;
-       }
-
-       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, bdaddr_type);
-}
-
-static int characteristic_handle_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct characteristic *chr = a;
-       uint16_t handle = GPOINTER_TO_UINT(b);
-
-       return chr->handle - handle;
-}
-
-static int watcher_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct watcher *watcher = a;
-       const struct watcher *match = b;
-       int ret;
-
-       ret = g_strcmp0(watcher->name, match->name);
-       if (ret != 0)
-               return ret;
-
-       return g_strcmp0(watcher->path, match->path);
-}
-
-static void append_char_dict(DBusMessageIter *iter, struct characteristic *chr)
-{
-       DBusMessageIter dict;
-       const char *name = "";
-       char *uuid;
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       uuid = g_strdup(chr->type);
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
-       g_free(uuid);
-
-       /* FIXME: Translate UUID to name. */
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &name);
-
-       if (chr->desc)
-               dict_append_entry(&dict, "Description", DBUS_TYPE_STRING,
-                                                               &chr->desc);
-
-       if (chr->value)
-               dict_append_array(&dict, "Value", DBUS_TYPE_BYTE, &chr->value,
-                                                               chr->vlen);
-
-       /* FIXME: Missing Format, Value and Representation */
-
-       dbus_message_iter_close_container(iter, &dict);
-}
-
-static void watcher_exit(DBusConnection *conn, void *user_data)
-{
-       struct watcher *watcher = user_data;
-       struct gatt_service *gatt = watcher->gatt;
-
-       DBG("%s watcher %s exited", gatt->path, watcher->name);
-
-       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
-       g_dbus_remove_watch(gatt->conn, watcher->id);
-       remove_attio(gatt);
-}
-
-static int characteristic_set_value(struct characteristic *chr,
-                                       const uint8_t *value, size_t vlen)
-{
-       chr->value = g_try_realloc(chr->value, vlen);
-       if (chr->value == NULL)
-               return -ENOMEM;
-
-       memcpy(chr->value, value, vlen);
-       chr->vlen = vlen;
-
-       return 0;
-}
-
-static void update_watchers(gpointer data, gpointer user_data)
-{
-       struct watcher *w = data;
-       struct characteristic *chr = user_data;
-       DBusConnection *conn = w->gatt->conn;
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(w->name, w->path,
-                               "org.bluez.Watcher", "ValueChanged");
-       if (msg == NULL)
-               return;
-
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &chr->path,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE,
-                       &chr->value, chr->vlen, DBUS_TYPE_INVALID);
-
-       dbus_message_set_no_reply(msg, TRUE);
-       g_dbus_send_message(conn, msg);
-}
-
-static void events_handler(const uint8_t *pdu, uint16_t len,
-                                                       gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-       struct characteristic *chr;
-       GSList *l;
-       uint8_t opdu[ATT_MAX_MTU];
-       guint handle;
-       uint16_t olen;
-
-       if (len < 3) {
-               DBG("Malformed notification/indication packet (opcode 0x%02x)",
-                                                                       pdu[0]);
-               return;
-       }
-
-       handle = att_get_u16(&pdu[1]);
-
-       l = g_slist_find_custom(gatt->chars, GUINT_TO_POINTER(handle),
-                                               characteristic_handle_cmp);
-       if (!l)
-               return;
-
-       chr = l->data;
-
-       if (chr == NULL) {
-               DBG("Attribute handle 0x%02x not found", handle);
-               return;
-       }
-
-       switch (pdu[0]) {
-       case ATT_OP_HANDLE_IND:
-               olen = enc_confirmation(opdu, sizeof(opdu));
-               g_attrib_send(gatt->attrib, 0, opdu[0], opdu, olen,
-                                               NULL, NULL, NULL);
-       case ATT_OP_HANDLE_NOTIFY:
-               if (characteristic_set_value(chr, &pdu[3], len - 3) < 0)
-                       DBG("Can't change Characteristic 0x%02x", handle);
-
-               g_slist_foreach(gatt->watchers, update_watchers, chr);
-               break;
-       }
-}
-
-static void offline_char_written(gpointer user_data)
-{
-       struct characteristic *chr = user_data;
-       struct gatt_service *gatt = chr->gatt;
-
-       gatt->offline_chars = g_slist_remove(gatt->offline_chars, chr);
-
-       remove_attio(gatt);
-}
-
-static void offline_char_write(gpointer data, gpointer user_data)
-{
-       struct characteristic *chr = data;
-       GAttrib *attrib = user_data;
-
-       gatt_write_cmd(attrib, chr->handle, chr->value, chr->vlen,
-                                               offline_char_written, chr);
-}
-
-static void char_discovered_cb(GSList *characteristics, guint8 status,
-                                                       gpointer user_data);
-
-static void attio_connected(GAttrib *attrib, gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-
-       gatt->attrib = g_attrib_ref(attrib);
-
-       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_NOTIFY,
-                                       events_handler, gatt, NULL);
-       g_attrib_register(gatt->attrib, ATT_OP_HANDLE_IND,
-                                       events_handler, gatt, NULL);
-
-       g_slist_foreach(gatt->offline_chars, offline_char_write, attrib);
-
-       if (gatt->query) {
-               struct gatt_primary *prim = gatt->prim;
-               struct query_data *qchr;
-
-               qchr = g_slist_nth_data(gatt->query->list, 0);
-               gatt_discover_char(gatt->attrib, prim->range.start,
-                                               prim->range.end, NULL,
-                                               char_discovered_cb, qchr);
-       }
-}
-
-static void attio_disconnected(gpointer user_data)
-{
-       struct gatt_service *gatt = user_data;
-
-       if (gatt->query && gatt->query->msg) {
-               DBusMessage *reply;
-
-               reply = btd_error_failed(gatt->query->msg,
-                                       "ATT IO channel was disconnected");
-               g_dbus_send_message(gatt->conn, reply);
-               dbus_message_unref(gatt->query->msg);
-       }
-
-       if (gatt->query) {
-               g_slist_free_full(gatt->query->list, g_free);
-               gatt->query = NULL;
-       }
-
-       if (gatt->attrib) {
-               g_attrib_unref(gatt->attrib);
-               gatt->attrib = NULL;
-       }
-}
-
-static DBusMessage *register_watcher(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct gatt_service *gatt = data;
-       struct watcher *watcher;
-       char *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = g_new0(struct watcher, 1);
-       watcher->name = g_strdup(sender);
-       watcher->gatt = gatt;
-       watcher->path = g_strdup(path);
-       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
-                                                       watcher, watcher_free);
-
-       if (gatt->attioid == 0)
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       attio_connected,
-                                                       attio_disconnected,
-                                                       gatt);
-
-       gatt->watchers = g_slist_append(gatt->watchers, watcher);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_watcher(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct gatt_service *gatt = data;
-       struct watcher *watcher, *match;
-       GSList *l;
-       char *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       match = g_new0(struct watcher, 1);
-       match->name = g_strdup(sender);
-       match->path = g_strdup(path);
-       l = g_slist_find_custom(gatt->watchers, match, watcher_cmp);
-       watcher_free(match);
-       if (!l)
-               return btd_error_not_authorized(msg);
-
-       watcher = l->data;
-       gatt->watchers = g_slist_remove(gatt->watchers, watcher);
-       g_dbus_remove_watch(conn, watcher->id);
-       remove_attio(gatt);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_value(DBusConnection *conn, DBusMessage *msg,
-                       DBusMessageIter *iter, struct characteristic *chr)
-{
-       struct gatt_service *gatt = chr->gatt;
-       DBusMessageIter sub;
-       uint8_t *value;
-       int len;
-
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY ||
-                       dbus_message_iter_get_element_type(iter) != DBUS_TYPE_BYTE)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(iter, &sub);
-
-       dbus_message_iter_get_fixed_array(&sub, &value, &len);
-
-       characteristic_set_value(chr, value, len);
-
-       if (gatt->attioid == 0)
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       attio_connected,
-                                                       attio_disconnected,
-                                                       gatt);
-
-       if (gatt->attrib)
-               gatt_write_cmd(gatt->attrib, chr->handle, value, len,
-                                                               NULL, NULL);
-       else
-               gatt->offline_chars = g_slist_append(gatt->offline_chars, chr);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct characteristic *chr = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       append_char_dict(&iter, chr);
-
-       return reply;
-}
-
-static DBusMessage *set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct characteristic *chr = data;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       if (g_str_equal("Value", property))
-               return set_value(conn, msg, &sub, chr);
-
-       return btd_error_invalid_args(msg);
-}
-
-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) },
-       { }
-};
-
-static char *characteristic_list_to_string(GSList *chars)
-{
-       GString *characteristics;
-       GSList *l;
-
-       characteristics = g_string_new(NULL);
-
-       for (l = chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-               char chr_str[64];
-
-               memset(chr_str, 0, sizeof(chr_str));
-
-               snprintf(chr_str, sizeof(chr_str), "%04X#%02X#%04X#%s ",
-                               chr->handle, chr->perm, chr->end, chr->type);
-
-               characteristics = g_string_append(characteristics, chr_str);
-       }
-
-       return g_string_free(characteristics, FALSE);
-}
-
-static void store_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint8_t bdaddr_type, uint16_t start,
-                                                               GSList *chars)
-{
-       char *characteristics;
-
-       characteristics = characteristic_list_to_string(chars);
-
-       write_device_characteristics(sba, dba, bdaddr_type, start,
-                                                       characteristics);
-
-       g_free(characteristics);
-}
-
-static void register_characteristic(gpointer data, gpointer user_data)
-{
-       struct characteristic *chr = data;
-       DBusConnection *conn = chr->gatt->conn;
-       const char *gatt_path = user_data;
-
-       chr->path = g_strdup_printf("%s/characteristic%04x", gatt_path,
-                                                               chr->handle);
-
-       g_dbus_register_interface(conn, chr->path, CHAR_INTERFACE,
-                                       char_methods, NULL, NULL, chr, NULL);
-
-       DBG("Registered: %s", chr->path);
-}
-
-static GSList *string_to_characteristic_list(struct gatt_service *gatt,
-                                                       const char *str)
-{
-       GSList *l = NULL;
-       char **chars;
-       int i;
-
-       if (str == NULL)
-               return NULL;
-
-       chars = g_strsplit(str, " ", 0);
-       if (chars == NULL)
-               return NULL;
-
-       for (i = 0; chars[i]; i++) {
-               struct characteristic *chr;
-               int ret;
-
-               chr = g_new0(struct characteristic, 1);
-
-               ret = sscanf(chars[i], "%04hX#%02hhX#%04hX#%s", &chr->handle,
-                               &chr->perm, &chr->end, chr->type);
-               if (ret < 4) {
-                       g_free(chr);
-                       continue;
-               }
-
-               chr->gatt = gatt;
-               l = g_slist_append(l, chr);
-       }
-
-       g_strfreev(chars);
-
-       return l;
-}
-
-static GSList *load_characteristics(struct gatt_service *gatt, uint16_t start)
-{
-       GSList *chrs_list;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type;
-       char *str;
-
-       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
-
-       str = read_device_characteristics(&sba, &dba, bdaddr_type, start);
-       if (str == NULL)
-               return NULL;
-
-       chrs_list = string_to_characteristic_list(gatt, str);
-
-       free(str);
-
-       return chrs_list;
-}
-
-static void store_attribute(struct gatt_service *gatt, uint16_t handle,
-                               uint16_t type, uint8_t *value, gsize len)
-{
-       struct btd_device *device = gatt->dev;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type;
-       bt_uuid_t uuid;
-       char *str, *tmp;
-       guint i;
-
-       str = g_malloc0(MAX_LEN_UUID_STR + len * 2 + 1);
-
-       bt_uuid16_create(&uuid, type);
-       bt_uuid_to_string(&uuid, str, MAX_LEN_UUID_STR);
-
-       str[MAX_LEN_UUID_STR - 1] = '#';
-
-       for (i = 0, tmp = str + MAX_LEN_UUID_STR; i < len; i++, tmp += 2)
-               sprintf(tmp, "%02X", value[i]);
-
-       gatt_get_address(gatt, &sba, &dba, NULL);
-
-       bdaddr_type = device_get_addr_type(device);
-
-       write_device_attribute(&sba, &dba, bdaddr_type, handle, str);
-
-       g_free(str);
-}
-
-static void query_list_append(struct gatt_service *gatt, struct query_data *data)
-{
-       struct query *query = gatt->query;
-
-       query->list = g_slist_append(query->list, data);
-}
-
-static void query_list_remove(struct gatt_service *gatt, struct query_data *data)
-{
-       struct query *query = gatt->query;
-
-       query->list = g_slist_remove(query->list, data);
-       if (query->list != NULL)
-               return;
-
-       g_free(query);
-       gatt->query = NULL;
-
-       remove_attio(gatt);
-}
-
-static void update_char_desc(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status == 0) {
-
-               g_free(chr->desc);
-
-               chr->desc = g_malloc(len);
-               memcpy(chr->desc, pdu + 1, len - 1);
-               chr->desc[len - 1] = '\0';
-
-               store_attribute(gatt, current->handle,
-                               GATT_CHARAC_USER_DESC_UUID,
-                               (void *) chr->desc, len);
-       } else if (status == ATT_ECODE_INSUFF_ENC) {
-               GIOChannel *io = g_attrib_get_channel(gatt->attrib);
-               BtIOSecLevel level = BT_IO_SEC_HIGH;
-
-               bt_io_get(io, BT_IO_L2CAP, 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, level,
-                               BT_IO_OPT_INVALID)) {
-                       gatt_read_char(gatt->attrib, current->handle, 0,
-                                       update_char_desc, current);
-                       return;
-               }
-       }
-
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_char_format(guint8 status, const guint8 *pdu, guint16 len,
-                                                               gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status != 0)
-               goto done;
-
-       if (len < 8)
-               goto done;
-
-       g_free(chr->format);
-
-       chr->format = g_new0(struct format, 1);
-       memcpy(chr->format, pdu + 1, 7);
-
-       store_attribute(gatt, current->handle, GATT_CHARAC_FMT_UUID,
-                               (void *) chr->format, sizeof(*chr->format));
-
-done:
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_char_value(guint8 status, const guint8 *pdu,
-                                       guint16 len, gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct characteristic *chr = current->chr;
-
-       if (status == 0)
-               characteristic_set_value(chr, pdu + 1, len - 1);
-       else if (status == ATT_ECODE_INSUFF_ENC) {
-               GIOChannel *io = g_attrib_get_channel(gatt->attrib);
-
-               if (bt_io_set(io, BT_IO_L2CAP, NULL,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
-                               BT_IO_OPT_INVALID)) {
-                       gatt_read_char(gatt->attrib, chr->handle, 0,
-                                       update_char_value, current);
-                       return;
-               }
-       }
-
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static int uuid_desc16_cmp(bt_uuid_t *uuid, guint16 desc)
-{
-       bt_uuid_t u16;
-
-       bt_uuid16_create(&u16, desc);
-
-       return bt_uuid_cmp(uuid, &u16);
-}
-
-static void descriptor_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
-{
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct att_data_list *list;
-       guint8 format;
-       int i;
-
-       if (status != 0)
-               goto done;
-
-       DBG("Find Information Response received");
-
-       list = dec_find_info_resp(pdu, plen, &format);
-       if (list == NULL)
-               goto done;
-
-       for (i = 0; i < list->num; i++) {
-               guint16 handle;
-               bt_uuid_t uuid;
-               uint8_t *info = list->data[i];
-               struct query_data *qfmt;
-
-               handle = att_get_u16(info);
-
-               if (format == 0x01) {
-                       uuid = att_get_uuid16(&info[2]);
-               } else {
-                       /* Currently, only "user description" and "presentation
-                        * format" descriptors are used, and both have 16-bit
-                        * UUIDs. Therefore there is no need to support format
-                        * 0x02 yet. */
-                       continue;
-               }
-               qfmt = g_new0(struct query_data, 1);
-               qfmt->gatt = current->gatt;
-               qfmt->chr = current->chr;
-               qfmt->handle = handle;
-
-               if (uuid_desc16_cmp(&uuid, GATT_CHARAC_USER_DESC_UUID) == 0) {
-                       query_list_append(gatt, qfmt);
-                       gatt_read_char(gatt->attrib, handle, 0, update_char_desc,
-                                                                       qfmt);
-               } else if (uuid_desc16_cmp(&uuid, GATT_CHARAC_FMT_UUID) == 0) {
-                       query_list_append(gatt, qfmt);
-                       gatt_read_char(gatt->attrib, handle, 0,
-                                               update_char_format, qfmt);
-               } else
-                       g_free(qfmt);
-       }
-
-       att_data_list_free(list);
-done:
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static void update_all_chars(gpointer data, gpointer user_data)
-{
-       struct query_data *qdesc, *qvalue;
-       struct characteristic *chr = data;
-       struct gatt_service *gatt = user_data;
-
-       qdesc = g_new0(struct query_data, 1);
-       qdesc->gatt = gatt;
-       qdesc->chr = chr;
-
-       query_list_append(gatt, qdesc);
-
-       gatt_find_info(gatt->attrib, chr->handle + 1, chr->end, descriptor_cb,
-                                                                       qdesc);
-
-       qvalue = g_new0(struct query_data, 1);
-       qvalue->gatt = gatt;
-       qvalue->chr = chr;
-
-       query_list_append(gatt, qvalue);
-
-       gatt_read_char(gatt->attrib, chr->handle, 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;
-       struct query_data *current = user_data;
-       struct gatt_service *gatt = current->gatt;
-       struct gatt_primary *prim = gatt->prim;
-       uint16_t *previous_end = NULL;
-       GSList *l;
-       bdaddr_t sba, dba;
-       uint8_t bdaddr_type;
-
-       if (status != 0) {
-               const char *str = att_ecode2str(status);
-
-               DBG("Discover all characteristics failed: %s", str);
-               reply = btd_error_failed(gatt->query->msg, str);
-               goto fail;
-       }
-
-       for (l = characteristics; l; l = l->next) {
-               struct gatt_char *current_chr = l->data;
-               struct characteristic *chr;
-               guint handle = current_chr->value_handle;
-               GSList *lchr;
-
-               lchr = g_slist_find_custom(gatt->chars,
-                       GUINT_TO_POINTER(handle), characteristic_handle_cmp);
-               if (lchr)
-                       continue;
-
-               chr = g_new0(struct characteristic, 1);
-               chr->gatt = gatt;
-               chr->perm = current_chr->properties;
-               chr->handle = current_chr->value_handle;
-               strncpy(chr->type, current_chr->uuid, sizeof(chr->type));
-
-               if (previous_end)
-                       *previous_end = current_chr->handle;
-
-               previous_end = &chr->end;
-
-               gatt->chars = g_slist_append(gatt->chars, chr);
-               register_characteristic(chr, gatt->path);
-       }
-
-       if (previous_end)
-               *previous_end = prim->range.end;
-
-       gatt_get_address(gatt, &sba, &dba, &bdaddr_type);
-       store_characteristics(&sba, &dba, bdaddr_type, prim->range.start,
-                                                               gatt->chars);
-
-       g_slist_foreach(gatt->chars, update_all_chars, gatt);
-
-       reply = create_discover_char_reply(gatt->query->msg, gatt->chars);
-
-fail:
-       dbus_message_unref(gatt->query->msg);
-       gatt->query->msg = NULL;
-
-       g_dbus_send_message(gatt->conn, reply);
-       query_list_remove(gatt, current);
-       g_free(current);
-}
-
-static DBusMessage *discover_char(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct gatt_service *gatt = data;
-       struct query *query;
-       struct query_data *qchr;
-
-       if (gatt->query)
-               return btd_error_busy(msg);
-
-       query = g_new0(struct query, 1);
-
-       qchr = g_new0(struct query_data, 1);
-       qchr->gatt = gatt;
-
-       query->msg = dbus_message_ref(msg);
-
-       if (gatt->attioid == 0) {
-               gatt->attioid = btd_device_add_attio_callback(gatt->dev,
-                                                       attio_connected,
-                                                       attio_disconnected,
-                                                       gatt);
-       } else if (gatt->attrib) {
-               struct gatt_primary *prim = gatt->prim;
-               gatt_discover_char(gatt->attrib, prim->range.start,
-                                               prim->range.end, NULL,
-                                               char_discovered_cb, qchr);
-       }
-
-       gatt->query = query;
-
-       query_list_append(gatt, qchr);
-
-       return NULL;
-}
-
-static DBusMessage *prim_get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct gatt_service *gatt = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       GSList *l;
-       char **chars;
-       const char *uuid;
-       int i;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       chars = g_new0(char *, g_slist_length(gatt->chars) + 1);
-
-       for (i = 0, l = gatt->chars; l; l = l->next, i++) {
-               struct characteristic *chr = l->data;
-               chars[i] = chr->path;
-       }
-
-       dict_append_array(&dict, "Characteristics", DBUS_TYPE_OBJECT_PATH,
-                                                               &chars, i);
-       uuid = gatt->prim->uuid;
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
-
-       g_free(chars);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static const GDBusMethodTable prim_methods[] = {
-       { GDBUS_ASYNC_METHOD("DiscoverCharacteristics",
-                       NULL, GDBUS_ARGS({ "characteristics", "ao" }),
-                       discover_char) },
-       { GDBUS_METHOD("RegisterCharacteristicsWatcher",
-                       GDBUS_ARGS({ "agent", "o" }), NULL,
-                       register_watcher) },
-       { GDBUS_METHOD("UnregisterCharacteristicsWatcher",
-                       GDBUS_ARGS({ "agent", "o" }), NULL,
-                       unregister_watcher) },
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       prim_get_properties) },
-       { }
-};
-
-static struct gatt_service *primary_register(DBusConnection *conn,
-                                               struct btd_device *device,
-                                               struct gatt_primary *prim,
-                                               int psm)
-{
-       struct gatt_service *gatt;
-       const char *device_path;
-
-       device_path = device_get_path(device);
-
-       gatt = g_new0(struct gatt_service, 1);
-       gatt->dev = btd_device_ref(device);
-       gatt->prim = prim;
-       gatt->psm = psm;
-       gatt->conn = dbus_connection_ref(conn);
-       gatt->path = g_strdup_printf("%s/service%04x", device_path,
-                                                               prim->range.start);
-
-       g_dbus_register_interface(gatt->conn, gatt->path,
-                                       CHAR_INTERFACE, prim_methods,
-                                       NULL, NULL, gatt, NULL);
-       gatt->chars = load_characteristics(gatt, prim->range.start);
-       g_slist_foreach(gatt->chars, register_characteristic, gatt->path);
-
-       return gatt;
-}
-
-GSList *attrib_client_register(DBusConnection *connection,
-                                       struct btd_device *device, int psm,
-                                       GAttrib *attrib, GSList *primaries)
-{
-       GSList *l, *services;
-
-       for (l = primaries, services = NULL; l; l = l->next) {
-               struct gatt_primary *prim = l->data;
-               struct gatt_service *gatt;
-
-               gatt = primary_register(connection, device, prim, psm);
-
-               DBG("Registered: %s", gatt->path);
-
-               services = g_slist_append(services, g_strdup(gatt->path));
-               gatt_services = g_slist_append(gatt_services, gatt);
-
-       }
-
-       return services;
-}
-
-static void primary_unregister(struct gatt_service *gatt)
-{
-       GSList *l;
-
-       for (l = gatt->chars; l; l = l->next) {
-               struct characteristic *chr = l->data;
-               g_dbus_unregister_interface(gatt->conn, chr->path,
-                                                       CHAR_INTERFACE);
-       }
-
-       g_dbus_unregister_interface(gatt->conn, gatt->path, CHAR_INTERFACE);
-
-       remove_attio(gatt);
-}
-
-static int path_cmp(gconstpointer data, gconstpointer user_data)
-{
-       const char *path = data;
-       const char *gatt_path = user_data;
-
-       return g_strcmp0(path, gatt_path);
-}
-
-void attrib_client_unregister(GSList *services)
-{
-       GSList *l, *left;
-
-       for (l = gatt_services, left = NULL; l; l = l->next) {
-               struct gatt_service *gatt = l->data;
-
-               if (!g_slist_find_custom(services, gatt->path, path_cmp)) {
-                       left = g_slist_append(left, gatt);
-                       continue;
-               }
-
-               primary_unregister(gatt);
-               gatt_service_free(gatt);
-       }
-
-       g_slist_free(gatt_services);
-       gatt_services = left;
-}
diff --git a/attrib/client.h b/attrib/client.h
deleted file mode 100644 (file)
index 948f030..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-GSList *attrib_client_register(DBusConnection *connection,
-                                       struct btd_device *device, int psm,
-                                       GAttrib *attrib, GSList *primaries);
-void attrib_client_unregister(GSList *services);
index a9de98c..a8ab582 100644 (file)
 #endif
 
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 #include <adapter.h>
 
+#include "lib/uuid.h"
 #include "gattrib.h"
 #include "att.h"
 #include "gatt.h"
@@ -68,11 +68,17 @@ static GSList *parse_opts(gatt_option opt1, va_list args)
 
        while (opt != GATT_OPT_INVALID) {
                switch (opt) {
-               case GATT_OPT_CHR_UUID:
+               case GATT_OPT_CHR_UUID16:
                        bt_uuid16_create(&info->uuid, va_arg(args, int));
                        /* characteristic declaration and value */
                        info->num_attrs += 2;
                        break;
+               case GATT_OPT_CHR_UUID:
+                       memcpy(&info->uuid, va_arg(args, bt_uuid_t *),
+                                                       sizeof(bt_uuid_t));
+                       /* characteristic declaration and value */
+                       info->num_attrs += 2;
+                       break;
                case GATT_OPT_CHR_PROPS:
                        info->props = va_arg(args, int);
 
@@ -108,7 +114,7 @@ static GSList *parse_opts(gatt_option opt1, va_list args)
                }
 
                opt = va_arg(args, gatt_option);
-               if (opt == GATT_OPT_CHR_UUID) {
+               if (opt == GATT_OPT_CHR_UUID16 || opt == GATT_OPT_CHR_UUID) {
                        info = g_new0(struct gatt_info, 1);
                        l = g_slist_append(l, info);
                }
@@ -139,7 +145,7 @@ static struct attribute *add_service_declaration(struct btd_adapter *adapter,
                                                ATT_NOT_PERMITTED, atval, len);
 }
 
-static int att_read_reqs(int authorization, int authentication, uint8_t props)
+static int att_read_req(int authorization, int authentication, uint8_t props)
 {
        if (authorization == GATT_CHR_VALUE_READ ||
                                authorization == GATT_CHR_VALUE_BOTH)
@@ -153,7 +159,7 @@ static int att_read_reqs(int authorization, int authentication, uint8_t props)
        return ATT_NONE;
 }
 
-static int att_write_reqs(int authorization, int authentication, uint8_t props)
+static int att_write_req(int authorization, int authentication, uint8_t props)
 {
        if (authorization == GATT_CHR_VALUE_WRITE ||
                                authorization == GATT_CHR_VALUE_BOTH)
@@ -168,7 +174,7 @@ static int att_write_reqs(int authorization, int authentication, uint8_t props)
        return ATT_NONE;
 }
 
-static gint find_callback(gconstpointer a, gconstpointer b)
+static int find_callback(gconstpointer a, gconstpointer b)
 {
        const struct attrib_cb *cb = a;
        unsigned int event = GPOINTER_TO_UINT(b);
@@ -179,26 +185,27 @@ static gint find_callback(gconstpointer a, gconstpointer b)
 static gboolean add_characteristic(struct btd_adapter *adapter,
                                uint16_t *handle, struct gatt_info *info)
 {
-       int read_reqs, write_reqs;
+       int read_req, write_req;
        uint16_t h = *handle;
        struct attribute *a;
        bt_uuid_t bt_uuid;
-       uint8_t atval[5];
+       uint8_t atval[ATT_MAX_VALUE_LEN];
        GSList *l;
 
-       if (!info->uuid.value.u16 || !info->props) {
+       if ((info->uuid.type != BT_UUID16 && info->uuid.type != BT_UUID128) ||
+                                                               !info->props) {
                error("Characteristic UUID or properties are missing");
                return FALSE;
        }
 
-       read_reqs = att_read_reqs(info->authorization, info->authentication,
+       read_req = att_read_req(info->authorization, info->authentication,
                                                                info->props);
-       write_reqs = att_write_reqs(info->authorization, info->authentication,
+       write_req = att_write_req(info->authorization, info->authentication,
                                                                info->props);
 
        /* TODO: static characteristic values are not supported, therefore a
         * callback must be always provided if a read/write property is set */
-       if (read_reqs != ATT_NOT_PERMITTED) {
+       if (read_req != ATT_NOT_PERMITTED) {
                gpointer reqs = GUINT_TO_POINTER(ATTRIB_READ);
 
                if (!g_slist_find_custom(info->callbacks, reqs,
@@ -208,7 +215,7 @@ static gboolean add_characteristic(struct btd_adapter *adapter,
                }
        }
 
-       if (write_reqs != ATT_NOT_PERMITTED) {
+       if (write_req != ATT_NOT_PERMITTED) {
                gpointer reqs = GUINT_TO_POINTER(ATTRIB_WRITE);
 
                if (!g_slist_find_custom(info->callbacks, reqs,
@@ -222,13 +229,13 @@ static gboolean add_characteristic(struct btd_adapter *adapter,
        bt_uuid16_create(&bt_uuid, GATT_CHARAC_UUID);
        atval[0] = info->props;
        att_put_u16(h + 1, &atval[1]);
-       att_put_u16(info->uuid.value.u16, &atval[3]);
+       att_put_uuid(info->uuid, &atval[3]);
        if (attrib_db_add(adapter, h++, &bt_uuid, ATT_NONE, ATT_NOT_PERMITTED,
-                                               atval, sizeof(atval)) == NULL)
+                               atval, 3 + info->uuid.type / 8) == NULL)
                return FALSE;
 
        /* characteristic value */
-       a = attrib_db_add(adapter, h++, &info->uuid, read_reqs, write_reqs,
+       a = attrib_db_add(adapter, h++, &info->uuid, read_req, write_req,
                                                                NULL, 0);
        if (a == NULL)
                return FALSE;
@@ -341,7 +348,7 @@ gboolean gatt_service_add(struct btd_adapter *adapter, uint16_t uuid,
        }
 
        g_assert(size < USHRT_MAX);
-       g_assert(h - start_handle == (uint16_t) size);
+       g_assert(h == 0 || (h - start_handle == (uint16_t) size));
        g_slist_free_full(chrs, free_gatt_info);
 
        return TRUE;
index b810e2e..728d3a8 100644 (file)
 
 typedef enum {
        GATT_OPT_INVALID = 0,
+
+       /* bt_uuid_t* value */
        GATT_OPT_CHR_UUID,
+
+       /* a uint16 value */
+       GATT_OPT_CHR_UUID16,
+
        GATT_OPT_CHR_PROPS,
        GATT_OPT_CHR_VALUE_CB,
        GATT_OPT_CHR_AUTHENTICATION,
index 6f9a11d..bb2cae1 100644 (file)
 #include <stdint.h>
 #include <stdlib.h>
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include "lib/uuid.h"
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
@@ -45,6 +45,22 @@ struct discover_primary {
        void *user_data;
 };
 
+/* Used for the Included Services Discovery (ISD) procedure */
+struct included_discovery {
+       GAttrib         *attrib;
+       int             refs;
+       int             err;
+       uint16_t        end_handle;
+       GSList          *includes;
+       gatt_cb_t       cb;
+       void            *user_data;
+};
+
+struct included_uuid_query {
+       struct included_discovery       *isd;
+       struct gatt_included            *included;
+};
+
 struct discover_char {
        GAttrib *attrib;
        bt_uuid_t *uuid;
@@ -61,6 +77,28 @@ static void discover_primary_free(struct discover_primary *dp)
        g_free(dp);
 }
 
+static struct included_discovery *isd_ref(struct included_discovery *isd)
+{
+       __sync_fetch_and_add(&isd->refs, 1);
+
+       return isd;
+}
+
+static void isd_unref(struct included_discovery *isd)
+{
+       if (__sync_sub_and_fetch(&isd->refs, 1) > 0)
+               return;
+
+       if (isd->err)
+               isd->cb(NULL, isd->err, isd->user_data);
+       else
+               isd->cb(isd->includes, isd->err, isd->user_data);
+
+       g_slist_free_full(isd->includes, g_free);
+       g_attrib_unref(isd->attrib);
+       g_free(isd);
+}
+
 static void discover_char_free(struct discover_char *dc)
 {
        g_slist_free_full(dc->characteristics, g_free);
@@ -84,7 +122,7 @@ static guint16 encode_discover_primary(uint16_t start, uint16_t end,
                uint16_t u16;
                uint128_t u128;
                const void *value;
-               int vlen;
+               size_t vlen;
 
                /* Discover primary service by service UUID */
 
@@ -114,7 +152,8 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
        struct att_range *range;
        uint8_t *buf;
        guint16 oplen;
-       int err = 0, buflen;
+       int err = 0;
+       size_t buflen;
 
        if (status) {
                err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
@@ -140,8 +179,7 @@ static void primary_by_uuid_cb(guint8 status, const guint8 *ipdu,
        if (oplen == 0)
                goto done;
 
-       g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_by_uuid_cb,
-                                                               dp, NULL);
+       g_attrib_send(dp->attrib, 0, buf, oplen, primary_by_uuid_cb, dp, NULL);
        return;
 
 done:
@@ -188,6 +226,7 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 
                primary = g_try_new0(struct gatt_primary, 1);
                if (!primary) {
+                       att_data_list_free(list);
                        err = ATT_ECODE_INSUFF_RESOURCES;
                        goto done;
                }
@@ -201,12 +240,12 @@ static void primary_all_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        err = 0;
 
        if (end != 0xffff) {
-               int buflen;
+               size_t buflen;
                uint8_t *buf = g_attrib_get_buffer(dp->attrib, &buflen);
                guint16 oplen = encode_discover_primary(end + 1, 0xffff, NULL,
                                                                buf, buflen);
 
-               g_attrib_send(dp->attrib, 0, buf[0], buf, oplen, primary_all_cb,
+               g_attrib_send(dp->attrib, 0, buf, oplen, primary_all_cb,
                                                                dp, NULL);
 
                return;
@@ -221,7 +260,7 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
                                                        gpointer user_data)
 {
        struct discover_primary *dp;
-       int buflen;
+       size_t buflen;
        uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        GAttribResultFunc cb;
        guint16 plen;
@@ -244,7 +283,162 @@ guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
        } else
                cb = primary_all_cb;
 
-       return g_attrib_send(attrib, 0, buf[0], buf, plen, cb, dp, NULL);
+       return g_attrib_send(attrib, 0, buf, plen, cb, dp, NULL);
+}
+
+static void resolve_included_uuid_cb(uint8_t status, const uint8_t *pdu,
+                                       uint16_t len, gpointer user_data)
+{
+       struct included_uuid_query *query = user_data;
+       struct included_discovery *isd = query->isd;
+       struct gatt_included *incl = query->included;
+       unsigned int err = status;
+       bt_uuid_t uuid;
+       size_t buflen;
+       uint8_t *buf;
+
+       if (err)
+               goto done;
+
+       buf = g_attrib_get_buffer(isd->attrib, &buflen);
+       if (dec_read_resp(pdu, len, buf, buflen) != 16) {
+               err = ATT_ECODE_IO;
+               goto done;
+       }
+
+       uuid = att_get_uuid128(buf);
+       bt_uuid_to_string(&uuid, incl->uuid, sizeof(incl->uuid));
+       isd->includes = g_slist_append(isd->includes, incl);
+
+done:
+       if (err)
+               g_free(incl);
+
+       if (isd->err == 0)
+               isd->err = err;
+
+       isd_unref(isd);
+
+       g_free(query);
+}
+
+static guint resolve_included_uuid(struct included_discovery *isd,
+                                       struct gatt_included *incl)
+{
+       struct included_uuid_query *query;
+       size_t buflen;
+       uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
+       guint16 oplen = enc_read_req(incl->range.start, buf, buflen);
+
+       query = g_new0(struct included_uuid_query, 1);
+       query->isd = isd_ref(isd);
+       query->included = incl;
+
+       return g_attrib_send(isd->attrib, 0, buf, oplen,
+                               resolve_included_uuid_cb, query, NULL);
+}
+
+static struct gatt_included *included_from_buf(const uint8_t *buf, gsize len)
+{
+       struct gatt_included *incl = g_new0(struct gatt_included, 1);
+
+       incl->handle = att_get_u16(&buf[0]);
+       incl->range.start = att_get_u16(&buf[2]);
+       incl->range.end = att_get_u16(&buf[4]);
+
+       if (len == 8) {
+               bt_uuid_t uuid128;
+               bt_uuid_t uuid16 = att_get_uuid16(&buf[6]);
+
+               bt_uuid_to_uuid128(&uuid16, &uuid128);
+               bt_uuid_to_string(&uuid128, incl->uuid, sizeof(incl->uuid));
+       }
+
+       return incl;
+}
+
+static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data);
+
+static guint find_included(struct included_discovery *isd, uint16_t start)
+{
+       bt_uuid_t uuid;
+       size_t buflen;
+       uint8_t *buf = g_attrib_get_buffer(isd->attrib, &buflen);
+       guint16 oplen;
+
+       bt_uuid16_create(&uuid, GATT_INCLUDE_UUID);
+       oplen = enc_read_by_type_req(start, isd->end_handle, &uuid,
+                                                       buf, buflen);
+
+       return g_attrib_send(isd->attrib, 0, buf, oplen, find_included_cb,
+                               isd_ref(isd), (GDestroyNotify) isd_unref);
+}
+
+static void find_included_cb(uint8_t status, const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct included_discovery *isd = user_data;
+       uint16_t last_handle = isd->end_handle;
+       unsigned int err = status;
+       struct att_data_list *list;
+       int i;
+
+       if (err == ATT_ECODE_ATTR_NOT_FOUND)
+               err = 0;
+
+       if (status)
+               goto done;
+
+       list = dec_read_by_type_resp(pdu, len);
+       if (list == NULL) {
+               err = ATT_ECODE_IO;
+               goto done;
+       }
+
+       if (list->len != 6 && list->len != 8) {
+               err = ATT_ECODE_IO;
+               att_data_list_free(list);
+               goto done;
+       }
+
+       for (i = 0; i < list->num; i++) {
+               struct gatt_included *incl;
+
+               incl = included_from_buf(list->data[i], list->len);
+               last_handle = incl->handle;
+
+               /* 128 bit UUID, needs resolving */
+               if (list->len == 6) {
+                       resolve_included_uuid(isd, incl);
+                       continue;
+               }
+
+               isd->includes = g_slist_append(isd->includes, incl);
+       }
+
+       att_data_list_free(list);
+
+       if (last_handle < isd->end_handle)
+               find_included(isd, last_handle + 1);
+
+done:
+       if (isd->err == 0)
+               isd->err = err;
+}
+
+unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
+                                       gatt_cb_t func, gpointer user_data)
+{
+       struct included_discovery *isd;
+
+       isd = g_new0(struct included_discovery, 1);
+       isd->attrib = g_attrib_ref(attrib);
+       isd->end_handle = end;
+       isd->cb = func;
+       isd->user_data = user_data;
+
+       return find_included(isd, start);
 }
 
 static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
@@ -252,15 +446,11 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
 {
        struct discover_char *dc = user_data;
        struct att_data_list *list;
-       unsigned int i, err;
-       int buflen;
-       uint8_t *buf;
-       guint16 oplen;
-       bt_uuid_t uuid;
+       unsigned int i, err = ATT_ECODE_ATTR_NOT_FOUND;
        uint16_t last = 0;
 
        if (status) {
-               err = status == ATT_ECODE_ATTR_NOT_FOUND ? 0 : status;
+               err = status;
                goto done;
        }
 
@@ -283,15 +473,15 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
                } else
                        uuid = att_get_uuid128(&value[5]);
 
+               if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid))
+                       continue;
+
                chars = g_try_new0(struct gatt_char, 1);
                if (!chars) {
                        err = ATT_ECODE_INSUFF_RESOURCES;
                        goto done;
                }
 
-               if (dc->uuid && bt_uuid_cmp(dc->uuid, &uuid))
-                       break;
-
                chars->handle = last;
                chars->properties = value[2];
                chars->value_handle = att_get_u16(&value[3]);
@@ -301,9 +491,13 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
        }
 
        att_data_list_free(list);
-       err = 0;
 
        if (last != 0 && (last + 1 < dc->end)) {
+               bt_uuid_t uuid;
+               guint16 oplen;
+               size_t buflen;
+               uint8_t *buf;
+
                buf = g_attrib_get_buffer(dc->attrib, &buflen);
 
                bt_uuid16_create(&uuid, GATT_CHARAC_UUID);
@@ -314,13 +508,15 @@ static void char_discovered_cb(guint8 status, const guint8 *ipdu, guint16 iplen,
                if (oplen == 0)
                        return;
 
-               g_attrib_send(dc->attrib, 0, buf[0], buf, oplen,
-                                               char_discovered_cb, dc, NULL);
+               g_attrib_send(dc->attrib, 0, buf, oplen, char_discovered_cb,
+                                                               dc, NULL);
 
                return;
        }
 
 done:
+       err = (dc->characteristics ? 0 : err);
+
        dc->cb(dc->characteristics, err, dc->user_data);
        discover_char_free(dc);
 }
@@ -329,7 +525,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
                                                bt_uuid_t *uuid, gatt_cb_t func,
                                                gpointer user_data)
 {
-       int buflen;
+       size_t buflen;
        uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        struct discover_char *dc;
        bt_uuid_t type_uuid;
@@ -351,7 +547,7 @@ guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
        dc->end = end;
        dc->uuid = g_memdup(uuid, sizeof(bt_uuid_t));
 
-       return g_attrib_send(attrib, 0, buf[0], buf, plen, char_discovered_cb,
+       return g_attrib_send(attrib, 0, buf, plen, char_discovered_cb,
                                                                dc, NULL);
 }
 
@@ -359,7 +555,7 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
                                        bt_uuid_t *uuid, GAttribResultFunc func,
                                        gpointer user_data)
 {
-       int buflen;
+       size_t buflen;
        uint8_t *buf = g_attrib_get_buffer(attrib, &buflen);
        guint16 plen;
 
@@ -367,8 +563,7 @@ guint gatt_read_char_by_uuid(GAttrib *attrib, uint16_t start, uint16_t end,
        if (plen == 0)
                return 0;
 
-       return g_attrib_send(attrib, 0, ATT_OP_READ_BY_TYPE_REQ,
-                                       buf, plen, func, user_data, NULL);
+       return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
 }
 
 struct read_long_data {
@@ -379,14 +574,14 @@ struct read_long_data {
        guint16 size;
        guint16 handle;
        guint id;
-       gint ref;
+       int ref;
 };
 
 static void read_long_destroy(gpointer user_data)
 {
        struct read_long_data *long_read = user_data;
 
-       if (g_atomic_int_dec_and_test(&long_read->ref) == FALSE)
+       if (__sync_sub_and_fetch(&long_read->ref, 1) > 0)
                return;
 
        if (long_read->buffer != NULL)
@@ -400,7 +595,7 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
 {
        struct read_long_data *long_read = user_data;
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint8 *tmp;
        guint16 plen;
        guint id;
@@ -427,12 +622,11 @@ static void read_blob_helper(guint8 status, const guint8 *rpdu, guint16 rlen,
 
        plen = enc_read_blob_req(long_read->handle, long_read->size - 1,
                                                                buf, buflen);
-       id = g_attrib_send(long_read->attrib, long_read->id,
-                               ATT_OP_READ_BLOB_REQ, buf, plen,
+       id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
                                read_blob_helper, long_read, read_long_destroy);
 
        if (id != 0) {
-               g_atomic_int_inc(&long_read->ref);
+               __sync_fetch_and_add(&long_read->ref, 1);
                return;
        }
 
@@ -447,7 +641,7 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
                                        guint16 rlen, gpointer user_data)
 {
        struct read_long_data *long_read = user_data;
-       int buflen;
+       size_t buflen;
        uint8_t *buf = g_attrib_get_buffer(long_read->attrib, &buflen);
        guint16 plen;
        guint id;
@@ -456,20 +650,20 @@ static void read_char_helper(guint8 status, const guint8 *rpdu,
                goto done;
 
        long_read->buffer = g_malloc(rlen);
-
-       if (long_read->buffer == NULL)
+       if (long_read->buffer == NULL) {
+               status = ATT_ECODE_INSUFF_RESOURCES;
                goto done;
+       }
 
        memcpy(long_read->buffer, rpdu, rlen);
        long_read->size = rlen;
 
        plen = enc_read_blob_req(long_read->handle, rlen - 1, buf, buflen);
-       id = g_attrib_send(long_read->attrib, long_read->id,
-                       ATT_OP_READ_BLOB_REQ, buf, plen, read_blob_helper,
-                       long_read, read_long_destroy);
 
+       id = g_attrib_send(long_read->attrib, long_read->id, buf, plen,
+                               read_blob_helper, long_read, read_long_destroy);
        if (id != 0) {
-               g_atomic_int_inc(&long_read->ref);
+               __sync_fetch_and_add(&long_read->ref, 1);
                return;
        }
 
@@ -479,11 +673,11 @@ done:
        long_read->func(status, rpdu, rlen, long_read->user_data);
 }
 
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
-                               GAttribResultFunc func, gpointer user_data)
+guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
+                                                       gpointer user_data)
 {
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint16 plen;
        guint id;
        struct read_long_data *long_read;
@@ -499,62 +693,144 @@ guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
        long_read->handle = handle;
 
        buf = g_attrib_get_buffer(attrib, &buflen);
-       if (offset > 0) {
-               plen = enc_read_blob_req(long_read->handle, offset, buf,
-                                                                       buflen);
-               id = g_attrib_send(attrib, 0, ATT_OP_READ_BLOB_REQ, buf, plen,
-                               read_blob_helper, long_read, read_long_destroy);
-       } else {
-               plen = enc_read_req(handle, buf, buflen);
-               id = g_attrib_send(attrib, 0, ATT_OP_READ_REQ, buf, plen,
-                               read_char_helper, long_read, read_long_destroy);
-       }
-
+       plen = enc_read_req(handle, buf, buflen);
+       id = g_attrib_send(attrib, 0, buf, plen, read_char_helper,
+                                               long_read, read_long_destroy);
        if (id == 0)
                g_free(long_read);
        else {
-               g_atomic_int_inc(&long_read->ref);
+               __sync_fetch_and_add(&long_read->ref, 1);
                long_read->id = id;
        }
 
        return id;
 }
 
-guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
-                       int vlen, GAttribResultFunc func, gpointer user_data)
+struct write_long_data {
+       GAttrib *attrib;
+       GAttribResultFunc func;
+       gpointer user_data;
+       guint16 handle;
+       uint16_t offset;
+       uint8_t *value;
+       size_t vlen;
+};
+
+static guint execute_write(GAttrib *attrib, uint8_t flags,
+                               GAttribResultFunc func, gpointer user_data)
 {
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint16 plen;
 
        buf = g_attrib_get_buffer(attrib, &buflen);
-       if (func)
+       plen = enc_exec_write_req(flags, buf, buflen);
+       if (plen == 0)
+               return 0;
+
+       return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
+}
+
+static guint prepare_write(struct write_long_data *long_write);
+
+static void prepare_write_cb(guint8 status, const guint8 *rpdu, guint16 rlen,
+                                                       gpointer user_data)
+{
+       struct write_long_data *long_write = user_data;
+
+       if (status != 0) {
+               long_write->func(status, rpdu, rlen, long_write->user_data);
+               return;
+       }
+
+       /* Skip Prepare Write Response PDU header (5 bytes) */
+       long_write->offset += rlen - 5;
+
+       if (long_write->offset == long_write->vlen) {
+               execute_write(long_write->attrib, ATT_WRITE_ALL_PREP_WRITES,
+                               long_write->func, long_write->user_data);
+               g_free(long_write->value);
+               g_free(long_write);
+
+               return;
+       }
+
+       prepare_write(long_write);
+}
+
+static guint prepare_write(struct write_long_data *long_write)
+{
+       GAttrib *attrib = long_write->attrib;
+       uint16_t handle = long_write->handle;
+       uint16_t offset = long_write->offset;
+       uint8_t *buf, *value = long_write->value + offset;
+       size_t buflen, vlen = long_write->vlen - offset;
+       guint16 plen;
+
+       buf = g_attrib_get_buffer(attrib, &buflen);
+
+       plen = enc_prep_write_req(handle, offset, value, vlen, buf, buflen);
+       if (plen == 0)
+               return 0;
+
+       return g_attrib_send(attrib, 0, buf, plen, prepare_write_cb, long_write,
+                                                                       NULL);
+}
+
+guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
+                       size_t vlen, GAttribResultFunc func, gpointer user_data)
+{
+       uint8_t *buf;
+       size_t buflen;
+       struct write_long_data *long_write;
+
+       buf = g_attrib_get_buffer(attrib, &buflen);
+
+       /* Use Write Request if payload fits on a single transfer, including 3
+        * bytes for the header. */
+       if (vlen <= buflen - 3) {
+               uint16_t plen;
+
                plen = enc_write_req(handle, value, vlen, buf, buflen);
-       else
-               plen = enc_write_cmd(handle, value, vlen, buf, buflen);
+               if (plen == 0)
+                       return 0;
+
+               return g_attrib_send(attrib, 0, buf, plen, func, user_data,
+                                                                       NULL);
+       }
+
+       /* Write Long Characteristic Values */
+       long_write = g_try_new0(struct write_long_data, 1);
+       if (long_write == NULL)
+               return 0;
+
+       long_write->attrib = attrib;
+       long_write->func = func;
+       long_write->user_data = user_data;
+       long_write->handle = handle;
+       long_write->value = g_memdup(value, vlen);
+       long_write->vlen = vlen;
 
-       return g_attrib_send(attrib, 0, buf[0], buf, plen, func,
-                                                       user_data, NULL);
+       return prepare_write(long_write);
 }
 
 guint gatt_exchange_mtu(GAttrib *attrib, uint16_t mtu, GAttribResultFunc func,
                                                        gpointer user_data)
 {
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint16 plen;
 
        buf = g_attrib_get_buffer(attrib, &buflen);
        plen = enc_mtu_req(mtu, buf, buflen);
-       return g_attrib_send(attrib, 0, ATT_OP_MTU_REQ, buf, plen, func,
-                                                       user_data, NULL);
+       return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
 }
 
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
+guint gatt_discover_char_desc(GAttrib *attrib, uint16_t start, uint16_t end,
                                GAttribResultFunc func, gpointer user_data)
 {
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint16 plen;
 
        buf = g_attrib_get_buffer(attrib, &buflen);
@@ -562,21 +838,19 @@ guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
        if (plen == 0)
                return 0;
 
-       return g_attrib_send(attrib, 0, ATT_OP_FIND_INFO_REQ, buf, plen, func,
-                                                       user_data, NULL);
+       return g_attrib_send(attrib, 0, buf, plen, func, user_data, NULL);
 }
 
 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
                                GDestroyNotify notify, gpointer user_data)
 {
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint16 plen;
 
        buf = g_attrib_get_buffer(attrib, &buflen);
        plen = enc_write_cmd(handle, value, vlen, buf, buflen);
-       return g_attrib_send(attrib, 0, ATT_OP_WRITE_CMD, buf, plen, NULL,
-                                                       user_data, notify);
+       return g_attrib_send(attrib, 0, buf, plen, NULL, user_data, notify);
 }
 
 static sdp_data_t *proto_seq_find(sdp_list_t *proto_list)
index 9ffe58f..e5abd85 100644 (file)
@@ -46,6 +46,8 @@
 #define GATT_CHARAC_FMT_UUID           0x2904
 #define GATT_CHARAC_AGREG_FMT_UUID     0x2905
 #define GATT_CHARAC_VALID_RANGE_UUID   0x2906
+#define GATT_EXTERNAL_REPORT_REFERENCE 0x2907
+#define GATT_REPORT_REFERENCE          0x2908
 
 /* Client Characteristic Configuration bit field */
 #define GATT_CLIENT_CHARAC_CFG_NOTIF_BIT       0x0001
@@ -55,6 +57,13 @@ typedef void (*gatt_cb_t) (GSList *l, guint8 status, gpointer user_data);
 
 struct gatt_primary {
        char uuid[MAX_LEN_UUID_STR + 1];
+       gboolean changed;
+       struct att_range range;
+};
+
+struct gatt_included {
+       char uuid[MAX_LEN_UUID_STR + 1];
+       uint16_t handle;
        struct att_range range;
 };
 
@@ -68,17 +77,21 @@ struct gatt_char {
 guint gatt_discover_primary(GAttrib *attrib, bt_uuid_t *uuid, gatt_cb_t func,
                                                        gpointer user_data);
 
+unsigned int gatt_find_included(GAttrib *attrib, uint16_t start, uint16_t end,
+                                       gatt_cb_t func, gpointer user_data);
+
 guint gatt_discover_char(GAttrib *attrib, uint16_t start, uint16_t end,
                                        bt_uuid_t *uuid, gatt_cb_t func,
                                        gpointer user_data);
 
-guint gatt_read_char(GAttrib *attrib, uint16_t handle, uint16_t offset,
-                               GAttribResultFunc func, gpointer user_data);
+guint gatt_read_char(GAttrib *attrib, uint16_t handle, GAttribResultFunc func,
+                                                       gpointer user_data);
 
 guint gatt_write_char(GAttrib *attrib, uint16_t handle, uint8_t *value,
-                       int vlen, GAttribResultFunc func, gpointer user_data);
+                                       size_t vlen, GAttribResultFunc func,
+                                       gpointer user_data);
 
-guint gatt_find_info(GAttrib *attrib, uint16_t start, uint16_t end,
+guint gatt_discover_char_desc(GAttrib *attrib, uint16_t start, uint16_t end,
                                GAttribResultFunc func, gpointer user_data);
 
 guint gatt_write_cmd(GAttrib *attrib, uint16_t handle, uint8_t *value, int vlen,
index 00f59d7..609b908 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include <glib.h>
 
 #include <stdio.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
+#include <btio/btio.h>
 
+#include "lib/uuid.h"
 #include "log.h"
 #include "att.h"
-#include "btio.h"
 #include "gattrib.h"
 
 #define GATT_TIMEOUT 30
 
 struct _GAttrib {
        GIOChannel *io;
-       gint refs;
+       int refs;
        uint8_t *buf;
-       int buflen;
+       size_t buflen;
        guint read_watch;
        guint write_watch;
        guint timeout_watch;
@@ -52,7 +57,7 @@ struct _GAttrib {
        guint next_cmd_id;
        GDestroyNotify destroy;
        gpointer destroy_user_data;
-       gboolean stale;
+       bool stale;
 };
 
 struct command {
@@ -61,7 +66,7 @@ struct command {
        guint8 *pdu;
        guint16 len;
        guint8 expected;
-       gboolean sent;
+       bool sent;
        GAttribResultFunc func;
        gpointer user_data;
        GDestroyNotify notify;
@@ -70,6 +75,7 @@ struct command {
 struct event {
        guint id;
        guint8 expected;
+       guint16 handle;
        GAttribNotifyFunc func;
        gpointer user_data;
        GDestroyNotify notify;
@@ -118,7 +124,7 @@ static guint8 opcode2expected(guint8 opcode)
        return 0;
 }
 
-static gboolean is_response(guint8 opcode)
+static bool is_response(guint8 opcode)
 {
        switch (opcode) {
        case ATT_OP_ERROR:
@@ -134,20 +140,22 @@ static gboolean is_response(guint8 opcode)
        case ATT_OP_PREP_WRITE_RESP:
        case ATT_OP_EXEC_WRITE_RESP:
        case ATT_OP_HANDLE_CNF:
-               return TRUE;
+               return true;
        }
 
-       return FALSE;
+       return false;
 }
 
 GAttrib *g_attrib_ref(GAttrib *attrib)
 {
+       int refs;
+
        if (!attrib)
                return NULL;
 
-       g_atomic_int_inc(&attrib->refs);
+       refs = __sync_add_and_fetch(&attrib->refs, 1);
 
-       DBG("%p: ref=%d", attrib, attrib->refs);
+       DBG("%p: ref=%d", attrib, refs);
 
        return attrib;
 }
@@ -214,16 +222,16 @@ static void attrib_destroy(GAttrib *attrib)
 
 void g_attrib_unref(GAttrib *attrib)
 {
-       gboolean ret;
+       int refs;
 
        if (!attrib)
                return;
 
-       ret = g_atomic_int_dec_and_test(&attrib->refs);
+       refs = __sync_sub_and_fetch(&attrib->refs, 1);
 
-       DBG("%p: ref=%d", attrib, attrib->refs);
+       DBG("%p: ref=%d", attrib, refs);
 
-       if (ret == FALSE)
+       if (refs > 0)
                return;
 
        attrib_destroy(attrib);
@@ -272,7 +280,7 @@ static gboolean disconnect_timeout(gpointer data)
        }
 
 done:
-       attrib->stale = TRUE;
+       attrib->stale = true;
 
        g_attrib_unref(attrib);
 
@@ -311,10 +319,16 @@ static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
        if (cmd->sent)
                return FALSE;
 
-       iostat = g_io_channel_write_chars(io, (gchar *) cmd->pdu, cmd->len,
+       iostat = g_io_channel_write_chars(io, (char *) cmd->pdu, cmd->len,
                                                                &len, &gerr);
-       if (iostat != G_IO_STATUS_NORMAL)
+       if (iostat != G_IO_STATUS_NORMAL) {
+               if (gerr) {
+                       error("%s", gerr->message);
+                       g_error_free(gerr);
+               }
+
                return FALSE;
+       }
 
        if (cmd->expected == 0) {
                g_queue_pop_head(queue);
@@ -323,7 +337,7 @@ static gboolean can_write_data(GIOChannel *io, GIOCondition cond,
                return TRUE;
        }
 
-       cmd->sent = TRUE;
+       cmd->sent = true;
 
        if (attrib->timeout_watch == 0)
                attrib->timeout_watch = g_timeout_add_seconds(GATT_TIMEOUT,
@@ -351,6 +365,30 @@ static void wake_up_sender(struct _GAttrib *attrib)
                                can_write_data, attrib, destroy_sender);
 }
 
+static bool match_event(struct event *evt, const uint8_t *pdu, gsize len)
+{
+       guint16 handle;
+
+       if (evt->expected == GATTRIB_ALL_EVENTS)
+               return true;
+
+       if (!is_response(pdu[0]) && evt->expected == GATTRIB_ALL_REQS)
+               return true;
+
+       if (evt->expected == pdu[0] && evt->handle == GATTRIB_ALL_HANDLES)
+               return true;
+
+       if (len < 3)
+               return false;
+
+       handle = att_get_u16(&pdu[1]);
+
+       if (evt->expected == pdu[0] && evt->handle == handle)
+               return true;
+
+       return false;
+}
+
 static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
 {
        struct _GAttrib *attrib = data;
@@ -359,7 +397,6 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        uint8_t buf[512], status;
        gsize len;
        GIOStatus iostat;
-       gboolean norequests, noresponses;
 
        if (attrib->stale)
                return FALSE;
@@ -371,7 +408,7 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
 
        memset(buf, 0, sizeof(buf));
 
-       iostat = g_io_channel_read_chars(io, (gchar *) buf, sizeof(buf),
+       iostat = g_io_channel_read_chars(io, (char *) buf, sizeof(buf),
                                                                &len, NULL);
        if (iostat != G_IO_STATUS_NORMAL) {
                status = ATT_ECODE_IO;
@@ -381,14 +418,11 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        for (l = attrib->events; l; l = l->next) {
                struct event *evt = l->data;
 
-               if (evt->expected == buf[0] ||
-                               evt->expected == GATTRIB_ALL_EVENTS ||
-                               (is_response(buf[0]) == FALSE &&
-                                               evt->expected == GATTRIB_ALL_REQS))
+               if (match_event(evt, buf, len))
                        evt->func(buf, len, evt->user_data);
        }
 
-       if (is_response(buf[0]) == FALSE)
+       if (!is_response(buf[0]))
                return TRUE;
 
        if (attrib->timeout_watch > 0) {
@@ -415,10 +449,9 @@ static gboolean received_data(GIOChannel *io, GIOCondition cond, gpointer data)
        status = 0;
 
 done:
-       norequests = attrib->requests == NULL ||
-                       g_queue_is_empty(attrib->requests);
-       noresponses = attrib->responses == NULL ||
-                       g_queue_is_empty(attrib->responses);
+       if (!g_queue_is_empty(attrib->requests) ||
+                                       !g_queue_is_empty(attrib->responses))
+               wake_up_sender(attrib);
 
        if (cmd) {
                if (cmd->func)
@@ -427,9 +460,6 @@ done:
                command_destroy(cmd);
        }
 
-       if (!norequests || !noresponses)
-               wake_up_sender(attrib);
-
        return TRUE;
 }
 
@@ -444,11 +474,8 @@ GAttrib *g_attrib_new(GIOChannel *io)
        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);
-
+       bt_io_get(io, &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);
@@ -475,12 +502,13 @@ GAttrib *g_attrib_new(GIOChannel *io)
        return g_attrib_ref(attrib);
 }
 
-guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
-                       const guint8 *pdu, guint16 len, GAttribResultFunc func,
-                       gpointer user_data, GDestroyNotify notify)
+guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
+                       GAttribResultFunc func, gpointer user_data,
+                       GDestroyNotify notify)
 {
        struct command *c;
        GQueue *queue;
+       uint8_t opcode;
 
        if (attrib->stale)
                return 0;
@@ -489,6 +517,8 @@ guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
        if (c == NULL)
                return 0;
 
+       opcode = pdu[0];
+
        c->opcode = opcode;
        c->expected = opcode2expected(opcode);
        c->pdu = g_malloc(len);
@@ -526,7 +556,7 @@ guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
        return c->id;
 }
 
-static gint command_cmp_by_id(gconstpointer a, gconstpointer b)
+static int command_cmp_by_id(gconstpointer a, gconstpointer b)
 {
        const struct command *cmd = a;
        guint id = GPOINTER_TO_UINT(b);
@@ -617,7 +647,7 @@ gboolean g_attrib_set_debug(GAttrib *attrib,
        return TRUE;
 }
 
-uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len)
+uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len)
 {
        if (len == NULL)
                return NULL;
@@ -639,7 +669,7 @@ gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu)
        return TRUE;
 }
 
-guint g_attrib_register(GAttrib *attrib, guint8 opcode,
+guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
                                GAttribNotifyFunc func, gpointer user_data,
                                GDestroyNotify notify)
 {
@@ -651,6 +681,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
                return 0;
 
        event->expected = opcode;
+       event->handle = handle;
        event->func = func;
        event->user_data = user_data;
        event->notify = notify;
@@ -661,7 +692,7 @@ guint g_attrib_register(GAttrib *attrib, guint8 opcode,
        return event->id;
 }
 
-static gint event_cmp_by_id(gconstpointer a, gconstpointer b)
+static int event_cmp_by_id(gconstpointer a, gconstpointer b)
 {
        const struct event *evt = a;
        guint id = GPOINTER_TO_UINT(b);
@@ -673,7 +704,7 @@ gboolean g_attrib_is_encrypted(GAttrib *attrib)
 {
        BtIOSecLevel sec_level;
 
-       if (!bt_io_get(attrib->io, BT_IO_L2CAP, NULL,
+       if (!bt_io_get(attrib->io, NULL,
                        BT_IO_OPT_SEC_LEVEL, &sec_level,
                        BT_IO_OPT_INVALID))
                return FALSE;
@@ -686,6 +717,11 @@ gboolean g_attrib_unregister(GAttrib *attrib, guint id)
        struct event *evt;
        GSList *l;
 
+       if (id == 0) {
+               warn("%s: invalid id", __func__);
+               return FALSE;
+       }
+
        l = g_slist_find_custom(attrib->events, GUINT_TO_POINTER(id),
                                                        event_cmp_by_id);
        if (l == NULL)
index f73b741..3fe92c7 100644 (file)
@@ -30,6 +30,7 @@ extern "C" {
 
 #define GATTRIB_ALL_EVENTS 0xFF
 #define GATTRIB_ALL_REQS 0xFE
+#define GATTRIB_ALL_HANDLES 0x0000
 
 struct _GAttrib;
 typedef struct _GAttrib GAttrib;
@@ -50,9 +51,9 @@ GIOChannel *g_attrib_get_channel(GAttrib *attrib);
 gboolean g_attrib_set_destroy_function(GAttrib *attrib,
                GDestroyNotify destroy, gpointer user_data);
 
-guint g_attrib_send(GAttrib *attrib, guint id, guint8 opcode,
-                       const guint8 *pdu, guint16 len, GAttribResultFunc func,
-                       gpointer user_data, GDestroyNotify notify);
+guint g_attrib_send(GAttrib *attrib, guint id, const guint8 *pdu, guint16 len,
+                       GAttribResultFunc func, gpointer user_data,
+                       GDestroyNotify notify);
 
 gboolean g_attrib_cancel(GAttrib *attrib, guint id);
 gboolean g_attrib_cancel_all(GAttrib *attrib);
@@ -60,13 +61,13 @@ gboolean g_attrib_cancel_all(GAttrib *attrib);
 gboolean g_attrib_set_debug(GAttrib *attrib,
                GAttribDebugFunc func, gpointer user_data);
 
-guint g_attrib_register(GAttrib *attrib, guint8 opcode,
-               GAttribNotifyFunc func, gpointer user_data,
-                                       GDestroyNotify notify);
+guint g_attrib_register(GAttrib *attrib, guint8 opcode, guint16 handle,
+                               GAttribNotifyFunc func, gpointer user_data,
+                               GDestroyNotify notify);
 
 gboolean g_attrib_is_encrypted(GAttrib *attrib);
 
-uint8_t *g_attrib_get_buffer(GAttrib *attrib, int *len);
+uint8_t *g_attrib_get_buffer(GAttrib *attrib, size_t *len);
 gboolean g_attrib_set_mtu(GAttrib *attrib, int mtu);
 
 gboolean g_attrib_unregister(GAttrib *attrib, guint id);
index 8a43ec1..f211dcd 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
-#include <bluetooth/uuid.h>
 
+#include "lib/uuid.h"
 #include "att.h"
-#include "btio.h"
+#include <btio/btio.h>
 #include "gattrib.h"
 #include "gatt.h"
 #include "gatttool.h"
 
-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 char *opt_src = NULL;
+static char *opt_dst = NULL;
+static char *opt_dst_type = NULL;
+static char *opt_value = NULL;
+static char *opt_sec_level = NULL;
 static bt_uuid_t *opt_uuid = NULL;
 static int opt_start = 0x0001;
 static int opt_end = 0xffff;
 static int opt_handle = -1;
 static int opt_mtu = 0;
 static int opt_psm = 0;
-static int opt_offset = 0;
 static gboolean opt_primary = FALSE;
 static gboolean opt_characteristics = FALSE;
 static gboolean opt_char_read = FALSE;
@@ -75,8 +74,9 @@ struct characteristic_data {
 static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
        GAttrib *attrib = user_data;
-       uint8_t opdu[ATT_MAX_MTU];
+       uint8_t *opdu;
        uint16_t handle, i, olen = 0;
+       size_t plen;
 
        handle = att_get_u16(&pdu[1]);
 
@@ -100,20 +100,21 @@ static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
        if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
                return;
 
-       olen = enc_confirmation(opdu, sizeof(opdu));
+       opdu = g_attrib_get_buffer(attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
 
        if (olen > 0)
-               g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+               g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
 }
 
 static gboolean listen_start(gpointer user_data)
 {
        GAttrib *attrib = user_data;
 
-       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler,
-                                                       attrib, NULL);
-       g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler,
-                                                       attrib, NULL);
+       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
+                                               events_handler, attrib, NULL);
+       g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
+                                               events_handler, attrib, NULL);
 
        return FALSE;
 }
@@ -226,15 +227,18 @@ static gboolean characteristics(gpointer user_data)
 static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                                        gpointer user_data)
 {
-       uint8_t value[ATT_MAX_MTU];
-       int i, vlen;
+       uint8_t value[plen];
+       ssize_t vlen;
+       int i;
 
        if (status != 0) {
                g_printerr("Characteristic value/descriptor read failed: %s\n",
                                                        att_ecode2str(status));
                goto done;
        }
-       if (!dec_read_resp(pdu, plen, value, &vlen)) {
+
+       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       if (vlen < 0) {
                g_printerr("Protocol error\n");
                goto done;
        }
@@ -244,21 +248,16 @@ static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
        g_print("\n");
 
 done:
-       if (opt_listen == FALSE)
+       if (!opt_listen)
                g_main_loop_quit(event_loop);
 }
 
 static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
                                        guint16 plen, gpointer user_data)
 {
-       struct characteristic_data *char_data = user_data;
        struct att_data_list *list;
        int i;
 
-       if (status == ATT_ECODE_ATTR_NOT_FOUND &&
-                                       char_data->start != opt_start)
-               goto done;
-
        if (status != 0) {
                g_printerr("Read characteristics by UUID failed: %s\n",
                                                        att_ecode2str(status));
@@ -273,8 +272,6 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
                uint8_t *value = list->data[i];
                int j;
 
-               char_data->start = att_get_u16(value) + 1;
-
                g_print("handle: 0x%04x \t value: ", att_get_u16(value));
                value += 2;
                for (j = 0; j < list->len - 2; j++, value++)
@@ -285,7 +282,6 @@ static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
        att_data_list_free(list);
 
 done:
-       g_free(char_data);
        g_main_loop_quit(event_loop);
 }
 
@@ -294,15 +290,9 @@ static gboolean characteristics_read(gpointer user_data)
        GAttrib *attrib = user_data;
 
        if (opt_uuid != NULL) {
-               struct characteristic_data *char_data;
-
-               char_data = g_new(struct characteristic_data, 1);
-               char_data->attrib = attrib;
-               char_data->start = opt_start;
-               char_data->end = opt_end;
 
                gatt_read_char_by_uuid(attrib, opt_start, opt_end, opt_uuid,
-                                               char_read_by_uuid_cb, char_data);
+                                               char_read_by_uuid_cb, NULL);
 
                return FALSE;
        }
@@ -313,7 +303,7 @@ static gboolean characteristics_read(gpointer user_data)
                return FALSE;
        }
 
-       gatt_read_char(attrib, opt_handle, opt_offset, char_read_cb, attrib);
+       gatt_read_char(attrib, opt_handle, char_read_cb, attrib);
 
        return FALSE;
 }
@@ -366,7 +356,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
                goto done;
        }
 
-       if (!dec_write_resp(pdu, plen)) {
+       if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
                g_printerr("Protocol error\n");
                goto done;
        }
@@ -374,7 +364,7 @@ static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
        g_print("Characteristic value was written successfully\n");
 
 done:
-       if (opt_listen == FALSE)
+       if (!opt_listen)
                g_main_loop_quit(event_loop);
 }
 
@@ -448,7 +438,7 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
        att_data_list_free(list);
 
 done:
-       if (opt_listen == FALSE)
+       if (!opt_listen)
                g_main_loop_quit(event_loop);
 }
 
@@ -456,7 +446,7 @@ static gboolean characteristics_desc(gpointer user_data)
 {
        GAttrib *attrib = user_data;
 
-       gatt_find_info(attrib, opt_start, opt_end, char_desc_cb, NULL);
+       gatt_discover_char_desc(attrib, opt_start, opt_end, char_desc_cb, NULL);
 
        return FALSE;
 }
@@ -493,8 +483,6 @@ static GOptionEntry char_rw_options[] = {
        { "value", 'n' , 0, G_OPTION_ARG_STRING, &opt_value,
                "Write characteristic value (required for write operation)",
                "0x0001" },
-       { "offset", 'o', 0, G_OPTION_ARG_INT, &opt_offset,
-               "Offset to long read characteristic by handle", "N"},
        {NULL},
 };
 
@@ -571,9 +559,9 @@ int main(int argc, char *argv[])
        g_option_context_add_group(context, char_rw_group);
        g_option_group_add_entries(char_rw_group, char_rw_options);
 
-       if (g_option_context_parse(context, &argc, &argv, &gerr) == FALSE) {
+       if (!g_option_context_parse(context, &argc, &argv, &gerr)) {
                g_printerr("%s\n", gerr->message);
-               g_error_free(gerr);
+               g_clear_error(&gerr);
        }
 
        if (opt_interactive) {
@@ -594,16 +582,24 @@ int main(int argc, char *argv[])
        else if (opt_char_desc)
                operation = characteristics_desc;
        else {
-               gchar *help = g_option_context_get_help(context, TRUE, NULL);
+               char *help = g_option_context_get_help(context, TRUE, NULL);
                g_print("%s\n", help);
                g_free(help);
                got_error = TRUE;
                goto done;
        }
 
+       if (opt_dst == NULL) {
+               g_print("Remote Bluetooth address required\n");
+               got_error = TRUE;
+               goto done;
+       }
+
        chan = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-                                       opt_psm, opt_mtu, connect_cb);
+                                       opt_psm, opt_mtu, connect_cb, &gerr);
        if (chan == NULL) {
+               g_printerr("%s\n", gerr->message);
+               g_clear_error(&gerr);
                got_error = TRUE;
                goto done;
        }
index a38339b..8f0913c 100644 (file)
  *
  */
 
-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 *dst_type, const gchar *sec_level,
-                       int psm, int mtu, BtIOConnect connect_cb);
+int interactive(const char *src, const char *dst, const char *dst_type,
+                                                               int psm);
+GIOChannel *gatt_connect(const char *src, const char *dst,
+                       const char *dst_type, const char *sec_level,
+                       int psm, int mtu, BtIOConnect connect_cb,
+                       GError **gerr);
 size_t gatt_attr_data_from_string(const char *str, uint8_t **data);
index 0a01cdf..5bd27af 100644 (file)
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <string.h>
 #include <stdlib.h>
+#include <stdarg.h>
 #include <errno.h>
 #include <stdio.h>
+#include <unistd.h>
+#include <signal.h>
+#include <sys/signalfd.h>
 #include <glib.h>
 
-#include <bluetooth/uuid.h>
-
 #include <readline/readline.h>
 #include <readline/history.h>
 
+#include "lib/uuid.h"
+#include <btio/btio.h>
 #include "att.h"
-#include "btio.h"
 #include "gattrib.h"
 #include "gatt.h"
 #include "gatttool.h"
+#include "client/display.h"
 
 static GIOChannel *iochannel = NULL;
 static GAttrib *attrib = NULL;
 static GMainLoop *event_loop;
 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 char *opt_src = NULL;
+static char *opt_dst = NULL;
+static char *opt_dst_type = NULL;
+static char *opt_sec_level = NULL;
 static int opt_psm = 0;
 static int opt_mtu = 0;
-
-struct characteristic_data {
-       uint16_t orig_start;
-       uint16_t start;
-       uint16_t end;
-       bt_uuid_t uuid;
-};
+static int start;
+static int end;
 
 static void cmd_help(int argcp, char **argvp);
 
-enum state {
+static enum state {
        STATE_DISCONNECTED,
        STATE_CONNECTING,
        STATE_CONNECTED
 } conn_state;
 
+#define error(fmt, arg...) \
+       rl_printf(COLOR_RED "Error: " COLOR_OFF fmt, ## arg)
+
+#define failed(fmt, arg...) \
+       rl_printf(COLOR_RED "Command Failed: " COLOR_OFF fmt, ## arg)
+
 static char *get_prompt(void)
 {
-       if (conn_state == STATE_CONNECTING) {
-               g_string_assign(prompt, "Connecting... ");
-               return prompt->str;
-       }
-
        if (conn_state == STATE_CONNECTED)
-               g_string_assign(prompt, "[CON]");
+               g_string_assign(prompt, COLOR_BLUE);
        else
-               g_string_assign(prompt, "[   ]");
+               g_string_assign(prompt, "");
 
        if (opt_dst)
                g_string_append_printf(prompt, "[%17s]", opt_dst);
        else
                g_string_append_printf(prompt, "[%17s]", "");
 
+       if (conn_state == STATE_CONNECTED)
+               g_string_append(prompt, COLOR_OFF);
+
        if (opt_psm)
                g_string_append(prompt, "[BR]");
        else
@@ -96,58 +104,64 @@ static void set_state(enum state st)
 {
        conn_state = st;
        rl_set_prompt(get_prompt());
-       rl_redisplay();
 }
 
 static void events_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
 {
-       uint8_t opdu[ATT_MAX_MTU];
+       uint8_t *opdu;
        uint16_t handle, i, olen;
+       size_t plen;
+       GString *s;
 
        handle = att_get_u16(&pdu[1]);
 
-       printf("\n");
        switch (pdu[0]) {
        case ATT_OP_HANDLE_NOTIFY:
-               printf("Notification handle = 0x%04x value: ", handle);
+               s = g_string_new(NULL);
+               g_string_printf(s, "Notification handle = 0x%04x value: ",
+                                                                       handle);
                break;
        case ATT_OP_HANDLE_IND:
-               printf("Indication   handle = 0x%04x value: ", handle);
+               s = g_string_new(NULL);
+               g_string_printf(s, "Indication   handle = 0x%04x value: ",
+                                                                       handle);
                break;
        default:
-               printf("Invalid opcode\n");
+               error("Invalid opcode\n");
                return;
        }
 
        for (i = 3; i < len; i++)
-               printf("%02x ", pdu[i]);
+               g_string_append_printf(s, "%02x ", pdu[i]);
 
-       printf("\n");
-       rl_forced_update_display();
+       rl_printf("%s\n", s->str);
+       g_string_free(s, TRUE);
 
        if (pdu[0] == ATT_OP_HANDLE_NOTIFY)
                return;
 
-       olen = enc_confirmation(opdu, sizeof(opdu));
+       opdu = g_attrib_get_buffer(attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
 
        if (olen > 0)
-               g_attrib_send(attrib, 0, opdu[0], opdu, olen, NULL, NULL, NULL);
+               g_attrib_send(attrib, 0, opdu, olen, NULL, NULL, NULL);
 }
 
 static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
 {
        if (err) {
-               printf("connect error: %s\n", err->message);
                set_state(STATE_DISCONNECTED);
+               error("%s\n", err->message);
                return;
        }
 
        attrib = g_attrib_new(iochannel);
-       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, events_handler,
-                                                       attrib, NULL);
-       g_attrib_register(attrib, ATT_OP_HANDLE_IND, events_handler,
-                                                       attrib, NULL);
+       g_attrib_register(attrib, ATT_OP_HANDLE_NOTIFY, GATTRIB_ALL_HANDLES,
+                                               events_handler, attrib, NULL);
+       g_attrib_register(attrib, ATT_OP_HANDLE_IND, GATTRIB_ALL_HANDLES,
+                                               events_handler, attrib, NULL);
        set_state(STATE_CONNECTED);
+       rl_printf("Connection successful\n");
 }
 
 static void disconnect_io()
@@ -171,19 +185,21 @@ static void primary_all_cb(GSList *services, guint8 status, gpointer user_data)
        GSList *l;
 
        if (status) {
-               printf("Discover all primary services failed: %s\n",
-                                                       att_ecode2str(status));
+               error("Discover all primary services failed: %s\n",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       if (services == NULL) {
+               error("No primary service found\n");
                return;
        }
 
-       printf("\n");
        for (l = services; l; l = l->next) {
                struct gatt_primary *prim = l->data;
-               printf("attr handle: 0x%04x, end grp handle: 0x%04x "
-                       "uuid: %s\n", prim->range.start, prim->range.end, prim->uuid);
+               rl_printf("attr handle: 0x%04x, end grp handle: 0x%04x uuid: %s\n",
+                               prim->range.start, prim->range.end, prim->uuid);
        }
-
-       rl_forced_update_display();
 }
 
 static void primary_by_uuid_cb(GSList *ranges, guint8 status,
@@ -192,19 +208,45 @@ static void primary_by_uuid_cb(GSList *ranges, guint8 status,
        GSList *l;
 
        if (status) {
-               printf("Discover primary services by UUID failed: %s\n",
+               error("Discover primary services by UUID failed: %s\n",
                                                        att_ecode2str(status));
                return;
        }
 
-       printf("\n");
+       if (ranges == NULL) {
+               error("No service UUID found\n");
+               return;
+       }
+
        for (l = ranges; l; l = l->next) {
                struct att_range *range = l->data;
-               g_print("Starting handle: 0x%04x Ending handle: 0x%04x\n",
+               rl_printf("Starting handle: 0x%04x Ending handle: 0x%04x\n",
                                                range->start, range->end);
        }
+}
+
+static void included_cb(GSList *includes, guint8 status, gpointer user_data)
+{
+       GSList *l;
+
+       if (status) {
+               error("Find included services failed: %s\n",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (includes == NULL) {
+               rl_printf("No included services found for this range\n");
+               return;
+       }
 
-       rl_forced_update_display();
+       for (l = includes; l; l = l->next) {
+               struct gatt_included *incl = l->data;
+               rl_printf("handle: 0x%04x, start handle: 0x%04x, "
+                                       "end handle: 0x%04x uuid: %s\n",
+                                       incl->handle, incl->range.start,
+                                       incl->range.end, incl->uuid);
+       }
 }
 
 static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
@@ -212,22 +254,19 @@ static void char_cb(GSList *characteristics, guint8 status, gpointer user_data)
        GSList *l;
 
        if (status) {
-               printf("Discover all characteristics failed: %s\n",
+               error("Discover all characteristics failed: %s\n",
                                                        att_ecode2str(status));
                return;
        }
 
-       printf("\n");
        for (l = characteristics; l; l = l->next) {
                struct gatt_char *chars = l->data;
 
-               printf("handle: 0x%04x, char properties: 0x%02x, char value "
+               rl_printf("handle: 0x%04x, char properties: 0x%02x, char value "
                                "handle: 0x%04x, uuid: %s\n", chars->handle,
                                chars->properties, chars->value_handle,
                                chars->uuid);
        }
-
-       rl_forced_update_display();
 }
 
 static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
@@ -235,11 +274,12 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
 {
        struct att_data_list *list;
        guint8 format;
+       uint16_t handle = 0xffff;
        int i;
 
        if (status != 0) {
-               printf("Discover all characteristic descriptors failed: "
-                                               "%s\n", att_ecode2str(status));
+               rl_printf("Discover descriptors finished: %s\n",
+                                               att_ecode2str(status));
                return;
        }
 
@@ -247,10 +287,8 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
        if (list == NULL)
                return;
 
-       printf("\n");
        for (i = 0; i < list->num; i++) {
                char uuidstr[MAX_LEN_UUID_STR];
-               uint16_t handle;
                uint8_t *value;
                bt_uuid_t uuid;
 
@@ -263,79 +301,77 @@ static void char_desc_cb(guint8 status, const guint8 *pdu, guint16 plen,
                        uuid = att_get_uuid128(&value[2]);
 
                bt_uuid_to_string(&uuid, uuidstr, MAX_LEN_UUID_STR);
-               printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
+               rl_printf("handle: 0x%04x, uuid: %s\n", handle, uuidstr);
        }
 
        att_data_list_free(list);
 
-       rl_forced_update_display();
+       if (handle != 0xffff && handle < end)
+               gatt_discover_char_desc(attrib, handle + 1, end, char_desc_cb,
+                                                                       NULL);
 }
 
 static void char_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                                        gpointer user_data)
 {
-       uint8_t value[ATT_MAX_MTU];
-       int i, vlen;
+       uint8_t value[plen];
+       ssize_t vlen;
+       int i;
+       GString *s;
 
        if (status != 0) {
-               printf("Characteristic value/descriptor read failed: %s\n",
+               error("Characteristic value/descriptor read failed: %s\n",
                                                        att_ecode2str(status));
                return;
        }
 
-       if (!dec_read_resp(pdu, plen, value, &vlen)) {
-               printf("Protocol error\n");
+       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       if (vlen < 0) {
+               error("Protocol error\n");
                return;
        }
 
-       printf("\nCharacteristic value/descriptor: ");
+       s = g_string_new("Characteristic value/descriptor: ");
        for (i = 0; i < vlen; i++)
-               printf("%02x ", value[i]);
-       printf("\n");
+               g_string_append_printf(s, "%02x ", value[i]);
 
-       rl_forced_update_display();
+       rl_printf("%s\n", s->str);
+       g_string_free(s, TRUE);
 }
 
 static void char_read_by_uuid_cb(guint8 status, const guint8 *pdu,
                                        guint16 plen, gpointer user_data)
 {
-       struct characteristic_data *char_data = user_data;
        struct att_data_list *list;
        int i;
-
-       if (status == ATT_ECODE_ATTR_NOT_FOUND &&
-                               char_data->start != char_data->orig_start)
-               goto done;
+       GString *s;
 
        if (status != 0) {
-               printf("Read characteristics by UUID failed: %s\n",
+               error("Read characteristics by UUID failed: %s\n",
                                                        att_ecode2str(status));
-               goto done;
+               return;
        }
 
        list = dec_read_by_type_resp(pdu, plen);
        if (list == NULL)
-               goto done;
+               return;
 
+       s = g_string_new(NULL);
        for (i = 0; i < list->num; i++) {
                uint8_t *value = list->data[i];
                int j;
 
-               char_data->start = att_get_u16(value) + 1;
-
-               printf("\nhandle: 0x%04x \t value: ", att_get_u16(value));
+               g_string_printf(s, "handle: 0x%04x \t value: ",
+                                                       att_get_u16(value));
                value += 2;
                for (j = 0; j < list->len - 2; j++, value++)
-                       printf("%02x ", *value);
-               printf("\n");
+                       g_string_append_printf(s, "%02x ", *value);
+
+               rl_printf("%s\n", s->str);
        }
 
        att_data_list_free(list);
-
-       rl_forced_update_display();
-
-done:
-       g_free(char_data);
+       g_string_free(s, TRUE);
 }
 
 static void cmd_exit(int argcp, char **argvp)
@@ -354,6 +390,8 @@ static gboolean channel_watcher(GIOChannel *chan, GIOCondition cond,
 
 static void cmd_connect(int argcp, char **argvp)
 {
+       GError *gerr = NULL;
+
        if (conn_state != STATE_DISCONNECTED)
                return;
 
@@ -369,16 +407,19 @@ static void cmd_connect(int argcp, char **argvp)
        }
 
        if (opt_dst == NULL) {
-               printf("Remote Bluetooth address required\n");
+               error("Remote Bluetooth address required\n");
                return;
        }
 
+       rl_printf("Attempting to connect to %s\n", opt_dst);
        set_state(STATE_CONNECTING);
        iochannel = gatt_connect(opt_src, opt_dst, opt_dst_type, opt_sec_level,
-                                               opt_psm, opt_mtu, connect_cb);
-       if (iochannel == NULL)
+                                       opt_psm, opt_mtu, connect_cb, &gerr);
+       if (iochannel == NULL) {
                set_state(STATE_DISCONNECTED);
-       else
+               error("%s\n", gerr->message);
+               g_error_free(gerr);
+       } else
                g_io_add_watch(iochannel, G_IO_HUP, channel_watcher, NULL);
 }
 
@@ -392,7 +433,7 @@ static void cmd_primary(int argcp, char **argvp)
        bt_uuid_t uuid;
 
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
@@ -402,7 +443,7 @@ static void cmd_primary(int argcp, char **argvp)
        }
 
        if (bt_string_to_uuid(&uuid, argvp[1]) < 0) {
-               printf("Invalid UUID\n");
+               error("Invalid UUID\n");
                return;
        }
 
@@ -422,20 +463,50 @@ static int strtohandle(const char *src)
        return dst;
 }
 
+static void cmd_included(int argcp, char **argvp)
+{
+       int start = 0x0001;
+       int end = 0xffff;
+
+       if (conn_state != STATE_CONNECTED) {
+               failed("Disconnected\n");
+               return;
+       }
+
+       if (argcp > 1) {
+               start = strtohandle(argvp[1]);
+               if (start < 0) {
+                       error("Invalid start handle: %s\n", argvp[1]);
+                       return;
+               }
+               end = start;
+       }
+
+       if (argcp > 2) {
+               end = strtohandle(argvp[2]);
+               if (end < 0) {
+                       error("Invalid end handle: %s\n", argvp[2]);
+                       return;
+               }
+       }
+
+       gatt_find_included(attrib, start, end, included_cb, NULL);
+}
+
 static void cmd_char(int argcp, char **argvp)
 {
        int start = 0x0001;
        int end = 0xffff;
 
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (argcp > 1) {
                start = strtohandle(argvp[1]);
                if (start < 0) {
-                       printf("Invalid start handle: %s\n", argvp[1]);
+                       error("Invalid start handle: %s\n", argvp[1]);
                        return;
                }
        }
@@ -443,7 +514,7 @@ static void cmd_char(int argcp, char **argvp)
        if (argcp > 2) {
                end = strtohandle(argvp[2]);
                if (end < 0) {
-                       printf("Invalid end handle: %s\n", argvp[2]);
+                       error("Invalid end handle: %s\n", argvp[2]);
                        return;
                }
        }
@@ -452,7 +523,7 @@ static void cmd_char(int argcp, char **argvp)
                bt_uuid_t uuid;
 
                if (bt_string_to_uuid(&uuid, argvp[3]) < 0) {
-                       printf("Invalid UUID\n");
+                       error("Invalid UUID\n");
                        return;
                }
 
@@ -465,94 +536,80 @@ static void cmd_char(int argcp, char **argvp)
 
 static void cmd_char_desc(int argcp, char **argvp)
 {
-       int start = 0x0001;
-       int end = 0xffff;
-
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (argcp > 1) {
                start = strtohandle(argvp[1]);
                if (start < 0) {
-                       printf("Invalid start handle: %s\n", argvp[1]);
+                       error("Invalid start handle: %s\n", argvp[1]);
                        return;
                }
-       }
+       } else
+               start = 0x0001;
 
        if (argcp > 2) {
                end = strtohandle(argvp[2]);
                if (end < 0) {
-                       printf("Invalid end handle: %s\n", argvp[2]);
+                       error("Invalid end handle: %s\n", argvp[2]);
                        return;
                }
-       }
+       } else
+               end = 0xffff;
 
-       gatt_find_info(attrib, start, end, char_desc_cb, NULL);
+       gatt_discover_char_desc(attrib, start, end, char_desc_cb, NULL);
 }
 
 static void cmd_read_hnd(int argcp, char **argvp)
 {
        int handle;
-       int offset = 0;
 
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (argcp < 2) {
-               printf("Missing argument: handle\n");
+               error("Missing argument: handle\n");
                return;
        }
 
        handle = strtohandle(argvp[1]);
        if (handle < 0) {
-               printf("Invalid handle: %s\n", argvp[1]);
+               error("Invalid handle: %s\n", argvp[1]);
                return;
        }
 
-       if (argcp > 2) {
-               char *e;
-
-               errno = 0;
-               offset = strtol(argvp[2], &e, 0);
-               if (errno != 0 || *e != '\0') {
-                       printf("Invalid offset: %s\n", argvp[2]);
-                       return;
-               }
-       }
-
-       gatt_read_char(attrib, handle, offset, char_read_cb, attrib);
+       gatt_read_char(attrib, handle, char_read_cb, attrib);
 }
 
 static void cmd_read_uuid(int argcp, char **argvp)
 {
-       struct characteristic_data *char_data;
        int start = 0x0001;
        int end = 0xffff;
        bt_uuid_t uuid;
 
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (argcp < 2) {
-               printf("Missing argument: UUID\n");
+               error("Missing argument: UUID\n");
                return;
        }
 
        if (bt_string_to_uuid(&uuid, argvp[1]) < 0) {
-               printf("Invalid UUID\n");
+               error("Invalid UUID\n");
                return;
        }
 
        if (argcp > 2) {
                start = strtohandle(argvp[2]);
                if (start < 0) {
-                       printf("Invalid start handle: %s\n", argvp[1]);
+                       error("Invalid start handle: %s\n", argvp[1]);
                        return;
                }
        }
@@ -560,36 +617,30 @@ static void cmd_read_uuid(int argcp, char **argvp)
        if (argcp > 3) {
                end = strtohandle(argvp[3]);
                if (end < 0) {
-                       printf("Invalid end handle: %s\n", argvp[2]);
+                       error("Invalid end handle: %s\n", argvp[2]);
                        return;
                }
        }
 
-       char_data = g_new(struct characteristic_data, 1);
-       char_data->orig_start = start;
-       char_data->start = start;
-       char_data->end = end;
-       char_data->uuid = uuid;
-
-       gatt_read_char_by_uuid(attrib, start, end, &char_data->uuid,
-                                       char_read_by_uuid_cb, char_data);
+       gatt_read_char_by_uuid(attrib, start, end, &uuid, char_read_by_uuid_cb,
+                                                                       NULL);
 }
 
 static void char_write_req_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                                        gpointer user_data)
 {
        if (status != 0) {
-               printf("Characteristic Write Request failed: "
+               error("Characteristic Write Request failed: "
                                                "%s\n", att_ecode2str(status));
                return;
        }
 
-       if (!dec_write_resp(pdu, plen)) {
-               printf("Protocol error\n");
+       if (!dec_write_resp(pdu, plen) && !dec_exec_write_resp(pdu, plen)) {
+               error("Protocol error\n");
                return;
        }
 
-       printf("Characteristic value was written successfully\n");
+       rl_printf("Characteristic value was written successfully\n");
 }
 
 static void cmd_char_write(int argcp, char **argvp)
@@ -599,24 +650,24 @@ static void cmd_char_write(int argcp, char **argvp)
        int handle;
 
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: disconnected\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (argcp < 3) {
-               printf("Usage: %s <handle> <new value>\n", argvp[0]);
+               rl_printf("Usage: %s <handle> <new value>\n", argvp[0]);
                return;
        }
 
        handle = strtohandle(argvp[1]);
        if (handle <= 0) {
-               printf("A valid handle is required\n");
+               error("A valid handle is required\n");
                return;
        }
 
        plen = gatt_attr_data_from_string(argvp[2], &value);
        if (plen == 0) {
-               g_printerr("Invalid value\n");
+               error("Invalid value\n");
                return;
        }
 
@@ -624,7 +675,7 @@ static void cmd_char_write(int argcp, char **argvp)
                gatt_write_char(attrib, handle, value, plen,
                                        char_write_req_cb, NULL);
        else
-               gatt_write_char(attrib, handle, value, plen, NULL, NULL);
+               gatt_write_cmd(attrib, handle, value, plen, NULL, NULL);
 
        g_free(value);
 }
@@ -635,7 +686,7 @@ static void cmd_sec_level(int argcp, char **argvp)
        BtIOSecLevel sec_level;
 
        if (argcp < 2) {
-               printf("sec-level: %s\n", opt_sec_level);
+               rl_printf("sec-level: %s\n", opt_sec_level);
                return;
        }
 
@@ -646,7 +697,7 @@ static void cmd_sec_level(int argcp, char **argvp)
        else if (strcasecmp(argvp[1], "low") == 0)
                sec_level = BT_IO_SEC_LOW;
        else {
-               printf("Allowed values: low | medium | high\n");
+               rl_printf("Allowed values: low | medium | high\n");
                return;
        }
 
@@ -657,16 +708,15 @@ static void cmd_sec_level(int argcp, char **argvp)
                return;
 
        if (opt_psm) {
-               printf("It must be reconnected to this change take effect\n");
+               rl_printf("Change will take effect on reconnection\n");
                return;
        }
 
-       bt_io_set(iochannel, BT_IO_L2CAP, &gerr,
+       bt_io_set(iochannel, &gerr,
                        BT_IO_OPT_SEC_LEVEL, sec_level,
                        BT_IO_OPT_INVALID);
-
        if (gerr) {
-               printf("Error: %s\n", gerr->message);
+               error("%s\n", gerr->message);
                g_error_free(gerr);
        }
 }
@@ -677,52 +727,50 @@ static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
        uint16_t mtu;
 
        if (status != 0) {
-               printf("Exchange MTU Request failed: %s\n",
-                                                       att_ecode2str(status));
+               error("Exchange MTU Request failed: %s\n",
+                                               att_ecode2str(status));
                return;
        }
 
        if (!dec_mtu_resp(pdu, plen, &mtu)) {
-               printf("Protocol error\n");
+               error("Protocol error\n");
                return;
        }
 
        mtu = MIN(mtu, opt_mtu);
        /* Set new value for MTU in client */
        if (g_attrib_set_mtu(attrib, mtu))
-               printf("MTU was exchanged successfully: %d\n", mtu);
+               rl_printf("MTU was exchanged successfully: %d\n", mtu);
        else
-               printf("Error exchanging MTU\n");
+               error("Error exchanging MTU\n");
 }
 
 static void cmd_mtu(int argcp, char **argvp)
 {
        if (conn_state != STATE_CONNECTED) {
-               printf("Command failed: not connected.\n");
+               failed("Disconnected\n");
                return;
        }
 
        if (opt_psm) {
-               printf("Command failed: operation is only available for LE"
-                                                       " transport.\n");
+               failed("Operation is only available for LE transport.\n");
                return;
        }
 
        if (argcp < 2) {
-               printf("Usage: mtu <value>\n");
+               rl_printf("Usage: mtu <value>\n");
                return;
        }
 
        if (opt_mtu) {
-               printf("Command failed: MTU exchange can only occur once per"
-                                                       " connection.\n");
+               failed("MTU exchange can only occur once per connection.\n");
                return;
        }
 
        errno = 0;
        opt_mtu = strtoll(argvp[1], NULL, 0);
        if (errno != 0 || opt_mtu < ATT_DEFAULT_LE_MTU) {
-               printf("Invalid value. Minimum MTU size is %d\n",
+               error("Invalid value. Minimum MTU size is %d\n",
                                                        ATT_DEFAULT_LE_MTU);
                return;
        }
@@ -748,11 +796,13 @@ static struct {
                "Disconnect from a remote device" },
        { "primary",            cmd_primary,    "[UUID]",
                "Primary Service Discovery" },
+       { "included",           cmd_included,   "[start hnd [end hnd]]",
+               "Find Included Services" },
        { "characteristics",    cmd_char,       "[start hnd [end hnd [UUID]]]",
                "Characteristics Discovery" },
        { "char-desc",          cmd_char_desc,  "[start hnd] [end hnd]",
                "Characteristics Descriptor Discovery" },
-       { "char-read-hnd",      cmd_read_hnd,   "<handle> [offset]",
+       { "char-read-hnd",      cmd_read_hnd,   "<handle>",
                "Characteristics Value/Descriptor Read by handle" },
        { "char-read-uuid",     cmd_read_uuid,  "<UUID> [start hnd] [end hnd]",
                "Characteristics Value/Descriptor Read by UUID" },
@@ -772,18 +822,18 @@ static void cmd_help(int argcp, char **argvp)
        int i;
 
        for (i = 0; commands[i].cmd; i++)
-               printf("%-15s %-30s %s\n", commands[i].cmd,
+               rl_printf("%-15s %-30s %s\n", commands[i].cmd,
                                commands[i].params, commands[i].desc);
 }
 
 static void parse_line(char *line_read)
 {
-       gchar **argvp;
+       char **argvp;
        int argcp;
        int i;
 
        if (line_read == NULL) {
-               printf("\n");
+               rl_printf("\n");
                cmd_exit(0, NULL);
                return;
        }
@@ -791,11 +841,12 @@ static void parse_line(char *line_read)
        line_read = g_strstrip(line_read);
 
        if (*line_read == '\0')
-               return;
+               goto done;
 
        add_history(line_read);
 
-       g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+       if (g_shell_parse_argv(line_read, &argcp, &argvp, NULL) == FALSE)
+               goto done;
 
        for (i = 0; commands[i].cmd; i++)
                if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
@@ -804,9 +855,12 @@ static void parse_line(char *line_read)
        if (commands[i].cmd)
                commands[i].func(argcp, argvp);
        else
-               printf("%s: command not found\n", argvp[0]);
+               error("%s: command not found\n", argvp[0]);
 
        g_strfreev(argvp);
+
+done:
+       free(line_read);
 }
 
 static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
@@ -849,11 +903,104 @@ static char **commands_completion(const char *text, int start, int end)
                return NULL;
 }
 
-int interactive(const gchar *src, const gchar *dst,
-               const gchar *dst_type, int psm)
+static guint setup_standard_input(void)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fileno(stdin));
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               prompt_read, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(event_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+               rl_replace_line("", 0);
+               rl_crlf();
+               rl_on_new_line();
+               rl_redisplay();
+               break;
+       case SIGTERM:
+               if (__terminated == 0) {
+                       rl_replace_line("", 0);
+                       rl_crlf();
+                       g_main_loop_quit(event_loop);
+               }
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+int interactive(const char *src, const char *dst,
+               const char *dst_type, int psm)
 {
-       GIOChannel *pchan;
-       gint events;
+       guint input;
+       guint signal;
 
        opt_sec_level = g_strdup("low");
 
@@ -866,19 +1013,19 @@ int interactive(const gchar *src, const gchar *dst,
 
        event_loop = g_main_loop_new(NULL, FALSE);
 
-       pchan = g_io_channel_unix_new(fileno(stdin));
-       g_io_channel_set_close_on_unref(pchan, TRUE);
-       events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
-       g_io_add_watch(pchan, events, prompt_read, NULL);
+       input = setup_standard_input();
+       signal = setup_signalfd();
 
        rl_attempted_completion_function = commands_completion;
+       rl_erase_empty_line = 1;
        rl_callback_handler_install(get_prompt(), parse_line);
 
        g_main_loop_run(event_loop);
 
        rl_callback_handler_remove();
        cmd_disconnect(0, NULL);
-       g_io_channel_unref(pchan);
+       g_source_remove(input);
+       g_source_remove(signal);
        g_main_loop_unref(event_loop);
        g_string_free(prompt, TRUE);
 
index d856fe2..77bab27 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdlib.h>
 #include <glib.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
-#include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 
+#include "lib/uuid.h"
+#include <btio/btio.h>
 #include "att.h"
 #include "gattrib.h"
 #include "gatt.h"
-#include "btio.h"
 #include "gatttool.h"
 
-GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
-                               const gchar *dst_type, const gchar *sec_level,
-                               int psm, int mtu, BtIOConnect connect_cb)
+GIOChannel *gatt_connect(const char *src, const char *dst,
+                               const char *dst_type, const char *sec_level,
+                               int psm, int mtu, BtIOConnect connect_cb,
+                               GError **gerr)
 {
        GIOChannel *chan;
        bdaddr_t sba, dba;
        uint8_t dest_type;
-       GError *err = NULL;
+       GError *tmp_err = NULL;
        BtIOSecLevel sec;
 
-       /* Remote device */
-       if (dst == NULL) {
-               g_printerr("Remote Bluetooth address required\n");
-               return NULL;
-       }
        str2ba(dst, &dba);
 
        /* Local adapter */
@@ -76,15 +76,16 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
                sec = BT_IO_SEC_LOW;
 
        if (psm == 0)
-               chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
+               chan = bt_io_connect(connect_cb, NULL, NULL, &tmp_err,
                                BT_IO_OPT_SOURCE_BDADDR, &sba,
+                               BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
                                BT_IO_OPT_DEST_BDADDR, &dba,
                                BT_IO_OPT_DEST_TYPE, dest_type,
                                BT_IO_OPT_CID, ATT_CID,
                                BT_IO_OPT_SEC_LEVEL, sec,
                                BT_IO_OPT_INVALID);
        else
-               chan = bt_io_connect(BT_IO_L2CAP, connect_cb, NULL, NULL, &err,
+               chan = bt_io_connect(connect_cb, NULL, NULL, &tmp_err,
                                BT_IO_OPT_SOURCE_BDADDR, &sba,
                                BT_IO_OPT_DEST_BDADDR, &dba,
                                BT_IO_OPT_PSM, psm,
@@ -92,9 +93,8 @@ GIOChannel *gatt_connect(const gchar *src, const gchar *dst,
                                BT_IO_OPT_SEC_LEVEL, sec,
                                BT_IO_OPT_INVALID);
 
-       if (err) {
-               g_printerr("%s\n", err->message);
-               g_error_free(err);
+       if (tmp_err) {
+               g_propagate_error(gerr, tmp_err);
                return NULL;
        }
 
diff --git a/audio/audio.conf b/audio/audio.conf
deleted file mode 100644 (file)
index fd6092a..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# Configuration file for the audio service
-
-# This section contains options which are not specific to any
-# particular interface
-[General]
-
-# Switch to master role for incoming connections (defaults to true)
-#Master=true
-
-# If we want to disable support for specific services
-# Defaults to supporting all implemented services
-#Disable=Gateway,Source,Socket
-
-# SCO routing. Either PCM or HCI (in which case audio is routed to/from ALSA)
-# Defaults to HCI
-#SCORouting=PCM
-
-# Automatically connect both A2DP and HFP/HSP profiles for incoming
-# connections. Some headsets that support both profiles will only connect the
-# other one automatically so the default setting of true is usually a good
-# idea.
-#AutoConnect=true
-
-# Headset interface specific options (i.e. options which affect how the audio
-# service interacts with remote headset devices)
-[Headset]
-
-# Set to true to support HFP, false means only HSP is supported
-# Defaults to true
-HFP=true
-
-# Maximum number of connected HSP/HFP devices per adapter. Defaults to 1
-MaxConnected=1
-
-# Set to true to enable use of fast connectable mode (faster page scanning)
-# 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
-#[A2DP]
-#SBCSources=1
-#MPEG12Sources=0
diff --git a/audio/avctp.c b/audio/avctp.c
deleted file mode 100644 (file)
index ae3c04e..0000000
+++ /dev/null
@@ -1,1115 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2011  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 <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <assert.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <netinet/in.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-
-#include "adapter.h"
-#include "../src/device.h"
-
-#include "log.h"
-#include "error.h"
-#include "uinput.h"
-#include "btio.h"
-#include "manager.h"
-#include "device.h"
-#include "avctp.h"
-#include "avrcp.h"
-
-#define QUIRK_NO_RELEASE 1 << 0
-
-/* Message types */
-#define AVCTP_COMMAND          0
-#define AVCTP_RESPONSE         1
-
-/* Packet types */
-#define AVCTP_PACKET_SINGLE    0
-#define AVCTP_PACKET_START     1
-#define AVCTP_PACKET_CONTINUE  2
-#define AVCTP_PACKET_END       3
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct avctp_header {
-       uint8_t ipid:1;
-       uint8_t cr:1;
-       uint8_t packet_type:2;
-       uint8_t transaction:4;
-       uint16_t pid;
-} __attribute__ ((packed));
-#define AVCTP_HEADER_LENGTH 3
-
-struct avc_header {
-       uint8_t code:4;
-       uint8_t _hdr0:4;
-       uint8_t subunit_id:3;
-       uint8_t subunit_type:5;
-       uint8_t opcode;
-} __attribute__ ((packed));
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct avctp_header {
-       uint8_t transaction:4;
-       uint8_t packet_type:2;
-       uint8_t cr:1;
-       uint8_t ipid:1;
-       uint16_t pid;
-} __attribute__ ((packed));
-#define AVCTP_HEADER_LENGTH 3
-
-struct avc_header {
-       uint8_t _hdr0:4;
-       uint8_t code:4;
-       uint8_t subunit_type:5;
-       uint8_t subunit_id:3;
-       uint8_t opcode;
-} __attribute__ ((packed));
-
-#else
-#error "Unknown byte order"
-#endif
-
-struct avctp_state_callback {
-       avctp_state_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-struct avctp_server {
-       bdaddr_t src;
-       GIOChannel *io;
-       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;
-
-       avctp_state_t state;
-
-       int uinput;
-
-       GIOChannel *io;
-       guint io_id;
-
-       uint16_t mtu;
-
-       uint8_t key_quirks[256];
-       GSList *handlers;
-};
-
-struct avctp_pdu_handler {
-       uint8_t opcode;
-       avctp_pdu_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-static struct {
-       const char *name;
-       uint8_t avc;
-       uint16_t uinput;
-} key_map[] = {
-       { "PLAY",               PLAY_OP,                KEY_PLAYCD },
-       { "STOP",               STAVC_OP_OP,            KEY_STOPCD },
-       { "PAUSE",              PAUSE_OP,               KEY_PAUSECD },
-       { "FORWARD",            FORWARD_OP,             KEY_NEXTSONG },
-       { "BACKWARD",           BACKWARD_OP,            KEY_PREVIOUSSONG },
-       { "REWIND",             REWIND_OP,              KEY_REWIND },
-       { "FAST FORWARD",       FAST_FORWARD_OP,        KEY_FASTFORWARD },
-       { NULL }
-};
-
-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);
-
-static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
-{
-       struct uinput_event event;
-
-       memset(&event, 0, sizeof(event));
-       event.type      = type;
-       event.code      = code;
-       event.value     = value;
-
-       return write(fd, &event, sizeof(event));
-}
-
-static void send_key(int fd, uint16_t key, int pressed)
-{
-       if (fd < 0)
-               return;
-
-       send_event(fd, EV_KEY, key, pressed);
-       send_event(fd, EV_SYN, SYN_REPORT, 0);
-}
-
-static size_t handle_panel_passthrough(struct avctp *session,
-                                       uint8_t transaction, uint8_t *code,
-                                       uint8_t *subunit, uint8_t *operands,
-                                       size_t operand_count, void *user_data)
-{
-       const char *status;
-       int pressed, i;
-
-       if (*code != AVC_CTYPE_CONTROL || *subunit != AVC_SUBUNIT_PANEL) {
-               *code = AVC_CTYPE_REJECTED;
-               return 0;
-       }
-
-       if (operand_count == 0)
-               goto done;
-
-       if (operands[0] & 0x80) {
-               status = "released";
-               pressed = 0;
-       } else {
-               status = "pressed";
-               pressed = 1;
-       }
-
-       for (i = 0; key_map[i].name != NULL; i++) {
-               uint8_t key_quirks;
-
-               if ((operands[0] & 0x7F) != key_map[i].avc)
-                       continue;
-
-               DBG("AV/C: %s %s", key_map[i].name, status);
-
-               key_quirks = session->key_quirks[key_map[i].avc];
-
-               if (key_quirks & QUIRK_NO_RELEASE) {
-                       if (!pressed) {
-                               DBG("AV/C: Ignoring release");
-                               break;
-                       }
-
-                       DBG("AV/C: treating key press as press + release");
-                       send_key(session->uinput, key_map[i].uinput, 1);
-                       send_key(session->uinput, key_map[i].uinput, 0);
-                       break;
-               }
-
-               send_key(session->uinput, key_map[i].uinput, pressed);
-               break;
-       }
-
-       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;
-       return operand_count;
-}
-
-static size_t handle_unit_info(struct avctp *session,
-                                       uint8_t transaction, uint8_t *code,
-                                       uint8_t *subunit, uint8_t *operands,
-                                       size_t operand_count, void *user_data)
-{
-       if (*code != AVC_CTYPE_STATUS) {
-               *code = AVC_CTYPE_REJECTED;
-               return 0;
-       }
-
-       *code = AVC_CTYPE_STABLE;
-
-       /* The first operand should be 0x07 for the UNITINFO response.
-        * Neither AVRCP (section 22.1, page 117) nor AVC Digital
-        * Interface Command Set (section 9.2.1, page 45) specs
-        * explain this value but both use it */
-       if (operand_count >= 1)
-               operands[0] = 0x07;
-       if (operand_count >= 2)
-               operands[1] = AVC_SUBUNIT_PANEL << 3;
-
-       DBG("reply to AVC_OP_UNITINFO");
-
-       return operand_count;
-}
-
-static size_t handle_subunit_info(struct avctp *session,
-                                       uint8_t transaction, uint8_t *code,
-                                       uint8_t *subunit, uint8_t *operands,
-                                       size_t operand_count, void *user_data)
-{
-       if (*code != AVC_CTYPE_STATUS) {
-               *code = AVC_CTYPE_REJECTED;
-               return 0;
-       }
-
-       *code = AVC_CTYPE_STABLE;
-
-       /* The first operand should be 0x07 for the UNITINFO response.
-        * Neither AVRCP (section 22.1, page 117) nor AVC Digital
-        * Interface Command Set (section 9.2.1, page 45) specs
-        * explain this value but both use it */
-       if (operand_count >= 2)
-               operands[1] = AVC_SUBUNIT_PANEL << 3;
-
-       DBG("reply to AVC_OP_SUBUNITINFO");
-
-       return operand_count;
-}
-
-static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
-{
-       for (; list; list = list->next) {
-               struct avctp_pdu_handler *handler = list->data;
-
-               if (handler->opcode == opcode)
-                       return handler;
-       }
-
-       return NULL;
-}
-
-static void avctp_disconnected(struct avctp *session)
-{
-       struct avctp_server *server;
-
-       if (!session)
-               return;
-
-       if (session->io) {
-               g_io_channel_shutdown(session->io, TRUE, NULL);
-               g_io_channel_unref(session->io);
-               session->io = NULL;
-       }
-
-       if (session->io_id) {
-               g_source_remove(session->io_id);
-               session->io_id = 0;
-
-               if (session->state == AVCTP_STATE_CONNECTING) {
-                       struct audio_device *dev;
-
-                       dev = manager_get_device(&session->server->src,
-                                                       &session->dst, FALSE);
-                       audio_device_cancel_authorization(dev, auth_cb,
-                                                               session);
-               }
-       }
-
-       if (session->uinput >= 0) {
-               char address[18];
-
-               ba2str(&session->dst, address);
-               DBG("AVCTP: closing uinput for %s", address);
-
-               ioctl(session->uinput, UI_DEV_DESTROY);
-               close(session->uinput);
-               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);
-}
-
-static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
-{
-       GSList *l;
-       struct audio_device *dev;
-       avctp_state_t old_state = session->state;
-
-       dev = manager_get_device(&session->server->src, &session->dst, FALSE);
-       if (dev == NULL) {
-               error("avdtp_set_state(): no matching audio device");
-               return;
-       }
-
-       session->state = new_state;
-
-       for (l = callbacks; l != NULL; l = l->next) {
-               struct avctp_state_callback *cb = l->data;
-               cb->cb(dev, old_state, new_state, cb->user_data);
-       }
-
-       switch (new_state) {
-       case AVCTP_STATE_DISCONNECTED:
-               DBG("AVCTP Disconnected");
-
-               avctp_disconnected(session);
-
-               if (old_state != AVCTP_STATE_CONNECTED)
-                       break;
-
-               if (!audio_device_is_active(dev, NULL))
-                       audio_device_set_authorized(dev, FALSE);
-
-               break;
-       case AVCTP_STATE_CONNECTING:
-               DBG("AVCTP Connecting");
-               break;
-       case AVCTP_STATE_CONNECTED:
-               DBG("AVCTP Connected");
-               break;
-       default:
-               error("Invalid AVCTP state %d", new_state);
-               return;
-       }
-}
-
-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)
-{
-       struct avctp *session = data;
-       uint8_t buf[1024], *operands, code, subunit;
-       struct avctp_header *avctp;
-       struct avc_header *avc;
-       int ret, packet_size, operand_count, sock;
-       struct avctp_pdu_handler *handler;
-
-       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
-               goto failed;
-
-       sock = g_io_channel_unix_get_fd(session->io);
-
-       ret = read(sock, buf, sizeof(buf));
-       if (ret <= 0)
-               goto failed;
-
-       DBG("Got %d bytes of data for AVCTP session %p", ret, session);
-
-       if ((unsigned int) ret < sizeof(struct avctp_header)) {
-               error("Too small AVCTP packet");
-               goto failed;
-       }
-
-       avctp = (struct avctp_header *) buf;
-
-       DBG("AVCTP transaction %u, packet type %u, C/R %u, IPID %u, "
-                       "PID 0x%04X",
-                       avctp->transaction, avctp->packet_type,
-                       avctp->cr, avctp->ipid, ntohs(avctp->pid));
-
-       ret -= sizeof(struct avctp_header);
-       if ((unsigned int) ret < sizeof(struct avc_header)) {
-               error("Too small AVCTP packet");
-               goto failed;
-       }
-
-       avc = (struct avc_header *) (buf + sizeof(struct avctp_header));
-
-       ret -= sizeof(struct avc_header);
-
-       operands = buf + sizeof(struct avctp_header) + sizeof(struct avc_header);
-       operand_count = ret;
-
-       DBG("AV/C %s 0x%01X, subunit_type 0x%02X, subunit_id 0x%01X, "
-                       "opcode 0x%02X, %d operands",
-                       avctp->cr ? "response" : "command",
-                       avc->code, avc->subunit_type, avc->subunit_id,
-                       avc->opcode, operand_count);
-
-       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;
-
-       if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
-               avc->code = AVC_CTYPE_NOT_IMPLEMENTED;
-               goto done;
-       }
-
-       if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
-               avctp->ipid = 1;
-               avc->code = AVC_CTYPE_REJECTED;
-               goto done;
-       }
-
-       handler = find_handler(handlers, avc->opcode);
-       if (!handler) {
-               DBG("handler not found for 0x%02x", avc->opcode);
-               packet_size += avrcp_handle_vendor_reject(&code, operands);
-               avc->code = code;
-               goto done;
-       }
-
-       code = avc->code;
-       subunit = avc->subunit_type;
-
-       packet_size += handler->cb(session, avctp->transaction, &code,
-                                       &subunit, operands, operand_count,
-                                       handler->user_data);
-
-       avc->code = code;
-       avc->subunit_type = subunit;
-
-done:
-       ret = write(sock, buf, packet_size);
-       if (ret != packet_size)
-               goto failed;
-
-       return TRUE;
-
-failed:
-       DBG("AVCTP session %p got disconnected", session);
-       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-       return FALSE;
-}
-
-static int uinput_create(char *name)
-{
-       struct uinput_dev dev;
-       int fd, err, i;
-
-       fd = open("/dev/uinput", O_RDWR);
-       if (fd < 0) {
-               fd = open("/dev/input/uinput", O_RDWR);
-               if (fd < 0) {
-                       fd = open("/dev/misc/uinput", O_RDWR);
-                       if (fd < 0) {
-                               err = -errno;
-                               error("Can't open input device: %s (%d)",
-                                                       strerror(-err), -err);
-                               return err;
-                       }
-               }
-       }
-
-       memset(&dev, 0, sizeof(dev));
-       if (name)
-               strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
-
-       dev.id.bustype = BUS_BLUETOOTH;
-       dev.id.vendor  = 0x0000;
-       dev.id.product = 0x0000;
-       dev.id.version = 0x0000;
-
-       if (write(fd, &dev, sizeof(dev)) < 0) {
-               err = -errno;
-               error("Can't write device information: %s (%d)",
-                                               strerror(-err), -err);
-               close(fd);
-               return err;
-       }
-
-       ioctl(fd, UI_SET_EVBIT, EV_KEY);
-       ioctl(fd, UI_SET_EVBIT, EV_REL);
-       ioctl(fd, UI_SET_EVBIT, EV_REP);
-       ioctl(fd, UI_SET_EVBIT, EV_SYN);
-
-       for (i = 0; key_map[i].name != NULL; i++)
-               ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
-
-       if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
-               err = -errno;
-               error("Can't create uinput device: %s (%d)",
-                                               strerror(-err), -err);
-               close(fd);
-               return err;
-       }
-
-       return fd;
-}
-
-static void init_uinput(struct avctp *session)
-{
-       struct audio_device *dev;
-       char address[18], name[248 + 1];
-
-       dev = manager_get_device(&session->server->src, &session->dst, FALSE);
-
-       device_get_name(dev->btd_dev, name, sizeof(name));
-       if (g_str_equal(name, "Nokia CK-20W")) {
-               session->key_quirks[FORWARD_OP] |= QUIRK_NO_RELEASE;
-               session->key_quirks[BACKWARD_OP] |= QUIRK_NO_RELEASE;
-               session->key_quirks[PLAY_OP] |= QUIRK_NO_RELEASE;
-               session->key_quirks[PAUSE_OP] |= QUIRK_NO_RELEASE;
-       }
-
-       ba2str(&session->dst, address);
-
-       session->uinput = uinput_create(address);
-       if (session->uinput < 0)
-               error("AVRCP: failed to init uinput for %s", address);
-       else
-               DBG("AVRCP: uinput initialized for %s", address);
-}
-
-static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
-{
-       struct avctp *session = data;
-       char address[18];
-       uint16_t imtu;
-       GError *gerr = NULL;
-
-       if (err) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-               error("%s", err->message);
-               return;
-       }
-
-       bt_io_get(chan, BT_IO_L2CAP, &gerr,
-                       BT_IO_OPT_DEST, &address,
-                       BT_IO_OPT_IMTU, &imtu,
-                       BT_IO_OPT_INVALID);
-       if (gerr) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-               error("%s", gerr->message);
-               g_error_free(gerr);
-               return;
-       }
-
-       DBG("AVCTP: connected to %s", address);
-
-       if (!session->io)
-               session->io = g_io_channel_ref(chan);
-
-       init_uinput(session);
-
-       avctp_set_state(session, AVCTP_STATE_CONNECTED);
-       session->mtu = imtu;
-       session->io_id = g_io_add_watch(chan,
-                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                               (GIOFunc) session_cb, session);
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct avctp *session = user_data;
-       GError *err = NULL;
-
-       if (session->io_id) {
-               g_source_remove(session->io_id);
-               session->io_id = 0;
-       }
-
-       if (derr && dbus_error_is_set(derr)) {
-               error("Access denied: %s", derr->message);
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-               return;
-       }
-
-       if (!bt_io_accept(session->io, avctp_connect_cb, session,
-                                                               NULL, &err)) {
-               error("bt_io_accept: %s", err->message);
-               g_error_free(err);
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-       }
-}
-
-static struct avctp_server *find_server(GSList *list, const bdaddr_t *src)
-{
-       for (; list; list = list->next) {
-               struct avctp_server *server = list->data;
-
-               if (bacmp(&server->src, src) == 0)
-                       return server;
-       }
-
-       return NULL;
-}
-
-static struct avctp *find_session(GSList *list, const bdaddr_t *dst)
-{
-       for (; list != NULL; list = g_slist_next(list)) {
-               struct avctp *s = list->data;
-
-               if (bacmp(dst, &s->dst))
-                       continue;
-
-               return s;
-       }
-
-       return NULL;
-}
-
-static struct avctp *avctp_get_internal(const bdaddr_t *src,
-                                                       const bdaddr_t *dst)
-{
-       struct avctp_server *server;
-       struct avctp *session;
-
-       assert(src != NULL);
-       assert(dst != NULL);
-
-       server = find_server(servers, src);
-       if (server == NULL)
-               return NULL;
-
-       session = find_session(server->sessions, dst);
-       if (session)
-               return session;
-
-       session = g_new0(struct avctp, 1);
-
-       session->server = server;
-       bacpy(&session->dst, dst);
-       session->state = AVCTP_STATE_DISCONNECTED;
-
-       server->sessions = g_slist_append(server->sessions, session);
-
-       return session;
-}
-
-static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
-{
-       struct avctp *session;
-       struct audio_device *dev;
-       char address[18];
-       bdaddr_t src, dst;
-       GError *err = NULL;
-
-       bt_io_get(chan, BT_IO_L2CAP, &err,
-                       BT_IO_OPT_SOURCE_BDADDR, &src,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_DEST, address,
-                       BT_IO_OPT_INVALID);
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-               g_io_channel_shutdown(chan, TRUE, NULL);
-               return;
-       }
-
-       DBG("AVCTP: incoming connect from %s", address);
-
-       session = avctp_get_internal(&src, &dst);
-       if (!session)
-               goto drop;
-
-       dev = manager_get_device(&src, &dst, FALSE);
-       if (!dev) {
-               dev = manager_get_device(&src, &dst, TRUE);
-               if (!dev) {
-                       error("Unable to get audio device object for %s",
-                                       address);
-                       goto drop;
-               }
-       }
-
-       if (dev->control == NULL) {
-               btd_device_add_uuid(dev->btd_dev, AVRCP_REMOTE_UUID);
-               if (dev->control == NULL)
-                       goto drop;
-       }
-
-       if (session->io) {
-               error("Refusing unexpected connect from %s", address);
-               goto drop;
-       }
-
-       avctp_set_state(session, AVCTP_STATE_CONNECTING);
-       session->io = g_io_channel_ref(chan);
-
-       if (audio_device_request_authorization(dev, AVRCP_TARGET_UUID,
-                                               auth_cb, session) < 0)
-               goto drop;
-
-       session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                                       session_cb, session);
-       return;
-
-drop:
-       if (!session || !session->io)
-               g_io_channel_shutdown(chan, TRUE, NULL);
-       if (session)
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-}
-
-static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master)
-{
-       GError *err = NULL;
-       GIOChannel *io;
-
-       io = bt_io_listen(BT_IO_L2CAP, NULL, avctp_confirm_cb, NULL,
-                               NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, src,
-                               BT_IO_OPT_PSM, AVCTP_PSM,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               g_error_free(err);
-       }
-
-       return io;
-}
-
-static unsigned int passthrough_id = 0;
-static unsigned int unit_id = 0;
-static unsigned int subunit_id = 0;
-
-int avctp_register(const bdaddr_t *src, gboolean master)
-{
-       struct avctp_server *server;
-
-       server = g_new0(struct avctp_server, 1);
-       if (!server)
-               return -ENOMEM;
-
-       server->io = avctp_server_socket(src, master);
-       if (!server->io) {
-               g_free(server);
-               return -1;
-       }
-
-       bacpy(&server->src, src);
-
-       servers = g_slist_append(servers, server);
-
-       if (!passthrough_id)
-               passthrough_id = avctp_register_pdu_handler(AVC_OP_PASSTHROUGH,
-                                       handle_panel_passthrough, NULL);
-
-       if (!unit_id)
-               unit_id = avctp_register_pdu_handler(AVC_OP_UNITINFO, handle_unit_info,
-                                                                       NULL);
-
-       if (!subunit_id)
-               subunit_id = avctp_register_pdu_handler(AVC_OP_SUBUNITINFO,
-                                               handle_subunit_info, NULL);
-
-       return 0;
-}
-
-void avctp_unregister(const bdaddr_t *src)
-{
-       struct avctp_server *server;
-
-       server = find_server(servers, src);
-       if (!server)
-               return;
-
-       while (server->sessions)
-               avctp_disconnected(server->sessions->data);
-
-       servers = g_slist_remove(servers, server);
-
-       g_io_channel_shutdown(server->io, TRUE, NULL);
-       g_io_channel_unref(server->io);
-       g_free(server);
-
-       if (servers)
-               return;
-
-       if (passthrough_id) {
-               avctp_unregister_pdu_handler(passthrough_id);
-               passthrough_id = 0;
-       }
-
-       if (unit_id) {
-               avctp_unregister_pdu_handler(unit_id);
-               passthrough_id = 0;
-       }
-
-       if (subunit_id) {
-               avctp_unregister_pdu_handler(subunit_id);
-               subunit_id = 0;
-       }
-}
-
-int avctp_send_passthrough(struct avctp *session, uint8_t op)
-{
-       unsigned char buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH + 2];
-       struct avctp_header *avctp = (void *) buf;
-       struct avc_header *avc = (void *) &buf[AVCTP_HEADER_LENGTH];
-       uint8_t *operands = &buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH];
-       int sk;
-
-       if (session->state != AVCTP_STATE_CONNECTED)
-               return -ENOTCONN;
-
-       memset(buf, 0, sizeof(buf));
-
-       avctp->transaction = id++;
-       avctp->packet_type = AVCTP_PACKET_SINGLE;
-       avctp->cr = AVCTP_COMMAND;
-       avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
-
-       avc->code = AVC_CTYPE_CONTROL;
-       avc->subunit_type = AVC_SUBUNIT_PANEL;
-       avc->opcode = AVC_OP_PASSTHROUGH;
-
-       operands[0] = op & 0x7f;
-       operands[1] = 0;
-
-       sk = g_io_channel_unix_get_fd(session->io);
-
-       if (write(sk, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       /* Button release */
-       avctp->transaction = id++;
-       operands[0] |= 0x80;
-
-       if (write(sk, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-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;
-       struct avctp_header *avctp;
-       struct avc_header *avc;
-       uint8_t *pdu;
-       int sk, err = 0;
-       uint16_t size;
-
-       if (session->state != AVCTP_STATE_CONNECTED)
-               return -ENOTCONN;
-
-       sk = g_io_channel_unix_get_fd(session->io);
-       size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH + operand_count;
-       buf = g_malloc0(size);
-
-       avctp = (void *) buf;
-       avc = (void *) &buf[AVCTP_HEADER_LENGTH];
-       pdu = (void *) &buf[AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH];
-
-       avctp->transaction = transaction;
-       avctp->packet_type = AVCTP_PACKET_SINGLE;
-       avctp->cr = cr;
-       avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
-
-       avc->code = code;
-       avc->subunit_type = subunit;
-       avc->opcode = opcode;
-
-       memcpy(pdu, operands, operand_count);
-
-       if (write(sk, buf, size) < 0)
-               err = -errno;
-
-       g_free(buf);
-       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;
-       static unsigned int id = 0;
-
-       state_cb = g_new(struct avctp_state_callback, 1);
-       state_cb->cb = cb;
-       state_cb->user_data = user_data;
-       state_cb->id = ++id;
-
-       callbacks = g_slist_append(callbacks, state_cb);
-
-       return state_cb->id;
-}
-
-gboolean avctp_remove_state_cb(unsigned int id)
-{
-       GSList *l;
-
-       for (l = callbacks; l != NULL; l = l->next) {
-               struct avctp_state_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       callbacks = g_slist_remove(callbacks, cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb,
-                                                       void *user_data)
-{
-       struct avctp_pdu_handler *handler;
-       static unsigned int id = 0;
-
-       handler = find_handler(handlers, opcode);
-       if (handler)
-               return 0;
-
-       handler = g_new(struct avctp_pdu_handler, 1);
-       handler->opcode = opcode;
-       handler->cb = cb;
-       handler->user_data = user_data;
-       handler->id = ++id;
-
-       handlers = g_slist_append(handlers, handler);
-
-       return handler->id;
-}
-
-gboolean avctp_unregister_pdu_handler(unsigned int id)
-{
-       GSList *l;
-
-       for (l = handlers; l != NULL; l = l->next) {
-               struct avctp_pdu_handler *handler = l->data;
-
-               if (handler->id == id) {
-                       handlers = g_slist_remove(handlers, handler);
-                       g_free(handler);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct avctp *session;
-       GError *err = NULL;
-       GIOChannel *io;
-
-       session = avctp_get_internal(src, dst);
-       if (!session)
-               return NULL;
-
-       if (session->state > AVCTP_STATE_DISCONNECTED)
-               return session;
-
-       avctp_set_state(session, AVCTP_STATE_CONNECTING);
-
-       io = bt_io_connect(BT_IO_L2CAP, avctp_connect_cb, session, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
-                               BT_IO_OPT_DEST_BDADDR, &session->dst,
-                               BT_IO_OPT_PSM, AVCTP_PSM,
-                               BT_IO_OPT_INVALID);
-       if (err) {
-               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-               error("%s", err->message);
-               g_error_free(err);
-               return NULL;
-       }
-
-       session->io = io;
-
-       return session;
-}
-
-void avctp_disconnect(struct avctp *session)
-{
-       if (!session->io)
-               return;
-
-       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
-}
-
-struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       return avctp_get_internal(src, dst);
-}
diff --git a/audio/avctp.h b/audio/avctp.h
deleted file mode 100644 (file)
index d0cbd97..0000000
+++ /dev/null
@@ -1,106 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#define AVCTP_PSM 23
-
-#define AVC_MTU 512
-#define AVC_HEADER_LENGTH 3
-
-/* ctype entries */
-#define AVC_CTYPE_CONTROL              0x0
-#define AVC_CTYPE_STATUS               0x1
-#define AVC_CTYPE_NOTIFY               0x3
-#define AVC_CTYPE_NOT_IMPLEMENTED      0x8
-#define AVC_CTYPE_ACCEPTED             0x9
-#define AVC_CTYPE_REJECTED             0xA
-#define AVC_CTYPE_STABLE               0xC
-#define AVC_CTYPE_CHANGED              0xD
-#define AVC_CTYPE_INTERIM              0xF
-
-/* opcodes */
-#define AVC_OP_VENDORDEP               0x00
-#define AVC_OP_UNITINFO                        0x30
-#define AVC_OP_SUBUNITINFO             0x31
-#define AVC_OP_PASSTHROUGH             0x7c
-
-/* subunits of interest */
-#define AVC_SUBUNIT_PANEL              0x09
-
-/* operands in passthrough commands */
-#define VOL_UP_OP                      0x41
-#define VOL_DOWN_OP                    0x42
-#define MUTE_OP                                0x43
-#define PLAY_OP                                0x44
-#define STAVC_OP_OP                    0x45
-#define PAUSE_OP                       0x46
-#define RECORD_OP                      0x47
-#define REWIND_OP                      0x48
-#define FAST_FORWARD_OP                        0x49
-#define EJECT_OP                       0x4a
-#define FORWARD_OP                     0x4b
-#define BACKWARD_OP                    0x4c
-
-struct avctp;
-
-typedef enum {
-       AVCTP_STATE_DISCONNECTED = 0,
-       AVCTP_STATE_CONNECTING,
-       AVCTP_STATE_CONNECTED
-} avctp_state_t;
-
-typedef void (*avctp_state_cb) (struct audio_device *dev,
-                               avctp_state_t old_state,
-                               avctp_state_t new_state,
-                               void *user_data);
-
-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);
-
-int avctp_register(const bdaddr_t *src, gboolean master);
-void avctp_unregister(const bdaddr_t *src);
-
-struct avctp *avctp_connect(const bdaddr_t *src, const bdaddr_t *dst);
-struct avctp *avctp_get(const bdaddr_t *src, const bdaddr_t *dst);
-void avctp_disconnect(struct avctp *session);
-
-unsigned int avctp_register_pdu_handler(uint8_t opcode, avctp_pdu_cb cb,
-                                                       void *user_data);
-gboolean avctp_unregister_pdu_handler(unsigned int id);
-
-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);
diff --git a/audio/avrcp.c b/audio/avrcp.c
deleted file mode 100644 (file)
index 89ee112..0000000
+++ /dev/null
@@ -1,1468 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2011  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 <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <assert.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#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"
-#include "manager.h"
-#include "avctp.h"
-#include "avrcp.h"
-#include "sdpd.h"
-#include "dbus-common.h"
-
-/* Company IDs for vendor dependent commands */
-#define IEEEID_BTSIG           0x001958
-
-/* Error codes for metadata transfer */
-#define E_INVALID_COMMAND      0x00
-#define E_INVALID_PARAM                0x01
-#define E_PARAM_NOT_FOUND      0x02
-#define E_INTERNAL             0x03
-
-/* Packet types */
-#define AVRCP_PACKET_TYPE_SINGLE       0x00
-#define AVRCP_PACKET_TYPE_START                0x01
-#define AVRCP_PACKET_TYPE_CONTINUING   0x02
-#define AVRCP_PACKET_TYPE_END          0x03
-
-/* PDU types for metadata transfer */
-#define AVRCP_GET_CAPABILITIES         0x10
-#define AVRCP_LIST_PLAYER_ATTRIBUTES   0X11
-#define AVRCP_LIST_PLAYER_VALUES       0x12
-#define AVRCP_GET_CURRENT_PLAYER_VALUE 0x13
-#define AVRCP_SET_PLAYER_VALUE         0x14
-#define AVRCP_GET_PLAYER_ATTRIBUTE_TEXT        0x15
-#define AVRCP_GET_PLAYER_VALUE_TEXT    0x16
-#define AVRCP_DISPLAYABLE_CHARSET      0x17
-#define AVRCP_CT_BATTERY_STATUS                0x18
-#define AVRCP_GET_ELEMENT_ATTRIBUTES   0x20
-#define AVRCP_GET_PLAY_STATUS          0x30
-#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,
-       BATTERY_STATUS_CRITICAL =       2,
-       BATTERY_STATUS_EXTERNAL =       3,
-       BATTERY_STATUS_FULL_CHARGE =    4,
-};
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct avrcp_header {
-       uint8_t company_id[3];
-       uint8_t pdu_id;
-       uint8_t packet_type:2;
-       uint8_t rsvd:6;
-       uint16_t params_len;
-       uint8_t params[0];
-} __attribute__ ((packed));
-#define AVRCP_HEADER_LENGTH 7
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct avrcp_header {
-       uint8_t company_id[3];
-       uint8_t pdu_id;
-       uint8_t rsvd:6;
-       uint8_t packet_type:2;
-       uint16_t params_len;
-       uint8_t params[0];
-} __attribute__ ((packed));
-#define AVRCP_HEADER_LENGTH 7
-
-#else
-#error "Unknown byte order"
-#endif
-
-#define AVRCP_MTU      (AVC_MTU - AVC_HEADER_LENGTH)
-#define AVRCP_PDU_MTU  (AVRCP_MTU - AVRCP_HEADER_LENGTH)
-
-struct avrcp_server {
-       bdaddr_t src;
-       uint32_t tg_record_id;
-       uint32_t ct_record_id;
-       GSList *players;
-       struct avrcp_player *active_player;
-};
-
-struct pending_pdu {
-       uint8_t pdu_id;
-       GList *attr_ids;
-       uint16_t offset;
-};
-
-struct avrcp_player {
-       struct avrcp_server *server;
-       struct avctp *session;
-       struct audio_device *dev;
-
-       unsigned int handler;
-       uint16_t registered_events;
-       uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
-       struct pending_pdu *pending_pdu;
-
-       struct avrcp_player_cb *cb;
-       void *user_data;
-       GDestroyNotify destroy;
-};
-
-static GSList *servers = NULL;
-static unsigned int avctp_id = 0;
-
-/* Company IDs supported by this device */
-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;
-       uuid_t root_uuid, l2cap, avctp, avrct;
-       sdp_profile_desc_t profile[1];
-       sdp_list_t *aproto, *proto[2];
-       sdp_record_t *record;
-       sdp_data_t *psm, *version, *features;
-       uint16_t lp = AVCTP_PSM;
-       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)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(0, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       /* Service Class ID List */
-       sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
-       svclass_id = sdp_list_append(0, &avrct);
-       sdp_set_service_classes(record, svclass_id);
-
-       /* Protocol Descriptor List */
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(0, &l2cap);
-       psm = sdp_data_alloc(SDP_UINT16, &lp);
-       proto[0] = sdp_list_append(proto[0], psm);
-       apseq = sdp_list_append(0, proto[0]);
-
-       sdp_uuid16_create(&avctp, AVCTP_UUID);
-       proto[1] = sdp_list_append(0, &avctp);
-       version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
-       proto[1] = sdp_list_append(proto[1], version);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       /* Bluetooth Profile Descriptor List */
-       sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-       profile[0].version = avrcp_ver;
-       pfseq = sdp_list_append(0, &profile[0]);
-       sdp_set_profile_descs(record, pfseq);
-
-       features = sdp_data_alloc(SDP_UINT16, &feat);
-       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-       sdp_set_info_attr(record, "AVRCP CT", 0, 0);
-
-       free(psm);
-       free(version);
-       sdp_list_free(proto[0], 0);
-       sdp_list_free(proto[1], 0);
-       sdp_list_free(apseq, 0);
-       sdp_list_free(pfseq, 0);
-       sdp_list_free(aproto, 0);
-       sdp_list_free(root, 0);
-       sdp_list_free(svclass_id, 0);
-
-       return record;
-}
-
-static sdp_record_t *avrcp_tg_record(void)
-{
-       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-       uuid_t root_uuid, l2cap, avctp, avrtg;
-       sdp_profile_desc_t profile[1];
-       sdp_list_t *aproto, *proto[2];
-       sdp_record_t *record;
-       sdp_data_t *psm, *version, *features;
-       uint16_t lp = AVCTP_PSM;
-       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)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(0, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       /* Service Class ID List */
-       sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
-       svclass_id = sdp_list_append(0, &avrtg);
-       sdp_set_service_classes(record, svclass_id);
-
-       /* Protocol Descriptor List */
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(0, &l2cap);
-       psm = sdp_data_alloc(SDP_UINT16, &lp);
-       proto[0] = sdp_list_append(proto[0], psm);
-       apseq = sdp_list_append(0, proto[0]);
-
-       sdp_uuid16_create(&avctp, AVCTP_UUID);
-       proto[1] = sdp_list_append(0, &avctp);
-       version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
-       proto[1] = sdp_list_append(proto[1], version);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       /* Bluetooth Profile Descriptor List */
-       sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
-       profile[0].version = avrcp_ver;
-       pfseq = sdp_list_append(0, &profile[0]);
-       sdp_set_profile_descs(record, pfseq);
-
-       features = sdp_data_alloc(SDP_UINT16, &feat);
-       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-       sdp_set_info_attr(record, "AVRCP TG", 0, 0);
-
-       free(psm);
-       free(version);
-       sdp_list_free(proto[0], 0);
-       sdp_list_free(proto[1], 0);
-       sdp_list_free(apseq, 0);
-       sdp_list_free(aproto, 0);
-       sdp_list_free(pfseq, 0);
-       sdp_list_free(root, 0);
-       sdp_list_free(svclass_id, 0);
-
-       return record;
-}
-
-static unsigned int attr_get_max_val(uint8_t attr)
-{
-       switch (attr) {
-       case AVRCP_ATTRIBUTE_EQUALIZER:
-               return AVRCP_EQUALIZER_ON;
-       case AVRCP_ATTRIBUTE_REPEAT_MODE:
-               return AVRCP_REPEAT_MODE_GROUP;
-       case AVRCP_ATTRIBUTE_SHUFFLE:
-               return AVRCP_SHUFFLE_GROUP;
-       case AVRCP_ATTRIBUTE_SCAN:
-               return AVRCP_SCAN_GROUP;
-       }
-
-       return 0;
-}
-
-static const char *battery_status_to_str(enum battery_status status)
-{
-       switch (status) {
-       case BATTERY_STATUS_NORMAL:
-               return "normal";
-       case BATTERY_STATUS_WARNING:
-               return "warning";
-       case BATTERY_STATUS_CRITICAL:
-               return "critical";
-       case BATTERY_STATUS_EXTERNAL:
-               return "external";
-       case BATTERY_STATUS_FULL_CHARGE:
-               return "fullcharge";
-       }
-
-       return NULL;
-}
-
-/*
- * get_company_id:
- *
- * Get three-byte Company_ID from incoming AVRCP message
- */
-static uint32_t get_company_id(const uint8_t cid[3])
-{
-       return cid[0] << 16 | cid[1] << 8 | cid[2];
-}
-
-/*
- * set_company_id:
- *
- * Set three-byte Company_ID into outgoing AVRCP message
- */
-static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
-{
-       cid[0] = cid_in >> 16;
-       cid[1] = cid_in >> 8;
-       cid[2] = cid_in;
-}
-
-int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data)
-{
-       uint8_t buf[AVRCP_HEADER_LENGTH + 9];
-       struct avrcp_header *pdu = (void *) buf;
-       uint16_t size;
-       int err;
-
-       if (player->session == NULL)
-               return -ENOTCONN;
-
-       if (!(player->registered_events & (1 << id)))
-               return 0;
-
-       memset(buf, 0, sizeof(buf));
-
-       set_company_id(pdu->company_id, IEEEID_BTSIG);
-
-       pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
-       pdu->params[0] = id;
-
-       DBG("id=%u", id);
-
-       switch (id) {
-       case AVRCP_EVENT_STATUS_CHANGED:
-               size = 2;
-               pdu->params[1] = *((uint8_t *)data);
-
-               break;
-       case AVRCP_EVENT_TRACK_CHANGED:
-               size = 9;
-               memcpy(&pdu->params[1], data, sizeof(uint64_t));
-
-               break;
-       case AVRCP_EVENT_TRACK_REACHED_END:
-       case AVRCP_EVENT_TRACK_REACHED_START:
-               size = 1;
-               break;
-       default:
-               error("Unknown event %u", id);
-               return -EINVAL;
-       }
-
-       pdu->params_len = htons(size);
-
-       err = avctp_send_vendordep(player->session, player->transaction_events[id],
-                                       AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
-                                       buf, size + AVRCP_HEADER_LENGTH);
-       if (err < 0)
-               return err;
-
-       /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */
-       player->registered_events ^= 1 << id;
-
-       return 0;
-}
-
-static uint16_t player_write_media_attribute(struct avrcp_player *player,
-                                               uint32_t id, uint8_t *buf,
-                                               uint16_t *pos,
-                                               uint16_t *offset)
-{
-       uint16_t len;
-       uint16_t attr_len;
-       char valstr[20];
-       void *value;
-
-       DBG("%u", id);
-
-       value = player->cb->get_metadata(id, player->user_data);
-       if (value == NULL) {
-               *offset = 0;
-               return 0;
-       }
-
-       switch (id) {
-       case AVRCP_MEDIA_ATTRIBUTE_TRACK:
-       case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS:
-       case AVRCP_MEDIA_ATTRIBUTE_DURATION:
-               snprintf(valstr, 20, "%u", GPOINTER_TO_UINT(value));
-               value = valstr;
-               break;
-       }
-
-       attr_len = strlen(value);
-       value = ((char *) value) + *offset;
-       len = attr_len - *offset;
-
-       if (len > AVRCP_PDU_MTU - *pos) {
-               len = AVRCP_PDU_MTU - *pos;
-               *offset += len;
-       } else {
-               *offset = 0;
-       }
-
-       memcpy(&buf[*pos], value, len);
-       *pos += len;
-
-       return attr_len;
-}
-
-static GList *player_fill_media_attribute(struct avrcp_player *player,
-                                       GList *attr_ids, uint8_t *buf,
-                                       uint16_t *pos, uint16_t *offset)
-{
-       struct media_attribute_header {
-               uint32_t id;
-               uint16_t charset;
-               uint16_t len;
-       } *hdr = NULL;
-       GList *l;
-
-       for (l = attr_ids; l != NULL; l = g_list_delete_link(l, l)) {
-               uint32_t attr = GPOINTER_TO_UINT(l->data);
-               uint16_t attr_len;
-
-               if (*offset == 0) {
-                       if (*pos + sizeof(*hdr) >= AVRCP_PDU_MTU)
-                               break;
-
-                       hdr = (void *) &buf[*pos];
-                       hdr->id = htonl(attr);
-                       hdr->charset = htons(0x6A); /* Always use UTF-8 */
-                       *pos += sizeof(*hdr);
-               }
-
-               attr_len = player_write_media_attribute(player, attr, buf,
-                                                               pos, offset);
-
-               if (hdr != NULL)
-                       hdr->len = htons(attr_len);
-
-               if (*offset > 0)
-                       break;
-       }
-
-       return l;
-}
-
-static struct pending_pdu *pending_pdu_new(uint8_t pdu_id, GList *attr_ids,
-                                                       unsigned int offset)
-{
-       struct pending_pdu *pending = g_new(struct pending_pdu, 1);
-
-       pending->pdu_id = pdu_id;
-       pending->attr_ids = attr_ids;
-       pending->offset = offset;
-
-       return pending;
-}
-
-static gboolean player_abort_pending_pdu(struct avrcp_player *player)
-{
-       if (player->pending_pdu == NULL)
-               return FALSE;
-
-       g_list_free(player->pending_pdu->attr_ids);
-       g_free(player->pending_pdu);
-       player->pending_pdu = NULL;
-
-       return TRUE;
-}
-
-static int player_set_attribute(struct avrcp_player *player,
-                                               uint8_t attr, uint8_t val)
-{
-       DBG("Change attribute: %u %u", attr, val);
-
-       return player->cb->set_setting(attr, val, player->user_data);
-}
-
-static int player_get_attribute(struct avrcp_player *player, uint8_t attr)
-{
-       int value;
-
-       DBG("attr %u", attr);
-
-       value = player->cb->get_setting(attr, player->user_data);
-       if (value < 0)
-               DBG("attr %u not supported by player", attr);
-
-       return value;
-}
-
-static uint8_t avrcp_handle_get_capabilities(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       unsigned int i;
-
-       if (len != 1)
-               goto err;
-
-       DBG("id=%u", pdu->params[0]);
-
-       switch (pdu->params[0]) {
-       case CAP_COMPANY_ID:
-               for (i = 0; i < G_N_ELEMENTS(company_ids); i++) {
-                       set_company_id(&pdu->params[2 + i * 3],
-                                                       company_ids[i]);
-               }
-
-               pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids)));
-               pdu->params[1] = G_N_ELEMENTS(company_ids);
-
-               return AVC_CTYPE_STABLE;
-       case CAP_EVENTS_SUPPORTED:
-               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;
-       }
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_list_player_attributes(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       unsigned int i;
-
-       if (len != 0) {
-               pdu->params_len = htons(1);
-               pdu->params[0] = E_INVALID_PARAM;
-               return AVC_CTYPE_REJECTED;
-       }
-
-       if (!player)
-               goto done;
-
-       for (i = 1; i <= AVRCP_ATTRIBUTE_SCAN; i++) {
-               if (player_get_attribute(player, i) < 0)
-                       continue;
-
-               len++;
-               pdu->params[len] = i;
-       }
-
-done:
-       pdu->params[0] = len;
-       pdu->params_len = htons(len + 1);
-
-       return AVC_CTYPE_STABLE;
-}
-
-static uint8_t avrcp_handle_list_player_values(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       unsigned int i;
-
-       if (len != 1 || !player)
-               goto err;
-
-       if (player_get_attribute(player, pdu->params[0]) < 0)
-               goto err;
-
-       len = attr_get_max_val(pdu->params[0]);
-
-       for (i = 1; i <= len; i++)
-               pdu->params[i] = i;
-
-       pdu->params[0] = len;
-       pdu->params_len = htons(len + 1);
-
-       return AVC_CTYPE_STABLE;
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_get_element_attributes(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       uint64_t *identifier = (uint64_t *) &pdu->params[0];
-       uint16_t pos;
-       uint8_t nattr;
-       GList *attr_ids;
-       uint16_t offset;
-
-       if (len < 9 || *identifier != 0)
-               goto err;
-
-       nattr = pdu->params[8];
-
-       if (len < nattr * sizeof(uint32_t) + 1)
-               goto err;
-
-       if (!nattr) {
-               /*
-                * Return all available information, at least
-                * title must be returned if there's a track selected.
-                */
-               attr_ids = player->cb->list_metadata(player->user_data);
-               len = g_list_length(attr_ids);
-       } else {
-               unsigned int i;
-               uint32_t *attr = (uint32_t *) &pdu->params[9];
-
-               for (i = 0, len = 0, attr_ids = NULL; i < nattr; i++, attr++) {
-                       uint32_t id = ntohl(bt_get_unaligned(attr));
-
-                       /* Don't add invalid attributes */
-                       if (id == AVRCP_MEDIA_ATTRIBUTE_ILLEGAL ||
-                                       id > AVRCP_MEDIA_ATTRIBUTE_LAST)
-                               continue;
-
-                       len++;
-                       attr_ids = g_list_prepend(attr_ids,
-                                                       GUINT_TO_POINTER(id));
-               }
-
-               attr_ids = g_list_reverse(attr_ids);
-       }
-
-       if (!len)
-               goto err;
-
-       player_abort_pending_pdu(player);
-       pos = 1;
-       offset = 0;
-       attr_ids = player_fill_media_attribute(player, attr_ids, pdu->params,
-                                                               &pos, &offset);
-
-       if (attr_ids != NULL) {
-               player->pending_pdu = pending_pdu_new(pdu->pdu_id, attr_ids,
-                                                               offset);
-               pdu->packet_type = AVRCP_PACKET_TYPE_START;
-       }
-
-       pdu->params[0] = len;
-       pdu->params_len = htons(pos);
-
-       return AVC_CTYPE_STABLE;
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_get_current_player_value(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       uint8_t *settings;
-       unsigned int i;
-
-       if (player == NULL || len <= 1 || pdu->params[0] != len - 1)
-               goto err;
-
-       /*
-        * Save a copy of requested settings because we can override them
-        * while responding
-        */
-       settings = g_memdup(&pdu->params[1], pdu->params[0]);
-       len = 0;
-
-       /*
-        * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs
-        * and send a response with the existent ones. Only if all IDs are
-        * non-existent we should send an error.
-        */
-       for (i = 0; i < pdu->params[0]; i++) {
-               int val;
-
-               if (settings[i] < AVRCP_ATTRIBUTE_EQUALIZER ||
-                                       settings[i] > AVRCP_ATTRIBUTE_SCAN) {
-                       DBG("Ignoring %u", settings[i]);
-                       continue;
-               }
-
-               val = player_get_attribute(player, settings[i]);
-               if (val < 0)
-                       continue;
-
-               pdu->params[++len] = settings[i];
-               pdu->params[++len] = val;
-       }
-
-       g_free(settings);
-
-       if (len) {
-               pdu->params[0] = len / 2;
-               pdu->params_len = htons(len + 1);
-
-               return AVC_CTYPE_STABLE;
-       }
-
-       error("No valid attributes in request");
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_set_player_value(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       unsigned int i;
-       uint8_t *param;
-
-       if (len < 3 || len > 2 * pdu->params[0] + 1U)
-               goto err;
-
-       /*
-        * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs
-        * and set the existent ones. Sec. 5.2.4 is not clear however how to
-        * indicate that a certain ID was not accepted. If at least one
-        * attribute is valid, we respond with no parameters. Otherwise an
-        * E_INVALID_PARAM is sent.
-        */
-       for (len = 0, i = 0, param = &pdu->params[1]; i < pdu->params[0];
-                                                       i++, param += 2) {
-               if (player_set_attribute(player, param[0], param[1]) < 0)
-                       continue;
-
-               len++;
-       }
-
-       if (len) {
-               pdu->params_len = 0;
-
-               return AVC_CTYPE_ACCEPTED;
-       }
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_displayable_charset(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-
-       if (len < 3) {
-               pdu->params_len = htons(1);
-               pdu->params[0] = E_INVALID_PARAM;
-               return AVC_CTYPE_REJECTED;
-       }
-
-       /*
-        * We acknowledge the commands, but we always use UTF-8 for
-        * encoding since CT is obliged to support it.
-        */
-       pdu->params_len = 0;
-       return AVC_CTYPE_STABLE;
-}
-
-static uint8_t avrcp_handle_ct_battery_status(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       const char *valstr;
-
-       if (len != 1)
-               goto err;
-
-       valstr = battery_status_to_str(pdu->params[0]);
-       if (valstr == NULL)
-               goto err;
-
-       pdu->params_len = 0;
-
-       return AVC_CTYPE_STABLE;
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_get_play_status(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       uint32_t position;
-       uint32_t duration;
-       void *pduration;
-
-       if (len != 0) {
-               pdu->params_len = htons(1);
-               pdu->params[0] = E_INVALID_PARAM;
-               return AVC_CTYPE_REJECTED;
-       }
-
-       position = player->cb->get_position(player->user_data);
-       pduration = player->cb->get_metadata(AVRCP_MEDIA_ATTRIBUTE_DURATION,
-                                                       player->user_data);
-       if (pduration != NULL)
-               duration = htonl(GPOINTER_TO_UINT(pduration));
-       else
-               duration = htonl(UINT32_MAX);
-
-       position = htonl(position);
-
-       memcpy(&pdu->params[0], &duration, 4);
-       memcpy(&pdu->params[4], &position, 4);
-       pdu->params[8] = player->cb->get_status(player->user_data);;
-
-       pdu->params_len = htons(9);
-
-       return AVC_CTYPE_STABLE;
-}
-
-static uint8_t avrcp_handle_register_notification(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       uint64_t uid;
-
-       /*
-        * 1 byte for EventID, 4 bytes for Playback interval but the latest
-        * one is applicable only for EVENT_PLAYBACK_POS_CHANGED. See AVRCP
-        * 1.3 spec, section 5.4.2.
-        */
-       if (len != 5)
-               goto err;
-
-       switch (pdu->params[0]) {
-       case AVRCP_EVENT_STATUS_CHANGED:
-               len = 2;
-               pdu->params[1] = player->cb->get_status(player->user_data);
-
-               break;
-       case AVRCP_EVENT_TRACK_CHANGED:
-               len = 9;
-               uid = player->cb->get_uid(player->user_data);
-               memcpy(&pdu->params[1], &uid, sizeof(uint64_t));
-
-               break;
-       case AVRCP_EVENT_TRACK_REACHED_END:
-       case AVRCP_EVENT_TRACK_REACHED_START:
-               len = 1;
-               break;
-       default:
-               /* All other events are not supported yet */
-               goto err;
-       }
-
-       /* Register event and save the transaction used */
-       player->registered_events |= (1 << pdu->params[0]);
-       player->transaction_events[pdu->params[0]] = transaction;
-
-       pdu->params_len = htons(len);
-
-       return AVC_CTYPE_INTERIM;
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_request_continuing(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       struct pending_pdu *pending;
-
-       if (len != 1 || player->pending_pdu == NULL)
-               goto err;
-
-       pending = player->pending_pdu;
-
-       if (pending->pdu_id != pdu->params[0])
-               goto err;
-
-
-       len = 0;
-       pending->attr_ids = player_fill_media_attribute(player,
-                                                       pending->attr_ids,
-                                                       pdu->params, &len,
-                                                       &pending->offset);
-       pdu->pdu_id = pending->pdu_id;
-
-       if (pending->attr_ids == NULL) {
-               g_free(player->pending_pdu);
-               player->pending_pdu = NULL;
-               pdu->packet_type = AVRCP_PACKET_TYPE_END;
-       } else {
-               pdu->packet_type = AVRCP_PACKET_TYPE_CONTINUING;
-       }
-
-       pdu->params_len = htons(len);
-
-       return AVC_CTYPE_STABLE;
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static uint8_t avrcp_handle_abort_continuing(struct avrcp_player *player,
-                                               struct avrcp_header *pdu,
-                                               uint8_t transaction)
-{
-       uint16_t len = ntohs(pdu->params_len);
-       struct pending_pdu *pending;
-
-       if (len != 1 || player->pending_pdu == NULL)
-               goto err;
-
-       pending = player->pending_pdu;
-
-       if (pending->pdu_id != pdu->params[0])
-               goto err;
-
-       player_abort_pending_pdu(player);
-       pdu->params_len = 0;
-
-       return AVC_CTYPE_ACCEPTED;
-
-err:
-       pdu->params_len = htons(1);
-       pdu->params[0] = E_INVALID_PARAM;
-       return AVC_CTYPE_REJECTED;
-}
-
-static struct pdu_handler {
-       uint8_t pdu_id;
-       uint8_t code;
-       uint8_t (*func) (struct avrcp_player *player,
-                                       struct avrcp_header *pdu,
-                                       uint8_t transaction);
-} handlers[] = {
-               { AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
-                                       avrcp_handle_get_capabilities },
-               { AVRCP_LIST_PLAYER_ATTRIBUTES, AVC_CTYPE_STATUS,
-                                       avrcp_handle_list_player_attributes },
-               { AVRCP_LIST_PLAYER_VALUES, AVC_CTYPE_STATUS,
-                                       avrcp_handle_list_player_values },
-               { AVRCP_GET_ELEMENT_ATTRIBUTES, AVC_CTYPE_STATUS,
-                                       avrcp_handle_get_element_attributes },
-               { AVRCP_GET_CURRENT_PLAYER_VALUE, AVC_CTYPE_STATUS,
-                                       avrcp_handle_get_current_player_value },
-               { AVRCP_SET_PLAYER_VALUE, AVC_CTYPE_CONTROL,
-                                       avrcp_handle_set_player_value },
-               { AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, AVC_CTYPE_STATUS,
-                                       NULL },
-               { AVRCP_GET_PLAYER_VALUE_TEXT, AVC_CTYPE_STATUS,
-                                       NULL },
-               { AVRCP_DISPLAYABLE_CHARSET, AVC_CTYPE_STATUS,
-                                       avrcp_handle_displayable_charset },
-               { AVRCP_CT_BATTERY_STATUS, AVC_CTYPE_STATUS,
-                                       avrcp_handle_ct_battery_status },
-               { AVRCP_GET_PLAY_STATUS, AVC_CTYPE_STATUS,
-                                       avrcp_handle_get_play_status },
-               { AVRCP_REGISTER_NOTIFICATION, AVC_CTYPE_NOTIFY,
-                                       avrcp_handle_register_notification },
-               { AVRCP_REQUEST_CONTINUING, AVC_CTYPE_CONTROL,
-                                       avrcp_handle_request_continuing },
-               { AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL,
-                                       avrcp_handle_abort_continuing },
-               { },
-};
-
-/* handle vendordep pdu inside an avctp packet */
-static size_t handle_vendordep_pdu(struct avctp *session, uint8_t transaction,
-                                       uint8_t *code, uint8_t *subunit,
-                                       uint8_t *operands, size_t operand_count,
-                                       void *user_data)
-{
-       struct avrcp_player *player = user_data;
-       struct pdu_handler *handler;
-       struct avrcp_header *pdu = (void *) operands;
-       uint32_t company_id = get_company_id(pdu->company_id);
-
-       if (company_id != IEEEID_BTSIG) {
-               *code = AVC_CTYPE_NOT_IMPLEMENTED;
-               return 0;
-       }
-
-       DBG("AVRCP PDU 0x%02X, company 0x%06X len 0x%04X",
-                       pdu->pdu_id, company_id, pdu->params_len);
-
-       pdu->packet_type = 0;
-       pdu->rsvd = 0;
-
-       if (operand_count < AVRCP_HEADER_LENGTH) {
-               pdu->params[0] = E_INVALID_COMMAND;
-               goto err_metadata;
-       }
-
-       for (handler = handlers; handler; handler++) {
-               if (handler->pdu_id == pdu->pdu_id)
-                       break;
-       }
-
-       if (!handler || handler->code != *code) {
-               pdu->params[0] = E_INVALID_COMMAND;
-               goto err_metadata;
-       }
-
-       if (!handler->func) {
-               pdu->params[0] = E_INVALID_PARAM;
-               goto err_metadata;
-       }
-
-       *code = handler->func(player, pdu, transaction);
-
-       if (*code != AVC_CTYPE_REJECTED &&
-                               pdu->pdu_id != AVRCP_GET_ELEMENT_ATTRIBUTES &&
-                               pdu->pdu_id != AVRCP_REQUEST_CONTINUING &&
-                               pdu->pdu_id != AVRCP_ABORT_CONTINUING)
-               player_abort_pending_pdu(player);
-
-       return AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
-
-err_metadata:
-       pdu->params_len = htons(1);
-       *code = AVC_CTYPE_REJECTED;
-
-       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) {
-               struct avrcp_server *server = list->data;
-
-               if (bacmp(&server->src, src) == 0)
-                       return server;
-       }
-
-       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)
-               return;
-
-       player = server->active_player;
-       if (!player)
-               return;
-
-       switch (new_state) {
-       case AVCTP_STATE_DISCONNECTED:
-               player->session = NULL;
-               player->dev = NULL;
-               player->registered_events = 0;
-
-               if (player->handler) {
-                       avctp_unregister_pdu_handler(player->handler);
-                       player->handler = 0;
-               }
-
-               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(
-                                                       AVC_OP_VENDORDEP,
-                                                       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;
-       }
-}
-
-gboolean avrcp_connect(struct audio_device *dev)
-{
-       struct avctp *session;
-
-       session = avctp_connect(&dev->src, &dev->dst);
-       if (session)
-               return FALSE;
-
-       return TRUE;
-}
-
-void avrcp_disconnect(struct audio_device *dev)
-{
-       struct avctp *session;
-
-       session = avctp_get(&dev->src, &dev->dst);
-       if (!session)
-               return;
-
-       avctp_disconnect(session);
-}
-
-int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
-{
-       sdp_record_t *record;
-       gboolean tmp, master = TRUE;
-       GError *err = NULL;
-       struct avrcp_server *server;
-
-       if (config) {
-               tmp = g_key_file_get_boolean(config, "General",
-                                                       "Master", &err);
-               if (err) {
-                       DBG("audio.conf: %s", err->message);
-                       g_error_free(err);
-               } else
-                       master = tmp;
-       }
-
-       server = g_new0(struct avrcp_server, 1);
-       if (!server)
-               return -ENOMEM;
-
-       record = avrcp_tg_record();
-       if (!record) {
-               error("Unable to allocate new service record");
-               g_free(server);
-               return -1;
-       }
-
-       if (add_record_to_server(src, record) < 0) {
-               error("Unable to register AVRCP target service record");
-               g_free(server);
-               sdp_record_free(record);
-               return -1;
-       }
-       server->tg_record_id = record->handle;
-
-       record = avrcp_ct_record();
-       if (!record) {
-               error("Unable to allocate new service record");
-               g_free(server);
-               return -1;
-       }
-
-       if (add_record_to_server(src, record) < 0) {
-               error("Unable to register AVRCP service record");
-               sdp_record_free(record);
-               g_free(server);
-               return -1;
-       }
-       server->ct_record_id = record->handle;
-
-       if (avctp_register(src, master) < 0) {
-               remove_record_from_server(server->ct_record_id);
-               remove_record_from_server(server->tg_record_id);
-               g_free(server);
-               return -1;
-       }
-
-       bacpy(&server->src, src);
-
-       servers = g_slist_append(servers, server);
-
-       return 0;
-}
-
-static void player_destroy(gpointer data)
-{
-       struct avrcp_player *player = data;
-
-       if (player->destroy)
-               player->destroy(player->user_data);
-
-       player_abort_pending_pdu(player);
-
-       if (player->handler)
-               avctp_unregister_pdu_handler(player->handler);
-
-       g_free(player);
-}
-
-void avrcp_unregister(const bdaddr_t *src)
-{
-       struct avrcp_server *server;
-
-       server = find_server(servers, src);
-       if (!server)
-               return;
-
-       g_slist_free_full(server->players, player_destroy);
-
-       servers = g_slist_remove(servers, server);
-
-       remove_record_from_server(server->ct_record_id);
-       remove_record_from_server(server->tg_record_id);
-
-       avctp_unregister(&server->src);
-       g_free(server);
-
-       if (servers)
-               return;
-
-       if (avctp_id) {
-               avctp_remove_state_cb(avctp_id);
-               avctp_id = 0;
-       }
-}
-
-struct avrcp_player *avrcp_register_player(const bdaddr_t *src,
-                                               struct avrcp_player_cb *cb,
-                                               void *user_data,
-                                               GDestroyNotify destroy)
-{
-       struct avrcp_server *server;
-       struct avrcp_player *player;
-
-       server = find_server(servers, src);
-       if (!server)
-               return NULL;
-
-       player = g_new0(struct avrcp_player, 1);
-       player->server = server;
-       player->cb = cb;
-       player->user_data = user_data;
-       player->destroy = destroy;
-
-       if (!server->players)
-               server->active_player = player;
-
-       if (!avctp_id)
-               avctp_id = avctp_add_state_cb(state_changed, NULL);
-
-       server->players = g_slist_append(server->players, player);
-
-       return player;
-}
-
-void avrcp_unregister_player(struct avrcp_player *player)
-{
-       struct avrcp_server *server = player->server;
-
-       server->players = g_slist_remove(server->players, player);
-
-       if (server->active_player == player)
-               server->active_player = g_slist_nth_data(server->players, 0);
-
-       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);
-}
diff --git a/audio/bluetooth.conf b/audio/bluetooth.conf
deleted file mode 100644 (file)
index 55b51e4..0000000
+++ /dev/null
@@ -1,36 +0,0 @@
-# Please note that this ALSA configuration file fragment needs be enabled in
-# /etc/asound.conf or a similar configuration file with directives similar to
-# the following:
-#
-#@hooks [
-#      {
-#              func load
-#              files [
-#                      "/etc/alsa/bluetooth.conf"
-#              ]
-#              errors false
-#      }
-#]
-
-pcm.rawbluetooth {
-       @args [ ADDRESS ]
-       @args.ADDRESS {
-               type string
-       }
-       type bluetooth
-       device $ADDRESS
-}
-
-pcm.bluetooth {
-       @args [ ADDRESS ]
-       @args.ADDRESS {
-               type string
-       }
-       type plug
-       slave {
-               pcm {
-                       type bluetooth
-                       device $ADDRESS
-               }
-       }
-}
diff --git a/audio/control.c b/audio/control.c
deleted file mode 100644 (file)
index c5a6a58..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2011  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 <stdlib.h>
-#include <stdint.h>
-#include <errno.h>
-#include <unistd.h>
-#include <assert.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "error.h"
-#include "device.h"
-#include "manager.h"
-#include "avctp.h"
-#include "control.h"
-#include "sdpd.h"
-#include "glib-helper.h"
-#include "dbus-common.h"
-
-static unsigned int avctp_id = 0;
-
-struct control {
-       struct audio_device *dev;
-       struct avctp *session;
-
-       gboolean target;
-};
-
-static void state_changed(struct audio_device *dev, avctp_state_t old_state,
-                               avctp_state_t new_state, void *user_data)
-{
-       struct control *control = dev->control;
-       gboolean value;
-
-       switch (new_state) {
-       case AVCTP_STATE_DISCONNECTED:
-               control->session = NULL;
-
-               if (old_state != AVCTP_STATE_CONNECTED)
-                       break;
-
-               value = FALSE;
-               g_dbus_emit_signal(dev->conn, dev->path,
-                                       AUDIO_CONTROL_INTERFACE,
-                                       "Disconnected", DBUS_TYPE_INVALID);
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_CONTROL_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &value);
-
-               break;
-       case AVCTP_STATE_CONNECTING:
-               if (control->session)
-                       break;
-
-               control->session = avctp_get(&dev->src, &dev->dst);
-
-               break;
-       case AVCTP_STATE_CONNECTED:
-               value = TRUE;
-               g_dbus_emit_signal(dev->conn, dev->path,
-                               AUDIO_CONTROL_INTERFACE, "Connected",
-                               DBUS_TYPE_INVALID);
-               emit_property_changed(dev->conn, dev->path,
-                               AUDIO_CONTROL_INTERFACE, "Connected",
-                               DBUS_TYPE_BOOLEAN, &value);
-               break;
-       default:
-               return;
-       }
-}
-
-static DBusMessage *control_is_connected(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               void *data)
-{
-       struct audio_device *device = data;
-       struct control *control = device->control;
-       DBusMessage *reply;
-       dbus_bool_t connected;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       connected = (control->session != NULL);
-
-       dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *volume_up(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct audio_device *device = data;
-       struct control *control = device->control;
-       int err;
-
-       if (!control->session)
-               return btd_error_not_connected(msg);
-
-       if (!control->target)
-               return btd_error_not_supported(msg);
-
-       err = avctp_send_passthrough(control->session, VOL_UP_OP);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *volume_down(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct audio_device *device = data;
-       struct control *control = device->control;
-       int err;
-
-       if (!control->session)
-               return btd_error_not_connected(msg);
-
-       if (!control->target)
-               return btd_error_not_supported(msg);
-
-       err = avctp_send_passthrough(control->session, VOL_DOWN_OP);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *control_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       gboolean value;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       /* Connected */
-       value = (device->control->session != NULL);
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 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)
-{
-       struct audio_device *dev = data;
-       struct control *control = dev->control;
-
-       DBG("Unregistered interface %s on path %s",
-               AUDIO_CONTROL_INTERFACE, dev->path);
-
-       if (control->session)
-               avctp_disconnect(control->session);
-
-       g_free(control);
-       dev->control = NULL;
-}
-
-void control_unregister(struct audio_device *dev)
-{
-       g_dbus_unregister_interface(dev->conn, dev->path,
-                                               AUDIO_CONTROL_INTERFACE);
-}
-
-void control_update(struct control *control, uint16_t uuid16)
-{
-       if (uuid16 == AV_REMOTE_TARGET_SVCLASS_ID)
-               control->target = TRUE;
-}
-
-struct control *control_init(struct audio_device *dev, uint16_t uuid16)
-{
-       struct control *control;
-
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_CONTROL_INTERFACE,
-                                       control_methods, control_signals, NULL,
-                                       dev, path_unregister))
-               return NULL;
-
-       DBG("Registered interface %s on path %s",
-               AUDIO_CONTROL_INTERFACE, dev->path);
-
-       control = g_new0(struct control, 1);
-       control->dev = dev;
-
-       control_update(control, uuid16);
-
-       if (!avctp_id)
-               avctp_id = avctp_add_state_cb(state_changed, NULL);
-
-       return control;
-}
-
-gboolean control_is_active(struct audio_device *dev)
-{
-       struct control *control = dev->control;
-
-       if (control && control->session)
-               return TRUE;
-
-       return FALSE;
-}
diff --git a/audio/ctl_bluetooth.c b/audio/ctl_bluetooth.c
deleted file mode 100644 (file)
index a16f476..0000000
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <sys/socket.h>
-#include <sys/un.h>
-
-#include <alsa/asoundlib.h>
-#include <alsa/control_external.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include "ipc.h"
-
-#ifdef ENABLE_DEBUG
-#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-#else
-#define DBG(fmt, arg...)
-#endif
-
-#define BLUETOOTH_MINVOL 0
-#define BLUETOOTH_MAXVOL 15
-
-struct bluetooth_data {
-       snd_ctl_ext_t ext;
-       int sock;
-};
-
-enum {
-       BLUETOOTH_PLAYBACK,
-       BLUETOOTH_CAPTURE,
-};
-
-static const char *vol_devices[2] = {
-       [BLUETOOTH_PLAYBACK]    = "Playback volume",
-       [BLUETOOTH_CAPTURE]     = "Capture volume",
-};
-
-static void bluetooth_exit(struct bluetooth_data *data)
-{
-       if (data == NULL)
-               return;
-
-       if (data->sock >= 0)
-               bt_audio_service_close(data->sock);
-
-       free(data);
-}
-
-static void bluetooth_close(snd_ctl_ext_t *ext)
-{
-       struct bluetooth_data *data = ext->private_data;
-
-       DBG("ext %p", ext);
-
-       bluetooth_exit(data);
-}
-
-static int bluetooth_elem_count(snd_ctl_ext_t *ext)
-{
-       DBG("ext %p", ext);
-
-       return 2;
-}
-
-static int bluetooth_elem_list(snd_ctl_ext_t *ext,
-                               unsigned int offset, snd_ctl_elem_id_t *id)
-{
-       DBG("ext %p offset %d id %p", ext, offset, id);
-
-       snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
-
-       if (offset > 1)
-               return -EINVAL;
-
-       snd_ctl_elem_id_set_name(id, vol_devices[offset]);
-
-       return 0;
-}
-
-static snd_ctl_ext_key_t bluetooth_find_elem(snd_ctl_ext_t *ext,
-                                               const snd_ctl_elem_id_t *id)
-{
-       const char *name = snd_ctl_elem_id_get_name(id);
-       int i;
-
-       DBG("ext %p id %p name '%s'", ext, id, name);
-
-       for (i = 0; i < 2; i++)
-               if (strcmp(name, vol_devices[i]) == 0)
-                       return i;
-
-       return SND_CTL_EXT_KEY_NOT_FOUND;
-}
-
-static int bluetooth_get_attribute(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
-                       int *type, unsigned int *acc, unsigned int *count)
-{
-       DBG("ext %p key %ld", ext, key);
-
-       *type = SND_CTL_ELEM_TYPE_INTEGER;
-       *acc = SND_CTL_EXT_ACCESS_READWRITE;
-       *count = 1;
-
-       return 0;
-}
-
-static int bluetooth_get_integer_info(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
-                                       long *imin, long *imax, long *istep)
-{
-       DBG("ext %p key %ld", ext, key);
-
-       *istep = 1;
-       *imin  = BLUETOOTH_MINVOL;
-       *imax  = BLUETOOTH_MAXVOL;
-
-       return 0;
-}
-
-static int bluetooth_send_ctl(struct bluetooth_data *data,
-                       uint8_t mode, uint8_t key, struct bt_control_rsp *rsp)
-{
-       int ret;
-       struct bt_control_req *req = (void *) rsp;
-       bt_audio_error_t *err = (void *) rsp;
-       const char *type, *name;
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_CONTROL;
-       req->h.length = sizeof(*req);
-
-       req->mode = mode;
-       req->key = key;
-
-       ret = send(data->sock, req, BT_SUGGESTED_BUFFER_SIZE, MSG_NOSIGNAL);
-       if (ret <= 0) {
-               SYSERR("Unable to request new volume value to server");
-               return  -errno;
-       }
-
-       ret = recv(data->sock, rsp, BT_SUGGESTED_BUFFER_SIZE, 0);
-       if (ret <= 0) {
-               SNDERR("Unable to receive new volume value from server");
-               return  -errno;
-       }
-
-       if (rsp->h.type == BT_ERROR) {
-               SNDERR("BT_CONTROL failed : %s (%d)",
-                                       strerror(err->posix_errno),
-                                       err->posix_errno);
-               return -err->posix_errno;
-       }
-
-       type = bt_audio_strtype(rsp->h.type);
-       if (!type) {
-               SNDERR("Bogus message type %d "
-                               "received from audio service",
-                               rsp->h.type);
-               return -EINVAL;
-       }
-
-       name = bt_audio_strname(rsp->h.name);
-       if (!name) {
-               SNDERR("Bogus message name %d "
-                               "received from audio service",
-                               rsp->h.name);
-               return -EINVAL;
-       }
-
-       if (rsp->h.name != BT_CONTROL) {
-               SNDERR("Unexpected message %s received", type);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int bluetooth_read_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
-                                                               long *value)
-{
-       struct bluetooth_data *data = ext->private_data;
-       int ret;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_control_rsp *rsp = (void *) buf;
-
-       DBG("ext %p key %ld", ext, key);
-
-       memset(buf, 0, sizeof(buf));
-       *value = 0;
-
-       ret = bluetooth_send_ctl(data, key, 0, rsp);
-       if (ret == 0)
-               *value = rsp->key;
-
-       return ret;
-}
-
-static int bluetooth_write_integer(snd_ctl_ext_t *ext, snd_ctl_ext_key_t key,
-                                                               long *value)
-{
-       struct bluetooth_data *data = ext->private_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_control_rsp *rsp = (void *) buf;
-       long current;
-       int ret, keyvalue;
-
-       DBG("ext %p key %ld", ext, key);
-
-       ret = bluetooth_read_integer(ext, key, &current);
-       if (ret < 0)
-               return ret;
-
-       if (*value == current)
-               return 0;
-
-       while (*value != current) {
-               keyvalue = (*value > current) ? BT_CONTROL_KEY_VOL_UP :
-                               BT_CONTROL_KEY_VOL_DOWN;
-
-               ret = bluetooth_send_ctl(data, key, keyvalue, rsp);
-               if (ret < 0)
-                       break;
-
-               current = keyvalue;
-       }
-
-       return ret;
-}
-
-static int bluetooth_read_event(snd_ctl_ext_t *ext, snd_ctl_elem_id_t *id,
-                                               unsigned int *event_mask)
-{
-       struct bluetooth_data *data = ext->private_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_control_ind *ind = (void *) buf;
-       int err;
-       const char *type, *name;
-
-       DBG("ext %p id %p", ext, id);
-
-       memset(buf, 0, sizeof(buf));
-
-       err = recv(data->sock, ind, BT_SUGGESTED_BUFFER_SIZE, MSG_DONTWAIT);
-       if (err < 0) {
-               err = -errno;
-               SNDERR("Failed while receiving data: %s (%d)", strerror(-err),
-                                                                       -err);
-               return err;
-       }
-
-       type = bt_audio_strtype(ind->h.type);
-       if (!type) {
-               SNDERR("Bogus message type %d "
-                               "received from audio service",
-                               ind->h.type);
-               return -EAGAIN;
-       }
-
-       name = bt_audio_strname(ind->h.name);
-       if (!name) {
-               SNDERR("Bogus message name %d "
-                               "received from audio service",
-                               ind->h.name);
-               return -EAGAIN;
-       }
-
-       if (ind->h.name != BT_CONTROL) {
-               SNDERR("Unexpected message %s received", name);
-               return -EAGAIN;
-       }
-
-       snd_ctl_elem_id_set_interface(id, SND_CTL_ELEM_IFACE_MIXER);
-       snd_ctl_elem_id_set_name(id, ind->mode == BLUETOOTH_PLAYBACK ?
-                               vol_devices[BLUETOOTH_PLAYBACK] :
-                               vol_devices[BLUETOOTH_CAPTURE]);
-       *event_mask = SND_CTL_EVENT_MASK_VALUE;
-
-       return 1;
-}
-
-static snd_ctl_ext_callback_t bluetooth_callback = {
-       .close                  = bluetooth_close,
-       .elem_count             = bluetooth_elem_count,
-       .elem_list              = bluetooth_elem_list,
-       .find_elem              = bluetooth_find_elem,
-       .get_attribute          = bluetooth_get_attribute,
-       .get_integer_info       = bluetooth_get_integer_info,
-       .read_integer           = bluetooth_read_integer,
-       .write_integer          = bluetooth_write_integer,
-       .read_event             = bluetooth_read_event,
-};
-
-static int bluetooth_init(struct bluetooth_data *data)
-{
-       int sk;
-
-       if (!data)
-               return -EINVAL;
-
-       memset(data, 0, sizeof(struct bluetooth_data));
-
-       data->sock = -1;
-
-       sk = bt_audio_service_open();
-       if (sk < 0)
-               return -errno;
-
-       data->sock = sk;
-
-       return 0;
-}
-
-SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth);
-
-SND_CTL_PLUGIN_DEFINE_FUNC(bluetooth)
-{
-       struct bluetooth_data *data;
-       int err;
-
-       DBG("Bluetooth Control plugin");
-
-       data = malloc(sizeof(struct bluetooth_data));
-       if (!data) {
-               err = -ENOMEM;
-               goto error;
-       }
-
-       err = bluetooth_init(data);
-       if (err < 0)
-               goto error;
-
-       data->ext.version = SND_CTL_EXT_VERSION;
-       data->ext.card_idx = -1;
-
-       strncpy(data->ext.id, "bluetooth", sizeof(data->ext.id) - 1);
-       strncpy(data->ext.driver, "Bluetooth-Audio", sizeof(data->ext.driver) - 1);
-       strncpy(data->ext.name, "Bluetooth Audio", sizeof(data->ext.name) - 1);
-       strncpy(data->ext.longname, "Bluetooth Audio", sizeof(data->ext.longname) - 1);
-       strncpy(data->ext.mixername, "Bluetooth Audio", sizeof(data->ext.mixername) - 1);
-
-       data->ext.callback = &bluetooth_callback;
-       data->ext.poll_fd = data->sock;
-       data->ext.private_data = data;
-
-       err = snd_ctl_ext_create(&data->ext, name, mode);
-       if (err < 0)
-               goto error;
-
-       *handlep = data->ext.handle;
-
-       return 0;
-
-error:
-       bluetooth_exit(data);
-
-       return err;
-}
-
-SND_CTL_PLUGIN_SYMBOL(bluetooth);
diff --git a/audio/device.c b/audio/device.c
deleted file mode 100644 (file)
index b7b993e..0000000
+++ /dev/null
@@ -1,872 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/param.h>
-#include <netinet/in.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#include "error.h"
-#include "ipc.h"
-#include "dbus-common.h"
-#include "device.h"
-#include "unix.h"
-#include "avdtp.h"
-#include "control.h"
-#include "avctp.h"
-#include "avrcp.h"
-#include "headset.h"
-#include "gateway.h"
-#include "sink.h"
-#include "source.h"
-
-#define AUDIO_INTERFACE "org.bluez.Audio"
-
-#define CONTROL_CONNECT_TIMEOUT 2
-#define AVDTP_CONNECT_TIMEOUT 1
-#define AVDTP_CONNECT_TIMEOUT_BOOST 1
-#define HEADSET_CONNECT_TIMEOUT 1
-
-typedef enum {
-       AUDIO_STATE_DISCONNECTED,
-       AUDIO_STATE_CONNECTING,
-       AUDIO_STATE_CONNECTED,
-} audio_state_t;
-
-struct service_auth {
-       service_auth_cb cb;
-       void *user_data;
-};
-
-struct dev_priv {
-       audio_state_t state;
-
-       headset_state_t hs_state;
-       sink_state_t sink_state;
-       avctp_state_t avctp_state;
-       GSList *auths;
-
-       DBusMessage *conn_req;
-       DBusMessage *dc_req;
-
-       guint control_timer;
-       guint avdtp_timer;
-       guint headset_timer;
-       guint dc_id;
-
-       gboolean disconnecting;
-       gboolean authorized;
-       guint auth_idle_id;
-};
-
-static unsigned int sink_callback_id = 0;
-static unsigned int avctp_callback_id = 0;
-static unsigned int avdtp_callback_id = 0;
-static unsigned int headset_callback_id = 0;
-
-static void device_free(struct audio_device *dev)
-{
-       struct dev_priv *priv = dev->priv;
-
-       if (dev->conn)
-               dbus_connection_unref(dev->conn);
-
-       btd_device_unref(dev->btd_dev);
-
-       if (priv) {
-               if (priv->auths)
-                       audio_device_cancel_authorization(dev, NULL, NULL);
-               if (priv->control_timer)
-                       g_source_remove(priv->control_timer);
-               if (priv->avdtp_timer)
-                       g_source_remove(priv->avdtp_timer);
-               if (priv->headset_timer)
-                       g_source_remove(priv->headset_timer);
-               if (priv->dc_req)
-                       dbus_message_unref(priv->dc_req);
-               if (priv->conn_req)
-                       dbus_message_unref(priv->conn_req);
-               if (priv->dc_id)
-                       device_remove_disconnect_watch(dev->btd_dev,
-                                                       priv->dc_id);
-               g_free(priv);
-       }
-
-       g_free(dev->path);
-       g_free(dev);
-}
-
-static const char *state2str(audio_state_t state)
-{
-       switch (state) {
-       case AUDIO_STATE_DISCONNECTED:
-               return "disconnected";
-       case AUDIO_STATE_CONNECTING:
-               return "connecting";
-       case AUDIO_STATE_CONNECTED:
-               return "connected";
-       default:
-               error("Invalid audio state %d", state);
-               return NULL;
-       }
-}
-
-static gboolean control_connect_timeout(gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-
-       dev->priv->control_timer = 0;
-
-       if (dev->control)
-               avrcp_connect(dev);
-
-       return FALSE;
-}
-
-static gboolean device_set_control_timer(struct audio_device *dev)
-{
-       struct dev_priv *priv = dev->priv;
-
-       if (!dev->control)
-               return FALSE;
-
-       if (priv->control_timer)
-               return FALSE;
-
-       priv->control_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
-                                                       control_connect_timeout,
-                                                       dev);
-
-       return TRUE;
-}
-
-static void device_remove_control_timer(struct audio_device *dev)
-{
-       if (dev->priv->control_timer)
-               g_source_remove(dev->priv->control_timer);
-       dev->priv->control_timer = 0;
-}
-
-static void device_remove_avdtp_timer(struct audio_device *dev)
-{
-       if (dev->priv->avdtp_timer)
-               g_source_remove(dev->priv->avdtp_timer);
-       dev->priv->avdtp_timer = 0;
-}
-
-static void device_remove_headset_timer(struct audio_device *dev)
-{
-       if (dev->priv->headset_timer)
-               g_source_remove(dev->priv->headset_timer);
-       dev->priv->headset_timer = 0;
-}
-
-static void disconnect_cb(struct btd_device *btd_dev, gboolean removal,
-                               void *user_data)
-{
-       struct audio_device *dev = user_data;
-       struct dev_priv *priv = dev->priv;
-
-       if (priv->state == AUDIO_STATE_DISCONNECTED)
-               return;
-
-       if (priv->disconnecting)
-               return;
-
-       priv->disconnecting = TRUE;
-
-       device_remove_control_timer(dev);
-       device_remove_avdtp_timer(dev);
-       device_remove_headset_timer(dev);
-
-       if (dev->control)
-               avrcp_disconnect(dev);
-
-       if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
-               sink_shutdown(dev->sink);
-       else if (priv->hs_state != HEADSET_STATE_DISCONNECTED)
-               headset_shutdown(dev);
-       else
-               priv->disconnecting = FALSE;
-}
-
-static void device_set_state(struct audio_device *dev, audio_state_t new_state)
-{
-       struct dev_priv *priv = dev->priv;
-       const char *state_str;
-       DBusMessage *reply = NULL;
-
-       state_str = state2str(new_state);
-       if (!state_str)
-               return;
-
-       if (new_state == AUDIO_STATE_DISCONNECTED) {
-               priv->authorized = FALSE;
-
-               if (priv->dc_id) {
-                       device_remove_disconnect_watch(dev->btd_dev,
-                                                       priv->dc_id);
-                       priv->dc_id = 0;
-               }
-       } else if (new_state == AUDIO_STATE_CONNECTING)
-               priv->dc_id = device_add_disconnect_watch(dev->btd_dev,
-                                               disconnect_cb, dev, NULL);
-
-       if (dev->priv->state == new_state) {
-               DBG("state change attempted from %s to %s",
-                                                       state_str, state_str);
-               return;
-       }
-
-       dev->priv->state = new_state;
-
-       if (new_state == AUDIO_STATE_DISCONNECTED) {
-               if (priv->dc_req) {
-                       reply = dbus_message_new_method_return(priv->dc_req);
-                       dbus_message_unref(priv->dc_req);
-                       priv->dc_req = NULL;
-                       g_dbus_send_message(dev->conn, reply);
-               }
-               priv->disconnecting = FALSE;
-       }
-
-       if (priv->conn_req && new_state != AUDIO_STATE_CONNECTING) {
-               if (new_state == AUDIO_STATE_CONNECTED)
-                       reply = dbus_message_new_method_return(priv->conn_req);
-               else
-                       reply = btd_error_failed(priv->conn_req,
-                                                       "Connect Failed");
-
-               dbus_message_unref(priv->conn_req);
-               priv->conn_req = NULL;
-               g_dbus_send_message(dev->conn, reply);
-       }
-
-       emit_property_changed(dev->conn, dev->path,
-                               AUDIO_INTERFACE, "State",
-                               DBUS_TYPE_STRING, &state_str);
-}
-
-static gboolean avdtp_connect_timeout(gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-
-       dev->priv->avdtp_timer = 0;
-
-       if (dev->sink) {
-               struct avdtp *session = avdtp_get(&dev->src, &dev->dst);
-
-               if (!session)
-                       return FALSE;
-
-               sink_setup_stream(dev->sink, session);
-               avdtp_unref(session);
-       }
-
-       return FALSE;
-}
-
-static gboolean device_set_avdtp_timer(struct audio_device *dev)
-{
-       struct dev_priv *priv = dev->priv;
-       guint timeout = AVDTP_CONNECT_TIMEOUT;
-
-       if (!dev->sink)
-               return FALSE;
-
-       if (priv->avdtp_timer)
-               return FALSE;
-
-       /* If the headset is the HSP/HFP RFCOMM initiator, give the headset
-        * time to initiate AVDTP signalling (and avoid further racing) */
-       if (dev->headset && headset_get_rfcomm_initiator(dev))
-               timeout += AVDTP_CONNECT_TIMEOUT_BOOST;
-
-       priv->avdtp_timer = g_timeout_add_seconds(timeout,
-                                                       avdtp_connect_timeout,
-                                                       dev);
-
-       return TRUE;
-}
-
-static gboolean headset_connect_timeout(gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct dev_priv *priv = dev->priv;
-
-       dev->priv->headset_timer = 0;
-
-       if (dev->headset == NULL)
-               return FALSE;
-
-       if (headset_config_stream(dev, FALSE, NULL, NULL) == 0) {
-               if (priv->state != AUDIO_STATE_CONNECTED &&
-                               (priv->sink_state == SINK_STATE_CONNECTED ||
-                               priv->sink_state == SINK_STATE_PLAYING))
-                       device_set_state(dev, AUDIO_STATE_CONNECTED);
-       }
-
-       return FALSE;
-}
-
-static gboolean device_set_headset_timer(struct audio_device *dev)
-{
-       struct dev_priv *priv = dev->priv;
-
-       if (!dev->headset)
-               return FALSE;
-
-       if (priv->headset_timer)
-               return FALSE;
-
-       priv->headset_timer = g_timeout_add_seconds(HEADSET_CONNECT_TIMEOUT,
-                                               headset_connect_timeout, dev);
-
-       return TRUE;
-}
-
-static void device_avdtp_cb(struct audio_device *dev, struct avdtp *session,
-                               avdtp_session_state_t old_state,
-                               avdtp_session_state_t new_state,
-                               void *user_data)
-{
-       if (!dev->sink || !dev->control)
-               return;
-
-       if (new_state == AVDTP_SESSION_STATE_CONNECTED) {
-               if (avdtp_stream_setup_active(session))
-                       device_set_control_timer(dev);
-               else
-                       avrcp_connect(dev);
-       }
-}
-
-static void device_sink_cb(struct audio_device *dev,
-                               sink_state_t old_state,
-                               sink_state_t new_state,
-                               void *user_data)
-{
-       struct dev_priv *priv = dev->priv;
-
-       if (!dev->sink)
-               return;
-
-       priv->sink_state = new_state;
-
-       switch (new_state) {
-       case SINK_STATE_DISCONNECTED:
-               if (dev->control) {
-                       device_remove_control_timer(dev);
-                       avrcp_disconnect(dev);
-               }
-               if (priv->hs_state != HEADSET_STATE_DISCONNECTED &&
-                               (priv->dc_req || priv->disconnecting)) {
-                       headset_shutdown(dev);
-                       break;
-               }
-               if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
-                       device_set_state(dev, AUDIO_STATE_DISCONNECTED);
-               else if (old_state == SINK_STATE_CONNECTING) {
-                       switch (priv->hs_state) {
-                       case HEADSET_STATE_CONNECTED:
-                       case HEADSET_STATE_PLAY_IN_PROGRESS:
-                       case HEADSET_STATE_PLAYING:
-                               device_set_state(dev, AUDIO_STATE_CONNECTED);
-                       default:
-                               break;
-                       }
-               }
-               break;
-       case SINK_STATE_CONNECTING:
-               device_remove_avdtp_timer(dev);
-               if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
-                       device_set_state(dev, AUDIO_STATE_CONNECTING);
-               break;
-       case SINK_STATE_CONNECTED:
-               if (old_state == SINK_STATE_PLAYING)
-                       break;
-               if (dev->auto_connect) {
-                       if (!dev->headset)
-                               device_set_state(dev, AUDIO_STATE_CONNECTED);
-                       else if (priv->hs_state == HEADSET_STATE_DISCONNECTED)
-                               device_set_headset_timer(dev);
-                       else if (priv->hs_state == HEADSET_STATE_CONNECTED ||
-                                       priv->hs_state == HEADSET_STATE_PLAY_IN_PROGRESS ||
-                                       priv->hs_state == HEADSET_STATE_PLAYING)
-                               device_set_state(dev, AUDIO_STATE_CONNECTED);
-               } else if (priv->hs_state == HEADSET_STATE_DISCONNECTED ||
-                               priv->hs_state == HEADSET_STATE_CONNECTING)
-                       device_set_state(dev, AUDIO_STATE_CONNECTED);
-               break;
-       case SINK_STATE_PLAYING:
-               break;
-       }
-}
-
-static void device_avctp_cb(struct audio_device *dev,
-                               avctp_state_t old_state,
-                               avctp_state_t new_state,
-                               void *user_data)
-{
-       if (!dev->control)
-               return;
-
-       dev->priv->avctp_state = new_state;
-
-       switch (new_state) {
-       case AVCTP_STATE_DISCONNECTED:
-               break;
-       case AVCTP_STATE_CONNECTING:
-               device_remove_control_timer(dev);
-               break;
-       case AVCTP_STATE_CONNECTED:
-               break;
-       }
-}
-
-static void device_headset_cb(struct audio_device *dev,
-                               headset_state_t old_state,
-                               headset_state_t new_state,
-                               void *user_data)
-{
-       struct dev_priv *priv = dev->priv;
-
-       if (!dev->headset)
-               return;
-
-       priv->hs_state = new_state;
-
-       switch (new_state) {
-       case HEADSET_STATE_DISCONNECTED:
-               device_remove_avdtp_timer(dev);
-               if (priv->sink_state != SINK_STATE_DISCONNECTED && dev->sink &&
-                               (priv->dc_req || priv->disconnecting)) {
-                       sink_shutdown(dev->sink);
-                       break;
-               }
-               if (priv->sink_state == SINK_STATE_DISCONNECTED)
-                       device_set_state(dev, AUDIO_STATE_DISCONNECTED);
-               else if (old_state == HEADSET_STATE_CONNECTING &&
-                               (priv->sink_state == SINK_STATE_CONNECTED ||
-                               priv->sink_state == SINK_STATE_PLAYING))
-                       device_set_state(dev, AUDIO_STATE_CONNECTED);
-               break;
-       case HEADSET_STATE_CONNECTING:
-               device_remove_headset_timer(dev);
-               if (priv->sink_state == SINK_STATE_DISCONNECTED)
-                       device_set_state(dev, AUDIO_STATE_CONNECTING);
-               break;
-       case HEADSET_STATE_CONNECTED:
-               if (old_state == HEADSET_STATE_CONNECTED ||
-                               old_state == HEADSET_STATE_PLAY_IN_PROGRESS ||
-                               old_state == HEADSET_STATE_PLAYING)
-                       break;
-               if (dev->auto_connect) {
-                       if (!dev->sink)
-                               device_set_state(dev, AUDIO_STATE_CONNECTED);
-                       else if (priv->sink_state == SINK_STATE_DISCONNECTED)
-                               device_set_avdtp_timer(dev);
-                       else if (priv->sink_state == SINK_STATE_CONNECTED ||
-                                       priv->sink_state == SINK_STATE_PLAYING)
-                               device_set_state(dev, AUDIO_STATE_CONNECTED);
-               } else if (priv->sink_state == SINK_STATE_DISCONNECTED ||
-                               priv->sink_state == SINK_STATE_CONNECTING)
-                       device_set_state(dev, AUDIO_STATE_CONNECTED);
-               break;
-       case HEADSET_STATE_PLAY_IN_PROGRESS:
-               break;
-       case HEADSET_STATE_PLAYING:
-               break;
-       }
-}
-
-static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct audio_device *dev = data;
-       struct dev_priv *priv = dev->priv;
-
-       if (priv->state == AUDIO_STATE_CONNECTING)
-               return btd_error_in_progress(msg);
-       else if (priv->state == AUDIO_STATE_CONNECTED)
-               return btd_error_already_connected(msg);
-
-       dev->auto_connect = TRUE;
-
-       if (dev->headset)
-               headset_config_stream(dev, FALSE, NULL, NULL);
-
-       if (priv->state != AUDIO_STATE_CONNECTING && dev->sink) {
-               struct avdtp *session = avdtp_get(&dev->src, &dev->dst);
-
-               if (!session)
-                       return btd_error_failed(msg,
-                                       "Failed to get AVDTP session");
-
-               sink_setup_stream(dev->sink, session);
-               avdtp_unref(session);
-       }
-
-       /* The previous calls should cause a call to the state callback to
-        * indicate AUDIO_STATE_CONNECTING */
-       if (priv->state != AUDIO_STATE_CONNECTING)
-               return btd_error_failed(msg, "Connect Failed");
-
-       priv->conn_req = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct audio_device *dev = data;
-       struct dev_priv *priv = dev->priv;
-
-       if (priv->state == AUDIO_STATE_DISCONNECTED)
-               return btd_error_not_connected(msg);
-
-       if (priv->dc_req)
-               return dbus_message_new_method_return(msg);
-
-       priv->dc_req = dbus_message_ref(msg);
-
-       if (dev->control) {
-               device_remove_control_timer(dev);
-               avrcp_disconnect(dev);
-       }
-
-       if (dev->sink && priv->sink_state != SINK_STATE_DISCONNECTED)
-               sink_shutdown(dev->sink);
-       else if (priv->hs_state != HEADSET_STATE_DISCONNECTED)
-               headset_shutdown(dev);
-       else {
-               dbus_message_unref(priv->dc_req);
-               priv->dc_req = NULL;
-               return dbus_message_new_method_return(msg);
-       }
-
-       return NULL;
-}
-
-static DBusMessage *dev_get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct audio_device *device = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       const char *state;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       /* State */
-       state = state2str(device->priv->state);
-       if (state)
-               dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 const GDBusSignalTable dev_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-       { }
-};
-
-struct audio_device *audio_device_register(DBusConnection *conn,
-                                       struct btd_device *device,
-                                       const char *path, const bdaddr_t *src,
-                                       const bdaddr_t *dst)
-{
-       struct audio_device *dev;
-
-       if (!conn || !path)
-               return NULL;
-
-       dev = g_new0(struct audio_device, 1);
-
-       dev->btd_dev = btd_device_ref(device);
-       dev->path = g_strdup(path);
-       bacpy(&dev->dst, dst);
-       bacpy(&dev->src, src);
-       dev->conn = dbus_connection_ref(conn);
-       dev->priv = g_new0(struct dev_priv, 1);
-       dev->priv->state = AUDIO_STATE_DISCONNECTED;
-
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_INTERFACE,
-                                       dev_methods, dev_signals, NULL,
-                                       dev, NULL)) {
-               error("Unable to register %s on %s", AUDIO_INTERFACE,
-                                                               dev->path);
-               device_free(dev);
-               return NULL;
-       }
-
-       DBG("Registered interface %s on path %s", AUDIO_INTERFACE,
-                                                               dev->path);
-
-       if (sink_callback_id == 0)
-               sink_callback_id = sink_add_state_cb(device_sink_cb, NULL);
-
-       if (avdtp_callback_id == 0)
-               avdtp_callback_id = avdtp_add_state_cb(device_avdtp_cb, NULL);
-       if (avctp_callback_id == 0)
-               avctp_callback_id = avctp_add_state_cb(device_avctp_cb, NULL);
-
-       if (headset_callback_id == 0)
-               headset_callback_id = headset_add_state_cb(device_headset_cb,
-                                                                       NULL);
-
-       return dev;
-}
-
-gboolean audio_device_is_active(struct audio_device *dev,
-                                               const char *interface)
-{
-       if (!interface) {
-               if ((dev->sink || dev->source) &&
-                               avdtp_is_connected(&dev->src, &dev->dst))
-                       return TRUE;
-               if (dev->headset && headset_is_active(dev))
-                       return TRUE;
-       } else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink &&
-                               avdtp_is_connected(&dev->src, &dev->dst))
-               return TRUE;
-       else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source &&
-                               avdtp_is_connected(&dev->src, &dev->dst))
-               return TRUE;
-       else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset &&
-                               headset_is_active(dev))
-               return TRUE;
-       else if (!strcmp(interface, AUDIO_CONTROL_INTERFACE) && dev->control &&
-                               control_is_active(dev))
-               return TRUE;
-       else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway &&
-                               gateway_is_active(dev))
-               return TRUE;
-
-       return FALSE;
-}
-
-void audio_device_unregister(struct audio_device *device)
-{
-       unix_device_removed(device);
-
-       if (device->hs_preauth_id) {
-               g_source_remove(device->hs_preauth_id);
-               device->hs_preauth_id = 0;
-       }
-
-       if (device->headset)
-               headset_unregister(device);
-
-       if (device->gateway)
-               gateway_unregister(device);
-
-       if (device->sink)
-               sink_unregister(device);
-
-       if (device->source)
-               source_unregister(device);
-
-       if (device->control)
-               control_unregister(device);
-
-       g_dbus_unregister_interface(device->conn, device->path,
-                                               AUDIO_INTERFACE);
-
-       device_free(device);
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct audio_device *dev = user_data;
-       struct dev_priv *priv = dev->priv;
-
-       if (derr == NULL)
-               priv->authorized = TRUE;
-
-       while (priv->auths) {
-               struct service_auth *auth = priv->auths->data;
-
-               auth->cb(derr, auth->user_data);
-               priv->auths = g_slist_remove(priv->auths, auth);
-               g_free(auth);
-       }
-}
-
-static gboolean auth_idle_cb(gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct dev_priv *priv = dev->priv;
-
-       priv->auth_idle_id = 0;
-
-       auth_cb(NULL, dev);
-
-       return FALSE;
-}
-
-static gboolean audio_device_is_connected(struct audio_device *dev)
-{
-       if (dev->headset) {
-               headset_state_t state = headset_get_state(dev);
-
-               if (state == HEADSET_STATE_CONNECTED ||
-                               state == HEADSET_STATE_PLAY_IN_PROGRESS ||
-                               state == HEADSET_STATE_PLAYING)
-                       return TRUE;
-       }
-
-       if (dev->sink) {
-               sink_state_t state = sink_get_state(dev);
-
-               if (state == SINK_STATE_CONNECTED ||
-                               state == SINK_STATE_PLAYING)
-                       return TRUE;
-       }
-
-       if (dev->source) {
-               source_state_t state = source_get_state(dev);
-
-               if (state == SOURCE_STATE_CONNECTED ||
-                               state == SOURCE_STATE_PLAYING)
-                       return TRUE;
-       }
-
-       return FALSE;
-}
-
-int audio_device_request_authorization(struct audio_device *dev,
-                                       const char *uuid, service_auth_cb cb,
-                                       void *user_data)
-{
-       struct dev_priv *priv = dev->priv;
-       struct service_auth *auth;
-       int err;
-
-       auth = g_try_new0(struct service_auth, 1);
-       if (!auth)
-               return -ENOMEM;
-
-       auth->cb = cb;
-       auth->user_data = user_data;
-
-       priv->auths = g_slist_append(priv->auths, auth);
-       if (g_slist_length(priv->auths) > 1)
-               return 0;
-
-       if (priv->authorized || audio_device_is_connected(dev)) {
-               priv->auth_idle_id = g_idle_add(auth_idle_cb, dev);
-               return 0;
-       }
-
-       err = btd_request_authorization(&dev->src, &dev->dst, uuid, auth_cb,
-                                       dev);
-       if (err < 0) {
-               priv->auths = g_slist_remove(priv->auths, auth);
-               g_free(auth);
-       }
-
-       return err;
-}
-
-int audio_device_cancel_authorization(struct audio_device *dev,
-                                       authorization_cb cb, void *user_data)
-{
-       struct dev_priv *priv = dev->priv;
-       GSList *l, *next;
-
-       for (l = priv->auths; l != NULL; l = next) {
-               struct service_auth *auth = l->data;
-
-               next = g_slist_next(l);
-
-               if (cb && auth->cb != cb)
-                       continue;
-
-               if (user_data && auth->user_data != user_data)
-                       continue;
-
-               priv->auths = g_slist_remove(priv->auths, auth);
-               g_free(auth);
-       }
-
-       if (g_slist_length(priv->auths) == 0) {
-               if (priv->auth_idle_id > 0) {
-                       g_source_remove(priv->auth_idle_id);
-                       priv->auth_idle_id = 0;
-               } else
-                       btd_cancel_authorization(&dev->src, &dev->dst);
-       }
-
-       return 0;
-}
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth)
-{
-       struct dev_priv *priv = dev->priv;
-
-       priv->authorized = auth;
-}
diff --git a/audio/device.h b/audio/device.h
deleted file mode 100644 (file)
index 75f1da9..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-struct source;
-struct control;
-struct target;
-struct sink;
-struct headset;
-struct gateway;
-struct dev_priv;
-
-struct audio_device {
-       struct btd_device *btd_dev;
-
-       DBusConnection *conn;
-       char *path;
-       bdaddr_t src;
-       bdaddr_t dst;
-
-       gboolean auto_connect;
-
-       struct headset *headset;
-       struct gateway *gateway;
-       struct sink *sink;
-       struct source *source;
-       struct control *control;
-       struct target *target;
-
-       guint hs_preauth_id;
-
-       struct dev_priv *priv;
-};
-
-struct audio_device *audio_device_register(DBusConnection *conn,
-                                       struct btd_device *device,
-                                       const char *path, const bdaddr_t *src,
-                                       const bdaddr_t *dst);
-
-void audio_device_unregister(struct audio_device *device);
-
-gboolean audio_device_is_active(struct audio_device *dev,
-                                               const char *interface);
-
-typedef void (*authorization_cb) (DBusError *derr, void *user_data);
-
-int audio_device_cancel_authorization(struct audio_device *dev,
-                                       authorization_cb cb, void *user_data);
-
-int audio_device_request_authorization(struct audio_device *dev,
-                                       const char *uuid, authorization_cb cb,
-                                       void *user_data);
-
-void audio_device_set_authorized(struct audio_device *dev, gboolean auth);
diff --git a/audio/gateway.c b/audio/gateway.c
deleted file mode 100644 (file)
index 6162948..0000000
+++ /dev/null
@@ -1,997 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2008-2009  Leonid Movshovich <event.riga@gmail.org>
- *  Copyright (C) 2010  ProFUSION embedded systems
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <fcntl.h>
-#include <errno.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include "sdp-client.h"
-#include "device.h"
-#include "gateway.h"
-#include "log.h"
-#include "error.h"
-#include "btio.h"
-#include "dbus-common.h"
-
-struct hf_agent {
-       char *name;     /* Bus id */
-       char *path;     /* D-Bus path */
-       guint watch;    /* Disconnect watch */
-};
-
-struct connect_cb {
-       unsigned int id;
-       gateway_stream_cb_t cb;
-       void *cb_data;
-};
-
-struct gateway {
-       gateway_state_t state;
-       GIOChannel *rfcomm;
-       GIOChannel *sco;
-       GIOChannel *incoming;
-       GSList *callbacks;
-       struct hf_agent *agent;
-       DBusMessage *msg;
-       int version;
-       gateway_lock_t lock;
-};
-
-struct gateway_state_callback {
-       gateway_state_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-static GSList *gateway_callbacks = NULL;
-
-int gateway_close(struct audio_device *device);
-
-GQuark gateway_error_quark(void)
-{
-       return g_quark_from_static_string("gateway-error-quark");
-}
-
-static const char *state2str(gateway_state_t state)
-{
-       switch (state) {
-       case GATEWAY_STATE_DISCONNECTED:
-               return "disconnected";
-       case GATEWAY_STATE_CONNECTING:
-               return "connecting";
-       case GATEWAY_STATE_CONNECTED:
-               return "connected";
-       case GATEWAY_STATE_PLAYING:
-               return "playing";
-       default:
-               return "";
-       }
-}
-
-static void agent_free(struct hf_agent *agent)
-{
-       if (!agent)
-               return;
-
-       g_free(agent->name);
-       g_free(agent->path);
-       g_free(agent);
-}
-
-static void change_state(struct audio_device *dev, gateway_state_t new_state)
-{
-       struct gateway *gw = dev->gateway;
-       const char *val;
-       GSList *l;
-       gateway_state_t old_state;
-
-       if (gw->state == new_state)
-               return;
-
-       val = state2str(new_state);
-       old_state = gw->state;
-       gw->state = new_state;
-
-       emit_property_changed(dev->conn, dev->path,
-                       AUDIO_GATEWAY_INTERFACE, "State",
-                       DBUS_TYPE_STRING, &val);
-
-       for (l = gateway_callbacks; l != NULL; l = l->next) {
-               struct gateway_state_callback *cb = l->data;
-               cb->cb(dev, old_state, new_state, cb->user_data);
-       }
-}
-
-void gateway_set_state(struct audio_device *dev, gateway_state_t new_state)
-{
-       switch (new_state) {
-       case GATEWAY_STATE_DISCONNECTED:
-               gateway_close(dev);
-               break;
-       case GATEWAY_STATE_CONNECTING:
-       case GATEWAY_STATE_CONNECTED:
-       case GATEWAY_STATE_PLAYING:
-               break;
-       }
-}
-
-static void agent_disconnect(struct audio_device *dev, struct hf_agent *agent)
-{
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(agent->name, agent->path,
-                       "org.bluez.HandsfreeAgent", "Release");
-
-       g_dbus_send_message(dev->conn, msg);
-}
-
-static gboolean agent_sendfd(struct hf_agent *agent, int fd,
-               DBusPendingCallNotifyFunction notify, void *data)
-{
-       struct audio_device *dev = data;
-       struct gateway *gw = dev->gateway;
-       DBusMessage *msg;
-       DBusPendingCall *call;
-
-       msg = dbus_message_new_method_call(agent->name, agent->path,
-                       "org.bluez.HandsfreeAgent", "NewConnection");
-
-       dbus_message_append_args(msg, DBUS_TYPE_UNIX_FD, &fd,
-                                       DBUS_TYPE_UINT16, &gw->version,
-                                       DBUS_TYPE_INVALID);
-
-       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);
-       dbus_message_unref(msg);
-
-       return TRUE;
-}
-
-static unsigned int connect_cb_new(struct gateway *gw,
-                                       gateway_stream_cb_t func,
-                                       void *user_data)
-{
-       struct connect_cb *cb;
-       static unsigned int free_cb_id = 1;
-
-       if (!func)
-               return 0;
-
-       cb = g_new(struct connect_cb, 1);
-
-       cb->cb = func;
-       cb->cb_data = user_data;
-       cb->id = free_cb_id++;
-
-       gw->callbacks = g_slist_append(gw->callbacks, cb);
-
-       return cb->id;
-}
-
-static void run_connect_cb(struct audio_device *dev, GError *err)
-{
-       struct gateway *gw = dev->gateway;
-       GSList *l;
-
-       for (l = gw->callbacks; l != NULL; l = l->next) {
-               struct connect_cb *cb = l->data;
-               cb->cb(dev, err, cb->cb_data);
-       }
-
-       g_slist_free_full(gw->callbacks, g_free);
-       gw->callbacks = NULL;
-}
-
-static gboolean sco_io_cb(GIOChannel *chan, GIOCondition cond,
-                       struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       DBG("sco connection is released");
-       g_io_channel_shutdown(gw->sco, TRUE, NULL);
-       g_io_channel_unref(gw->sco);
-       gw->sco = NULL;
-       change_state(dev, GATEWAY_STATE_CONNECTED);
-
-       return FALSE;
-}
-
-static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
-{
-       struct audio_device *dev = (struct audio_device *) user_data;
-       struct gateway *gw = dev->gateway;
-
-       DBG("at the begin of sco_connect_cb() in gateway.c");
-
-       gw->sco = g_io_channel_ref(chan);
-
-       if (err) {
-               error("sco_connect_cb(): %s", err->message);
-               gateway_suspend_stream(dev);
-               return;
-       }
-
-       g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                               (GIOFunc) sco_io_cb, dev);
-
-       change_state(dev, GATEWAY_STATE_PLAYING);
-       run_connect_cb(dev, NULL);
-}
-
-static gboolean rfcomm_disconnect_cb(GIOChannel *chan, GIOCondition cond,
-                       struct audio_device *dev)
-{
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       gateway_close(dev);
-
-       return FALSE;
-}
-
-static void newconnection_reply(DBusPendingCall *call, void *data)
-{
-       struct audio_device *dev = data;
-       struct gateway *gw = dev->gateway;
-       DBusMessage *reply = dbus_pending_call_steal_reply(call);
-       DBusError derr;
-
-       if (!dev->gateway->rfcomm) {
-               DBG("RFCOMM disconnected from server before agent reply");
-               goto done;
-       }
-
-       dbus_error_init(&derr);
-       if (!dbus_set_error_from_message(&derr, reply)) {
-               DBG("Agent reply: file descriptor passed successfully");
-               g_io_add_watch(gw->rfcomm, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                       (GIOFunc) rfcomm_disconnect_cb, dev);
-               change_state(dev, GATEWAY_STATE_CONNECTED);
-               goto done;
-       }
-
-       DBG("Agent reply: %s", derr.message);
-
-       dbus_error_free(&derr);
-       gateway_close(dev);
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void rfcomm_connect_cb(GIOChannel *chan, GError *err,
-                               gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct gateway *gw = dev->gateway;
-       DBusMessage *reply;
-       int sk, ret;
-
-       if (err) {
-               error("connect(): %s", err->message);
-               goto fail;
-       }
-
-       if (!gw->agent) {
-               error("Handsfree Agent not registered");
-               goto fail;
-       }
-
-       sk = g_io_channel_unix_get_fd(chan);
-
-       if (gw->rfcomm == NULL)
-               gw->rfcomm = g_io_channel_ref(chan);
-
-       ret = agent_sendfd(gw->agent, sk, newconnection_reply, dev);
-
-       if (!gw->msg)
-               return;
-
-       if (ret)
-               reply = dbus_message_new_method_return(gw->msg);
-       else
-               reply = btd_error_failed(gw->msg, "Can't pass file descriptor");
-
-       g_dbus_send_message(dev->conn, reply);
-
-       return;
-
-fail:
-       if (gw->msg) {
-               DBusMessage *reply;
-               reply = btd_error_failed(gw->msg, "Connect failed");
-               g_dbus_send_message(dev->conn, reply);
-       }
-
-       gateway_close(dev);
-}
-
-static int get_remote_profile_version(sdp_record_t *rec)
-{
-       uuid_t uuid;
-       sdp_list_t *profiles;
-       sdp_profile_desc_t *desc;
-       int ver = 0;
-
-       sdp_uuid16_create(&uuid, HANDSFREE_PROFILE_ID);
-
-       sdp_get_profile_descs(rec, &profiles);
-       if (profiles == NULL)
-               goto done;
-
-       desc = profiles->data;
-
-       if (sdp_uuid16_cmp(&desc->uuid, &uuid) == 0)
-               ver = desc->version;
-
-       sdp_list_free(profiles, free);
-
-done:
-       return ver;
-}
-
-static void get_incoming_record_cb(sdp_list_t *recs, int err,
-                                       gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct gateway *gw = dev->gateway;
-       GError *gerr = NULL;
-
-       if (err < 0) {
-               error("Unable to get service record: %s (%d)", strerror(-err),
-                                       -err);
-               goto fail;
-       }
-
-       if (!recs || !recs->data) {
-               error("No records found");
-               goto fail;
-       }
-
-       gw->version = get_remote_profile_version(recs->data);
-       if (gw->version == 0)
-               goto fail;
-
-       rfcomm_connect_cb(gw->incoming, gerr, dev);
-       return;
-
-fail:
-       gateway_close(dev);
-}
-
-static void unregister_incoming(gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct gateway *gw = dev->gateway;
-
-       if (gw->incoming) {
-               g_io_channel_unref(gw->incoming);
-               gw->incoming = NULL;
-       }
-}
-
-static void rfcomm_incoming_cb(GIOChannel *chan, GError *err,
-                               gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct gateway *gw = dev->gateway;
-       uuid_t uuid;
-
-       gw->incoming = g_io_channel_ref(chan);
-
-       sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
-       if (bt_search_service(&dev->src, &dev->dst, &uuid,
-                                               get_incoming_record_cb, dev,
-                                               unregister_incoming) == 0)
-               return;
-
-       unregister_incoming(dev);
-       gateway_close(dev);
-}
-
-static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct gateway *gw = dev->gateway;
-       int ch;
-       sdp_list_t *protos, *classes;
-       uuid_t uuid;
-       GIOChannel *io;
-       GError *gerr = NULL;
-
-       if (err < 0) {
-               error("Unable to get service record: %s (%d)", strerror(-err),
-                                       -err);
-               goto fail;
-       }
-
-       if (!recs || !recs->data) {
-               error("No records found");
-               err = -EIO;
-               goto fail;
-       }
-
-       if (sdp_get_service_classes(recs->data, &classes) < 0) {
-               error("Unable to get service classes from record");
-               err = -EINVAL;
-               goto fail;
-       }
-
-       if (sdp_get_access_protos(recs->data, &protos) < 0) {
-               error("Unable to get access protocols from record");
-               err = -ENODATA;
-               goto fail;
-       }
-
-       gw->version = get_remote_profile_version(recs->data);
-       if (gw->version == 0) {
-               error("Unable to get profile version from record");
-               err = -EINVAL;
-               goto fail;
-       }
-
-       memcpy(&uuid, classes->data, sizeof(uuid));
-       sdp_list_free(classes, free);
-
-       if (!sdp_uuid128_to_uuid(&uuid) || uuid.type != SDP_UUID16 ||
-                       uuid.value.uuid16 != HANDSFREE_AGW_SVCLASS_ID) {
-               sdp_list_free(protos, NULL);
-               error("Invalid service record or not HFP");
-               err = -EIO;
-               goto fail;
-       }
-
-       ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-       sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-       sdp_list_free(protos, NULL);
-       if (ch <= 0) {
-               error("Unable to extract RFCOMM channel from service record");
-               err = -EIO;
-               goto fail;
-       }
-
-       io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, dev, NULL, &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) {
-               error("Unable to connect: %s", gerr->message);
-               goto fail;
-       }
-
-       g_io_channel_unref(io);
-       return;
-
-fail:
-       if (gw->msg) {
-               DBusMessage *reply = btd_error_failed(gw->msg,
-                                       gerr ? gerr->message : strerror(-err));
-               g_dbus_send_message(dev->conn, reply);
-       }
-
-       gateway_close(dev);
-
-       if (gerr)
-               g_error_free(gerr);
-}
-
-static int get_records(struct audio_device *device)
-{
-       uuid_t uuid;
-
-       change_state(device, GATEWAY_STATE_CONNECTING);
-       sdp_uuid16_create(&uuid, HANDSFREE_AGW_SVCLASS_ID);
-       return bt_search_service(&device->src, &device->dst, &uuid,
-                               get_record_cb, device, NULL);
-}
-
-static DBusMessage *ag_connect(DBusConnection *conn, DBusMessage *msg,
-                               void *data)
-{
-       struct audio_device *au_dev = (struct audio_device *) data;
-       struct gateway *gw = au_dev->gateway;
-       int err;
-
-       if (!gw->agent)
-               return btd_error_agent_not_available(msg);
-
-       err = get_records(au_dev);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       gw->msg = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-int gateway_close(struct audio_device *device)
-{
-       GError *gerr = NULL;
-       struct gateway *gw = device->gateway;
-       int sock;
-
-       if (gw->rfcomm) {
-               sock = g_io_channel_unix_get_fd(gw->rfcomm);
-               shutdown(sock, SHUT_RDWR);
-
-               g_io_channel_shutdown(gw->rfcomm, TRUE, NULL);
-               g_io_channel_unref(gw->rfcomm);
-               gw->rfcomm = NULL;
-       }
-
-       if (gw->sco) {
-               g_io_channel_shutdown(gw->sco, TRUE, NULL);
-               g_io_channel_unref(gw->sco);
-               gw->sco = NULL;
-       }
-
-       change_state(device, GATEWAY_STATE_DISCONNECTED);
-       g_set_error(&gerr, GATEWAY_ERROR,
-                       GATEWAY_ERROR_DISCONNECTED, "Disconnected");
-       run_connect_cb(device, gerr);
-       g_error_free(gerr);
-
-       return 0;
-}
-
-static DBusMessage *ag_disconnect(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct gateway *gw = device->gateway;
-       DBusMessage *reply = NULL;
-       char gw_addr[18];
-
-       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;
-
-       gateway_close(device);
-       ba2str(&device->dst, gw_addr);
-       DBG("Disconnected from %s, %s", gw_addr, device->path);
-
-       return reply;
-}
-
-static void agent_exited(DBusConnection *conn, void *data)
-{
-       struct gateway *gateway = data;
-       struct hf_agent *agent = gateway->agent;
-
-       DBG("Agent %s exited", agent->name);
-
-       agent_free(agent);
-       gateway->agent = NULL;
-}
-
-static DBusMessage *ag_get_properties(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct gateway *gw = device->gateway;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       const char *value;
-
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       value = state2str(gw->state);
-       dict_append_entry(&dict, "State",
-                       DBUS_TYPE_STRING, &value);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static DBusMessage *register_agent(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct gateway *gw = device->gateway;
-       struct hf_agent *agent;
-       const char *path, *name;
-
-       if (gw->agent)
-               return btd_error_already_exists(msg);
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       name = dbus_message_get_sender(msg);
-       agent = g_new0(struct hf_agent, 1);
-
-       agent->name = g_strdup(name);
-       agent->path = g_strdup(path);
-
-       agent->watch = g_dbus_add_disconnect_watch(conn, name,
-                                               agent_exited, gw, NULL);
-
-       gw->agent = agent;
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_agent(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct gateway *gw = device->gateway;
-       const char *path;
-
-       if (!gw->agent)
-               goto done;
-
-       if (strcmp(gw->agent->name, dbus_message_get_sender(msg)) != 0)
-               return btd_error_not_authorized(msg);
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       if (strcmp(gw->agent->path, path) != 0)
-               return btd_error_does_not_exist(msg);
-
-       g_dbus_remove_watch(device->conn, gw->agent->watch);
-
-       agent_free(gw->agent);
-       gw->agent = NULL;
-
-done:
-       return dbus_message_new_method_return(msg);
-}
-
-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 const GDBusSignalTable gateway_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-       { }
-};
-
-static void path_unregister(void *data)
-{
-       struct audio_device *dev = data;
-
-       DBG("Unregistered interface %s on path %s",
-               AUDIO_GATEWAY_INTERFACE, dev->path);
-
-       gateway_close(dev);
-
-       g_free(dev->gateway);
-       dev->gateway = NULL;
-}
-
-void gateway_unregister(struct audio_device *dev)
-{
-       if (dev->gateway->agent)
-               agent_disconnect(dev, dev->gateway->agent);
-
-       g_dbus_unregister_interface(dev->conn, dev->path,
-                                               AUDIO_GATEWAY_INTERFACE);
-}
-
-struct gateway *gateway_init(struct audio_device *dev)
-{
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_GATEWAY_INTERFACE,
-                                       gateway_methods, gateway_signals,
-                                       NULL, dev, path_unregister))
-               return NULL;
-
-       return g_new0(struct gateway, 1);
-}
-
-gboolean gateway_is_connected(struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (gw->state == GATEWAY_STATE_CONNECTED)
-               return TRUE;
-
-       return FALSE;
-}
-
-gboolean gateway_is_active(struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (gw->state != GATEWAY_STATE_DISCONNECTED)
-               return TRUE;
-
-       return FALSE;
-}
-
-int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
-{
-       if (!io)
-               return -EINVAL;
-
-       dev->gateway->rfcomm = g_io_channel_ref(io);
-
-       change_state(dev, GATEWAY_STATE_CONNECTING);
-
-       return 0;
-}
-
-int gateway_connect_sco(struct audio_device *dev, GIOChannel *io)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (gw->sco)
-               return -EISCONN;
-
-       gw->sco = g_io_channel_ref(io);
-
-       g_io_add_watch(gw->sco, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                               (GIOFunc) sco_io_cb, dev);
-
-       change_state(dev, GATEWAY_STATE_PLAYING);
-
-       return 0;
-}
-
-void gateway_start_service(struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-       GError *err = NULL;
-
-       if (gw->rfcomm == NULL)
-               return;
-
-       if (!bt_io_accept(gw->rfcomm, rfcomm_incoming_cb, dev, NULL, &err)) {
-               error("bt_io_accept: %s", err->message);
-               g_error_free(err);
-               gateway_close(dev);
-       }
-}
-
-static gboolean request_stream_cb(gpointer data)
-{
-       run_connect_cb(data, NULL);
-       return FALSE;
-}
-
-/* These are functions to be called from unix.c for audio system
- * ifaces (alsa, gstreamer, etc.) */
-unsigned int gateway_request_stream(struct audio_device *dev,
-                               gateway_stream_cb_t cb, void *user_data)
-{
-       struct gateway *gw = dev->gateway;
-       GError *err = NULL;
-       GIOChannel *io;
-
-       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);
-                       g_error_free(err);
-                       return 0;
-               }
-       } else
-               g_idle_add(request_stream_cb, dev);
-
-       return connect_cb_new(gw, cb, user_data);
-}
-
-int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
-                               void *user_data)
-{
-       struct gateway *gw = dev->gateway;
-       unsigned int id;
-
-       id = connect_cb_new(gw, cb, user_data);
-
-       if (!gw->rfcomm)
-               get_records(dev);
-       else if (cb)
-               g_idle_add(request_stream_cb, dev);
-
-       return id;
-}
-
-gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id)
-{
-       struct gateway *gw = dev->gateway;
-       GSList *l;
-       struct connect_cb *cb = NULL;
-
-       for (l = gw->callbacks; l != NULL; l = l->next) {
-               struct connect_cb *tmp = l->data;
-
-               if (tmp->id == id) {
-                       cb = tmp;
-                       break;
-               }
-       }
-
-       if (!cb)
-               return FALSE;
-
-       gw->callbacks = g_slist_remove(gw->callbacks, cb);
-       g_free(cb);
-
-       gateway_suspend_stream(dev);
-
-       return TRUE;
-}
-
-int gateway_get_sco_fd(struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (!gw || !gw->sco)
-               return -1;
-
-       return g_io_channel_unix_get_fd(gw->sco);
-}
-
-void gateway_suspend_stream(struct audio_device *dev)
-{
-       GError *gerr = NULL;
-       struct gateway *gw = dev->gateway;
-
-       if (!gw || !gw->sco)
-               return;
-
-       g_io_channel_shutdown(gw->sco, TRUE, NULL);
-       g_io_channel_unref(gw->sco);
-       gw->sco = NULL;
-       g_set_error(&gerr, GATEWAY_ERROR, GATEWAY_ERROR_SUSPENDED, "Suspended");
-       run_connect_cb(dev, gerr);
-       g_error_free(gerr);
-       change_state(dev, GATEWAY_STATE_CONNECTED);
-}
-
-unsigned int gateway_add_state_cb(gateway_state_cb cb, void *user_data)
-{
-       struct gateway_state_callback *state_cb;
-       static unsigned int id = 0;
-
-       state_cb = g_new(struct gateway_state_callback, 1);
-       state_cb->cb = cb;
-       state_cb->user_data = user_data;
-       state_cb->id = ++id;
-
-       gateway_callbacks = g_slist_append(gateway_callbacks, state_cb);
-
-       return state_cb->id;
-}
-
-gboolean gateway_remove_state_cb(unsigned int id)
-{
-       GSList *l;
-
-       for (l = gateway_callbacks; l != NULL; l = l->next) {
-               struct gateway_state_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       gateway_callbacks = g_slist_remove(gateway_callbacks,
-                                                                       cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-gateway_lock_t gateway_get_lock(struct audio_device *dev)
-{
-       struct gateway *gw = dev->gateway;
-
-       return gw->lock;
-}
-
-gboolean gateway_lock(struct audio_device *dev, gateway_lock_t lock)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (gw->lock & lock)
-               return FALSE;
-
-       gw->lock |= lock;
-
-       return TRUE;
-}
-
-gboolean gateway_unlock(struct audio_device *dev, gateway_lock_t lock)
-{
-       struct gateway *gw = dev->gateway;
-
-       if (!(gw->lock & lock))
-               return FALSE;
-
-       gw->lock &= ~lock;
-
-       if (gw->lock)
-               return TRUE;
-
-       if (gw->state == GATEWAY_STATE_PLAYING)
-               gateway_suspend_stream(dev);
-
-       return TRUE;
-}
diff --git a/audio/gateway.h b/audio/gateway.h
deleted file mode 100644 (file)
index 77f5787..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#define AUDIO_GATEWAY_INTERFACE "org.bluez.HandsfreeGateway"
-
-#define DEFAULT_HFP_HS_CHANNEL 7
-
-typedef enum {
-       GATEWAY_STATE_DISCONNECTED,
-       GATEWAY_STATE_CONNECTING,
-       GATEWAY_STATE_CONNECTED,
-       GATEWAY_STATE_PLAYING,
-} gateway_state_t;
-
-typedef enum {
-       GATEWAY_LOCK_READ = 1,
-       GATEWAY_LOCK_WRITE = 1 << 1,
-} gateway_lock_t;
-
-typedef enum {
-       GATEWAY_ERROR_DISCONNECTED,
-       GATEWAY_ERROR_SUSPENDED,
-} gateway_error_t;
-
-#define GATEWAY_ERROR gateway_error_quark()
-
-GQuark gateway_error_quark(void);
-
-typedef void (*gateway_state_cb) (struct audio_device *dev,
-                                       gateway_state_t old_state,
-                                       gateway_state_t new_state,
-                                       void *user_data);
-typedef void (*gateway_stream_cb_t) (struct audio_device *dev, GError *err,
-               void *user_data);
-
-void gateway_set_state(struct audio_device *dev, gateway_state_t new_state);
-void gateway_unregister(struct audio_device *dev);
-struct gateway *gateway_init(struct audio_device *device);
-gboolean gateway_is_active(struct audio_device *dev);
-gboolean gateway_is_connected(struct audio_device *dev);
-int gateway_connect_rfcomm(struct audio_device *dev, GIOChannel *io);
-int gateway_connect_sco(struct audio_device *dev, GIOChannel *chan);
-void gateway_start_service(struct audio_device *device);
-unsigned int gateway_request_stream(struct audio_device *dev,
-                       gateway_stream_cb_t cb, void *user_data);
-int gateway_config_stream(struct audio_device *dev, gateway_stream_cb_t cb,
-                       void *user_data);
-gboolean gateway_cancel_stream(struct audio_device *dev, unsigned int id);
-int gateway_get_sco_fd(struct audio_device *dev);
-void gateway_suspend_stream(struct audio_device *dev);
-unsigned int gateway_add_state_cb(gateway_state_cb cb, void *user_data);
-gboolean gateway_remove_state_cb(unsigned int id);
-gateway_lock_t gateway_get_lock(struct audio_device *dev);
-gboolean gateway_lock(struct audio_device *dev, gateway_lock_t lock);
-gboolean gateway_unlock(struct audio_device *dev, gateway_lock_t lock);
diff --git a/audio/gsta2dpsink.c b/audio/gsta2dpsink.c
deleted file mode 100644 (file)
index c8f6346..0000000
+++ /dev/null
@@ -1,729 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <unistd.h>
-#include <pthread.h>
-
-#include "gstpragma.h"
-#include "gsta2dpsink.h"
-
-GST_DEBUG_CATEGORY_STATIC(gst_a2dp_sink_debug);
-#define GST_CAT_DEFAULT gst_a2dp_sink_debug
-
-#define A2DP_SBC_RTP_PAYLOAD_TYPE 1
-#define TEMPLATE_MAX_BITPOOL_STR "64"
-
-#define DEFAULT_AUTOCONNECT TRUE
-
-enum {
-       PROP_0,
-       PROP_DEVICE,
-       PROP_AUTOCONNECT,
-       PROP_TRANSPORT
-};
-
-GST_BOILERPLATE(GstA2dpSink, gst_a2dp_sink, GstBin, GST_TYPE_BIN);
-
-static const GstElementDetails gst_a2dp_sink_details =
-       GST_ELEMENT_DETAILS("Bluetooth A2DP sink",
-                               "Sink/Audio",
-                               "Plays audio to an A2DP device",
-                               "Marcel Holtmann <marcel@holtmann.org>");
-
-static GstStaticPadTemplate gst_a2dp_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-                       GST_STATIC_CAPS("audio/x-sbc, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
-                               "blocks = (int) { 4, 8, 12, 16 }, "
-                               "subbands = (int) { 4, 8 }, "
-                               "allocation = (string) { \"snr\", \"loudness\" }, "
-                               "bitpool = (int) [ 2, "
-                               TEMPLATE_MAX_BITPOOL_STR " ]; "
-                               "audio/mpeg"
-                               ));
-
-static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event);
-static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps);
-static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad);
-static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self);
-static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self);
-static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self);
-
-static void gst_a2dp_sink_finalize(GObject *obj)
-{
-       GstA2dpSink *self = GST_A2DP_SINK(obj);
-
-       g_mutex_free(self->cb_mutex);
-
-       G_OBJECT_CLASS(parent_class)->finalize(obj);
-}
-
-static GstState gst_a2dp_sink_get_state(GstA2dpSink *self)
-{
-       GstState current, pending;
-
-       gst_element_get_state(GST_ELEMENT(self), &current, &pending, 0);
-       if (pending == GST_STATE_VOID_PENDING)
-               return current;
-
-       return pending;
-}
-
-/*
- * Helper function to create elements, add to the bin and link it
- * to another element.
- */
-static GstElement *gst_a2dp_sink_init_element(GstA2dpSink *self,
-                       const gchar *elementname, const gchar *name,
-                       GstElement *link_to)
-{
-       GstElement *element;
-       GstState state;
-
-       GST_LOG_OBJECT(self, "Initializing %s", elementname);
-
-       element = gst_element_factory_make(elementname, name);
-       if (element == NULL) {
-               GST_DEBUG_OBJECT(self, "Couldn't create %s", elementname);
-               return NULL;
-       }
-
-       if (!gst_bin_add(GST_BIN(self), element)) {
-               GST_DEBUG_OBJECT(self, "failed to add %s to the bin",
-                                               elementname);
-               goto cleanup_and_fail;
-       }
-
-       state = gst_a2dp_sink_get_state(self);
-       if (gst_element_set_state(element, state) ==
-                       GST_STATE_CHANGE_FAILURE) {
-               GST_DEBUG_OBJECT(self, "%s failed to go to playing",
-                                               elementname);
-               goto remove_element_and_fail;
-       }
-
-       if (link_to != NULL)
-               if (!gst_element_link(link_to, element)) {
-                       GST_DEBUG_OBJECT(self, "couldn't link %s",
-                                       elementname);
-                       goto remove_element_and_fail;
-               }
-
-       return element;
-
-remove_element_and_fail:
-       gst_element_set_state(element, GST_STATE_NULL);
-       gst_bin_remove(GST_BIN(self), element);
-       return NULL;
-
-cleanup_and_fail:
-       g_object_unref(G_OBJECT(element));
-
-       return NULL;
-}
-
-static void gst_a2dp_sink_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_set_details(element_class,
-               &gst_a2dp_sink_details);
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&gst_a2dp_sink_factory));
-}
-
-static void gst_a2dp_sink_set_property(GObject *object, guint prop_id,
-                                       const GValue *value, GParamSpec *pspec)
-{
-       GstA2dpSink *self = GST_A2DP_SINK(object);
-
-       switch (prop_id) {
-       case PROP_DEVICE:
-               if (self->sink != NULL)
-                       gst_avdtp_sink_set_device(self->sink,
-                               g_value_get_string(value));
-
-               if (self->device != NULL)
-                       g_free(self->device);
-               self->device = g_value_dup_string(value);
-               break;
-
-       case PROP_TRANSPORT:
-               if (self->sink != NULL)
-                       gst_avdtp_sink_set_transport(self->sink,
-                               g_value_get_string(value));
-
-               if (self->transport != NULL)
-                       g_free(self->transport);
-               self->transport = g_value_dup_string(value);
-               break;
-
-       case PROP_AUTOCONNECT:
-               self->autoconnect = g_value_get_boolean(value);
-
-               if (self->sink != NULL)
-                       g_object_set(G_OBJECT(self->sink), "auto-connect",
-                                       self->autoconnect, NULL);
-               break;
-
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static void gst_a2dp_sink_get_property(GObject *object, guint prop_id,
-                                       GValue *value, GParamSpec *pspec)
-{
-       GstA2dpSink *self = GST_A2DP_SINK(object);
-       gchar *device, *transport;
-
-       switch (prop_id) {
-       case PROP_DEVICE:
-               if (self->sink != NULL) {
-                       device = gst_avdtp_sink_get_device(self->sink);
-                       if (device != NULL)
-                               g_value_take_string(value, device);
-               }
-               break;
-       case PROP_AUTOCONNECT:
-               if (self->sink != NULL)
-                       g_object_get(G_OBJECT(self->sink), "auto-connect",
-                               &self->autoconnect, NULL);
-
-               g_value_set_boolean(value, self->autoconnect);
-               break;
-       case PROP_TRANSPORT:
-               if (self->sink != NULL) {
-                       transport = gst_avdtp_sink_get_transport(self->sink);
-                       if (transport != NULL)
-                               g_value_take_string(value, transport);
-               }
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static gboolean gst_a2dp_sink_init_ghost_pad(GstA2dpSink *self)
-{
-       GstPad *capsfilter_pad;
-
-       /* we search for the capsfilter sinkpad */
-       capsfilter_pad = gst_element_get_static_pad(self->capsfilter, "sink");
-
-       /* now we add a ghostpad */
-       self->ghostpad = GST_GHOST_PAD(gst_ghost_pad_new("sink",
-               capsfilter_pad));
-       g_object_unref(capsfilter_pad);
-
-       /* the getcaps of our ghostpad must reflect the device caps */
-       gst_pad_set_getcaps_function(GST_PAD(self->ghostpad),
-                               gst_a2dp_sink_get_caps);
-       self->ghostpad_setcapsfunc = GST_PAD_SETCAPSFUNC(self->ghostpad);
-       gst_pad_set_setcaps_function(GST_PAD(self->ghostpad),
-                       GST_DEBUG_FUNCPTR(gst_a2dp_sink_set_caps));
-
-       /* we need to handle events on our own and we also need the eventfunc
-        * of the ghostpad for forwarding calls */
-       self->ghostpad_eventfunc = GST_PAD_EVENTFUNC(GST_PAD(self->ghostpad));
-       gst_pad_set_event_function(GST_PAD(self->ghostpad),
-                       gst_a2dp_sink_handle_event);
-
-       if (!gst_element_add_pad(GST_ELEMENT(self), GST_PAD(self->ghostpad)))
-               GST_ERROR_OBJECT(self, "failed to add ghostpad");
-
-       return TRUE;
-}
-
-static void gst_a2dp_sink_remove_dynamic_elements(GstA2dpSink *self)
-{
-       if (self->rtp) {
-               GST_LOG_OBJECT(self, "removing rtp element from the bin");
-               if (!gst_bin_remove(GST_BIN(self), GST_ELEMENT(self->rtp)))
-                       GST_WARNING_OBJECT(self, "failed to remove rtp "
-                                       "element from bin");
-               else
-                       self->rtp = NULL;
-       }
-}
-
-static GstStateChangeReturn gst_a2dp_sink_change_state(GstElement *element,
-                       GstStateChange transition)
-{
-       GstStateChangeReturn ret = GST_STATE_CHANGE_SUCCESS;
-       GstA2dpSink *self = GST_A2DP_SINK(element);
-
-       switch (transition) {
-       case GST_STATE_CHANGE_READY_TO_PAUSED:
-               self->taglist = gst_tag_list_new();
-
-               gst_a2dp_sink_init_fakesink(self);
-               break;
-
-       case GST_STATE_CHANGE_NULL_TO_READY:
-               self->sink_is_in_bin = FALSE;
-               self->sink = GST_AVDTP_SINK(gst_element_factory_make(
-                               "avdtpsink", "avdtpsink"));
-               if (self->sink == NULL) {
-                       GST_WARNING_OBJECT(self, "failed to create avdtpsink");
-                       return GST_STATE_CHANGE_FAILURE;
-               }
-
-               if (self->device != NULL)
-                       gst_avdtp_sink_set_device(self->sink,
-                                       self->device);
-
-               if (self->transport != NULL)
-                       gst_avdtp_sink_set_transport(self->sink,
-                                       self->transport);
-
-               g_object_set(G_OBJECT(self->sink), "auto-connect",
-                                       self->autoconnect, NULL);
-
-               ret = gst_element_set_state(GST_ELEMENT(self->sink),
-                       GST_STATE_READY);
-               break;
-       default:
-               break;
-       }
-
-       if (ret == GST_STATE_CHANGE_FAILURE)
-               return ret;
-
-       ret = GST_ELEMENT_CLASS(parent_class)->change_state(element,
-                                                               transition);
-
-       switch (transition) {
-       case GST_STATE_CHANGE_PAUSED_TO_READY:
-               if (self->taglist) {
-                       gst_tag_list_free(self->taglist);
-                       self->taglist = NULL;
-               }
-               if (self->newseg_event != NULL) {
-                       gst_event_unref(self->newseg_event);
-                       self->newseg_event = NULL;
-               }
-               gst_a2dp_sink_remove_fakesink(self);
-               break;
-
-       case GST_STATE_CHANGE_READY_TO_NULL:
-               if (self->sink_is_in_bin) {
-                       if (!gst_bin_remove(GST_BIN(self),
-                                               GST_ELEMENT(self->sink)))
-                               GST_WARNING_OBJECT(self, "Failed to remove "
-                                               "avdtpsink from bin");
-               } else if (self->sink != NULL) {
-                       gst_element_set_state(GST_ELEMENT(self->sink),
-                                       GST_STATE_NULL);
-                       g_object_unref(G_OBJECT(self->sink));
-               }
-
-               self->sink = NULL;
-
-               gst_a2dp_sink_remove_dynamic_elements(self);
-               break;
-       default:
-               break;
-       }
-
-       return ret;
-}
-
-static void gst_a2dp_sink_class_init(GstA2dpSinkClass *klass)
-{
-       GObjectClass *object_class = G_OBJECT_CLASS(klass);
-       GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
-
-       parent_class = g_type_class_peek_parent(klass);
-
-       object_class->set_property = GST_DEBUG_FUNCPTR(
-                                       gst_a2dp_sink_set_property);
-       object_class->get_property = GST_DEBUG_FUNCPTR(
-                                       gst_a2dp_sink_get_property);
-
-       object_class->finalize = GST_DEBUG_FUNCPTR(
-                                       gst_a2dp_sink_finalize);
-
-       element_class->change_state = GST_DEBUG_FUNCPTR(
-                                       gst_a2dp_sink_change_state);
-
-       g_object_class_install_property(object_class, PROP_DEVICE,
-                       g_param_spec_string("device", "Device",
-                       "Bluetooth remote device address",
-                       NULL, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_AUTOCONNECT,
-                       g_param_spec_boolean("auto-connect", "Auto-connect",
-                       "Automatically attempt to connect to device",
-                       DEFAULT_AUTOCONNECT, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_TRANSPORT,
-                       g_param_spec_string("transport", "Transport",
-                       "Use configured transport",
-                       NULL, G_PARAM_READWRITE));
-
-       GST_DEBUG_CATEGORY_INIT(gst_a2dp_sink_debug, "a2dpsink", 0,
-                               "A2DP sink element");
-}
-
-GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self)
-{
-       return gst_avdtp_sink_get_device_caps(self->sink);
-}
-
-static GstCaps *gst_a2dp_sink_get_caps(GstPad *pad)
-{
-       GstCaps *caps;
-       GstCaps *caps_aux;
-       GstA2dpSink *self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
-
-       if (self->sink == NULL) {
-               GST_DEBUG_OBJECT(self, "a2dpsink isn't initialized "
-                       "returning template caps");
-               caps = gst_static_pad_template_get_caps(
-                               &gst_a2dp_sink_factory);
-       } else {
-               GST_LOG_OBJECT(self, "Getting device caps");
-               caps = gst_a2dp_sink_get_device_caps(self);
-               if (caps == NULL)
-                       caps = gst_static_pad_template_get_caps(
-                                       &gst_a2dp_sink_factory);
-       }
-       caps_aux = gst_caps_copy(caps);
-       g_object_set(self->capsfilter, "caps", caps_aux, NULL);
-       gst_caps_unref(caps_aux);
-       return caps;
-}
-
-static gboolean gst_a2dp_sink_init_avdtp_sink(GstA2dpSink *self)
-{
-       GstElement *sink;
-
-       /* check if we don't need a new sink */
-       if (self->sink_is_in_bin)
-               return TRUE;
-
-       if (self->sink == NULL)
-               sink = gst_element_factory_make("avdtpsink", "avdtpsink");
-       else
-               sink = GST_ELEMENT(self->sink);
-
-       if (sink == NULL) {
-               GST_ERROR_OBJECT(self, "Couldn't create avdtpsink");
-               return FALSE;
-       }
-
-       if (!gst_bin_add(GST_BIN(self), sink)) {
-               GST_ERROR_OBJECT(self, "failed to add avdtpsink "
-                       "to the bin");
-               goto cleanup_and_fail;
-       }
-
-       if (gst_element_set_state(sink, GST_STATE_READY) ==
-                       GST_STATE_CHANGE_FAILURE) {
-               GST_ERROR_OBJECT(self, "avdtpsink failed to go to ready");
-               goto remove_element_and_fail;
-       }
-
-       if (!gst_element_link(GST_ELEMENT(self->rtp), sink)) {
-               GST_ERROR_OBJECT(self, "couldn't link rtpsbcpay "
-                       "to avdtpsink");
-               goto remove_element_and_fail;
-       }
-
-       self->sink = GST_AVDTP_SINK(sink);
-       self->sink_is_in_bin = TRUE;
-       g_object_set(G_OBJECT(self->sink), "device", self->device, NULL);
-       g_object_set(G_OBJECT(self->sink), "transport", self->transport, NULL);
-
-       gst_element_set_state(sink, GST_STATE_PAUSED);
-
-       return TRUE;
-
-remove_element_and_fail:
-       gst_element_set_state(sink, GST_STATE_NULL);
-       gst_bin_remove(GST_BIN(self), sink);
-       return FALSE;
-
-cleanup_and_fail:
-       if (sink != NULL)
-               g_object_unref(G_OBJECT(sink));
-
-       return FALSE;
-}
-
-static gboolean gst_a2dp_sink_init_rtp_sbc_element(GstA2dpSink *self)
-{
-       GstElement *rtppay;
-
-       /* if we already have a rtp, we don't need a new one */
-       if (self->rtp != NULL)
-               return TRUE;
-
-       rtppay = gst_a2dp_sink_init_element(self, "rtpsbcpay", "rtp",
-                                               self->capsfilter);
-       if (rtppay == NULL)
-               return FALSE;
-
-       self->rtp = GST_BASE_RTP_PAYLOAD(rtppay);
-       g_object_set(G_OBJECT(self->rtp), "min-frames", -1, NULL);
-
-       gst_element_set_state(rtppay, GST_STATE_PAUSED);
-
-       return TRUE;
-}
-
-static gboolean gst_a2dp_sink_init_rtp_mpeg_element(GstA2dpSink *self)
-{
-       GstElement *rtppay;
-
-       /* check if we don't need a new rtp */
-       if (self->rtp)
-               return TRUE;
-
-       GST_LOG_OBJECT(self, "Initializing rtp mpeg element");
-       /* if capsfilter is not created then we can't have our rtp element */
-       if (self->capsfilter == NULL)
-               return FALSE;
-
-       rtppay = gst_a2dp_sink_init_element(self, "rtpmpapay", "rtp",
-                                       self->capsfilter);
-       if (rtppay == NULL)
-               return FALSE;
-
-       self->rtp = GST_BASE_RTP_PAYLOAD(rtppay);
-
-       gst_element_set_state(rtppay, GST_STATE_PAUSED);
-
-       return TRUE;
-}
-
-static gboolean gst_a2dp_sink_init_dynamic_elements(GstA2dpSink *self,
-                                               GstCaps *caps)
-{
-       GstStructure *structure;
-       GstEvent *event;
-       GstPad *capsfilterpad;
-       gboolean crc;
-       gchar *mode = NULL;
-
-       structure = gst_caps_get_structure(caps, 0);
-
-       /* before everything we need to remove fakesink */
-       gst_a2dp_sink_remove_fakesink(self);
-
-       /* first, we need to create our rtp payloader */
-       if (gst_structure_has_name(structure, "audio/x-sbc")) {
-               GST_LOG_OBJECT(self, "sbc media received");
-               if (!gst_a2dp_sink_init_rtp_sbc_element(self))
-                       return FALSE;
-       } else if (gst_structure_has_name(structure, "audio/mpeg")) {
-               GST_LOG_OBJECT(self, "mp3 media received");
-               if (!gst_a2dp_sink_init_rtp_mpeg_element(self))
-                       return FALSE;
-       } else {
-               GST_ERROR_OBJECT(self, "Unexpected media type");
-               return FALSE;
-       }
-
-       if (!gst_a2dp_sink_init_avdtp_sink(self))
-               return FALSE;
-
-       /* check if we should push the taglist FIXME should we push this?
-        * we can send the tags directly if needed */
-       if (self->taglist != NULL &&
-                       gst_structure_has_name(structure, "audio/mpeg")) {
-
-               event = gst_event_new_tag(self->taglist);
-
-               /* send directly the crc */
-               if (gst_tag_list_get_boolean(self->taglist, "has-crc", &crc))
-                       gst_avdtp_sink_set_crc(self->sink, crc);
-
-               if (gst_tag_list_get_string(self->taglist, "channel-mode",
-                               &mode))
-                       gst_avdtp_sink_set_channel_mode(self->sink, mode);
-
-               capsfilterpad = gst_ghost_pad_get_target(self->ghostpad);
-               gst_pad_send_event(capsfilterpad, event);
-               self->taglist = NULL;
-               g_free(mode);
-       }
-
-       if (!gst_avdtp_sink_set_device_caps(self->sink, caps))
-               return FALSE;
-
-       g_object_set(G_OBJECT(self->rtp), "mtu",
-               gst_avdtp_sink_get_link_mtu(self->sink), NULL);
-
-       /* we forward our new segment here if we have one */
-       if (self->newseg_event) {
-               gst_pad_send_event(GST_BASE_RTP_PAYLOAD_SINKPAD(self->rtp),
-                                       self->newseg_event);
-               self->newseg_event = NULL;
-       }
-
-       return TRUE;
-}
-
-static gboolean gst_a2dp_sink_set_caps(GstPad *pad, GstCaps *caps)
-{
-       GstA2dpSink *self;
-
-       self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
-       GST_INFO_OBJECT(self, "setting caps");
-
-       /* now we know the caps */
-       gst_a2dp_sink_init_dynamic_elements(self, caps);
-
-       return self->ghostpad_setcapsfunc(GST_PAD(self->ghostpad), caps);
-}
-
-/* used for catching newsegment events while we don't have a sink, for
- * later forwarding it to the sink */
-static gboolean gst_a2dp_sink_handle_event(GstPad *pad, GstEvent *event)
-{
-       GstA2dpSink *self;
-       GstTagList *taglist = NULL;
-       GstObject *parent;
-
-       self = GST_A2DP_SINK(GST_PAD_PARENT(pad));
-       parent = gst_element_get_parent(GST_ELEMENT(self->sink));
-
-       if (GST_EVENT_TYPE(event) == GST_EVENT_NEWSEGMENT &&
-                       parent != GST_OBJECT_CAST(self)) {
-               if (self->newseg_event != NULL)
-                       gst_event_unref(self->newseg_event);
-               self->newseg_event = gst_event_ref(event);
-
-       } else if (GST_EVENT_TYPE(event) == GST_EVENT_TAG &&
-                       parent != GST_OBJECT_CAST(self)) {
-               if (self->taglist == NULL)
-                       gst_event_parse_tag(event, &self->taglist);
-               else {
-                       gst_event_parse_tag(event, &taglist);
-                       gst_tag_list_insert(self->taglist, taglist,
-                                       GST_TAG_MERGE_REPLACE);
-               }
-       }
-
-       if (parent != NULL)
-               gst_object_unref(GST_OBJECT(parent));
-
-       return self->ghostpad_eventfunc(GST_PAD(self->ghostpad), event);
-}
-
-static gboolean gst_a2dp_sink_init_caps_filter(GstA2dpSink *self)
-{
-       GstElement *element;
-
-       element = gst_element_factory_make("capsfilter", "filter");
-       if (element == NULL)
-               goto failed;
-
-       if (!gst_bin_add(GST_BIN(self), element))
-               goto failed;
-
-       self->capsfilter = element;
-       return TRUE;
-
-failed:
-       GST_ERROR_OBJECT(self, "Failed to initialize caps filter");
-       return FALSE;
-}
-
-static gboolean gst_a2dp_sink_init_fakesink(GstA2dpSink *self)
-{
-       if (self->fakesink != NULL)
-               return TRUE;
-
-       g_mutex_lock(self->cb_mutex);
-       self->fakesink = gst_a2dp_sink_init_element(self, "fakesink",
-                       "fakesink", self->capsfilter);
-       g_mutex_unlock(self->cb_mutex);
-
-       if (!self->fakesink)
-               return FALSE;
-
-       return TRUE;
-}
-
-static gboolean gst_a2dp_sink_remove_fakesink(GstA2dpSink *self)
-{
-       g_mutex_lock(self->cb_mutex);
-
-       if (self->fakesink != NULL) {
-               gst_element_set_locked_state(self->fakesink, TRUE);
-               gst_element_set_state(self->fakesink, GST_STATE_NULL);
-
-               gst_bin_remove(GST_BIN(self), self->fakesink);
-               self->fakesink = NULL;
-       }
-
-       g_mutex_unlock(self->cb_mutex);
-
-       return TRUE;
-}
-
-static void gst_a2dp_sink_init(GstA2dpSink *self,
-                       GstA2dpSinkClass *klass)
-{
-       self->sink = NULL;
-       self->fakesink = NULL;
-       self->rtp = NULL;
-       self->device = NULL;
-       self->transport = NULL;
-       self->autoconnect = DEFAULT_AUTOCONNECT;
-       self->capsfilter = NULL;
-       self->newseg_event = NULL;
-       self->taglist = NULL;
-       self->ghostpad = NULL;
-       self->sink_is_in_bin = FALSE;
-
-       self->cb_mutex = g_mutex_new();
-
-       /* we initialize our capsfilter */
-       gst_a2dp_sink_init_caps_filter(self);
-       g_object_set(self->capsfilter, "caps",
-               gst_static_pad_template_get_caps(&gst_a2dp_sink_factory),
-               NULL);
-
-       gst_a2dp_sink_init_fakesink(self);
-
-       gst_a2dp_sink_init_ghost_pad(self);
-
-}
-
-gboolean gst_a2dp_sink_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "a2dpsink",
-                       GST_RANK_MARGINAL, GST_TYPE_A2DP_SINK);
-}
diff --git a/audio/gsta2dpsink.h b/audio/gsta2dpsink.h
deleted file mode 100644 (file)
index 1a591b2..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifndef __GST_A2DP_SINK_H__
-#define __GST_A2DP_SINK_H__
-
-#include <gst/gst.h>
-#include <gst/rtp/gstbasertppayload.h>
-#include "gstavdtpsink.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_A2DP_SINK \
-       (gst_a2dp_sink_get_type())
-#define GST_A2DP_SINK(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_A2DP_SINK,GstA2dpSink))
-#define GST_A2DP_SINK_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_A2DP_SINK,GstA2dpSinkClass))
-#define GST_IS_A2DP_SINK(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_A2DP_SINK))
-#define GST_IS_A2DP_SINK_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_A2DP_SINK))
-
-typedef struct _GstA2dpSink GstA2dpSink;
-typedef struct _GstA2dpSinkClass GstA2dpSinkClass;
-
-struct _GstA2dpSink {
-       GstBin bin;
-
-       GstBaseRTPPayload *rtp;
-       GstAvdtpSink *sink;
-       GstElement *capsfilter;
-       GstElement *fakesink;
-
-       gchar *device;
-       gchar *transport;
-       gboolean autoconnect;
-       gboolean sink_is_in_bin;
-
-       GstGhostPad *ghostpad;
-       GstPadSetCapsFunction ghostpad_setcapsfunc;
-       GstPadEventFunction ghostpad_eventfunc;
-
-       GstEvent *newseg_event;
-       /* Store the tags received before the a2dpsender sink is created
-        * when it is created we forward this to it */
-       GstTagList *taglist;
-
-       GMutex *cb_mutex;
-};
-
-struct _GstA2dpSinkClass {
-       GstBinClass parent_class;
-};
-
-GType gst_a2dp_sink_get_type(void);
-
-gboolean gst_a2dp_sink_plugin_init (GstPlugin * plugin);
-
-GstCaps *gst_a2dp_sink_get_device_caps(GstA2dpSink *self);
-
-G_END_DECLS
-
-#endif
diff --git a/audio/gstavdtpsink.c b/audio/gstavdtpsink.c
deleted file mode 100644 (file)
index 1f374fc..0000000
+++ /dev/null
@@ -1,2034 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <unistd.h>
-#include <sys/un.h>
-#include <sys/socket.h>
-#include <fcntl.h>
-#include <pthread.h>
-
-#include <netinet/in.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include <gst/rtp/gstrtpbuffer.h>
-
-#include <dbus/dbus.h>
-
-#include "ipc.h"
-#include "rtp.h"
-#include "a2dp-codecs.h"
-
-#include "gstpragma.h"
-#include "gstavdtpsink.h"
-
-GST_DEBUG_CATEGORY_STATIC(avdtp_sink_debug);
-#define GST_CAT_DEFAULT avdtp_sink_debug
-
-#define BUFFER_SIZE 2048
-#define TEMPLATE_MAX_BITPOOL 64
-#define CRC_PROTECTED 1
-#define CRC_UNPROTECTED 0
-
-#define DEFAULT_AUTOCONNECT TRUE
-
-#define GST_AVDTP_SINK_MUTEX_LOCK(s) G_STMT_START {    \
-               g_mutex_lock(s->sink_lock);             \
-       } G_STMT_END
-
-#define GST_AVDTP_SINK_MUTEX_UNLOCK(s) G_STMT_START {  \
-               g_mutex_unlock(s->sink_lock);           \
-       } G_STMT_END
-
-struct bluetooth_data {
-       struct bt_get_capabilities_rsp *caps; /* Bluetooth device caps */
-       guint link_mtu;
-
-       DBusConnection *conn;
-       guint8 codec; /* Bluetooth transport configuration */
-       gchar *uuid;
-       guint8 *config;
-       gint config_size;
-
-       gchar buffer[BUFFER_SIZE];      /* Codec transfer buffer */
-};
-
-#define IS_SBC(n) (strcmp((n), "audio/x-sbc") == 0)
-#define IS_MPEG_AUDIO(n) (strcmp((n), "audio/mpeg") == 0)
-
-enum {
-       PROP_0,
-       PROP_DEVICE,
-       PROP_AUTOCONNECT,
-       PROP_TRANSPORT
-};
-
-GST_BOILERPLATE(GstAvdtpSink, gst_avdtp_sink, GstBaseSink,
-                       GST_TYPE_BASE_SINK);
-
-static const GstElementDetails avdtp_sink_details =
-       GST_ELEMENT_DETAILS("Bluetooth AVDTP sink",
-                               "Sink/Audio",
-                               "Plays audio to an A2DP device",
-                               "Marcel Holtmann <marcel@holtmann.org>");
-
-static GstStaticPadTemplate avdtp_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("application/x-rtp, "
-                               "media = (string) \"audio\","
-                               "payload = (int) "
-                                       GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-                               "clock-rate = (int) { 16000, 32000, "
-                                       "44100, 48000 }, "
-                               "encoding-name = (string) \"SBC\"; "
-                               "application/x-rtp, "
-                               "media = (string) \"audio\", "
-                               "payload = (int) "
-                               GST_RTP_PAYLOAD_MPA_STRING ", "
-                               "clock-rate = (int) 90000; "
-                               "application/x-rtp, "
-                               "media = (string) \"audio\", "
-                               "payload = (int) "
-                               GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-                               "clock-rate = (int) 90000, "
-                               "encoding-name = (string) \"MPA\""
-                               ));
-
-static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self,
-                                       const bt_audio_msg_header_t *msg);
-static int gst_avdtp_sink_audioservice_expect(GstAvdtpSink *self,
-                                       bt_audio_msg_header_t *outmsg,
-                                       guint8 expected_name);
-
-
-static void gst_avdtp_sink_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&avdtp_sink_factory));
-
-       gst_element_class_set_details(element_class, &avdtp_sink_details);
-}
-
-static void gst_avdtp_sink_transport_release(GstAvdtpSink *self)
-{
-       DBusMessage *msg;
-       const char *access_type = "w";
-
-       msg = dbus_message_new_method_call("org.bluez", self->transport,
-                                               "org.bluez.MediaTransport",
-                                               "Release");
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &access_type,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_connection_send(self->data->conn, msg, NULL);
-
-       dbus_message_unref(msg);
-}
-
-static gboolean gst_avdtp_sink_stop(GstBaseSink *basesink)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-
-       GST_INFO_OBJECT(self, "stop");
-
-       if (self->watch_id != 0) {
-               g_source_remove(self->watch_id);
-               self->watch_id = 0;
-       }
-
-       if (self->server) {
-               bt_audio_service_close(g_io_channel_unix_get_fd(self->server));
-               g_io_channel_unref(self->server);
-               self->server = NULL;
-       }
-
-       if (self->stream) {
-               g_io_channel_shutdown(self->stream, TRUE, NULL);
-               g_io_channel_unref(self->stream);
-               self->stream = NULL;
-       }
-
-       if (self->data) {
-               if (self->transport)
-                       gst_avdtp_sink_transport_release(self);
-               if (self->data->conn)
-                       dbus_connection_unref(self->data->conn);
-               g_free(self->data);
-               self->data = NULL;
-       }
-
-       if (self->stream_caps) {
-               gst_caps_unref(self->stream_caps);
-               self->stream_caps = NULL;
-       }
-
-       if (self->dev_caps) {
-               gst_caps_unref(self->dev_caps);
-               self->dev_caps = NULL;
-       }
-
-       return TRUE;
-}
-
-static void gst_avdtp_sink_finalize(GObject *object)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(object);
-
-       if (self->data)
-               gst_avdtp_sink_stop(GST_BASE_SINK(self));
-
-       if (self->device)
-               g_free(self->device);
-
-       if (self->transport)
-               g_free(self->transport);
-
-       g_mutex_free(self->sink_lock);
-
-       G_OBJECT_CLASS(parent_class)->finalize(object);
-}
-
-static void gst_avdtp_sink_set_property(GObject *object, guint prop_id,
-                                       const GValue *value, GParamSpec *pspec)
-{
-       GstAvdtpSink *sink = GST_AVDTP_SINK(object);
-
-       switch (prop_id) {
-       case PROP_DEVICE:
-               if (sink->device)
-                       g_free(sink->device);
-               sink->device = g_value_dup_string(value);
-               break;
-
-       case PROP_AUTOCONNECT:
-               sink->autoconnect = g_value_get_boolean(value);
-               break;
-
-       case PROP_TRANSPORT:
-               if (sink->transport)
-                       g_free(sink->transport);
-               sink->transport = g_value_dup_string(value);
-               break;
-
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static void gst_avdtp_sink_get_property(GObject *object, guint prop_id,
-                                       GValue *value, GParamSpec *pspec)
-{
-       GstAvdtpSink *sink = GST_AVDTP_SINK(object);
-
-       switch (prop_id) {
-       case PROP_DEVICE:
-               g_value_set_string(value, sink->device);
-               break;
-
-       case PROP_AUTOCONNECT:
-               g_value_set_boolean(value, sink->autoconnect);
-               break;
-
-       case PROP_TRANSPORT:
-               g_value_set_string(value, sink->transport);
-               break;
-
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static gint gst_avdtp_sink_bluetooth_recvmsg_fd(GstAvdtpSink *sink)
-{
-       int err, ret;
-
-       ret = bt_audio_service_get_data_fd(
-                       g_io_channel_unix_get_fd(sink->server));
-
-       if (ret < 0) {
-               err = -errno;
-               GST_ERROR_OBJECT(sink, "Unable to receive fd: %s (%d)",
-                               strerror(-err), -err);
-               return err;
-       }
-
-       sink->stream = g_io_channel_unix_new(ret);
-       g_io_channel_set_encoding(sink->stream, NULL, NULL);
-       GST_DEBUG_OBJECT(sink, "stream_fd=%d", ret);
-
-       return 0;
-}
-
-static codec_capabilities_t *gst_avdtp_find_caps(GstAvdtpSink *sink,
-                                               uint8_t codec_type)
-{
-       struct bt_get_capabilities_rsp *rsp = sink->data->caps;
-       codec_capabilities_t *codec = (void *) rsp->data;
-       int bytes_left = rsp->h.length - sizeof(*rsp);
-
-       while (bytes_left > 0) {
-               if ((codec->type == codec_type) &&
-                               !(codec->lock & BT_WRITE_LOCK))
-                       break;
-
-               bytes_left -= codec->length;
-               codec = (void *) codec + codec->length;
-       }
-
-       if (bytes_left <= 0)
-               return NULL;
-
-       return codec;
-}
-
-static gboolean gst_avdtp_sink_init_sbc_pkt_conf(GstAvdtpSink *sink,
-                                       GstCaps *caps,
-                                       sbc_capabilities_t *pkt)
-{
-       sbc_capabilities_t *cfg;
-       const GValue *value = NULL;
-       const char *pref, *name;
-       gint rate, subbands, blocks;
-       GstStructure *structure = gst_caps_get_structure(caps, 0);
-
-       cfg = (void *) gst_avdtp_find_caps(sink, BT_A2DP_SBC_SINK);
-       name = gst_structure_get_name(structure);
-
-       if (!(IS_SBC(name))) {
-               GST_ERROR_OBJECT(sink, "Unexpected format %s, "
-                               "was expecting sbc", name);
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "rate");
-       rate = g_value_get_int(value);
-       if (rate == 44100)
-               cfg->frequency = BT_SBC_SAMPLING_FREQ_44100;
-       else if (rate == 48000)
-               cfg->frequency = BT_SBC_SAMPLING_FREQ_48000;
-       else if (rate == 32000)
-               cfg->frequency = BT_SBC_SAMPLING_FREQ_32000;
-       else if (rate == 16000)
-               cfg->frequency = BT_SBC_SAMPLING_FREQ_16000;
-       else {
-               GST_ERROR_OBJECT(sink, "Invalid rate while setting caps");
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "mode");
-       pref = g_value_get_string(value);
-       if (strcmp(pref, "mono") == 0)
-               cfg->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
-       else if (strcmp(pref, "dual") == 0)
-               cfg->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
-       else if (strcmp(pref, "stereo") == 0)
-               cfg->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
-       else if (strcmp(pref, "joint") == 0)
-               cfg->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
-       else {
-               GST_ERROR_OBJECT(sink, "Invalid mode %s", pref);
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "allocation");
-       pref = g_value_get_string(value);
-       if (strcmp(pref, "loudness") == 0)
-               cfg->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
-       else if (strcmp(pref, "snr") == 0)
-               cfg->allocation_method = BT_A2DP_ALLOCATION_SNR;
-       else {
-               GST_ERROR_OBJECT(sink, "Invalid allocation: %s", pref);
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "subbands");
-       subbands = g_value_get_int(value);
-       if (subbands == 8)
-               cfg->subbands = BT_A2DP_SUBBANDS_8;
-       else if (subbands == 4)
-               cfg->subbands = BT_A2DP_SUBBANDS_4;
-       else {
-               GST_ERROR_OBJECT(sink, "Invalid subbands %d", subbands);
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "blocks");
-       blocks = g_value_get_int(value);
-       if (blocks == 16)
-               cfg->block_length = BT_A2DP_BLOCK_LENGTH_16;
-       else if (blocks == 12)
-               cfg->block_length = BT_A2DP_BLOCK_LENGTH_12;
-       else if (blocks == 8)
-               cfg->block_length = BT_A2DP_BLOCK_LENGTH_8;
-       else if (blocks == 4)
-               cfg->block_length = BT_A2DP_BLOCK_LENGTH_4;
-       else {
-               GST_ERROR_OBJECT(sink, "Invalid blocks %d", blocks);
-               return FALSE;
-       }
-
-       value = gst_structure_get_value(structure, "bitpool");
-       cfg->max_bitpool = cfg->min_bitpool = g_value_get_int(value);
-
-       memcpy(pkt, cfg, sizeof(*pkt));
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_conf_recv_stream_fd(
-                                       GstAvdtpSink *self)
-{
-       struct bluetooth_data *data = self->data;
-       gint ret;
-       GError *gerr = NULL;
-       GIOStatus status;
-       GIOFlags flags;
-       int fd;
-
-       /* Proceed if stream was already acquired */
-       if (self->stream != NULL)
-               goto proceed;
-
-       ret = gst_avdtp_sink_bluetooth_recvmsg_fd(self);
-       if (ret < 0)
-               return FALSE;
-
-       if (!self->stream) {
-               GST_ERROR_OBJECT(self, "Error while configuring device: "
-                               "could not acquire audio socket");
-               return FALSE;
-       }
-
-proceed:
-       /* set stream socket to nonblock */
-       GST_LOG_OBJECT(self, "setting stream socket to nonblock");
-       flags = g_io_channel_get_flags(self->stream);
-       flags |= G_IO_FLAG_NONBLOCK;
-       status = g_io_channel_set_flags(self->stream, flags, &gerr);
-       if (status != G_IO_STATUS_NORMAL) {
-               if (gerr)
-                       GST_WARNING_OBJECT(self, "Error while "
-                               "setting server socket to nonblock: "
-                               "%s", gerr->message);
-               else
-                       GST_WARNING_OBJECT(self, "Error while "
-                                       "setting server "
-                                       "socket to nonblock");
-       }
-
-       fd = g_io_channel_unix_get_fd(self->stream);
-
-       /* It is possible there is some outstanding
-       data in the pipe - we have to empty it */
-       GST_LOG_OBJECT(self, "emptying stream pipe");
-       while (1) {
-               ssize_t bread = read(fd, data->buffer, data->link_mtu);
-               if (bread <= 0)
-                       break;
-       }
-
-       /* set stream socket to block */
-       GST_LOG_OBJECT(self, "setting stream socket to block");
-       flags = g_io_channel_get_flags(self->stream);
-       flags &= ~G_IO_FLAG_NONBLOCK;
-       status = g_io_channel_set_flags(self->stream, flags, &gerr);
-       if (status != G_IO_STATUS_NORMAL) {
-               if (gerr)
-                       GST_WARNING_OBJECT(self, "Error while "
-                               "setting server socket to block:"
-                               "%s", gerr->message);
-               else
-                       GST_WARNING_OBJECT(self, "Error while "
-                               "setting server "
-                               "socket to block");
-       }
-
-       memset(data->buffer, 0, sizeof(data->buffer));
-
-       return TRUE;
-}
-
-static gboolean server_callback(GIOChannel *chan,
-                                       GIOCondition cond, gpointer data)
-{
-       if (cond & G_IO_HUP || cond & G_IO_NVAL)
-               return FALSE;
-       else if (cond & G_IO_ERR)
-               GST_WARNING_OBJECT(GST_AVDTP_SINK(data),
-                                       "Untreated callback G_IO_ERR");
-
-       return TRUE;
-}
-
-static GstStructure *gst_avdtp_sink_parse_sbc_caps(
-                       GstAvdtpSink *self, sbc_capabilities_t *sbc)
-{
-       GstStructure *structure;
-       GValue *value;
-       GValue *list;
-       gboolean mono, stereo;
-
-       if (sbc == NULL)
-               return NULL;
-
-       structure = gst_structure_empty_new("audio/x-sbc");
-       value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING);
-
-       /* mode */
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
-               g_value_set_static_string(value, "mono");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) {
-               g_value_set_static_string(value, "stereo");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) {
-               g_value_set_static_string(value, "dual");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) {
-               g_value_set_static_string(value, "joint");
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "mode", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* subbands */
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       value = g_value_init(value, G_TYPE_INT);
-       if (sbc->subbands & BT_A2DP_SUBBANDS_4) {
-               g_value_set_int(value, 4);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->subbands & BT_A2DP_SUBBANDS_8) {
-               g_value_set_int(value, 8);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "subbands", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* blocks */
-       value = g_value_init(value, G_TYPE_INT);
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) {
-               g_value_set_int(value, 16);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) {
-               g_value_set_int(value, 12);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) {
-               g_value_set_int(value, 8);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) {
-               g_value_set_int(value, 4);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "blocks", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* allocation */
-       g_value_init(value, G_TYPE_STRING);
-       list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST);
-       if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {
-               g_value_set_static_string(value, "loudness");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {
-               g_value_set_static_string(value, "snr");
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "allocation", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* rate */
-       g_value_init(value, G_TYPE_INT);
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) {
-               g_value_set_int(value, 48000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) {
-               g_value_set_int(value, 44100);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) {
-               g_value_set_int(value, 32000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) {
-               g_value_set_int(value, 16000);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "rate", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* bitpool */
-       value = g_value_init(value, GST_TYPE_INT_RANGE);
-       gst_value_set_int_range(value,
-                       MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),
-                       MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));
-       gst_structure_set_value(structure, "bitpool", value);
-       g_value_unset(value);
-
-       /* channels */
-       mono = FALSE;
-       stereo = FALSE;
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               mono = TRUE;
-       if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
-                       (sbc->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
-                       (sbc->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
-               stereo = TRUE;
-
-       if (mono && stereo) {
-               g_value_init(value, GST_TYPE_INT_RANGE);
-               gst_value_set_int_range(value, 1, 2);
-       } else {
-               g_value_init(value, G_TYPE_INT);
-               if (mono)
-                       g_value_set_int(value, 1);
-               else if (stereo)
-                       g_value_set_int(value, 2);
-               else {
-                       GST_ERROR_OBJECT(self,
-                               "Unexpected number of channels");
-                       g_value_set_int(value, 0);
-               }
-       }
-
-       gst_structure_set_value(structure, "channels", value);
-       g_free(value);
-
-       return structure;
-}
-
-static GstStructure *gst_avdtp_sink_parse_mpeg_caps(
-                       GstAvdtpSink *self, mpeg_capabilities_t *mpeg)
-{
-       GstStructure *structure;
-       GValue *value;
-       GValue *list;
-       gboolean valid_layer = FALSE;
-       gboolean mono, stereo;
-
-       if (!mpeg)
-               return NULL;
-
-       GST_LOG_OBJECT(self, "parsing mpeg caps");
-
-       structure = gst_structure_empty_new("audio/mpeg");
-       value = g_new0(GValue, 1);
-       g_value_init(value, G_TYPE_INT);
-
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       g_value_set_int(value, 1);
-       gst_value_list_prepend_value(list, value);
-       g_value_set_int(value, 2);
-       gst_value_list_prepend_value(list, value);
-       gst_structure_set_value(structure, "mpegversion", list);
-       g_free(list);
-
-       /* layer */
-       GST_LOG_OBJECT(self, "setting mpeg layer");
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (mpeg->layer & BT_MPEG_LAYER_1) {
-               g_value_set_int(value, 1);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (mpeg->layer & BT_MPEG_LAYER_2) {
-               g_value_set_int(value, 2);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (mpeg->layer & BT_MPEG_LAYER_3) {
-               g_value_set_int(value, 3);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (list) {
-               gst_structure_set_value(structure, "layer", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       if (!valid_layer) {
-               gst_structure_free(structure);
-               g_free(value);
-               return NULL;
-       }
-
-       /* rate */
-       GST_LOG_OBJECT(self, "setting mpeg rate");
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) {
-               g_value_set_int(value, 48000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) {
-               g_value_set_int(value, 44100);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) {
-               g_value_set_int(value, 32000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) {
-               g_value_set_int(value, 24000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) {
-               g_value_set_int(value, 22050);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) {
-               g_value_set_int(value, 16000);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "rate", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* channels */
-       GST_LOG_OBJECT(self, "setting mpeg channels");
-       mono = FALSE;
-       stereo = FALSE;
-       if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               mono = TRUE;
-       if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
-                       (mpeg->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
-                       (mpeg->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
-               stereo = TRUE;
-
-       if (mono && stereo) {
-               g_value_init(value, GST_TYPE_INT_RANGE);
-               gst_value_set_int_range(value, 1, 2);
-       } else {
-               g_value_init(value, G_TYPE_INT);
-               if (mono)
-                       g_value_set_int(value, 1);
-               else if (stereo)
-                       g_value_set_int(value, 2);
-               else {
-                       GST_ERROR_OBJECT(self,
-                               "Unexpected number of channels");
-                       g_value_set_int(value, 0);
-               }
-       }
-       gst_structure_set_value(structure, "channels", value);
-       g_free(value);
-
-       return structure;
-}
-
-static GstStructure *gst_avdtp_sink_parse_sbc_raw(GstAvdtpSink *self)
-{
-       a2dp_sbc_t *sbc = (a2dp_sbc_t *) self->data->config;
-       GstStructure *structure;
-       GValue *value;
-       GValue *list;
-       gboolean mono, stereo;
-
-       structure = gst_structure_empty_new("audio/x-sbc");
-       value = g_value_init(g_new0(GValue, 1), G_TYPE_STRING);
-
-       /* mode */
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
-               g_value_set_static_string(value, "mono");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) {
-               g_value_set_static_string(value, "stereo");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) {
-               g_value_set_static_string(value, "dual");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO) {
-               g_value_set_static_string(value, "joint");
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "mode", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* subbands */
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       value = g_value_init(value, G_TYPE_INT);
-       if (sbc->subbands & BT_A2DP_SUBBANDS_4) {
-               g_value_set_int(value, 4);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->subbands & BT_A2DP_SUBBANDS_8) {
-               g_value_set_int(value, 8);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "subbands", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* blocks */
-       value = g_value_init(value, G_TYPE_INT);
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_16) {
-               g_value_set_int(value, 16);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_12) {
-               g_value_set_int(value, 12);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_8) {
-               g_value_set_int(value, 8);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->block_length & BT_A2DP_BLOCK_LENGTH_4) {
-               g_value_set_int(value, 4);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "blocks", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* allocation */
-       g_value_init(value, G_TYPE_STRING);
-       list = g_value_init(g_new0(GValue,1), GST_TYPE_LIST);
-       if (sbc->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS) {
-               g_value_set_static_string(value, "loudness");
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->allocation_method & BT_A2DP_ALLOCATION_SNR) {
-               g_value_set_static_string(value, "snr");
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "allocation", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* rate */
-       g_value_init(value, G_TYPE_INT);
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_48000) {
-               g_value_set_int(value, 48000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_44100) {
-               g_value_set_int(value, 44100);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_32000) {
-               g_value_set_int(value, 32000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (sbc->frequency & BT_SBC_SAMPLING_FREQ_16000) {
-               g_value_set_int(value, 16000);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "rate", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* bitpool */
-       value = g_value_init(value, GST_TYPE_INT_RANGE);
-       gst_value_set_int_range(value,
-                       MIN(sbc->min_bitpool, TEMPLATE_MAX_BITPOOL),
-                       MIN(sbc->max_bitpool, TEMPLATE_MAX_BITPOOL));
-       gst_structure_set_value(structure, "bitpool", value);
-       g_value_unset(value);
-
-       /* channels */
-       mono = FALSE;
-       stereo = FALSE;
-       if (sbc->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               mono = TRUE;
-       if ((sbc->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
-                       (sbc->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
-                       (sbc->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
-               stereo = TRUE;
-
-       if (mono && stereo) {
-               g_value_init(value, GST_TYPE_INT_RANGE);
-               gst_value_set_int_range(value, 1, 2);
-       } else {
-               g_value_init(value, G_TYPE_INT);
-               if (mono)
-                       g_value_set_int(value, 1);
-               else if (stereo)
-                       g_value_set_int(value, 2);
-               else {
-                       GST_ERROR_OBJECT(self,
-                               "Unexpected number of channels");
-                       g_value_set_int(value, 0);
-               }
-       }
-
-       gst_structure_set_value(structure, "channels", value);
-       g_free(value);
-
-       return structure;
-}
-
-static GstStructure *gst_avdtp_sink_parse_mpeg_raw(GstAvdtpSink *self)
-{
-       a2dp_mpeg_t *mpeg = (a2dp_mpeg_t *) self->data->config;
-       GstStructure *structure;
-       GValue *value;
-       GValue *list;
-       gboolean valid_layer = FALSE;
-       gboolean mono, stereo;
-
-       GST_LOG_OBJECT(self, "parsing mpeg caps");
-
-       structure = gst_structure_empty_new("audio/mpeg");
-       value = g_new0(GValue, 1);
-       g_value_init(value, G_TYPE_INT);
-
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       g_value_set_int(value, 1);
-       gst_value_list_prepend_value(list, value);
-       g_value_set_int(value, 2);
-       gst_value_list_prepend_value(list, value);
-       gst_structure_set_value(structure, "mpegversion", list);
-       g_free(list);
-
-       /* layer */
-       GST_LOG_OBJECT(self, "setting mpeg layer");
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (mpeg->layer & BT_MPEG_LAYER_1) {
-               g_value_set_int(value, 1);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (mpeg->layer & BT_MPEG_LAYER_2) {
-               g_value_set_int(value, 2);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (mpeg->layer & BT_MPEG_LAYER_3) {
-               g_value_set_int(value, 3);
-               gst_value_list_prepend_value(list, value);
-               valid_layer = TRUE;
-       }
-       if (list) {
-               gst_structure_set_value(structure, "layer", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       if (!valid_layer) {
-               gst_structure_free(structure);
-               g_free(value);
-               return NULL;
-       }
-
-       /* rate */
-       GST_LOG_OBJECT(self, "setting mpeg rate");
-       list = g_value_init(g_new0(GValue, 1), GST_TYPE_LIST);
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_48000) {
-               g_value_set_int(value, 48000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_44100) {
-               g_value_set_int(value, 44100);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_32000) {
-               g_value_set_int(value, 32000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_24000) {
-               g_value_set_int(value, 24000);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_22050) {
-               g_value_set_int(value, 22050);
-               gst_value_list_prepend_value(list, value);
-       }
-       if (mpeg->frequency & BT_MPEG_SAMPLING_FREQ_16000) {
-               g_value_set_int(value, 16000);
-               gst_value_list_prepend_value(list, value);
-       }
-       g_value_unset(value);
-       if (list) {
-               gst_structure_set_value(structure, "rate", list);
-               g_free(list);
-               list = NULL;
-       }
-
-       /* channels */
-       GST_LOG_OBJECT(self, "setting mpeg channels");
-       mono = FALSE;
-       stereo = FALSE;
-       if (mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               mono = TRUE;
-       if ((mpeg->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO) ||
-                       (mpeg->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL) ||
-                       (mpeg->channel_mode &
-                       BT_A2DP_CHANNEL_MODE_JOINT_STEREO))
-               stereo = TRUE;
-
-       if (mono && stereo) {
-               g_value_init(value, GST_TYPE_INT_RANGE);
-               gst_value_set_int_range(value, 1, 2);
-       } else {
-               g_value_init(value, G_TYPE_INT);
-               if (mono)
-                       g_value_set_int(value, 1);
-               else if (stereo)
-                       g_value_set_int(value, 2);
-               else {
-                       GST_ERROR_OBJECT(self,
-                               "Unexpected number of channels");
-                       g_value_set_int(value, 0);
-               }
-       }
-       gst_structure_set_value(structure, "channels", value);
-       g_free(value);
-
-       return structure;
-}
-
-static gboolean gst_avdtp_sink_update_config(GstAvdtpSink *self)
-{
-       GstStructure *structure;
-       gchar *tmp;
-
-       switch (self->data->codec) {
-       case A2DP_CODEC_SBC:
-               structure = gst_avdtp_sink_parse_sbc_raw(self);
-               break;
-       case A2DP_CODEC_MPEG12:
-               structure = gst_avdtp_sink_parse_mpeg_raw(self);
-               break;
-       default:
-               GST_ERROR_OBJECT(self, "Unsupported configuration");
-               return FALSE;
-       }
-
-       if (structure == NULL)
-               return FALSE;
-
-       if (self->dev_caps != NULL)
-               gst_caps_unref(self->dev_caps);
-
-       self->dev_caps = gst_caps_new_full(structure, NULL);
-
-       tmp = gst_caps_to_string(self->dev_caps);
-       GST_DEBUG_OBJECT(self, "Transport configuration: %s", tmp);
-       g_free(tmp);
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_update_caps(GstAvdtpSink *self)
-{
-       sbc_capabilities_t *sbc;
-       mpeg_capabilities_t *mpeg;
-       GstStructure *sbc_structure;
-       GstStructure *mpeg_structure;
-       gchar *tmp;
-
-       GST_LOG_OBJECT(self, "updating device caps");
-
-       if (self->data->config_size != 0 && self->data->config != NULL)
-               return gst_avdtp_sink_update_config(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);
-
-       if (self->dev_caps != NULL)
-               gst_caps_unref(self->dev_caps);
-       self->dev_caps = gst_caps_new_full(sbc_structure, NULL);
-       if (mpeg_structure != NULL)
-               gst_caps_append_structure(self->dev_caps, mpeg_structure);
-
-       tmp = gst_caps_to_string(self->dev_caps);
-       GST_DEBUG_OBJECT(self, "Device capabilities: %s", tmp);
-       g_free(tmp);
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_get_capabilities(GstAvdtpSink *self)
-{
-       gchar buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_get_capabilities_req *req = (void *) buf;
-       struct bt_get_capabilities_rsp *rsp = (void *) buf;
-       int err;
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_GET_CAPABILITIES;
-       req->h.length = sizeof(*req);
-
-       if (self->device == NULL)
-               return FALSE;
-       strncpy(req->destination, self->device, 18);
-       if (self->autoconnect)
-               req->flags |= BT_FLAG_AUTOCONNECT;
-
-       err = gst_avdtp_sink_audioservice_send(self, &req->h);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while asking device caps");
-               return FALSE;
-       }
-
-       rsp->h.length = 0;
-       err = gst_avdtp_sink_audioservice_expect(self,
-                                       &rsp->h, BT_GET_CAPABILITIES);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while getting device caps");
-               return FALSE;
-       }
-
-       self->data->caps = g_malloc0(rsp->h.length);
-       memcpy(self->data->caps, rsp, rsp->h.length);
-       if (!gst_avdtp_sink_update_caps(self)) {
-               GST_WARNING_OBJECT(self, "failed to update capabilities");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-static gint gst_avdtp_sink_get_channel_mode(const gchar *mode)
-{
-       if (strcmp(mode, "stereo") == 0)
-               return BT_A2DP_CHANNEL_MODE_STEREO;
-       else if (strcmp(mode, "joint-stereo") == 0)
-               return BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
-       else if (strcmp(mode, "dual-channel") == 0)
-               return BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
-       else if (strcmp(mode, "mono") == 0)
-               return BT_A2DP_CHANNEL_MODE_MONO;
-       else
-               return -1;
-}
-
-static void gst_avdtp_sink_tag(const GstTagList *taglist,
-                       const gchar *tag, gpointer user_data)
-{
-       gboolean crc;
-       gchar *channel_mode = NULL;
-       GstAvdtpSink *self = GST_AVDTP_SINK(user_data);
-
-       if (strcmp(tag, "has-crc") == 0) {
-
-               if (!gst_tag_list_get_boolean(taglist, tag, &crc)) {
-                       GST_WARNING_OBJECT(self, "failed to get crc tag");
-                       return;
-               }
-
-               gst_avdtp_sink_set_crc(self, crc);
-
-       } else if (strcmp(tag, "channel-mode") == 0) {
-
-               if (!gst_tag_list_get_string(taglist, tag, &channel_mode)) {
-                       GST_WARNING_OBJECT(self,
-                               "failed to get channel-mode tag");
-                       return;
-               }
-
-               self->channel_mode = gst_avdtp_sink_get_channel_mode(
-                                       channel_mode);
-               if (self->channel_mode == -1)
-                       GST_WARNING_OBJECT(self, "Received invalid channel "
-                                       "mode: %s", channel_mode);
-               g_free(channel_mode);
-
-       } else
-               GST_DEBUG_OBJECT(self, "received unused tag: %s", tag);
-}
-
-static gboolean gst_avdtp_sink_event(GstBaseSink *basesink,
-                       GstEvent *event)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-       GstTagList *taglist = NULL;
-
-       if (GST_EVENT_TYPE(event) == GST_EVENT_TAG) {
-               /* we check the tags, mp3 has tags that are importants and
-                * are outside caps */
-               gst_event_parse_tag(event, &taglist);
-               gst_tag_list_foreach(taglist, gst_avdtp_sink_tag, self);
-       }
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_transport_parse_property(GstAvdtpSink *self,
-                                                       DBusMessageIter *i)
-{
-       const char *key;
-       DBusMessageIter variant_i;
-
-       if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_STRING) {
-               GST_ERROR_OBJECT(self, "Property name not a string.");
-               return FALSE;
-       }
-
-       dbus_message_iter_get_basic(i, &key);
-
-       if (!dbus_message_iter_next(i))  {
-               GST_ERROR_OBJECT(self, "Property value missing");
-               return FALSE;
-       }
-
-       if (dbus_message_iter_get_arg_type(i) != DBUS_TYPE_VARIANT) {
-               GST_ERROR_OBJECT(self, "Property value not a variant.");
-               return FALSE;
-       }
-
-       dbus_message_iter_recurse(i, &variant_i);
-
-       switch (dbus_message_iter_get_arg_type(&variant_i)) {
-       case DBUS_TYPE_BYTE: {
-               uint8_t value;
-               dbus_message_iter_get_basic(&variant_i, &value);
-
-               if (g_str_equal(key, "Codec") == TRUE)
-                       self->data->codec = value;
-
-               break;
-       }
-       case DBUS_TYPE_STRING: {
-               const char *value;
-               dbus_message_iter_get_basic(&variant_i, &value);
-
-               if (g_str_equal(key, "UUID") == TRUE) {
-                       g_free(self->data->uuid);
-                       self->data->uuid = g_strdup(value);
-               }
-
-               break;
-       }
-       case DBUS_TYPE_ARRAY: {
-               DBusMessageIter array_i;
-               char *value;
-               int size;
-
-               dbus_message_iter_recurse(&variant_i, &array_i);
-               dbus_message_iter_get_fixed_array(&array_i, &value, &size);
-
-               if (g_str_equal(key, "Configuration")) {
-                       g_free(self->data->config);
-                       self->data->config = g_new0(guint8, size);
-                       self->data->config_size = size;
-                       memcpy(self->data->config, value, size);
-               }
-
-               break;
-       }
-       }
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_transport_acquire(GstAvdtpSink *self)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *access_type = "w";
-       int fd;
-       uint16_t imtu, omtu;
-
-       dbus_error_init(&err);
-
-       if (self->data->conn == NULL)
-               self->data->conn = dbus_bus_get(DBUS_BUS_SYSTEM, &err);
-
-       msg = dbus_message_new_method_call("org.bluez", self->transport,
-                                               "org.bluez.MediaTransport",
-                                               "Acquire");
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &access_type,
-                                       DBUS_TYPE_INVALID);
-
-       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;
-
-       if (dbus_message_get_args(reply, &err, DBUS_TYPE_UNIX_FD, &fd,
-                                               DBUS_TYPE_UINT16, &imtu,
-                                               DBUS_TYPE_UINT16, &omtu,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               goto fail;
-
-       dbus_message_unref(reply);
-
-       self->stream = g_io_channel_unix_new(fd);
-       g_io_channel_set_encoding(self->stream, NULL, NULL);
-       g_io_channel_set_close_on_unref(self->stream, TRUE);
-       self->data->link_mtu = omtu;
-       GST_DEBUG_OBJECT(self, "stream_fd=%d mtu=%d", fd, omtu);
-
-       return TRUE;
-
-fail:
-       GST_ERROR_OBJECT(self, "Failed to acquire transport stream: %s",
-                               err.message);
-
-       dbus_error_free(&err);
-
-       if (reply)
-               dbus_message_unref(reply);
-
-       return FALSE;
-}
-
-static gboolean gst_avdtp_sink_transport_get_properties(GstAvdtpSink *self)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter arg_i, ele_i;
-       DBusError err;
-
-       dbus_error_init(&err);
-
-       /* Transport need to be acquire first to make sure the MTUs are
-          available */
-       if (gst_avdtp_sink_transport_acquire(self) == FALSE)
-               return FALSE;
-
-       msg = dbus_message_new_method_call("org.bluez", self->transport,
-                                               "org.bluez.MediaTransport",
-                                               "GetProperties");
-       reply = dbus_connection_send_with_reply_and_block(self->data->conn,
-                                                       msg, -1, &err);
-
-       if (dbus_error_is_set(&err) || reply == NULL) {
-               GST_ERROR_OBJECT(self, "Failed to get transport properties: %s",
-                                       err.message);
-               goto fail;
-       }
-
-       if (!dbus_message_iter_init(reply, &arg_i)) {
-               GST_ERROR_OBJECT(self, "GetProperties reply has no arguments.");
-               goto fail;
-       }
-
-       if (dbus_message_iter_get_arg_type(&arg_i) != DBUS_TYPE_ARRAY) {
-               GST_ERROR_OBJECT(self, "GetProperties argument is not an array.");
-               goto fail;
-       }
-
-       dbus_message_iter_recurse(&arg_i, &ele_i);
-       while (dbus_message_iter_get_arg_type(&ele_i) != DBUS_TYPE_INVALID) {
-
-               if (dbus_message_iter_get_arg_type(&ele_i) ==
-                               DBUS_TYPE_DICT_ENTRY) {
-                       DBusMessageIter dict_i;
-
-                       dbus_message_iter_recurse(&ele_i, &dict_i);
-
-                       gst_avdtp_sink_transport_parse_property(self, &dict_i);
-               }
-
-               if (!dbus_message_iter_next(&ele_i))
-                       break;
-       }
-
-       return gst_avdtp_sink_update_caps(self);
-
-fail:
-       dbus_message_unref(msg);
-       dbus_message_unref(reply);
-       return FALSE;
-
-}
-
-static gboolean gst_avdtp_sink_start(GstBaseSink *basesink)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-       gint sk;
-       gint err;
-
-       GST_INFO_OBJECT(self, "start");
-
-       self->data = g_new0(struct bluetooth_data, 1);
-
-       self->stream = NULL;
-       self->stream_caps = NULL;
-       self->mp3_using_crc = -1;
-       self->channel_mode = -1;
-
-       if (self->transport != NULL)
-               return gst_avdtp_sink_transport_get_properties(self);
-
-       self->watch_id = 0;
-
-       sk = bt_audio_service_open();
-       if (sk < 0) {
-               err = -errno;
-               GST_ERROR_OBJECT(self, "Cannot open connection to bt "
-                       "audio service: %s %d", strerror(-err), -err);
-               return FALSE;
-       }
-
-       self->server = g_io_channel_unix_new(sk);
-       g_io_channel_set_encoding(self->server, NULL, NULL);
-       self->watch_id = g_io_add_watch(self->server, G_IO_HUP | G_IO_ERR |
-                                       G_IO_NVAL, server_callback, self);
-
-       if (!gst_avdtp_sink_get_capabilities(self)) {
-               GST_ERROR_OBJECT(self, "failed to get capabilities "
-                               "from device");
-               goto failed;
-       }
-
-       return TRUE;
-
-failed:
-       bt_audio_service_close(sk);
-       return FALSE;
-}
-
-static gboolean gst_avdtp_sink_stream_start(GstAvdtpSink *self)
-{
-       gchar buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_start_stream_req *req = (void *) buf;
-       struct bt_start_stream_rsp *rsp = (void *) buf;
-       struct bt_new_stream_ind *ind = (void *) buf;
-       int err;
-
-       if (self->transport != NULL)
-               return gst_avdtp_sink_conf_recv_stream_fd(self);
-
-       memset(req, 0, sizeof(buf));
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_START_STREAM;
-       req->h.length = sizeof(*req);
-
-       err = gst_avdtp_sink_audioservice_send(self, &req->h);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error occurred while sending "
-                                       "start packet");
-               return FALSE;
-       }
-
-       rsp->h.length = sizeof(*rsp);
-       err = gst_avdtp_sink_audioservice_expect(self, &rsp->h,
-                                                       BT_START_STREAM);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while stream "
-                       "start confirmation");
-               return FALSE;
-       }
-
-       ind->h.length = sizeof(*ind);
-       err = gst_avdtp_sink_audioservice_expect(self, &ind->h,
-                                                       BT_NEW_STREAM);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while receiving "
-                       "stream filedescriptor");
-               return FALSE;
-       }
-
-       if (!gst_avdtp_sink_conf_recv_stream_fd(self))
-               return FALSE;
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_init_mp3_pkt_conf(
-               GstAvdtpSink *self, GstCaps *caps,
-               mpeg_capabilities_t *pkt)
-{
-       const GValue *value = NULL;
-       gint rate, layer;
-       const gchar *name;
-       GstStructure *structure = gst_caps_get_structure(caps, 0);
-
-       name = gst_structure_get_name(structure);
-
-       if (!(IS_MPEG_AUDIO(name))) {
-               GST_ERROR_OBJECT(self, "Unexpected format %s, "
-                               "was expecting mp3", name);
-               return FALSE;
-       }
-
-       /* layer */
-       value = gst_structure_get_value(structure, "layer");
-       layer = g_value_get_int(value);
-       if (layer == 1)
-               pkt->layer = BT_MPEG_LAYER_1;
-       else if (layer == 2)
-               pkt->layer = BT_MPEG_LAYER_2;
-       else if (layer == 3)
-               pkt->layer = BT_MPEG_LAYER_3;
-       else {
-               GST_ERROR_OBJECT(self, "Unexpected layer: %d", layer);
-               return FALSE;
-       }
-
-       /* crc */
-       if (self->mp3_using_crc != -1)
-               pkt->crc = self->mp3_using_crc;
-       else {
-               GST_ERROR_OBJECT(self, "No info about crc was received, "
-                               " can't proceed");
-               return FALSE;
-       }
-
-       /* channel mode */
-       if (self->channel_mode != -1)
-               pkt->channel_mode = self->channel_mode;
-       else {
-               GST_ERROR_OBJECT(self, "No info about channel mode "
-                               "received, can't proceed");
-               return FALSE;
-       }
-
-       /* mpf - we will only use the mandatory one */
-       pkt->mpf = 0;
-
-       value = gst_structure_get_value(structure, "rate");
-       rate = g_value_get_int(value);
-       if (rate == 44100)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_44100;
-       else if (rate == 48000)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_48000;
-       else if (rate == 32000)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_32000;
-       else if (rate == 24000)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_24000;
-       else if (rate == 22050)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_22050;
-       else if (rate == 16000)
-               pkt->frequency = BT_MPEG_SAMPLING_FREQ_16000;
-       else {
-               GST_ERROR_OBJECT(self, "Invalid rate while setting caps");
-               return FALSE;
-       }
-
-       /* vbr - we always say its vbr, we don't have how to know it */
-       pkt->bitrate = 0x8000;
-
-       return TRUE;
-}
-
-static gboolean gst_avdtp_sink_configure(GstAvdtpSink *self,
-                       GstCaps *caps)
-{
-       gchar buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_open_req *open_req = (void *) buf;
-       struct bt_open_rsp *open_rsp = (void *) buf;
-       struct bt_set_configuration_req *req = (void *) buf;
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-       gboolean ret;
-       gchar *temp;
-       GstStructure *structure;
-       codec_capabilities_t *codec = NULL;
-       int err;
-
-       temp = gst_caps_to_string(caps);
-       GST_DEBUG_OBJECT(self, "configuring device with caps: %s", temp);
-       g_free(temp);
-
-       /* Transport already configured */
-       if (self->transport != NULL)
-               return TRUE;
-
-       structure = gst_caps_get_structure(caps, 0);
-
-       if (gst_structure_has_name(structure, "audio/x-sbc"))
-               codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_SBC_SINK);
-       else if (gst_structure_has_name(structure, "audio/mpeg"))
-               codec = (void *) gst_avdtp_find_caps(self, BT_A2DP_MPEG12_SINK);
-
-       if (codec == NULL) {
-               GST_ERROR_OBJECT(self, "Couldn't parse caps "
-                               "to packet configuration");
-               return FALSE;
-       }
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       open_req->h.type = BT_REQUEST;
-       open_req->h.name = BT_OPEN;
-       open_req->h.length = sizeof(*open_req);
-
-       strncpy(open_req->destination, self->device, 18);
-       open_req->seid = codec->seid;
-       open_req->lock = BT_WRITE_LOCK;
-
-       err = gst_avdtp_sink_audioservice_send(self, &open_req->h);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error occurred while sending "
-                                       "open packet");
-               return FALSE;
-       }
-
-       open_rsp->h.length = sizeof(*open_rsp);
-       err = gst_avdtp_sink_audioservice_expect(self, &open_rsp->h,
-                                                               BT_OPEN);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while receiving device "
-                                       "confirmation");
-               return FALSE;
-       }
-
-       memset(req, 0, sizeof(buf));
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_SET_CONFIGURATION;
-       req->h.length = sizeof(*req);
-       memcpy(&req->codec, codec, sizeof(req->codec));
-
-       if (codec->type == BT_A2DP_SBC_SINK)
-               ret = gst_avdtp_sink_init_sbc_pkt_conf(self, caps,
-                               (void *) &req->codec);
-       else
-               ret = gst_avdtp_sink_init_mp3_pkt_conf(self, caps,
-                               (void *) &req->codec);
-
-       if (!ret) {
-               GST_ERROR_OBJECT(self, "Couldn't parse caps "
-                               "to packet configuration");
-               return FALSE;
-       }
-
-       req->h.length += req->codec.length - sizeof(req->codec);
-       err = gst_avdtp_sink_audioservice_send(self, &req->h);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error occurred while sending "
-                                       "configurarion packet");
-               return FALSE;
-       }
-
-       rsp->h.length = sizeof(*rsp);
-       err = gst_avdtp_sink_audioservice_expect(self, &rsp->h,
-                                                       BT_SET_CONFIGURATION);
-       if (err < 0) {
-               GST_ERROR_OBJECT(self, "Error while receiving device "
-                                       "confirmation");
-               return FALSE;
-       }
-
-       self->data->link_mtu = rsp->link_mtu;
-
-       return TRUE;
-}
-
-static GstFlowReturn gst_avdtp_sink_preroll(GstBaseSink *basesink,
-                                       GstBuffer *buffer)
-{
-       GstAvdtpSink *sink = GST_AVDTP_SINK(basesink);
-       gboolean ret;
-
-       GST_AVDTP_SINK_MUTEX_LOCK(sink);
-
-       ret = gst_avdtp_sink_stream_start(sink);
-
-       GST_AVDTP_SINK_MUTEX_UNLOCK(sink);
-
-       if (!ret)
-               return GST_FLOW_ERROR;
-
-       return GST_FLOW_OK;
-}
-
-static GstFlowReturn gst_avdtp_sink_render(GstBaseSink *basesink,
-                                       GstBuffer *buffer)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-       ssize_t ret;
-       int fd;
-
-       fd = g_io_channel_unix_get_fd(self->stream);
-
-       ret = write(fd, GST_BUFFER_DATA(buffer), GST_BUFFER_SIZE(buffer));
-       if (ret < 0) {
-               GST_ERROR_OBJECT(self, "Error while writting to socket: %s",
-                                                       strerror(errno));
-               return GST_FLOW_ERROR;
-       }
-
-       return GST_FLOW_OK;
-}
-
-static gboolean gst_avdtp_sink_unlock(GstBaseSink *basesink)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-
-       if (self->stream != NULL)
-               g_io_channel_flush(self->stream, NULL);
-
-       return TRUE;
-}
-
-static GstFlowReturn gst_avdtp_sink_buffer_alloc(GstBaseSink *basesink,
-                               guint64 offset, guint size, GstCaps *caps,
-                               GstBuffer **buf)
-{
-       GstAvdtpSink *self = GST_AVDTP_SINK(basesink);
-
-       *buf = gst_buffer_new_and_alloc(size);
-       if (!(*buf)) {
-               GST_ERROR_OBJECT(self, "buffer allocation failed");
-               return GST_FLOW_ERROR;
-       }
-
-       gst_buffer_set_caps(*buf, caps);
-
-       GST_BUFFER_OFFSET(*buf) = offset;
-
-       return GST_FLOW_OK;
-}
-
-static void gst_avdtp_sink_class_init(GstAvdtpSinkClass *klass)
-{
-       GObjectClass *object_class = G_OBJECT_CLASS(klass);
-       GstBaseSinkClass *basesink_class = GST_BASE_SINK_CLASS(klass);
-
-       parent_class = g_type_class_peek_parent(klass);
-
-       object_class->finalize = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_finalize);
-       object_class->set_property = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_set_property);
-       object_class->get_property = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_get_property);
-
-       basesink_class->start = GST_DEBUG_FUNCPTR(gst_avdtp_sink_start);
-       basesink_class->stop = GST_DEBUG_FUNCPTR(gst_avdtp_sink_stop);
-       basesink_class->render = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_render);
-       basesink_class->preroll = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_preroll);
-       basesink_class->unlock = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_unlock);
-       basesink_class->event = GST_DEBUG_FUNCPTR(
-                                       gst_avdtp_sink_event);
-
-       basesink_class->buffer_alloc =
-               GST_DEBUG_FUNCPTR(gst_avdtp_sink_buffer_alloc);
-
-       g_object_class_install_property(object_class, PROP_DEVICE,
-                                       g_param_spec_string("device", "Device",
-                                       "Bluetooth remote device address",
-                                       NULL, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_AUTOCONNECT,
-                                       g_param_spec_boolean("auto-connect",
-                                       "Auto-connect",
-                                       "Automatically attempt to connect "
-                                       "to device", DEFAULT_AUTOCONNECT,
-                                       G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_TRANSPORT,
-                                       g_param_spec_string("transport",
-                                       "Transport",
-                                       "Use configured transport",
-                                       NULL, G_PARAM_READWRITE));
-
-       GST_DEBUG_CATEGORY_INIT(avdtp_sink_debug, "avdtpsink", 0,
-                               "A2DP headset sink element");
-}
-
-static void gst_avdtp_sink_init(GstAvdtpSink *self,
-                       GstAvdtpSinkClass *klass)
-{
-       self->device = NULL;
-       self->transport = NULL;
-       self->data = NULL;
-
-       self->stream = NULL;
-
-       self->dev_caps = NULL;
-
-       self->autoconnect = DEFAULT_AUTOCONNECT;
-
-       self->sink_lock = g_mutex_new();
-
-       /* FIXME this is for not synchronizing with clock, should be tested
-        * with devices to see the behaviour
-       gst_base_sink_set_sync(GST_BASE_SINK(self), FALSE);
-       */
-}
-
-static int gst_avdtp_sink_audioservice_send(GstAvdtpSink *self,
-                                       const bt_audio_msg_header_t *msg)
-{
-       ssize_t written;
-       const char *type, *name;
-       uint16_t length;
-       int fd, err;
-
-       length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
-
-       fd = g_io_channel_unix_get_fd(self->server);
-
-       written = write(fd, msg, length);
-       if (written < 0) {
-               err = -errno;
-               GST_ERROR_OBJECT(self, "Error sending data to audio service:"
-                       " %s", strerror(-err));
-               return err;
-       }
-
-       type = bt_audio_strtype(msg->type);
-       name = bt_audio_strname(msg->name);
-
-       GST_DEBUG_OBJECT(self, "sent: %s -> %s", type, name);
-
-       return 0;
-}
-
-static int gst_avdtp_sink_audioservice_recv(GstAvdtpSink *self,
-                                               bt_audio_msg_header_t *inmsg)
-{
-       ssize_t bytes_read;
-       const char *type, *name;
-       uint16_t length;
-       int fd, err = 0;
-
-       length = inmsg->length ? inmsg->length : BT_SUGGESTED_BUFFER_SIZE;
-
-       fd = g_io_channel_unix_get_fd(self->server);
-
-       bytes_read = read(fd, inmsg, length);
-       if (bytes_read < 0) {
-               err = -errno;
-               GST_ERROR_OBJECT(self, "Error receiving data from "
-                               "audio service: %s", strerror(-err));
-               return err;
-       }
-
-       type = bt_audio_strtype(inmsg->type);
-       if (!type) {
-               err = -EINVAL;
-               GST_ERROR_OBJECT(self, "Bogus message type %d "
-                               "received from audio service",
-                               inmsg->type);
-       }
-
-       name = bt_audio_strname(inmsg->name);
-       if (!name) {
-               err = -EINVAL;
-               GST_ERROR_OBJECT(self, "Bogus message name %d "
-                               "received from audio service",
-                               inmsg->name);
-       }
-
-       if (inmsg->type == BT_ERROR) {
-               bt_audio_error_t *msg = (void *) inmsg;
-               err = -EINVAL;
-               GST_ERROR_OBJECT(self, "%s failed : "
-                                       "%s(%d)",
-                                       name,
-                                       strerror(msg->posix_errno),
-                                       msg->posix_errno);
-       }
-
-       GST_DEBUG_OBJECT(self, "received: %s <- %s", type, name);
-
-       return err;
-}
-
-static int gst_avdtp_sink_audioservice_expect(GstAvdtpSink *self,
-                                               bt_audio_msg_header_t *outmsg,
-                                               guint8 expected_name)
-{
-       int err;
-
-       err = gst_avdtp_sink_audioservice_recv(self, outmsg);
-       if (err < 0)
-               return err;
-
-       if (outmsg->name != expected_name)
-               return -EINVAL;
-
-       return 0;
-}
-
-gboolean gst_avdtp_sink_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "avdtpsink", GST_RANK_NONE,
-                                                       GST_TYPE_AVDTP_SINK);
-}
-
-
-/* public functions */
-GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink)
-{
-       if (sink->dev_caps == NULL)
-               return NULL;
-
-       return gst_caps_copy(sink->dev_caps);
-}
-
-gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *self,
-                       GstCaps *caps)
-{
-       gboolean ret;
-
-       GST_DEBUG_OBJECT(self, "setting device caps");
-       GST_AVDTP_SINK_MUTEX_LOCK(self);
-       ret = gst_avdtp_sink_configure(self, caps);
-
-       if (self->stream_caps)
-               gst_caps_unref(self->stream_caps);
-       self->stream_caps = gst_caps_ref(caps);
-
-       GST_AVDTP_SINK_MUTEX_UNLOCK(self);
-
-       return ret;
-}
-
-guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink)
-{
-       return sink->data->link_mtu;
-}
-
-void gst_avdtp_sink_set_device(GstAvdtpSink *self, const gchar *dev)
-{
-       if (self->device != NULL)
-               g_free(self->device);
-
-       GST_LOG_OBJECT(self, "Setting device: %s", dev);
-       self->device = g_strdup(dev);
-}
-
-void gst_avdtp_sink_set_transport(GstAvdtpSink *self, const gchar *trans)
-{
-       if (self->transport != NULL)
-               g_free(self->transport);
-
-       GST_LOG_OBJECT(self, "Setting transport: %s", trans);
-       self->transport = g_strdup(trans);
-}
-
-gchar *gst_avdtp_sink_get_device(GstAvdtpSink *self)
-{
-       return g_strdup(self->device);
-}
-
-gchar *gst_avdtp_sink_get_transport(GstAvdtpSink *self)
-{
-       return g_strdup(self->transport);
-}
-
-void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc)
-{
-       gint new_crc;
-
-       new_crc = crc ? CRC_PROTECTED : CRC_UNPROTECTED;
-
-       /* test if we already received a different crc */
-       if (self->mp3_using_crc != -1 && new_crc != self->mp3_using_crc) {
-               GST_WARNING_OBJECT(self, "crc changed during stream");
-               return;
-       }
-       self->mp3_using_crc = new_crc;
-
-}
-
-void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self,
-                       const gchar *mode)
-{
-       gint new_mode;
-
-       new_mode = gst_avdtp_sink_get_channel_mode(mode);
-
-       if (self->channel_mode != -1 && new_mode != self->channel_mode) {
-               GST_WARNING_OBJECT(self, "channel mode changed during stream");
-               return;
-       }
-
-       self->channel_mode = new_mode;
-       if (self->channel_mode == -1)
-               GST_WARNING_OBJECT(self, "Received invalid channel "
-                               "mode: %s", mode);
-}
diff --git a/audio/gstavdtpsink.h b/audio/gstavdtpsink.h
deleted file mode 100644 (file)
index c4e5645..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifndef __GST_AVDTP_SINK_H
-#define __GST_AVDTP_SINK_H
-
-#include <gst/gst.h>
-#include <gst/base/gstbasesink.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_AVDTP_SINK \
-       (gst_avdtp_sink_get_type())
-#define GST_AVDTP_SINK(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_AVDTP_SINK,\
-               GstAvdtpSink))
-#define GST_AVDTP_SINK_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_AVDTP_SINK,\
-               GstAvdtpSinkClass))
-#define GST_IS_AVDTP_SINK(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_AVDTP_SINK))
-#define GST_IS_AVDTP_SINK_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_AVDTP_SINK))
-
-typedef struct _GstAvdtpSink GstAvdtpSink;
-typedef struct _GstAvdtpSinkClass GstAvdtpSinkClass;
-
-struct bluetooth_data;
-
-struct _GstAvdtpSink {
-       GstBaseSink sink;
-
-       gchar *device;
-       gchar *transport;
-       GIOChannel *stream;
-
-       struct bluetooth_data *data;
-       gboolean autoconnect;
-       GIOChannel *server;
-
-       /* mp3 stream data (outside caps data)*/
-       gint mp3_using_crc;
-       gint channel_mode;
-
-       /* stream connection data */
-       GstCaps *stream_caps;
-
-       GstCaps *dev_caps;
-
-       GMutex *sink_lock;
-
-       guint watch_id;
-};
-
-struct _GstAvdtpSinkClass {
-       GstBaseSinkClass parent_class;
-};
-
-GType gst_avdtp_sink_get_type(void);
-
-GstCaps *gst_avdtp_sink_get_device_caps(GstAvdtpSink *sink);
-gboolean gst_avdtp_sink_set_device_caps(GstAvdtpSink *sink,
-                       GstCaps *caps);
-
-guint gst_avdtp_sink_get_link_mtu(GstAvdtpSink *sink);
-
-void gst_avdtp_sink_set_device(GstAvdtpSink *sink,
-               const gchar* device);
-
-void gst_avdtp_sink_set_transport(GstAvdtpSink *sink,
-               const gchar *transport);
-
-gchar *gst_avdtp_sink_get_device(GstAvdtpSink *sink);
-
-gchar *gst_avdtp_sink_get_transport(GstAvdtpSink *sink);
-
-gboolean gst_avdtp_sink_plugin_init(GstPlugin *plugin);
-
-void gst_avdtp_sink_set_crc(GstAvdtpSink *self, gboolean crc);
-
-void gst_avdtp_sink_set_channel_mode(GstAvdtpSink *self,
-                       const gchar *mode);
-
-
-G_END_DECLS
-
-#endif /* __GST_AVDTP_SINK_H */
diff --git a/audio/gstbluetooth.c b/audio/gstbluetooth.c
deleted file mode 100644 (file)
index 9930820..0000000
+++ /dev/null
@@ -1,109 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include <gst/gst.h>
-
-#include "gstsbcutil.h"
-#include <sbc.h>
-
-#include "gstsbcenc.h"
-#include "gstsbcdec.h"
-#include "gstsbcparse.h"
-#include "gstavdtpsink.h"
-#include "gsta2dpsink.h"
-#include "gstrtpsbcpay.h"
-
-static GstStaticCaps sbc_caps = GST_STATIC_CAPS("audio/x-sbc");
-
-#define SBC_CAPS (gst_static_caps_get(&sbc_caps))
-
-static void sbc_typefind(GstTypeFind *tf, gpointer ignore)
-{
-       GstCaps *caps;
-       guint8 *aux;
-       sbc_t sbc;
-       guint8 *data = gst_type_find_peek(tf, 0, 32);
-
-       if (data == NULL)
-               return;
-
-       if (sbc_init(&sbc, 0) < 0)
-               return;
-
-       aux = g_new(guint8, 32);
-       memcpy(aux, data, 32);
-       if (sbc_parse(&sbc, aux, 32) < 0)
-               goto done;
-
-       caps = gst_sbc_parse_caps_from_sbc(&sbc);
-       gst_type_find_suggest(tf, GST_TYPE_FIND_POSSIBLE, caps);
-       gst_caps_unref(caps);
-
-done:
-       g_free(aux);
-       sbc_finish(&sbc);
-}
-
-static gchar *sbc_exts[] = { "sbc", NULL };
-
-static gboolean plugin_init(GstPlugin *plugin)
-{
-       GST_INFO("Bluetooth plugin %s", VERSION);
-
-       if (gst_type_find_register(plugin, "sbc",
-                       GST_RANK_PRIMARY, sbc_typefind, sbc_exts,
-                                       SBC_CAPS, NULL, NULL) == FALSE)
-               return FALSE;
-
-       if (!gst_sbc_enc_plugin_init(plugin))
-               return FALSE;
-
-       if (!gst_sbc_dec_plugin_init(plugin))
-               return FALSE;
-
-       if (!gst_sbc_parse_plugin_init(plugin))
-               return FALSE;
-
-       if (!gst_avdtp_sink_plugin_init(plugin))
-               return FALSE;
-
-       if (!gst_a2dp_sink_plugin_init(plugin))
-               return FALSE;
-
-       if (!gst_rtp_sbc_pay_plugin_init(plugin))
-               return FALSE;
-
-       return TRUE;
-}
-
-extern GstPluginDesc gst_plugin_desc __attribute__ ((visibility("default")));
-
-GST_PLUGIN_DEFINE(GST_VERSION_MAJOR, GST_VERSION_MINOR,
-       "bluetooth", "Bluetooth plugin library",
-       plugin_init, VERSION, "LGPL", "BlueZ", "http://www.bluez.org/")
diff --git a/audio/gstrtpsbcpay.c b/audio/gstrtpsbcpay.c
deleted file mode 100644 (file)
index 11aa733..0000000
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include "gstpragma.h"
-#include "gstrtpsbcpay.h"
-#include <math.h>
-#include <string.h>
-
-#define RTP_SBC_PAYLOAD_HEADER_SIZE 1
-#define DEFAULT_MIN_FRAMES 0
-#define RTP_SBC_HEADER_TOTAL (12 + RTP_SBC_PAYLOAD_HEADER_SIZE)
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct rtp_payload {
-       guint8 frame_count:4;
-       guint8 rfa0:1;
-       guint8 is_last_fragment:1;
-       guint8 is_first_fragment:1;
-       guint8 is_fragmented:1;
-} __attribute__ ((packed));
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct rtp_payload {
-       guint8 is_fragmented:1;
-       guint8 is_first_fragment:1;
-       guint8 is_last_fragment:1;
-       guint8 rfa0:1;
-       guint8 frame_count:4;
-} __attribute__ ((packed));
-
-#else
-#error "Unknown byte order"
-#endif
-
-enum {
-       PROP_0,
-       PROP_MIN_FRAMES
-};
-
-GST_DEBUG_CATEGORY_STATIC(gst_rtp_sbc_pay_debug);
-#define GST_CAT_DEFAULT gst_rtp_sbc_pay_debug
-
-GST_BOILERPLATE(GstRtpSBCPay, gst_rtp_sbc_pay, GstBaseRTPPayload,
-               GST_TYPE_BASE_RTP_PAYLOAD);
-
-static const GstElementDetails gst_rtp_sbc_pay_details =
-       GST_ELEMENT_DETAILS("RTP packet payloader",
-                               "Codec/Payloader/Network",
-                               "Payload SBC audio as RTP packets",
-                               "Thiago Sousa Santos "
-                               "<thiagoss@lcc.ufcg.edu.br>");
-
-static GstStaticPadTemplate gst_rtp_sbc_pay_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-sbc, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
-                               "blocks = (int) { 4, 8, 12, 16 }, "
-                               "subbands = (int) { 4, 8 }, "
-                               "allocation = (string) { \"snr\", \"loudness\" }, "
-                               "bitpool = (int) [ 2, 64 ]")
-       );
-
-static GstStaticPadTemplate gst_rtp_sbc_pay_src_factory =
-       GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS(
-                       "application/x-rtp, "
-                       "media = (string) \"audio\","
-                       "payload = (int) " GST_RTP_PAYLOAD_DYNAMIC_STRING ", "
-                       "clock-rate = (int) { 16000, 32000, 44100, 48000 },"
-                       "encoding-name = (string) \"SBC\"")
-       );
-
-static void gst_rtp_sbc_pay_set_property(GObject *object, guint prop_id,
-                               const GValue *value, GParamSpec *pspec);
-static void gst_rtp_sbc_pay_get_property(GObject *object, guint prop_id,
-                               GValue *value, GParamSpec *pspec);
-
-static gint gst_rtp_sbc_pay_get_frame_len(gint subbands, gint channels,
-               gint blocks, gint bitpool, const gchar *channel_mode)
-{
-       gint len;
-       gint join;
-
-       len = 4 + (4 * subbands * channels)/8;
-
-       if (strcmp(channel_mode, "mono") == 0 ||
-               strcmp(channel_mode, "dual") == 0)
-               len += ((blocks * channels * bitpool) + 7) / 8;
-       else {
-               join = strcmp(channel_mode, "joint") == 0 ? 1 : 0;
-               len += ((join * subbands + blocks * bitpool) + 7) / 8;
-       }
-
-       return len;
-}
-
-static gboolean gst_rtp_sbc_pay_set_caps(GstBaseRTPPayload *payload,
-                       GstCaps *caps)
-{
-       GstRtpSBCPay *sbcpay;
-       gint rate, subbands, channels, blocks, bitpool;
-       gint frame_len;
-       const gchar *channel_mode;
-       GstStructure *structure;
-
-       sbcpay = GST_RTP_SBC_PAY(payload);
-
-       structure = gst_caps_get_structure(caps, 0);
-       if (!gst_structure_get_int(structure, "rate", &rate))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "channels", &channels))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "blocks", &blocks))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "bitpool", &bitpool))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "subbands", &subbands))
-               return FALSE;
-
-       channel_mode = gst_structure_get_string(structure, "mode");
-       if (!channel_mode)
-               return FALSE;
-
-       frame_len = gst_rtp_sbc_pay_get_frame_len(subbands, channels, blocks,
-                               bitpool, channel_mode);
-
-       sbcpay->frame_length = frame_len;
-
-       gst_basertppayload_set_options(payload, "audio", TRUE, "SBC", rate);
-
-       GST_DEBUG_OBJECT(payload, "calculated frame length: %d ", frame_len);
-
-       return gst_basertppayload_set_outcaps(payload, NULL);
-}
-
-static GstFlowReturn gst_rtp_sbc_pay_flush_buffers(GstRtpSBCPay *sbcpay)
-{
-       guint available;
-       guint max_payload;
-       GstBuffer *outbuf;
-       guint8 *payload_data;
-       guint frame_count;
-       guint payload_length;
-       struct rtp_payload *payload;
-
-       if (sbcpay->frame_length == 0) {
-               GST_ERROR_OBJECT(sbcpay, "Frame length is 0");
-               return GST_FLOW_ERROR;
-       }
-
-       available = gst_adapter_available(sbcpay->adapter);
-
-       max_payload = gst_rtp_buffer_calc_payload_len(
-               GST_BASE_RTP_PAYLOAD_MTU(sbcpay) - RTP_SBC_PAYLOAD_HEADER_SIZE,
-               0, 0);
-
-       max_payload = MIN(max_payload, available);
-       frame_count = max_payload / sbcpay->frame_length;
-       payload_length = frame_count * sbcpay->frame_length;
-       if (payload_length == 0) /* Nothing to send */
-               return GST_FLOW_OK;
-
-       outbuf = gst_rtp_buffer_new_allocate(payload_length +
-                       RTP_SBC_PAYLOAD_HEADER_SIZE, 0, 0);
-
-       gst_rtp_buffer_set_payload_type(outbuf,
-                       GST_BASE_RTP_PAYLOAD_PT(sbcpay));
-
-       payload_data = gst_rtp_buffer_get_payload(outbuf);
-       payload = (struct rtp_payload *) payload_data;
-       memset(payload, 0, sizeof(struct rtp_payload));
-       payload->frame_count = frame_count;
-
-       gst_adapter_copy(sbcpay->adapter, payload_data +
-                       RTP_SBC_PAYLOAD_HEADER_SIZE, 0, payload_length);
-       gst_adapter_flush(sbcpay->adapter, payload_length);
-
-       GST_BUFFER_TIMESTAMP(outbuf) = sbcpay->timestamp;
-       GST_DEBUG_OBJECT(sbcpay, "Pushing %d bytes", payload_length);
-
-       return gst_basertppayload_push(GST_BASE_RTP_PAYLOAD(sbcpay), outbuf);
-}
-
-static GstFlowReturn gst_rtp_sbc_pay_handle_buffer(GstBaseRTPPayload *payload,
-                       GstBuffer *buffer)
-{
-       GstRtpSBCPay *sbcpay;
-       guint available;
-
-       /* FIXME check for negotiation */
-
-       sbcpay = GST_RTP_SBC_PAY(payload);
-       sbcpay->timestamp = GST_BUFFER_TIMESTAMP(buffer);
-
-       gst_adapter_push(sbcpay->adapter, buffer);
-
-       available = gst_adapter_available(sbcpay->adapter);
-       if (available + RTP_SBC_HEADER_TOTAL >=
-                               GST_BASE_RTP_PAYLOAD_MTU(sbcpay) ||
-                       (available >
-                               (sbcpay->min_frames * sbcpay->frame_length)))
-               return gst_rtp_sbc_pay_flush_buffers(sbcpay);
-
-       return GST_FLOW_OK;
-}
-
-static gboolean gst_rtp_sbc_pay_handle_event(GstPad *pad,
-                               GstEvent *event)
-{
-       GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(GST_PAD_PARENT(pad));
-
-       switch (GST_EVENT_TYPE(event)) {
-       case GST_EVENT_EOS:
-               gst_rtp_sbc_pay_flush_buffers(sbcpay);
-               break;
-       default:
-               break;
-       }
-
-       return FALSE;
-}
-
-static void gst_rtp_sbc_pay_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&gst_rtp_sbc_pay_sink_factory));
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&gst_rtp_sbc_pay_src_factory));
-
-       gst_element_class_set_details(element_class, &gst_rtp_sbc_pay_details);
-}
-
-static void gst_rtp_sbc_pay_finalize(GObject *object)
-{
-       GstRtpSBCPay *sbcpay = GST_RTP_SBC_PAY(object);
-       g_object_unref(sbcpay->adapter);
-
-       GST_CALL_PARENT(G_OBJECT_CLASS, finalize, (object));
-}
-
-static void gst_rtp_sbc_pay_class_init(GstRtpSBCPayClass *klass)
-{
-       GObjectClass *gobject_class;
-       GstBaseRTPPayloadClass *payload_class =
-               GST_BASE_RTP_PAYLOAD_CLASS(klass);
-
-       gobject_class = G_OBJECT_CLASS(klass);
-       parent_class = g_type_class_peek_parent(klass);
-
-       gobject_class->finalize = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_finalize);
-       gobject_class->set_property = GST_DEBUG_FUNCPTR(
-                       gst_rtp_sbc_pay_set_property);
-       gobject_class->get_property = GST_DEBUG_FUNCPTR(
-                       gst_rtp_sbc_pay_get_property);
-
-       payload_class->set_caps = GST_DEBUG_FUNCPTR(gst_rtp_sbc_pay_set_caps);
-       payload_class->handle_buffer = GST_DEBUG_FUNCPTR(
-                       gst_rtp_sbc_pay_handle_buffer);
-       payload_class->handle_event = GST_DEBUG_FUNCPTR(
-                       gst_rtp_sbc_pay_handle_event);
-
-       /* properties */
-       g_object_class_install_property(G_OBJECT_CLASS(klass),
-               PROP_MIN_FRAMES,
-               g_param_spec_int("min-frames", "minimum frame number",
-               "Minimum quantity of frames to send in one packet "
-               "(-1 for maximum allowed by the mtu)",
-               -1, G_MAXINT, DEFAULT_MIN_FRAMES, G_PARAM_READWRITE));
-
-       GST_DEBUG_CATEGORY_INIT(gst_rtp_sbc_pay_debug, "rtpsbcpay", 0,
-                               "RTP SBC payloader");
-}
-
-static void gst_rtp_sbc_pay_set_property(GObject *object, guint prop_id,
-                                       const GValue *value, GParamSpec *pspec)
-{
-       GstRtpSBCPay *sbcpay;
-
-       sbcpay = GST_RTP_SBC_PAY(object);
-
-       switch (prop_id) {
-       case PROP_MIN_FRAMES:
-               sbcpay->min_frames = g_value_get_int(value);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-       break;
-       }
-}
-
-static void gst_rtp_sbc_pay_get_property(GObject *object, guint prop_id,
-                                       GValue *value, GParamSpec *pspec)
-{
-       GstRtpSBCPay *sbcpay;
-
-       sbcpay = GST_RTP_SBC_PAY(object);
-
-       switch (prop_id) {
-       case PROP_MIN_FRAMES:
-               g_value_set_int(value, sbcpay->min_frames);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-       break;
-       }
-}
-
-static void gst_rtp_sbc_pay_init(GstRtpSBCPay *self, GstRtpSBCPayClass *klass)
-{
-       self->adapter = gst_adapter_new();
-       self->frame_length = 0;
-       self->timestamp = 0;
-
-       self->min_frames = DEFAULT_MIN_FRAMES;
-}
-
-gboolean gst_rtp_sbc_pay_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "rtpsbcpay", GST_RANK_NONE,
-                                                       GST_TYPE_RTP_SBC_PAY);
-}
diff --git a/audio/gstrtpsbcpay.h b/audio/gstrtpsbcpay.h
deleted file mode 100644 (file)
index 398de82..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gst/gst.h>
-#include <gst/rtp/gstbasertppayload.h>
-#include <gst/base/gstadapter.h>
-#include <gst/rtp/gstrtpbuffer.h>
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_RTP_SBC_PAY \
-       (gst_rtp_sbc_pay_get_type())
-#define GST_RTP_SBC_PAY(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_RTP_SBC_PAY,\
-               GstRtpSBCPay))
-#define GST_RTP_SBC_PAY_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_RTP_SBC_PAY,\
-               GstRtpSBCPayClass))
-#define GST_IS_RTP_SBC_PAY(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_RTP_SBC_PAY))
-#define GST_IS_RTP_SBC_PAY_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_RTP_SBC_PAY))
-
-typedef struct _GstRtpSBCPay GstRtpSBCPay;
-typedef struct _GstRtpSBCPayClass GstRtpSBCPayClass;
-
-struct _GstRtpSBCPay {
-       GstBaseRTPPayload base;
-
-       GstAdapter *adapter;
-       GstClockTime timestamp;
-
-       guint frame_length;
-
-       guint min_frames;
-};
-
-struct _GstRtpSBCPayClass {
-       GstBaseRTPPayloadClass parent_class;
-};
-
-GType gst_rtp_sbc_pay_get_type(void);
-
-gboolean gst_rtp_sbc_pay_plugin_init (GstPlugin * plugin);
-
-G_END_DECLS
diff --git a/audio/gstsbcdec.c b/audio/gstsbcdec.c
deleted file mode 100644 (file)
index c52834e..0000000
+++ /dev/null
@@ -1,221 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include "gstpragma.h"
-#include "gstsbcutil.h"
-#include "gstsbcdec.h"
-
-GST_DEBUG_CATEGORY_STATIC(sbc_dec_debug);
-#define GST_CAT_DEFAULT sbc_dec_debug
-
-GST_BOILERPLATE(GstSbcDec, gst_sbc_dec, GstElement, GST_TYPE_ELEMENT);
-
-static const GstElementDetails sbc_dec_details =
-       GST_ELEMENT_DETAILS("Bluetooth SBC decoder",
-                               "Codec/Decoder/Audio",
-                               "Decode a SBC audio stream",
-                               "Marcel Holtmann <marcel@holtmann.org>");
-
-static GstStaticPadTemplate sbc_dec_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-sbc"));
-
-static GstStaticPadTemplate sbc_dec_src_factory =
-       GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-raw-int, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "endianness = (int) BYTE_ORDER, "
-                               "signed = (boolean) true, "
-                               "width = (int) 16, "
-                               "depth = (int) 16"));
-
-static GstFlowReturn sbc_dec_chain(GstPad *pad, GstBuffer *buffer)
-{
-       GstSbcDec *dec = GST_SBC_DEC(gst_pad_get_parent(pad));
-       GstFlowReturn res = GST_FLOW_OK;
-       guint size, codesize, offset = 0;
-       guint8 *data;
-
-       codesize = sbc_get_codesize(&dec->sbc);
-
-       if (dec->buffer) {
-               GstBuffer *temp = buffer;
-               buffer = gst_buffer_span(dec->buffer, 0, buffer,
-                       GST_BUFFER_SIZE(dec->buffer) + GST_BUFFER_SIZE(buffer));
-               gst_buffer_unref(temp);
-               gst_buffer_unref(dec->buffer);
-               dec->buffer = NULL;
-       }
-
-       data = GST_BUFFER_DATA(buffer);
-       size = GST_BUFFER_SIZE(buffer);
-
-       while (offset < size) {
-               GstBuffer *output;
-               GstPadTemplate *template;
-               GstCaps *caps;
-               int consumed;
-
-               res = gst_pad_alloc_buffer_and_set_caps(dec->srcpad,
-                                               GST_BUFFER_OFFSET_NONE,
-                                               codesize, NULL, &output);
-
-               if (res != GST_FLOW_OK)
-                       goto done;
-
-               consumed = sbc_decode(&dec->sbc, data + offset, size - offset,
-                                       GST_BUFFER_DATA(output), codesize,
-                                       NULL);
-               if (consumed <= 0)
-                       break;
-
-               /* we will reuse the same caps object */
-               if (dec->outcaps == NULL) {
-                       caps = gst_caps_new_simple("audio/x-raw-int",
-                                       "rate", G_TYPE_INT,
-                                       gst_sbc_parse_rate_from_sbc(
-                                               dec->sbc.frequency),
-                                       "channels", G_TYPE_INT,
-                                       gst_sbc_get_channel_number(
-                                               dec->sbc.mode),
-                                       NULL);
-
-                       template = gst_static_pad_template_get(&sbc_dec_src_factory);
-
-                       dec->outcaps = gst_caps_intersect(caps,
-                                               gst_pad_template_get_caps(template));
-
-                       gst_caps_unref(caps);
-               }
-
-               gst_buffer_set_caps(output, dec->outcaps);
-
-               /* FIXME get a real timestamp */
-               GST_BUFFER_TIMESTAMP(output) = GST_CLOCK_TIME_NONE;
-
-               res = gst_pad_push(dec->srcpad, output);
-               if (res != GST_FLOW_OK)
-                       goto done;
-
-               offset += consumed;
-       }
-
-       if (offset < size)
-               dec->buffer = gst_buffer_create_sub(buffer,
-                                                       offset, size - offset);
-
-done:
-       gst_buffer_unref(buffer);
-       gst_object_unref(dec);
-
-       return res;
-}
-
-static GstStateChangeReturn sbc_dec_change_state(GstElement *element,
-                                               GstStateChange transition)
-{
-       GstSbcDec *dec = GST_SBC_DEC(element);
-
-       switch (transition) {
-       case GST_STATE_CHANGE_READY_TO_PAUSED:
-               GST_DEBUG("Setup subband codec");
-               if (dec->buffer) {
-                       gst_buffer_unref(dec->buffer);
-                       dec->buffer = NULL;
-               }
-               sbc_init(&dec->sbc, 0);
-               dec->outcaps = NULL;
-               break;
-
-       case GST_STATE_CHANGE_PAUSED_TO_READY:
-               GST_DEBUG("Finish subband codec");
-               if (dec->buffer) {
-                       gst_buffer_unref(dec->buffer);
-                       dec->buffer = NULL;
-               }
-               sbc_finish(&dec->sbc);
-               if (dec->outcaps) {
-                       gst_caps_unref(dec->outcaps);
-                       dec->outcaps = NULL;
-               }
-               break;
-
-       default:
-               break;
-       }
-
-       return parent_class->change_state(element, transition);
-}
-
-static void gst_sbc_dec_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_dec_sink_factory));
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_dec_src_factory));
-
-       gst_element_class_set_details(element_class, &sbc_dec_details);
-}
-
-static void gst_sbc_dec_class_init(GstSbcDecClass *klass)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
-
-       parent_class = g_type_class_peek_parent(klass);
-
-       element_class->change_state = GST_DEBUG_FUNCPTR(sbc_dec_change_state);
-
-       GST_DEBUG_CATEGORY_INIT(sbc_dec_debug, "sbcdec", 0,
-                                               "SBC decoding element");
-}
-
-static void gst_sbc_dec_init(GstSbcDec *self, GstSbcDecClass *klass)
-{
-       self->sinkpad = gst_pad_new_from_static_template(
-                       &sbc_dec_sink_factory, "sink");
-       gst_pad_set_chain_function(self->sinkpad, GST_DEBUG_FUNCPTR(
-                       sbc_dec_chain));
-       gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
-
-       self->srcpad = gst_pad_new_from_static_template(
-                       &sbc_dec_src_factory, "src");
-       gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
-
-       self->outcaps = NULL;
-}
-
-gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "sbcdec", GST_RANK_PRIMARY,
-                                                       GST_TYPE_SBC_DEC);
-}
diff --git a/audio/gstsbcdec.h b/audio/gstsbcdec.h
deleted file mode 100644 (file)
index c77feae..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gst/gst.h>
-
-#include "sbc.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_SBC_DEC \
-       (gst_sbc_dec_get_type())
-#define GST_SBC_DEC(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_DEC,GstSbcDec))
-#define GST_SBC_DEC_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_DEC,GstSbcDecClass))
-#define GST_IS_SBC_DEC(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_DEC))
-#define GST_IS_SBC_DEC_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_DEC))
-
-typedef struct _GstSbcDec GstSbcDec;
-typedef struct _GstSbcDecClass GstSbcDecClass;
-
-struct _GstSbcDec {
-       GstElement element;
-
-       GstPad *sinkpad;
-       GstPad *srcpad;
-
-       GstBuffer *buffer;
-
-       /* caps for outgoing buffers */
-       GstCaps *outcaps;
-
-       sbc_t sbc;
-};
-
-struct _GstSbcDecClass {
-       GstElementClass parent_class;
-};
-
-GType gst_sbc_dec_get_type(void);
-
-gboolean gst_sbc_dec_plugin_init(GstPlugin *plugin);
-
-G_END_DECLS
diff --git a/audio/gstsbcenc.c b/audio/gstsbcenc.c
deleted file mode 100644 (file)
index 8948371..0000000
+++ /dev/null
@@ -1,601 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include "gstpragma.h"
-#include "gstsbcutil.h"
-#include "gstsbcenc.h"
-
-#define SBC_ENC_DEFAULT_MODE SBC_MODE_AUTO
-#define SBC_ENC_DEFAULT_BLOCKS 0
-#define SBC_ENC_DEFAULT_SUB_BANDS 0
-#define SBC_ENC_DEFAULT_ALLOCATION SBC_AM_AUTO
-#define SBC_ENC_DEFAULT_RATE 0
-#define SBC_ENC_DEFAULT_CHANNELS 0
-
-#define SBC_ENC_BITPOOL_AUTO 1
-#define SBC_ENC_BITPOOL_MIN 2
-#define SBC_ENC_BITPOOL_MIN_STR "2"
-#define SBC_ENC_BITPOOL_MAX 64
-#define SBC_ENC_BITPOOL_MAX_STR "64"
-
-GST_DEBUG_CATEGORY_STATIC(sbc_enc_debug);
-#define GST_CAT_DEFAULT sbc_enc_debug
-
-#define GST_TYPE_SBC_MODE (gst_sbc_mode_get_type())
-
-static GType gst_sbc_mode_get_type(void)
-{
-       static GType sbc_mode_type = 0;
-       static GEnumValue sbc_modes[] = {
-               {  SBC_MODE_MONO,               "Mono",         "mono"  },
-               {  SBC_MODE_DUAL_CHANNEL,       "Dual Channel", "dual"  },
-               {  SBC_MODE_STEREO,             "Stereo",       "stereo"},
-               {  SBC_MODE_JOINT_STEREO,       "Joint Stereo", "joint" },
-               {  SBC_MODE_AUTO,               "Auto",         "auto"  },
-               { -1, NULL, NULL}
-       };
-
-       if (!sbc_mode_type)
-               sbc_mode_type = g_enum_register_static("GstSbcMode", sbc_modes);
-
-       return sbc_mode_type;
-}
-
-#define GST_TYPE_SBC_ALLOCATION (gst_sbc_allocation_get_type())
-
-static GType gst_sbc_allocation_get_type(void)
-{
-       static GType sbc_allocation_type = 0;
-       static GEnumValue sbc_allocations[] = {
-               { SBC_AM_LOUDNESS,      "Loudness",     "loudness" },
-               { SBC_AM_SNR,           "SNR",          "snr" },
-               { SBC_AM_AUTO,          "Auto",         "auto" },
-               { -1, NULL, NULL}
-       };
-
-       if (!sbc_allocation_type)
-               sbc_allocation_type = g_enum_register_static(
-                               "GstSbcAllocation", sbc_allocations);
-
-       return sbc_allocation_type;
-}
-
-#define GST_TYPE_SBC_BLOCKS (gst_sbc_blocks_get_type())
-
-static GType gst_sbc_blocks_get_type(void)
-{
-       static GType sbc_blocks_type = 0;
-       static GEnumValue sbc_blocks[] = {
-               { 0,    "Auto",         "auto" },
-               { 4,    "4",            "4" },
-               { 8,    "8",            "8" },
-               { 12,   "12",           "12" },
-               { 16,   "16",           "16" },
-               { -1, NULL, NULL}
-       };
-
-       if (!sbc_blocks_type)
-               sbc_blocks_type = g_enum_register_static(
-                               "GstSbcBlocks", sbc_blocks);
-
-       return sbc_blocks_type;
-}
-
-#define GST_TYPE_SBC_SUBBANDS (gst_sbc_subbands_get_type())
-
-static GType gst_sbc_subbands_get_type(void)
-{
-       static GType sbc_subbands_type = 0;
-       static GEnumValue sbc_subbands[] = {
-               { 0,    "Auto",         "auto" },
-               { 4,    "4 subbands",   "4" },
-               { 8,    "8 subbands",   "8" },
-               { -1, NULL, NULL}
-       };
-
-       if (!sbc_subbands_type)
-               sbc_subbands_type = g_enum_register_static(
-                               "GstSbcSubbands", sbc_subbands);
-
-       return sbc_subbands_type;
-}
-
-enum {
-       PROP_0,
-       PROP_MODE,
-       PROP_ALLOCATION,
-       PROP_BLOCKS,
-       PROP_SUBBANDS,
-       PROP_BITPOOL
-};
-
-GST_BOILERPLATE(GstSbcEnc, gst_sbc_enc, GstElement, GST_TYPE_ELEMENT);
-
-static const GstElementDetails sbc_enc_details =
-       GST_ELEMENT_DETAILS("Bluetooth SBC encoder",
-                               "Codec/Encoder/Audio",
-                               "Encode a SBC audio stream",
-                               "Marcel Holtmann <marcel@holtmann.org>");
-
-static GstStaticPadTemplate sbc_enc_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-raw-int, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "endianness = (int) BYTE_ORDER, "
-                               "signed = (boolean) true, "
-                               "width = (int) 16, "
-                               "depth = (int) 16"));
-
-static GstStaticPadTemplate sbc_enc_src_factory =
-       GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-sbc, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
-                               "blocks = (int) { 4, 8, 12, 16 }, "
-                               "subbands = (int) { 4, 8 }, "
-                               "allocation = (string) { \"snr\", \"loudness\" }, "
-                               "bitpool = (int) [ " SBC_ENC_BITPOOL_MIN_STR
-                               ", " SBC_ENC_BITPOOL_MAX_STR " ]"));
-
-gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps);
-
-static GstCaps *sbc_enc_generate_srcpad_caps(GstSbcEnc *enc)
-{
-       GstCaps *src_caps;
-       GstStructure *structure;
-       GEnumValue *enum_value;
-       GEnumClass *enum_class;
-       GValue *value;
-
-       src_caps = gst_caps_copy(gst_pad_get_pad_template_caps(enc->srcpad));
-       structure = gst_caps_get_structure(src_caps, 0);
-
-       value = g_new0(GValue, 1);
-
-       if (enc->rate != 0)
-               gst_sbc_util_set_structure_int_param(structure, "rate",
-                       enc->rate, value);
-
-       if (enc->channels != 0)
-               gst_sbc_util_set_structure_int_param(structure, "channels",
-                       enc->channels, value);
-
-       if (enc->subbands != 0)
-               gst_sbc_util_set_structure_int_param(structure, "subbands",
-                       enc->subbands, value);
-
-       if (enc->blocks != 0)
-               gst_sbc_util_set_structure_int_param(structure, "blocks",
-                       enc->blocks, value);
-
-       if (enc->bitpool != SBC_ENC_BITPOOL_AUTO)
-               gst_sbc_util_set_structure_int_param(structure, "bitpool",
-                       enc->bitpool, value);
-
-       if (enc->mode != SBC_ENC_DEFAULT_MODE) {
-               enum_class = g_type_class_ref(GST_TYPE_SBC_MODE);
-               enum_value = g_enum_get_value(enum_class, enc->mode);
-               gst_sbc_util_set_structure_string_param(structure, "mode",
-                       enum_value->value_nick, value);
-               g_type_class_unref(enum_class);
-       }
-
-       if (enc->allocation != SBC_AM_AUTO) {
-               enum_class = g_type_class_ref(GST_TYPE_SBC_ALLOCATION);
-               enum_value = g_enum_get_value(enum_class, enc->allocation);
-               gst_sbc_util_set_structure_string_param(structure, "allocation",
-                       enum_value->value_nick, value);
-               g_type_class_unref(enum_class);
-       }
-
-       g_free(value);
-
-       return src_caps;
-}
-
-static GstCaps *sbc_enc_src_getcaps(GstPad *pad)
-{
-       GstSbcEnc *enc;
-
-       enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
-
-       return sbc_enc_generate_srcpad_caps(enc);
-}
-
-static gboolean sbc_enc_src_setcaps(GstPad *pad, GstCaps *caps)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
-
-       GST_LOG_OBJECT(enc, "setting srcpad caps");
-
-       return gst_sbc_enc_fill_sbc_params(enc, caps);
-}
-
-static GstCaps *sbc_enc_src_caps_fixate(GstSbcEnc *enc, GstCaps *caps)
-{
-       gchar *error_message = NULL;
-       GstCaps *result;
-
-       result = gst_sbc_util_caps_fixate(caps, &error_message);
-
-       if (!result) {
-               GST_WARNING_OBJECT(enc, "Invalid input caps caused parsing "
-                               "error: %s", error_message);
-               g_free(error_message);
-               return NULL;
-       }
-
-       return result;
-}
-
-static GstCaps *sbc_enc_get_fixed_srcpad_caps(GstSbcEnc *enc)
-{
-       GstCaps *caps;
-       gboolean res = TRUE;
-       GstCaps *result_caps = NULL;
-
-       caps = gst_pad_get_allowed_caps(enc->srcpad);
-       if (caps == NULL)
-               caps = sbc_enc_src_getcaps(enc->srcpad);
-
-       if (caps == GST_CAPS_NONE || gst_caps_is_empty(caps)) {
-               res = FALSE;
-               goto done;
-       }
-
-       result_caps = sbc_enc_src_caps_fixate(enc, caps);
-
-done:
-       gst_caps_unref(caps);
-
-       if (!res)
-               return NULL;
-
-       return result_caps;
-}
-
-static gboolean sbc_enc_sink_setcaps(GstPad *pad, GstCaps *caps)
-{
-       GstSbcEnc *enc;
-       GstStructure *structure;
-       GstCaps *src_caps;
-       gint rate, channels;
-       gboolean res;
-
-       enc = GST_SBC_ENC(GST_PAD_PARENT(pad));
-       structure = gst_caps_get_structure(caps, 0);
-
-       if (!gst_structure_get_int(structure, "rate", &rate))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "channels", &channels))
-               return FALSE;
-
-       enc->rate = rate;
-       enc->channels = channels;
-
-       src_caps = sbc_enc_get_fixed_srcpad_caps(enc);
-       if (!src_caps)
-               return FALSE;
-       res = gst_pad_set_caps(enc->srcpad, src_caps);
-       gst_caps_unref(src_caps);
-
-       return res;
-}
-
-gboolean gst_sbc_enc_fill_sbc_params(GstSbcEnc *enc, GstCaps *caps)
-{
-       if (!gst_caps_is_fixed(caps)) {
-               GST_DEBUG_OBJECT(enc, "didn't receive fixed caps, "
-                               "returning false");
-               return FALSE;
-       }
-
-       if (!gst_sbc_util_fill_sbc_params(&enc->sbc, caps))
-               return FALSE;
-
-       if (enc->rate != 0 && gst_sbc_parse_rate_from_sbc(enc->sbc.frequency)
-                                != enc->rate)
-               goto fail;
-
-       if (enc->channels != 0 && gst_sbc_get_channel_number(enc->sbc.mode)
-                               != enc->channels)
-               goto fail;
-
-       if (enc->blocks != 0 && gst_sbc_parse_blocks_from_sbc(enc->sbc.blocks)
-                                != enc->blocks)
-               goto fail;
-
-       if (enc->subbands != 0 && gst_sbc_parse_subbands_from_sbc(
-                               enc->sbc.subbands) != enc->subbands)
-               goto fail;
-
-       if (enc->mode != SBC_ENC_DEFAULT_MODE && enc->sbc.mode != enc->mode)
-               goto fail;
-
-       if (enc->allocation != SBC_AM_AUTO &&
-                               enc->sbc.allocation != enc->allocation)
-               goto fail;
-
-       if (enc->bitpool != SBC_ENC_BITPOOL_AUTO &&
-                               enc->sbc.bitpool != enc->bitpool)
-               goto fail;
-
-       enc->codesize = sbc_get_codesize(&enc->sbc);
-       enc->frame_length = sbc_get_frame_length(&enc->sbc);
-       enc->frame_duration = sbc_get_frame_duration(&enc->sbc);
-
-       GST_DEBUG_OBJECT(enc, "codesize: %d, frame_length: %d, frame_duration:"
-                       " %d", enc->codesize, enc->frame_length,
-                       enc->frame_duration);
-
-       return TRUE;
-
-fail:
-       memset(&enc->sbc, 0, sizeof(sbc_t));
-       return FALSE;
-}
-
-static GstFlowReturn sbc_enc_chain(GstPad *pad, GstBuffer *buffer)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(gst_pad_get_parent(pad));
-       GstAdapter *adapter = enc->adapter;
-       GstFlowReturn res = GST_FLOW_OK;
-
-       gst_adapter_push(adapter, buffer);
-
-       while (gst_adapter_available(adapter) >= enc->codesize &&
-                                                       res == GST_FLOW_OK) {
-               GstBuffer *output;
-               GstCaps *caps;
-               const guint8 *data;
-               gint consumed;
-
-               caps = GST_PAD_CAPS(enc->srcpad);
-               res = gst_pad_alloc_buffer_and_set_caps(enc->srcpad,
-                                               GST_BUFFER_OFFSET_NONE,
-                                               enc->frame_length, caps,
-                                               &output);
-               if (res != GST_FLOW_OK)
-                       goto done;
-
-               data = gst_adapter_peek(adapter, enc->codesize);
-
-               consumed = sbc_encode(&enc->sbc, (gpointer) data,
-                                       enc->codesize,
-                                       GST_BUFFER_DATA(output),
-                                       GST_BUFFER_SIZE(output), NULL);
-               if (consumed <= 0) {
-                       GST_DEBUG_OBJECT(enc, "comsumed < 0, codesize: %d",
-                                       enc->codesize);
-                       break;
-               }
-               gst_adapter_flush(adapter, consumed);
-
-               GST_BUFFER_TIMESTAMP(output) = GST_BUFFER_TIMESTAMP(buffer);
-               /* we have only 1 frame */
-               GST_BUFFER_DURATION(output) = enc->frame_duration;
-
-               res = gst_pad_push(enc->srcpad, output);
-
-               if (res != GST_FLOW_OK)
-                       goto done;
-       }
-
-done:
-       gst_object_unref(enc);
-
-       return res;
-}
-
-static GstStateChangeReturn sbc_enc_change_state(GstElement *element,
-                                               GstStateChange transition)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(element);
-
-       switch (transition) {
-       case GST_STATE_CHANGE_READY_TO_PAUSED:
-               GST_DEBUG("Setup subband codec");
-               sbc_init(&enc->sbc, 0);
-               break;
-
-       case GST_STATE_CHANGE_PAUSED_TO_READY:
-               GST_DEBUG("Finish subband codec");
-               sbc_finish(&enc->sbc);
-               break;
-
-       default:
-               break;
-       }
-
-       return parent_class->change_state(element, transition);
-}
-
-static void gst_sbc_enc_dispose(GObject *object)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(object);
-
-       if (enc->adapter != NULL)
-               g_object_unref(G_OBJECT(enc->adapter));
-
-       enc->adapter = NULL;
-}
-
-static void gst_sbc_enc_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_enc_sink_factory));
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_enc_src_factory));
-
-       gst_element_class_set_details(element_class, &sbc_enc_details);
-}
-
-static void gst_sbc_enc_set_property(GObject *object, guint prop_id,
-                                       const GValue *value, GParamSpec *pspec)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(object);
-
-       /* changes to those properties will only happen on the next caps
-        * negotiation */
-
-       switch (prop_id) {
-       case PROP_MODE:
-               enc->mode = g_value_get_enum(value);
-               break;
-       case PROP_ALLOCATION:
-               enc->allocation = g_value_get_enum(value);
-               break;
-       case PROP_BLOCKS:
-               enc->blocks = g_value_get_enum(value);
-               break;
-       case PROP_SUBBANDS:
-               enc->subbands = g_value_get_enum(value);
-               break;
-       case PROP_BITPOOL:
-               enc->bitpool = g_value_get_int(value);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static void gst_sbc_enc_get_property(GObject *object, guint prop_id,
-                                       GValue *value, GParamSpec *pspec)
-{
-       GstSbcEnc *enc = GST_SBC_ENC(object);
-
-       switch (prop_id) {
-       case PROP_MODE:
-               g_value_set_enum(value, enc->mode);
-               break;
-       case PROP_ALLOCATION:
-               g_value_set_enum(value, enc->allocation);
-               break;
-       case PROP_BLOCKS:
-               g_value_set_enum(value, enc->blocks);
-               break;
-       case PROP_SUBBANDS:
-               g_value_set_enum(value, enc->subbands);
-               break;
-       case PROP_BITPOOL:
-               g_value_set_int(value, enc->bitpool);
-               break;
-       default:
-               G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
-               break;
-       }
-}
-
-static void gst_sbc_enc_class_init(GstSbcEncClass *klass)
-{
-       GObjectClass *object_class = G_OBJECT_CLASS(klass);
-       GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
-
-       parent_class = g_type_class_peek_parent(klass);
-
-       object_class->set_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_set_property);
-       object_class->get_property = GST_DEBUG_FUNCPTR(gst_sbc_enc_get_property);
-       object_class->dispose = GST_DEBUG_FUNCPTR(gst_sbc_enc_dispose);
-
-       element_class->change_state = GST_DEBUG_FUNCPTR(sbc_enc_change_state);
-
-       g_object_class_install_property(object_class, PROP_MODE,
-                       g_param_spec_enum("mode", "Mode",
-                               "Encoding mode", GST_TYPE_SBC_MODE,
-                               SBC_ENC_DEFAULT_MODE, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_ALLOCATION,
-                       g_param_spec_enum("allocation", "Allocation",
-                               "Allocation method", GST_TYPE_SBC_ALLOCATION,
-                               SBC_ENC_DEFAULT_ALLOCATION, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_BLOCKS,
-                       g_param_spec_enum("blocks", "Blocks",
-                               "Blocks", GST_TYPE_SBC_BLOCKS,
-                               SBC_ENC_DEFAULT_BLOCKS, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_SUBBANDS,
-                       g_param_spec_enum("subbands", "Sub bands",
-                               "Number of sub bands", GST_TYPE_SBC_SUBBANDS,
-                               SBC_ENC_DEFAULT_SUB_BANDS, G_PARAM_READWRITE));
-
-       g_object_class_install_property(object_class, PROP_BITPOOL,
-                       g_param_spec_int("bitpool", "Bitpool",
-                               "Bitpool (use 1 for automatic selection)",
-                               SBC_ENC_BITPOOL_AUTO, SBC_ENC_BITPOOL_MAX,
-                               SBC_ENC_BITPOOL_AUTO, G_PARAM_READWRITE));
-
-       GST_DEBUG_CATEGORY_INIT(sbc_enc_debug, "sbcenc", 0,
-                                               "SBC encoding element");
-}
-
-static void gst_sbc_enc_init(GstSbcEnc *self, GstSbcEncClass *klass)
-{
-       self->sinkpad = gst_pad_new_from_static_template(
-               &sbc_enc_sink_factory, "sink");
-       gst_pad_set_setcaps_function(self->sinkpad,
-                       GST_DEBUG_FUNCPTR(sbc_enc_sink_setcaps));
-       gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
-
-       self->srcpad = gst_pad_new_from_static_template(
-               &sbc_enc_src_factory, "src");
-       gst_pad_set_getcaps_function(self->srcpad,
-               GST_DEBUG_FUNCPTR(sbc_enc_src_getcaps));
-       gst_pad_set_setcaps_function(self->srcpad,
-               GST_DEBUG_FUNCPTR(sbc_enc_src_setcaps));
-       gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
-
-       gst_pad_set_chain_function(self->sinkpad,
-               GST_DEBUG_FUNCPTR(sbc_enc_chain));
-
-       self->subbands = SBC_ENC_DEFAULT_SUB_BANDS;
-       self->blocks = SBC_ENC_DEFAULT_BLOCKS;
-       self->mode = SBC_ENC_DEFAULT_MODE;
-       self->allocation = SBC_ENC_DEFAULT_ALLOCATION;
-       self->rate = SBC_ENC_DEFAULT_RATE;
-       self->channels = SBC_ENC_DEFAULT_CHANNELS;
-       self->bitpool = SBC_ENC_BITPOOL_AUTO;
-
-       self->frame_length = 0;
-       self->frame_duration = 0;
-
-       self->adapter = gst_adapter_new();
-}
-
-gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "sbcenc",
-                       GST_RANK_NONE, GST_TYPE_SBC_ENC);
-}
diff --git a/audio/gstsbcenc.h b/audio/gstsbcenc.h
deleted file mode 100644 (file)
index 0329351..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gst/gst.h>
-#include <gst/base/gstadapter.h>
-
-#include "sbc.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_SBC_ENC \
-       (gst_sbc_enc_get_type())
-#define GST_SBC_ENC(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_ENC,GstSbcEnc))
-#define GST_SBC_ENC_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_ENC,GstSbcEncClass))
-#define GST_IS_SBC_ENC(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_ENC))
-#define GST_IS_SBC_ENC_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_ENC))
-
-typedef struct _GstSbcEnc GstSbcEnc;
-typedef struct _GstSbcEncClass GstSbcEncClass;
-
-struct _GstSbcEnc {
-       GstElement element;
-
-       GstPad *sinkpad;
-       GstPad *srcpad;
-       GstAdapter *adapter;
-
-       gint rate;
-       gint channels;
-       gint mode;
-       gint blocks;
-       gint allocation;
-       gint subbands;
-       gint bitpool;
-
-       guint codesize;
-       gint frame_length;
-       gint frame_duration;
-
-       sbc_t sbc;
-};
-
-struct _GstSbcEncClass {
-       GstElementClass parent_class;
-};
-
-GType gst_sbc_enc_get_type(void);
-
-gboolean gst_sbc_enc_plugin_init(GstPlugin *plugin);
-
-G_END_DECLS
diff --git a/audio/gstsbcparse.c b/audio/gstsbcparse.c
deleted file mode 100644 (file)
index bc4c0c7..0000000
+++ /dev/null
@@ -1,219 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <string.h>
-
-#include "gstpragma.h"
-#include "gstsbcutil.h"
-#include "gstsbcparse.h"
-
-GST_DEBUG_CATEGORY_STATIC(sbc_parse_debug);
-#define GST_CAT_DEFAULT sbc_parse_debug
-
-GST_BOILERPLATE(GstSbcParse, gst_sbc_parse, GstElement, GST_TYPE_ELEMENT);
-
-static const GstElementDetails sbc_parse_details =
-       GST_ELEMENT_DETAILS("Bluetooth SBC parser",
-                               "Codec/Parser/Audio",
-                               "Parse a SBC audio stream",
-                               "Marcel Holtmann <marcel@holtmann.org>");
-
-static GstStaticPadTemplate sbc_parse_sink_factory =
-       GST_STATIC_PAD_TEMPLATE("sink", GST_PAD_SINK, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-sbc,"
-                               "parsed = (boolean) false"));
-
-static GstStaticPadTemplate sbc_parse_src_factory =
-       GST_STATIC_PAD_TEMPLATE("src", GST_PAD_SRC, GST_PAD_ALWAYS,
-               GST_STATIC_CAPS("audio/x-sbc, "
-                               "rate = (int) { 16000, 32000, 44100, 48000 }, "
-                               "channels = (int) [ 1, 2 ], "
-                               "mode = (string) { \"mono\", \"dual\", \"stereo\", \"joint\" }, "
-                               "blocks = (int) { 4, 8, 12, 16 }, "
-                               "subbands = (int) { 4, 8 }, "
-                               "allocation = (string) { \"snr\", \"loudness\" },"
-                               "bitpool = (int) [ 2, 64 ],"
-                               "parsed = (boolean) true"));
-
-static GstFlowReturn sbc_parse_chain(GstPad *pad, GstBuffer *buffer)
-{
-       GstSbcParse *parse = GST_SBC_PARSE(gst_pad_get_parent(pad));
-       GstFlowReturn res = GST_FLOW_OK;
-       guint size, offset = 0;
-       guint8 *data;
-
-       /* FIXME use a gstadpter */
-       if (parse->buffer) {
-               GstBuffer *temp;
-               temp = buffer;
-               buffer = gst_buffer_span(parse->buffer, 0, buffer,
-                       GST_BUFFER_SIZE(parse->buffer)
-                       + GST_BUFFER_SIZE(buffer));
-               gst_buffer_unref(parse->buffer);
-               gst_buffer_unref(temp);
-               parse->buffer = NULL;
-       }
-
-       data = GST_BUFFER_DATA(buffer);
-       size = GST_BUFFER_SIZE(buffer);
-
-       while (offset < size) {
-               GstBuffer *output;
-               int consumed;
-
-               consumed = sbc_parse(&parse->new_sbc, data + offset,
-                                       size - offset);
-               if (consumed <= 0)
-                       break;
-
-               if (parse->first_parsing || (memcmp(&parse->sbc,
-                               &parse->new_sbc, sizeof(sbc_t)) != 0)) {
-
-                       memcpy(&parse->sbc, &parse->new_sbc, sizeof(sbc_t));
-                       if (parse->outcaps != NULL)
-                               gst_caps_unref(parse->outcaps);
-
-                       parse->outcaps = gst_sbc_parse_caps_from_sbc(
-                                               &parse->sbc);
-
-                       parse->first_parsing = FALSE;
-               }
-
-               res = gst_pad_alloc_buffer_and_set_caps(parse->srcpad,
-                                               GST_BUFFER_OFFSET_NONE,
-                                               consumed, parse->outcaps, &output);
-
-               if (res != GST_FLOW_OK)
-                       goto done;
-
-               memcpy(GST_BUFFER_DATA(output), data + offset, consumed);
-
-               res = gst_pad_push(parse->srcpad, output);
-               if (res != GST_FLOW_OK)
-                       goto done;
-
-               offset += consumed;
-       }
-
-       if (offset < size)
-               parse->buffer = gst_buffer_create_sub(buffer,
-                                                       offset, size - offset);
-
-done:
-       gst_buffer_unref(buffer);
-       gst_object_unref(parse);
-
-       return res;
-}
-
-static GstStateChangeReturn sbc_parse_change_state(GstElement *element,
-                                               GstStateChange transition)
-{
-       GstSbcParse *parse = GST_SBC_PARSE(element);
-
-       switch (transition) {
-       case GST_STATE_CHANGE_READY_TO_PAUSED:
-               GST_DEBUG("Setup subband codec");
-
-               parse->channels = -1;
-               parse->rate = -1;
-               parse->first_parsing = TRUE;
-
-               sbc_init(&parse->sbc, 0);
-               break;
-
-       case GST_STATE_CHANGE_PAUSED_TO_READY:
-               GST_DEBUG("Finish subband codec");
-
-               if (parse->buffer) {
-                       gst_buffer_unref(parse->buffer);
-                       parse->buffer = NULL;
-               }
-               if (parse->outcaps != NULL) {
-                       gst_caps_unref(parse->outcaps);
-                       parse->outcaps = NULL;
-               }
-
-               sbc_finish(&parse->sbc);
-               break;
-
-       default:
-               break;
-       }
-
-       return parent_class->change_state(element, transition);
-}
-
-static void gst_sbc_parse_base_init(gpointer g_class)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(g_class);
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_parse_sink_factory));
-
-       gst_element_class_add_pad_template(element_class,
-               gst_static_pad_template_get(&sbc_parse_src_factory));
-
-       gst_element_class_set_details(element_class, &sbc_parse_details);
-}
-
-static void gst_sbc_parse_class_init(GstSbcParseClass *klass)
-{
-       GstElementClass *element_class = GST_ELEMENT_CLASS(klass);
-
-       parent_class = g_type_class_peek_parent(klass);
-
-       element_class->change_state = GST_DEBUG_FUNCPTR(sbc_parse_change_state);
-
-       GST_DEBUG_CATEGORY_INIT(sbc_parse_debug, "sbcparse", 0,
-                               "SBC parsing element");
-}
-
-static void gst_sbc_parse_init(GstSbcParse *self, GstSbcParseClass *klass)
-{
-       self->sinkpad = gst_pad_new_from_static_template(
-               &sbc_parse_sink_factory, "sink");
-       gst_pad_set_chain_function(self->sinkpad,
-               GST_DEBUG_FUNCPTR(sbc_parse_chain));
-       gst_element_add_pad(GST_ELEMENT(self), self->sinkpad);
-
-       self->srcpad = gst_pad_new_from_static_template(
-               &sbc_parse_src_factory, "src");
-       gst_element_add_pad(GST_ELEMENT(self), self->srcpad);
-
-       self->outcaps = NULL;
-       self->buffer = NULL;
-       self->channels = -1;
-       self->rate = -1;
-       self->first_parsing = TRUE;
-}
-
-gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin)
-{
-       return gst_element_register(plugin, "sbcparse", GST_RANK_NONE,
-                                                       GST_TYPE_SBC_PARSE);
-}
diff --git a/audio/gstsbcparse.h b/audio/gstsbcparse.h
deleted file mode 100644 (file)
index ecb8be4..0000000
+++ /dev/null
@@ -1,69 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gst/gst.h>
-
-#include "sbc.h"
-
-G_BEGIN_DECLS
-
-#define GST_TYPE_SBC_PARSE \
-       (gst_sbc_parse_get_type())
-#define GST_SBC_PARSE(obj) \
-       (G_TYPE_CHECK_INSTANCE_CAST((obj),GST_TYPE_SBC_PARSE,GstSbcParse))
-#define GST_SBC_PARSE_CLASS(klass) \
-       (G_TYPE_CHECK_CLASS_CAST((klass),GST_TYPE_SBC_PARSE,GstSbcParseClass))
-#define GST_IS_SBC_PARSE(obj) \
-       (G_TYPE_CHECK_INSTANCE_TYPE((obj),GST_TYPE_SBC_PARSE))
-#define GST_IS_SBC_PARSE_CLASS(obj) \
-       (G_TYPE_CHECK_CLASS_TYPE((klass),GST_TYPE_SBC_PARSE))
-
-typedef struct _GstSbcParse GstSbcParse;
-typedef struct _GstSbcParseClass GstSbcParseClass;
-
-struct _GstSbcParse {
-       GstElement element;
-
-       GstPad *sinkpad;
-       GstPad *srcpad;
-
-       GstBuffer *buffer;
-
-       sbc_t sbc;
-       sbc_t new_sbc;
-       GstCaps *outcaps;
-       gboolean first_parsing;
-
-       gint channels;
-       gint rate;
-};
-
-struct _GstSbcParseClass {
-       GstElementClass parent_class;
-};
-
-GType gst_sbc_parse_get_type(void);
-
-gboolean gst_sbc_parse_plugin_init(GstPlugin *plugin);
-
-G_END_DECLS
diff --git a/audio/gstsbcutil.c b/audio/gstsbcutil.c
deleted file mode 100644 (file)
index f596b41..0000000
+++ /dev/null
@@ -1,520 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <math.h>
-#include "gstsbcutil.h"
-
-/*
- * Selects one rate from a list of possible rates
- * TODO - use a better approach to this (it is selecting the last element)
- */
-gint gst_sbc_select_rate_from_list(const GValue *value)
-{
-       guint size = gst_value_list_get_size(value);
-       return g_value_get_int(gst_value_list_get_value(value, size-1));
-}
-
-/*
- * Selects one number of channels option from a range of possible numbers
- * TODO - use a better approach to this (it is selecting the maximum value)
- */
-gint gst_sbc_select_channels_from_range(const GValue *value)
-{
-       return gst_value_get_int_range_max(value);
-}
-
-/*
- * Selects one number of blocks from a list of possible blocks
- * TODO - use a better approach to this (it is selecting the last element)
- */
-gint gst_sbc_select_blocks_from_list(const GValue *value)
-{
-       guint size = gst_value_list_get_size(value);
-       return g_value_get_int(gst_value_list_get_value(value, size-1));
-}
-
-/*
- * Selects one number of subbands from a list
- * TODO - use a better approach to this (it is selecting the last element)
- */
-gint gst_sbc_select_subbands_from_list(const GValue *value)
-{
-       guint size = gst_value_list_get_size(value);
-       return g_value_get_int(gst_value_list_get_value(value, size-1));
-}
-
-/*
- * Selects one bitpool option from a range
- * TODO - use a better approach to this (it is selecting the maximum value)
- */
-gint gst_sbc_select_bitpool_from_range(const GValue *value)
-{
-       return gst_value_get_int_range_max(value);
-}
-
-/*
- * Selects one allocation mode from the ones on the list
- * TODO - use a better approach
- */
-const gchar *gst_sbc_get_allocation_from_list(const GValue *value)
-{
-       guint size = gst_value_list_get_size(value);
-       return g_value_get_string(gst_value_list_get_value(value, size-1));
-}
-
-/*
- * Selects one mode from the ones on the list
- */
-const gchar *gst_sbc_get_mode_from_list(const GValue *list, gint channels)
-{
-       unsigned int i;
-       const GValue *value;
-       const gchar *aux;
-       gboolean joint, stereo, dual, mono;
-       guint size = gst_value_list_get_size(list);
-
-       joint = stereo = dual = mono = FALSE;
-
-       for (i = 0; i < size; i++) {
-               value = gst_value_list_get_value(list, i);
-               aux = g_value_get_string(value);
-               if (strcmp("joint", aux) == 0)
-                       joint = TRUE;
-               else if (strcmp("stereo", aux) == 0)
-                       stereo = TRUE;
-               else if (strcmp("dual", aux) == 0)
-                       dual = TRUE;
-               else if (strcmp("mono", aux) == 0)
-                       mono = TRUE;
-       }
-
-       if (channels == 1 && mono)
-               return "mono";
-       else if (channels == 2) {
-               if (joint)
-                       return "joint";
-               else if (stereo)
-                       return "stereo";
-               else if (dual)
-                       return "dual";
-       }
-
-       return NULL;
-}
-
-gint gst_sbc_parse_rate_from_sbc(gint frequency)
-{
-       switch (frequency) {
-       case SBC_FREQ_16000:
-               return 16000;
-       case SBC_FREQ_32000:
-               return 32000;
-       case SBC_FREQ_44100:
-               return 44100;
-       case SBC_FREQ_48000:
-               return 48000;
-       default:
-               return 0;
-       }
-}
-
-gint gst_sbc_parse_rate_to_sbc(gint rate)
-{
-       switch (rate) {
-       case 16000:
-               return SBC_FREQ_16000;
-       case 32000:
-               return SBC_FREQ_32000;
-       case 44100:
-               return SBC_FREQ_44100;
-       case 48000:
-               return SBC_FREQ_48000;
-       default:
-               return -1;
-       }
-}
-
-gint gst_sbc_get_channel_number(gint mode)
-{
-       switch (mode) {
-       case SBC_MODE_JOINT_STEREO:
-       case SBC_MODE_STEREO:
-       case SBC_MODE_DUAL_CHANNEL:
-               return 2;
-       case SBC_MODE_MONO:
-               return 1;
-       default:
-               return 0;
-       }
-}
-
-gint gst_sbc_parse_subbands_from_sbc(gint subbands)
-{
-       switch (subbands) {
-       case SBC_SB_4:
-               return 4;
-       case SBC_SB_8:
-               return 8;
-       default:
-               return 0;
-       }
-}
-
-gint gst_sbc_parse_subbands_to_sbc(gint subbands)
-{
-       switch (subbands) {
-       case 4:
-               return SBC_SB_4;
-       case 8:
-               return SBC_SB_8;
-       default:
-               return -1;
-       }
-}
-
-gint gst_sbc_parse_blocks_from_sbc(gint blocks)
-{
-       switch (blocks) {
-       case SBC_BLK_4:
-               return 4;
-       case SBC_BLK_8:
-               return 8;
-       case SBC_BLK_12:
-               return 12;
-       case SBC_BLK_16:
-               return 16;
-       default:
-               return 0;
-       }
-}
-
-gint gst_sbc_parse_blocks_to_sbc(gint blocks)
-{
-       switch (blocks) {
-       case 4:
-               return SBC_BLK_4;
-       case 8:
-               return SBC_BLK_8;
-       case 12:
-               return SBC_BLK_12;
-       case 16:
-               return SBC_BLK_16;
-       default:
-               return -1;
-       }
-}
-
-const gchar *gst_sbc_parse_mode_from_sbc(gint mode)
-{
-       switch (mode) {
-       case SBC_MODE_MONO:
-               return "mono";
-       case SBC_MODE_DUAL_CHANNEL:
-               return "dual";
-       case SBC_MODE_STEREO:
-               return "stereo";
-       case SBC_MODE_JOINT_STEREO:
-       case SBC_MODE_AUTO:
-               return "joint";
-       default:
-               return NULL;
-       }
-}
-
-gint gst_sbc_parse_mode_to_sbc(const gchar *mode)
-{
-       if (g_ascii_strcasecmp(mode, "joint") == 0)
-               return SBC_MODE_JOINT_STEREO;
-       else if (g_ascii_strcasecmp(mode, "stereo") == 0)
-               return SBC_MODE_STEREO;
-       else if (g_ascii_strcasecmp(mode, "dual") == 0)
-               return SBC_MODE_DUAL_CHANNEL;
-       else if (g_ascii_strcasecmp(mode, "mono") == 0)
-               return SBC_MODE_MONO;
-       else if (g_ascii_strcasecmp(mode, "auto") == 0)
-               return SBC_MODE_JOINT_STEREO;
-       else
-               return -1;
-}
-
-const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc)
-{
-       switch (alloc) {
-       case SBC_AM_LOUDNESS:
-               return "loudness";
-       case SBC_AM_SNR:
-               return "snr";
-       case SBC_AM_AUTO:
-               return "loudness";
-       default:
-               return NULL;
-       }
-}
-
-gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation)
-{
-       if (g_ascii_strcasecmp(allocation, "loudness") == 0)
-               return SBC_AM_LOUDNESS;
-       else if (g_ascii_strcasecmp(allocation, "snr") == 0)
-               return SBC_AM_SNR;
-       else
-               return SBC_AM_LOUDNESS;
-}
-
-GstCaps *gst_sbc_parse_caps_from_sbc(sbc_t *sbc)
-{
-       GstCaps *caps;
-       const gchar *mode_str;
-       const gchar *allocation_str;
-
-       mode_str = gst_sbc_parse_mode_from_sbc(sbc->mode);
-       allocation_str = gst_sbc_parse_allocation_from_sbc(sbc->allocation);
-       caps = gst_caps_new_simple("audio/x-sbc",
-                               "rate", G_TYPE_INT,
-                               gst_sbc_parse_rate_from_sbc(sbc->frequency),
-                               "channels", G_TYPE_INT,
-                               gst_sbc_get_channel_number(sbc->mode),
-                               "mode", G_TYPE_STRING, mode_str,
-                               "subbands", G_TYPE_INT,
-                               gst_sbc_parse_subbands_from_sbc(sbc->subbands),
-                               "blocks", G_TYPE_INT,
-                               gst_sbc_parse_blocks_from_sbc(sbc->blocks),
-                               "allocation", G_TYPE_STRING, allocation_str,
-                               "bitpool", G_TYPE_INT, sbc->bitpool,
-                               NULL);
-
-       return caps;
-}
-
-/*
- * Given a GstCaps, this will return a fixed GstCaps on successful conversion.
- * If an error occurs, it will return NULL and error_message will contain the
- * error message.
- *
- * error_message must be passed NULL, if an error occurs, the caller has the
- * ownership of the error_message, it must be freed after use.
- */
-GstCaps *gst_sbc_util_caps_fixate(GstCaps *caps, gchar **error_message)
-{
-       GstCaps *result;
-       GstStructure *structure;
-       const GValue *value;
-       gboolean error = FALSE;
-       gint temp, rate, channels, blocks, subbands, bitpool;
-       const gchar *allocation = NULL;
-       const gchar *mode = NULL;
-
-       g_assert(*error_message == NULL);
-
-       structure = gst_caps_get_structure(caps, 0);
-
-       if (!gst_structure_has_field(structure, "rate")) {
-               error = TRUE;
-               *error_message = g_strdup("no rate");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "rate");
-               if (GST_VALUE_HOLDS_LIST(value))
-                       temp = gst_sbc_select_rate_from_list(value);
-               else
-                       temp = g_value_get_int(value);
-               rate = temp;
-       }
-
-       if (!gst_structure_has_field(structure, "channels")) {
-               error = TRUE;
-               *error_message = g_strdup("no channels");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "channels");
-               if (GST_VALUE_HOLDS_INT_RANGE(value))
-                       temp = gst_sbc_select_channels_from_range(value);
-               else
-                       temp = g_value_get_int(value);
-               channels = temp;
-       }
-
-       if (!gst_structure_has_field(structure, "blocks")) {
-               error = TRUE;
-               *error_message = g_strdup("no blocks.");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "blocks");
-               if (GST_VALUE_HOLDS_LIST(value))
-                       temp = gst_sbc_select_blocks_from_list(value);
-               else
-                       temp = g_value_get_int(value);
-               blocks = temp;
-       }
-
-       if (!gst_structure_has_field(structure, "subbands")) {
-               error = TRUE;
-               *error_message = g_strdup("no subbands");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "subbands");
-               if (GST_VALUE_HOLDS_LIST(value))
-                       temp = gst_sbc_select_subbands_from_list(value);
-               else
-                       temp = g_value_get_int(value);
-               subbands = temp;
-       }
-
-       if (!gst_structure_has_field(structure, "bitpool")) {
-               error = TRUE;
-               *error_message = g_strdup("no bitpool");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "bitpool");
-               if (GST_VALUE_HOLDS_INT_RANGE(value))
-                       temp = gst_sbc_select_bitpool_from_range(value);
-               else
-                       temp = g_value_get_int(value);
-               bitpool = temp;
-       }
-
-       if (!gst_structure_has_field(structure, "allocation")) {
-               error = TRUE;
-               *error_message = g_strdup("no allocation");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "allocation");
-               if (GST_VALUE_HOLDS_LIST(value))
-                       allocation = gst_sbc_get_allocation_from_list(value);
-               else
-                       allocation = g_value_get_string(value);
-       }
-
-       if (!gst_structure_has_field(structure, "mode")) {
-               error = TRUE;
-               *error_message = g_strdup("no mode");
-               goto error;
-       } else {
-               value = gst_structure_get_value(structure, "mode");
-               if (GST_VALUE_HOLDS_LIST(value)) {
-                       mode = gst_sbc_get_mode_from_list(value, channels);
-               } else
-                       mode = g_value_get_string(value);
-       }
-
-       /* perform validation
-        * if channels is 1, we must have channel mode = mono
-        * if channels is 2, we can't have channel mode = mono */
-       if ( (channels == 1 && (strcmp(mode, "mono") != 0) ) ||
-                       ( channels == 2 && ( strcmp(mode, "mono") == 0))) {
-               *error_message = g_strdup_printf("Invalid combination of "
-                                       "channels (%d) and channel mode (%s)",
-                                       channels, mode);
-               error = TRUE;
-       }
-
-error:
-       if (error)
-               return NULL;
-
-       result = gst_caps_new_simple("audio/x-sbc",
-                                       "rate", G_TYPE_INT, rate,
-                                       "channels", G_TYPE_INT, channels,
-                                       "mode", G_TYPE_STRING, mode,
-                                       "blocks", G_TYPE_INT, blocks,
-                                       "subbands", G_TYPE_INT, subbands,
-                                       "allocation", G_TYPE_STRING, allocation,
-                                       "bitpool", G_TYPE_INT, bitpool,
-                                       NULL);
-
-       return result;
-}
-
-/**
- * Sets the int field_value to the  param "field" on the structure.
- * value is used to do the operation, it must be a uninitialized (zero-filled)
- * GValue, it will be left unitialized at the end of the function.
- */
-void gst_sbc_util_set_structure_int_param(GstStructure *structure,
-                       const gchar *field, gint field_value,
-                       GValue *value)
-{
-       value = g_value_init(value, G_TYPE_INT);
-       g_value_set_int(value, field_value);
-       gst_structure_set_value(structure, field, value);
-       g_value_unset(value);
-}
-
-/**
- * Sets the string field_value to the  param "field" on the structure.
- * value is used to do the operation, it must be a uninitialized (zero-filled)
- * GValue, it will be left unitialized at the end of the function.
- */
-void gst_sbc_util_set_structure_string_param(GstStructure *structure,
-                       const gchar *field, const gchar *field_value,
-                       GValue *value)
-{
-       value = g_value_init(value, G_TYPE_STRING);
-       g_value_set_string(value, field_value);
-       gst_structure_set_value(structure, field, value);
-       g_value_unset(value);
-}
-
-gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps)
-{
-       GstStructure *structure;
-       gint rate, channels, subbands, blocks, bitpool;
-       const gchar *mode;
-       const gchar *allocation;
-
-       g_assert(gst_caps_is_fixed(caps));
-
-       structure = gst_caps_get_structure(caps, 0);
-
-       if (!gst_structure_get_int(structure, "rate", &rate))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "channels", &channels))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "subbands", &subbands))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "blocks", &blocks))
-               return FALSE;
-       if (!gst_structure_get_int(structure, "bitpool", &bitpool))
-               return FALSE;
-
-       if (!(mode = gst_structure_get_string(structure, "mode")))
-               return FALSE;
-       if (!(allocation = gst_structure_get_string(structure, "allocation")))
-               return FALSE;
-
-       if (channels == 1 && strcmp(mode, "mono") != 0)
-               return FALSE;
-
-       sbc->frequency = gst_sbc_parse_rate_to_sbc(rate);
-       sbc->blocks = gst_sbc_parse_blocks_to_sbc(blocks);
-       sbc->subbands = gst_sbc_parse_subbands_to_sbc(subbands);
-       sbc->bitpool = bitpool;
-       sbc->mode = gst_sbc_parse_mode_to_sbc(mode);
-       sbc->allocation = gst_sbc_parse_allocation_to_sbc(allocation);
-
-       return TRUE;
-}
diff --git a/audio/gstsbcutil.h b/audio/gstsbcutil.h
deleted file mode 100644 (file)
index 5e47119..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gst/gst.h>
-
-#include "sbc.h"
-#include <string.h>
-
-#define SBC_AM_AUTO 0x02
-#define SBC_MODE_AUTO 0x04
-
-gint gst_sbc_select_rate_from_list(const GValue *value);
-
-gint gst_sbc_select_channels_from_range(const GValue *value);
-
-gint gst_sbc_select_blocks_from_list(const GValue *value);
-
-gint gst_sbc_select_subbands_from_list(const GValue *value);
-
-gint gst_sbc_select_bitpool_from_range(const GValue *value);
-
-const gchar *gst_sbc_get_allocation_from_list(const GValue *value);
-
-const gchar *gst_sbc_get_mode_from_list(const GValue *value, gint channels);
-
-gint gst_sbc_get_channel_number(gint mode);
-gint gst_sbc_parse_rate_from_sbc(gint frequency);
-gint gst_sbc_parse_rate_to_sbc(gint rate);
-
-gint gst_sbc_parse_subbands_from_sbc(gint subbands);
-gint gst_sbc_parse_subbands_to_sbc(gint subbands);
-
-gint gst_sbc_parse_blocks_from_sbc(gint blocks);
-gint gst_sbc_parse_blocks_to_sbc(gint blocks);
-
-const gchar *gst_sbc_parse_mode_from_sbc(gint mode);
-gint gst_sbc_parse_mode_to_sbc(const gchar *mode);
-
-const gchar *gst_sbc_parse_allocation_from_sbc(gint alloc);
-gint gst_sbc_parse_allocation_to_sbc(const gchar *allocation);
-
-GstCaps* gst_sbc_parse_caps_from_sbc(sbc_t *sbc);
-
-GstCaps* gst_sbc_util_caps_fixate(GstCaps *caps, gchar** error_message);
-
-void gst_sbc_util_set_structure_int_param(GstStructure *structure,
-                       const gchar* field, gint field_value,
-                       GValue *value);
-
-void gst_sbc_util_set_structure_string_param(GstStructure *structure,
-                       const gchar* field, const gchar* field_value,
-                       GValue *value);
-
-gboolean gst_sbc_util_fill_sbc_params(sbc_t *sbc, GstCaps *caps);
diff --git a/audio/headset.c b/audio/headset.c
deleted file mode 100644 (file)
index 729e4dc..0000000
+++ /dev/null
@@ -1,3007 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <signal.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-#include <assert.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "device.h"
-#include "manager.h"
-#include "error.h"
-#include "telephony.h"
-#include "headset.h"
-#include "sdp-client.h"
-#include "btio.h"
-#include "dbus-common.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#define DC_TIMEOUT 3
-
-#define RING_INTERVAL 3
-
-#define BUF_SIZE 1024
-
-#define HEADSET_GAIN_SPEAKER 'S'
-#define HEADSET_GAIN_MICROPHONE 'M'
-
-static struct {
-       gboolean telephony_ready;       /* Telephony plugin initialized */
-       uint32_t features;              /* HFP AG features */
-       const struct indicator *indicators;     /* Available HFP indicators */
-       int er_mode;                    /* Event reporting mode */
-       int er_ind;                     /* Event reporting for indicators */
-       int rh;                         /* Response and Hold state */
-       char *number;                   /* Incoming phone number */
-       int number_type;                /* Incoming number type */
-       guint ring_timer;               /* For incoming call indication */
-       const char *chld;               /* Response to AT+CHLD=? */
-} ag = {
-       .telephony_ready = FALSE,
-       .features = 0,
-       .er_mode = 3,
-       .er_ind = 0,
-       .rh = BTRH_NOT_SUPPORTED,
-       .number = NULL,
-       .number_type = 0,
-       .ring_timer = 0,
-};
-
-static gboolean sco_hci = TRUE;
-static gboolean fast_connectable = FALSE;
-
-static GSList *active_devices = NULL;
-
-static char *str_state[] = {
-       "HEADSET_STATE_DISCONNECTED",
-       "HEADSET_STATE_CONNECTING",
-       "HEADSET_STATE_CONNECTED",
-       "HEADSET_STATE_PLAY_IN_PROGRESS",
-       "HEADSET_STATE_PLAYING",
-};
-
-struct headset_state_callback {
-       headset_state_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-struct headset_nrec_callback {
-       unsigned int id;
-       headset_nrec_cb cb;
-       void *user_data;
-};
-
-struct connect_cb {
-       unsigned int id;
-       headset_stream_cb_t cb;
-       void *cb_data;
-};
-
-struct pending_connect {
-       DBusMessage *msg;
-       DBusPendingCall *call;
-       GIOChannel *io;
-       int err;
-       headset_state_t target_state;
-       GSList *callbacks;
-       uint16_t svclass;
-};
-
-struct headset_slc {
-       char buf[BUF_SIZE];
-       int data_start;
-       int data_length;
-
-       gboolean cli_active;
-       gboolean cme_enabled;
-       gboolean cwa_enabled;
-       gboolean pending_ring;
-       gboolean inband_ring;
-       gboolean nrec;
-       gboolean nrec_req;
-
-       int sp_gain;
-       int mic_gain;
-
-       unsigned int hf_features;
-};
-
-struct headset {
-       uint32_t hsp_handle;
-       uint32_t hfp_handle;
-
-       int rfcomm_ch;
-
-       GIOChannel *rfcomm;
-       GIOChannel *tmp_rfcomm;
-       GIOChannel *sco;
-       guint sco_id;
-
-       gboolean auto_dc;
-
-       guint dc_timer;
-
-       gboolean hfp_active;
-       gboolean search_hfp;
-       gboolean rfcomm_initiator;
-
-       headset_state_t state;
-       struct pending_connect *pending;
-
-       headset_lock_t lock;
-       struct headset_slc *slc;
-       GSList *nrec_cbs;
-};
-
-struct event {
-       const char *cmd;
-       int (*callback) (struct audio_device *device, const char *buf);
-};
-
-static GSList *headset_callbacks = NULL;
-
-static void error_connect_failed(DBusConnection *conn, DBusMessage *msg,
-                                                               int err)
-{
-       DBusMessage *reply = btd_error_failed(msg,
-                       err < 0 ? strerror(-err) : "Connect failed");
-       g_dbus_send_message(conn, reply);
-}
-
-static int rfcomm_connect(struct audio_device *device, headset_stream_cb_t cb,
-                               void *user_data, unsigned int *cb_id);
-static int get_records(struct audio_device *device, headset_stream_cb_t cb,
-                       void *user_data, unsigned int *cb_id);
-
-static void print_ag_features(uint32_t features)
-{
-       GString *gstr;
-       char *str;
-
-       if (features == 0) {
-               DBG("HFP AG features: (none)");
-               return;
-       }
-
-       gstr = g_string_new("HFP AG features: ");
-
-       if (features & AG_FEATURE_THREE_WAY_CALLING)
-               g_string_append(gstr, "\"Three-way calling\" ");
-       if (features & AG_FEATURE_EC_ANDOR_NR)
-               g_string_append(gstr, "\"EC and/or NR function\" ");
-       if (features & AG_FEATURE_VOICE_RECOGNITION)
-               g_string_append(gstr, "\"Voice recognition function\" ");
-       if (features & AG_FEATURE_INBAND_RINGTONE)
-               g_string_append(gstr, "\"In-band ring tone capability\" ");
-       if (features & AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG)
-               g_string_append(gstr, "\"Attach a number to a voice tag\" ");
-       if (features & AG_FEATURE_REJECT_A_CALL)
-               g_string_append(gstr, "\"Ability to reject a call\" ");
-       if (features & AG_FEATURE_ENHANCED_CALL_STATUS)
-               g_string_append(gstr, "\"Enhanced call status\" ");
-       if (features & AG_FEATURE_ENHANCED_CALL_CONTROL)
-               g_string_append(gstr, "\"Enhanced call control\" ");
-       if (features & AG_FEATURE_EXTENDED_ERROR_RESULT_CODES)
-               g_string_append(gstr, "\"Extended Error Result Codes\" ");
-
-       str = g_string_free(gstr, FALSE);
-
-       DBG("%s", str);
-
-       g_free(str);
-}
-
-static void print_hf_features(uint32_t features)
-{
-       GString *gstr;
-       char *str;
-
-       if (features == 0) {
-               DBG("HFP HF features: (none)");
-               return;
-       }
-
-       gstr = g_string_new("HFP HF features: ");
-
-       if (features & HF_FEATURE_EC_ANDOR_NR)
-               g_string_append(gstr, "\"EC and/or NR function\" ");
-       if (features & HF_FEATURE_CALL_WAITING_AND_3WAY)
-               g_string_append(gstr, "\"Call waiting and 3-way calling\" ");
-       if (features & HF_FEATURE_CLI_PRESENTATION)
-               g_string_append(gstr, "\"CLI presentation capability\" ");
-       if (features & HF_FEATURE_VOICE_RECOGNITION)
-               g_string_append(gstr, "\"Voice recognition activation\" ");
-       if (features & HF_FEATURE_REMOTE_VOLUME_CONTROL)
-               g_string_append(gstr, "\"Remote volume control\" ");
-       if (features & HF_FEATURE_ENHANCED_CALL_STATUS)
-               g_string_append(gstr, "\"Enhanced call status\" ");
-       if (features & HF_FEATURE_ENHANCED_CALL_CONTROL)
-               g_string_append(gstr, "\"Enhanced call control\" ");
-
-       str = g_string_free(gstr, FALSE);
-
-       DBG("%s", str);
-
-       g_free(str);
-}
-
-static const char *state2str(headset_state_t state)
-{
-       switch (state) {
-       case HEADSET_STATE_DISCONNECTED:
-               return "disconnected";
-       case HEADSET_STATE_CONNECTING:
-               return "connecting";
-       case HEADSET_STATE_CONNECTED:
-       case HEADSET_STATE_PLAY_IN_PROGRESS:
-               return "connected";
-       case HEADSET_STATE_PLAYING:
-               return "playing";
-       }
-
-       return NULL;
-}
-
-static int headset_send_valist(struct headset *hs, char *format, va_list ap)
-{
-       char rsp[BUF_SIZE];
-       ssize_t total_written, count;
-       int fd;
-
-       count = vsnprintf(rsp, sizeof(rsp), format, ap);
-
-       if (count < 0)
-               return -EINVAL;
-
-       if (!hs->rfcomm) {
-               error("headset_send: the headset is not connected");
-               return -EIO;
-       }
-
-       total_written = 0;
-       fd = g_io_channel_unix_get_fd(hs->rfcomm);
-
-       while (total_written < count) {
-               ssize_t written;
-
-               written = write(fd, rsp + total_written,
-                               count - total_written);
-               if (written < 0)
-                       return -errno;
-
-               total_written += written;
-       }
-
-       return 0;
-}
-
-static int __attribute__((format(printf, 2, 3)))
-                       headset_send(struct headset *hs, char *format, ...)
-{
-       va_list ap;
-       int ret;
-
-       va_start(ap, format);
-       ret = headset_send_valist(hs, format, ap);
-       va_end(ap);
-
-       return ret;
-}
-
-static int supported_features(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-       int err;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       slc->hf_features = strtoul(&buf[8], NULL, 10);
-
-       print_hf_features(slc->hf_features);
-
-       err = headset_send(hs, "\r\n+BRSF: %u\r\n", ag.features);
-       if (err < 0)
-               return err;
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-static char *indicator_ranges(const struct indicator *indicators)
-{
-       int i;
-       GString *gstr;
-
-       gstr = g_string_new("\r\n+CIND: ");
-
-       for (i = 0; indicators[i].desc != NULL; i++) {
-               if (i == 0)
-                       g_string_append_printf(gstr, "(\"%s\",(%s))",
-                                               indicators[i].desc,
-                                               indicators[i].range);
-               else
-                       g_string_append_printf(gstr, ",(\"%s\",(%s))",
-                                               indicators[i].desc,
-                                               indicators[i].range);
-       }
-
-       g_string_append(gstr, "\r\n");
-
-       return g_string_free(gstr, FALSE);
-}
-
-static char *indicator_values(const struct indicator *indicators)
-{
-       int i;
-       GString *gstr;
-
-       gstr = g_string_new("\r\n+CIND: ");
-
-       for (i = 0; indicators[i].desc != NULL; i++) {
-               if (i == 0)
-                       g_string_append_printf(gstr, "%d", indicators[i].val);
-               else
-                       g_string_append_printf(gstr, ",%d", indicators[i].val);
-       }
-
-       g_string_append(gstr, "\r\n");
-
-       return g_string_free(gstr, FALSE);
-}
-
-static int report_indicators(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       int err;
-       char *str;
-
-       if (strlen(buf) < 8)
-               return -EINVAL;
-
-       if (ag.indicators == NULL) {
-               error("HFP AG indicators not initialized");
-               return headset_send(hs, "\r\nERROR\r\n");
-       }
-
-       if (buf[7] == '=')
-               str = indicator_ranges(ag.indicators);
-       else
-               str = indicator_values(ag.indicators);
-
-       err = headset_send(hs, "%s", str);
-
-       g_free(str);
-
-       if (err < 0)
-               return err;
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-static void pending_connect_complete(struct connect_cb *cb, struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (hs->pending->err < 0)
-               cb->cb(NULL, cb->cb_data);
-       else
-               cb->cb(dev, cb->cb_data);
-}
-
-static void pending_connect_finalize(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-       struct pending_connect *p = hs->pending;
-
-       if (p == NULL)
-               return;
-
-       if (p->svclass)
-               bt_cancel_discovery(&dev->src, &dev->dst);
-
-       g_slist_foreach(p->callbacks, (GFunc) pending_connect_complete, dev);
-
-       g_slist_free_full(p->callbacks, g_free);
-
-       if (p->io) {
-               g_io_channel_shutdown(p->io, TRUE, NULL);
-               g_io_channel_unref(p->io);
-       }
-
-       if (p->msg)
-               dbus_message_unref(p->msg);
-
-       if (p->call) {
-               dbus_pending_call_cancel(p->call);
-               dbus_pending_call_unref(p->call);
-       }
-
-       g_free(p);
-
-       hs->pending = NULL;
-}
-
-static void pending_connect_init(struct headset *hs, headset_state_t target_state)
-{
-       if (hs->pending) {
-               if (hs->pending->target_state < target_state)
-                       hs->pending->target_state = target_state;
-               return;
-       }
-
-       hs->pending = g_new0(struct pending_connect, 1);
-       hs->pending->target_state = target_state;
-}
-
-static unsigned int connect_cb_new(struct headset *hs,
-                                       headset_state_t target_state,
-                                       headset_stream_cb_t func,
-                                       void *user_data)
-{
-       struct connect_cb *cb;
-       static unsigned int free_cb_id = 1;
-
-       pending_connect_init(hs, target_state);
-
-       if (!func)
-               return 0;
-
-       cb = g_new(struct connect_cb, 1);
-
-       cb->cb = func;
-       cb->cb_data = user_data;
-       cb->id = free_cb_id++;
-
-       hs->pending->callbacks = g_slist_append(hs->pending->callbacks,
-                                               cb);
-
-       return cb->id;
-}
-
-static void __attribute__((format(printf, 3, 4)))
-               send_foreach_headset(GSList *devices,
-                                       int (*cmp) (struct headset *hs),
-                                       char *format, ...)
-{
-       GSList *l;
-       va_list ap;
-
-       for (l = devices; l != NULL; l = l->next) {
-               struct audio_device *device = l->data;
-               struct headset *hs = device->headset;
-               int ret;
-
-               assert(hs != NULL);
-
-               if (cmp && cmp(hs) != 0)
-                       continue;
-
-               va_start(ap, format);
-               ret = headset_send_valist(hs, format, ap);
-               if (ret < 0)
-                       error("Failed to send to headset: %s (%d)",
-                                       strerror(-ret), -ret);
-               va_end(ap);
-       }
-}
-
-static int cli_cmp(struct headset *hs)
-{
-       struct headset_slc *slc = hs->slc;
-
-       if (!hs->hfp_active)
-               return -1;
-
-       if (slc->cli_active)
-               return 0;
-       else
-               return -1;
-}
-
-static gboolean ring_timer_cb(gpointer data)
-{
-       send_foreach_headset(active_devices, NULL, "\r\nRING\r\n");
-
-       if (ag.number)
-               send_foreach_headset(active_devices, cli_cmp,
-                                       "\r\n+CLIP: \"%s\",%d\r\n",
-                                       ag.number, ag.number_type);
-
-       return TRUE;
-}
-
-static void sco_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
-{
-       int sk;
-       struct audio_device *dev = user_data;
-       struct headset *hs = dev->headset;
-       struct headset_slc *slc = hs->slc;
-       struct pending_connect *p = hs->pending;
-
-       if (err) {
-               error("%s", err->message);
-
-               if (p != NULL) {
-                       p->err = -errno;
-                       if (p->msg)
-                               error_connect_failed(dev->conn, p->msg, p->err);
-                       pending_connect_finalize(dev);
-               }
-
-               if (hs->rfcomm)
-                       headset_set_state(dev, HEADSET_STATE_CONNECTED);
-               else
-                       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-
-               return;
-       }
-
-       DBG("SCO socket opened for headset %s", dev->path);
-
-       sk = g_io_channel_unix_get_fd(chan);
-
-       DBG("SCO fd=%d", sk);
-
-       if (p) {
-               p->io = NULL;
-               if (p->msg) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(p->msg);
-                       g_dbus_send_message(dev->conn, reply);
-               }
-
-               pending_connect_finalize(dev);
-       }
-
-       fcntl(sk, F_SETFL, 0);
-
-       headset_set_state(dev, HEADSET_STATE_PLAYING);
-
-       if (slc->pending_ring) {
-               ring_timer_cb(NULL);
-               ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
-                                               ring_timer_cb,
-                                               NULL);
-               slc->pending_ring = FALSE;
-       }
-}
-
-static int sco_connect(struct audio_device *dev, headset_stream_cb_t cb,
-                       void *user_data, unsigned int *cb_id)
-{
-       struct headset *hs = dev->headset;
-       GError *err = NULL;
-       GIOChannel *io;
-
-       if (hs->state != HEADSET_STATE_CONNECTED)
-               return -EINVAL;
-
-       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_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               g_error_free(err);
-               return -EIO;
-       }
-
-       hs->sco = io;
-
-       headset_set_state(dev, HEADSET_STATE_PLAY_IN_PROGRESS);
-
-       pending_connect_init(hs, HEADSET_STATE_PLAYING);
-
-       if (cb) {
-               unsigned int id = connect_cb_new(hs, HEADSET_STATE_PLAYING,
-                                                       cb, user_data);
-               if (cb_id)
-                       *cb_id = id;
-       }
-
-       return 0;
-}
-
-static int hfp_cmp(struct headset *hs)
-{
-       if (hs->hfp_active)
-               return 0;
-       else
-               return -1;
-}
-
-static void hfp_slc_complete(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-       struct pending_connect *p = hs->pending;
-
-       DBG("HFP Service Level Connection established");
-
-       headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
-       if (p == NULL)
-               return;
-
-       if (p->target_state == HEADSET_STATE_CONNECTED) {
-               if (p->msg) {
-                       DBusMessage *reply = dbus_message_new_method_return(p->msg);
-                       g_dbus_send_message(dev->conn, reply);
-               }
-               pending_connect_finalize(dev);
-               return;
-       }
-
-       p->err = sco_connect(dev, NULL, NULL, NULL);
-       if (p->err < 0) {
-               if (p->msg)
-                       error_connect_failed(dev->conn, p->msg, p->err);
-               pending_connect_finalize(dev);
-       }
-}
-
-static int telephony_generic_rsp(struct audio_device *device, cme_error_t err)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if ((err != CME_ERROR_NONE) && slc->cme_enabled)
-               return headset_send(hs, "\r\n+CME ERROR: %d\r\n", err);
-
-       switch (err) {
-       case CME_ERROR_NONE:
-               return headset_send(hs, "\r\nOK\r\n");
-       case CME_ERROR_NO_NETWORK_SERVICE:
-               return headset_send(hs, "\r\nNO CARRIER\r\n");
-       default:
-               return headset_send(hs, "\r\nERROR\r\n");
-       }
-}
-
-int telephony_event_reporting_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;
-       int ret;
-
-       if (err != CME_ERROR_NONE)
-               return telephony_generic_rsp(telephony_device, err);
-
-       ret = headset_send(hs, "\r\nOK\r\n");
-       if (ret < 0)
-               return ret;
-
-       if (hs->state != HEADSET_STATE_CONNECTING)
-               return 0;
-
-       if (slc->hf_features & HF_FEATURE_CALL_WAITING_AND_3WAY &&
-                       ag.features & AG_FEATURE_THREE_WAY_CALLING)
-               return 0;
-
-       hfp_slc_complete(device);
-
-       return 0;
-}
-
-static int event_reporting(struct audio_device *dev, const char *buf)
-{
-       char **tokens; /* <mode>, <keyp>, <disp>, <ind>, <bfr> */
-
-       if (strlen(buf) < 13)
-               return -EINVAL;
-
-       tokens = g_strsplit(&buf[8], ",", 5);
-       if (g_strv_length(tokens) < 4) {
-               g_strfreev(tokens);
-               return -EINVAL;
-       }
-
-       ag.er_mode = atoi(tokens[0]);
-       ag.er_ind = atoi(tokens[3]);
-
-       g_strfreev(tokens);
-       tokens = NULL;
-
-       DBG("Event reporting (CMER): mode=%d, ind=%d",
-                       ag.er_mode, ag.er_ind);
-
-       switch (ag.er_ind) {
-       case 0:
-       case 1:
-               telephony_event_reporting_req(dev, ag.er_ind);
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int call_hold(struct audio_device *dev, const char *buf)
-{
-       struct headset *hs = dev->headset;
-       int err;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       if (buf[8] != '?') {
-               telephony_call_hold_req(dev, &buf[8]);
-               return 0;
-       }
-
-       err = headset_send(hs, "\r\n+CHLD: (%s)\r\n", ag.chld);
-       if (err < 0)
-               return err;
-
-       err = headset_send(hs, "\r\nOK\r\n");
-       if (err < 0)
-               return err;
-
-       if (hs->state != HEADSET_STATE_CONNECTING)
-               return 0;
-
-       hfp_slc_complete(dev);
-
-       return 0;
-}
-
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int key_press(struct audio_device *device, const char *buf)
-{
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       g_dbus_emit_signal(device->conn, device->path,
-                       AUDIO_HEADSET_INTERFACE, "AnswerRequested",
-                       DBUS_TYPE_INVALID);
-
-       if (ag.ring_timer) {
-               g_source_remove(ag.ring_timer);
-               ag.ring_timer = 0;
-       }
-
-       telephony_key_press_req(device, &buf[8]);
-
-       return 0;
-}
-
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int answer_call(struct audio_device *device, const char *buf)
-{
-       if (ag.ring_timer) {
-               g_source_remove(ag.ring_timer);
-               ag.ring_timer = 0;
-       }
-
-       if (ag.number) {
-               g_free(ag.number);
-               ag.number = NULL;
-       }
-
-       telephony_answer_call_req(device);
-
-       return 0;
-}
-
-int telephony_terminate_call_rsp(void *telephony_device,
-                                       cme_error_t err)
-{
-       struct audio_device *device = telephony_device;
-       struct headset *hs = device->headset;
-
-       if (err != CME_ERROR_NONE)
-               return telephony_generic_rsp(telephony_device, err);
-
-       g_dbus_emit_signal(device->conn, device->path,
-                       AUDIO_HEADSET_INTERFACE, "CallTerminated",
-                       DBUS_TYPE_INVALID);
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-static int terminate_call(struct audio_device *device, const char *buf)
-{
-       if (ag.number) {
-               g_free(ag.number);
-               ag.number = NULL;
-       }
-
-       if (ag.ring_timer) {
-               g_source_remove(ag.ring_timer);
-               ag.ring_timer = 0;
-       }
-
-       telephony_terminate_call_req(device);
-
-       return 0;
-}
-
-static int cli_notification(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       slc->cli_active = buf[8] == '1' ? TRUE : FALSE;
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_response_and_hold_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int response_and_hold(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-
-       if (strlen(buf) < 8)
-               return -EINVAL;
-
-       if (ag.rh == BTRH_NOT_SUPPORTED)
-               return telephony_generic_rsp(device, CME_ERROR_NOT_SUPPORTED);
-
-       if (buf[7] == '=') {
-               telephony_response_and_hold_req(device, atoi(&buf[8]) < 0);
-               return 0;
-       }
-
-       if (ag.rh >= 0)
-               headset_send(hs, "\r\n+BTRH: %d\r\n", ag.rh);
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int last_dialed_number(struct audio_device *device, const char *buf)
-{
-       telephony_last_dialed_number_req(device);
-
-       return 0;
-}
-
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int dial_number(struct audio_device *device, const char *buf)
-{
-       char number[BUF_SIZE];
-       size_t buf_len;
-
-       buf_len = strlen(buf);
-
-       if (buf[buf_len - 1] != ';') {
-               DBG("Rejecting non-voice call dial request");
-               return -EINVAL;
-       }
-
-       memset(number, 0, sizeof(number));
-       strncpy(number, &buf[3], buf_len - 4);
-
-       telephony_dial_number_req(device, number);
-
-       return 0;
-}
-
-static int headset_set_gain(struct audio_device *device, uint16_t gain, char type)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-       const char *name, *property;
-
-       if (gain > 15) {
-               error("Invalid gain value: %u", gain);
-               return -EINVAL;
-       }
-
-       switch (type) {
-       case HEADSET_GAIN_SPEAKER:
-               if (slc->sp_gain == gain) {
-                       DBG("Ignoring no-change in speaker gain");
-                       return -EALREADY;
-               }
-               name = "SpeakerGainChanged";
-               property = "SpeakerGain";
-               slc->sp_gain = gain;
-               break;
-       case HEADSET_GAIN_MICROPHONE:
-               if (slc->mic_gain == gain) {
-                       DBG("Ignoring no-change in microphone gain");
-                       return -EALREADY;
-               }
-               name = "MicrophoneGainChanged";
-               property = "MicrophoneGain";
-               slc->mic_gain = gain;
-               break;
-       default:
-               error("Unknown gain setting");
-               return -EINVAL;
-       }
-
-       g_dbus_emit_signal(device->conn, device->path,
-                               AUDIO_HEADSET_INTERFACE, name,
-                               DBUS_TYPE_UINT16, &gain,
-                               DBUS_TYPE_INVALID);
-
-       emit_property_changed(device->conn, device->path,
-                               AUDIO_HEADSET_INTERFACE, property,
-                               DBUS_TYPE_UINT16, &gain);
-
-       return 0;
-}
-
-static int signal_gain_setting(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       dbus_uint16_t gain;
-       int err;
-
-       if (strlen(buf) < 8) {
-               error("Too short string for Gain setting");
-               return -EINVAL;
-       }
-
-       gain = (dbus_uint16_t) strtol(&buf[7], NULL, 10);
-
-       err = headset_set_gain(device, gain, buf[5]);
-       if (err < 0 && err != -EALREADY)
-               return err;
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int dtmf_tone(struct audio_device *device, const char *buf)
-{
-       char tone;
-
-       if (strlen(buf) < 8) {
-               error("Too short string for DTMF tone");
-               return -EINVAL;
-       }
-
-       tone = buf[7];
-       if (tone >= '#' && tone <= 'D')
-               telephony_transmit_dtmf_req(device, tone);
-       else
-               return -EINVAL;
-
-       return 0;
-}
-
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int subscriber_number(struct audio_device *device, const char *buf)
-{
-       telephony_subscriber_number_req(device);
-
-       return 0;
-}
-
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-static int list_current_calls(struct audio_device *device, const char *buf)
-{
-       telephony_list_current_calls_req(device);
-
-       return 0;
-}
-
-static int extended_errors(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       if (buf[8] == '1') {
-               slc->cme_enabled = TRUE;
-               DBG("CME errors enabled for headset %p", hs);
-       } else {
-               slc->cme_enabled = FALSE;
-               DBG("CME errors disabled for headset %p", hs);
-       }
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-static int call_waiting_notify(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       if (buf[8] == '1') {
-               slc->cwa_enabled = TRUE;
-               DBG("Call waiting notification enabled for headset %p", hs);
-       } else {
-               slc->cwa_enabled = FALSE;
-               DBG("Call waiting notification disabled for headset %p", hs);
-       }
-
-       return headset_send(hs, "\r\nOK\r\n");
-}
-
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_nr_and_ec_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;
-
-       if (err == CME_ERROR_NONE) {
-               GSList *l;
-
-               for (l = hs->nrec_cbs; l; l = l->next) {
-                       struct headset_nrec_callback *nrec_cb = l->data;
-
-                       nrec_cb->cb(device, slc->nrec_req, nrec_cb->user_data);
-               }
-
-               slc->nrec = hs->slc->nrec_req;
-       }
-
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err)
-{
-       return telephony_generic_rsp(telephony_device, err);
-}
-
-int telephony_operator_selection_ind(int mode, const char *oper)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       send_foreach_headset(active_devices, hfp_cmp,
-                               "\r\n+COPS: %d,0,\"%s\"\r\n",
-                               mode, oper);
-       return 0;
-}
-
-static int operator_selection(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-
-       if (strlen(buf) < 8)
-               return -EINVAL;
-
-       switch (buf[7]) {
-       case '?':
-               telephony_operator_selection_req(device);
-               break;
-       case '=':
-               return headset_send(hs, "\r\nOK\r\n");
-       default:
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int nr_and_ec(struct audio_device *device, const char *buf)
-{
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       if (buf[8] == '0')
-               slc->nrec_req = FALSE;
-       else
-               slc->nrec_req = TRUE;
-
-       telephony_nr_and_ec_req(device, slc->nrec_req);
-
-       return 0;
-}
-
-static int voice_dial(struct audio_device *device, const char *buf)
-{
-       gboolean enable;
-
-       if (strlen(buf) < 9)
-               return -EINVAL;
-
-       if (buf[8] == '0')
-               enable = FALSE;
-       else
-               enable = TRUE;
-
-       telephony_voice_dial_req(device, enable);
-
-       return 0;
-}
-
-static int apple_command(struct audio_device *device, const char *buf)
-{
-       DBG("Got Apple command: %s", buf);
-
-       return telephony_generic_rsp(device, CME_ERROR_NONE);
-}
-
-static struct event event_callbacks[] = {
-       { "ATA", answer_call },
-       { "ATD", dial_number },
-       { "AT+VG", signal_gain_setting },
-       { "AT+BRSF", supported_features },
-       { "AT+CIND", report_indicators },
-       { "AT+CMER", event_reporting },
-       { "AT+CHLD", call_hold },
-       { "AT+CHUP", terminate_call },
-       { "AT+CKPD", key_press },
-       { "AT+CLIP", cli_notification },
-       { "AT+BTRH", response_and_hold },
-       { "AT+BLDN", last_dialed_number },
-       { "AT+VTS", dtmf_tone },
-       { "AT+CNUM", subscriber_number },
-       { "AT+CLCC", list_current_calls },
-       { "AT+CMEE", extended_errors },
-       { "AT+CCWA", call_waiting_notify },
-       { "AT+COPS", operator_selection },
-       { "AT+NREC", nr_and_ec },
-       { "AT+BVRA", voice_dial },
-       { "AT+XAPL", apple_command },
-       { "AT+IPHONEACCEV", apple_command },
-       { 0 }
-};
-
-static int handle_event(struct audio_device *device, const char *buf)
-{
-       struct event *ev;
-
-       DBG("Received %s", buf);
-
-       for (ev = event_callbacks; ev->cmd; ev++) {
-               if (!strncmp(buf, ev->cmd, strlen(ev->cmd)))
-                       return ev->callback(device, buf);
-       }
-
-       return -EINVAL;
-}
-
-static void close_sco(struct audio_device *device)
-{
-       struct headset *hs = device->headset;
-
-       if (hs->sco) {
-               int sock = g_io_channel_unix_get_fd(hs->sco);
-               shutdown(sock, SHUT_RDWR);
-               g_io_channel_shutdown(hs->sco, TRUE, NULL);
-               g_io_channel_unref(hs->sco);
-               hs->sco = NULL;
-       }
-
-       if (hs->sco_id) {
-               g_source_remove(hs->sco_id);
-               hs->sco_id = 0;
-       }
-}
-
-static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond,
-                               struct audio_device *device)
-{
-       struct headset *hs;
-       struct headset_slc *slc;
-       unsigned char buf[BUF_SIZE];
-       ssize_t bytes_read;
-       size_t free_space;
-       int fd;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       hs = device->headset;
-       slc = hs->slc;
-
-       if (cond & (G_IO_ERR | G_IO_HUP)) {
-               DBG("ERR or HUP on RFCOMM socket");
-               goto failed;
-       }
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       bytes_read = read(fd, buf, sizeof(buf) - 1);
-       if (bytes_read < 0)
-               return TRUE;
-
-       free_space = sizeof(slc->buf) - slc->data_start -
-                       slc->data_length - 1;
-
-       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 incoming buffer");
-               goto failed;
-       }
-
-       memcpy(&slc->buf[slc->data_start], buf, bytes_read);
-       slc->data_length += bytes_read;
-
-       /* Make sure the data is null terminated so we can use string
-        * functions */
-       slc->buf[slc->data_start + slc->data_length] = '\0';
-
-       while (slc->data_length > 0) {
-               char *cr;
-               int err;
-               off_t cmd_len;
-
-               cr = strchr(&slc->buf[slc->data_start], '\r');
-               if (!cr)
-                       break;
-
-               cmd_len = 1 + (off_t) cr - (off_t) &slc->buf[slc->data_start];
-               *cr = '\0';
-
-               if (cmd_len > 1)
-                       err = handle_event(device, &slc->buf[slc->data_start]);
-               else
-                       /* Silently skip empty commands */
-                       err = 0;
-
-               if (err == -EINVAL) {
-                       error("Badly formated or unrecognized command: %s",
-                                       &slc->buf[slc->data_start]);
-                       err = telephony_generic_rsp(device,
-                                               CME_ERROR_NOT_SUPPORTED);
-                       if (err < 0)
-                               goto failed;
-               } else if (err < 0)
-                       error("Error handling command %s: %s (%d)",
-                                               &slc->buf[slc->data_start],
-                                               strerror(-err), -err);
-
-               slc->data_start += cmd_len;
-               slc->data_length -= cmd_len;
-
-               if (!slc->data_length)
-                       slc->data_start = 0;
-       }
-
-       return TRUE;
-
-failed:
-       headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
-       return FALSE;
-}
-
-static gboolean sco_cb(GIOChannel *chan, GIOCondition cond,
-                       struct audio_device *device)
-{
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       error("Audio connection got disconnected");
-
-       pending_connect_finalize(device);
-       headset_set_state(device, HEADSET_STATE_CONNECTED);
-
-       return FALSE;
-}
-
-void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct headset *hs = dev->headset;
-       struct pending_connect *p = hs->pending;
-       char hs_address[18];
-
-       if (err) {
-               error("%s", err->message);
-               goto failed;
-       }
-
-       /* For HFP telephony isn't ready just disconnect */
-       if (hs->hfp_active && !ag.telephony_ready) {
-               error("Unable to accept HFP connection since the telephony "
-                               "subsystem isn't initialized");
-               goto failed;
-       }
-
-       hs->rfcomm = hs->tmp_rfcomm;
-       hs->tmp_rfcomm = NULL;
-
-       ba2str(&dev->dst, hs_address);
-
-       if (p)
-               p->io = NULL;
-       else
-               hs->auto_dc = FALSE;
-
-       g_io_add_watch(chan, G_IO_IN | G_IO_ERR | G_IO_HUP| G_IO_NVAL,
-                       (GIOFunc) rfcomm_io_cb, dev);
-
-       DBG("%s: Connected to %s", dev->path, hs_address);
-
-       hs->slc = g_new0(struct headset_slc, 1);
-       hs->slc->sp_gain = 15;
-       hs->slc->mic_gain = 15;
-       hs->slc->nrec = TRUE;
-
-       /* In HFP mode wait for Service Level Connection */
-       if (hs->hfp_active)
-               return;
-
-       headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
-       if (p && p->target_state == HEADSET_STATE_PLAYING) {
-               p->err = sco_connect(dev, NULL, NULL, NULL);
-               if (p->err < 0)
-                       goto failed;
-               return;
-       }
-
-       if (p && p->msg) {
-               DBusMessage *reply = dbus_message_new_method_return(p->msg);
-               g_dbus_send_message(dev->conn, reply);
-       }
-
-       pending_connect_finalize(dev);
-
-       return;
-
-failed:
-       if (p && p->msg)
-               error_connect_failed(dev->conn, p->msg, p->err);
-       pending_connect_finalize(dev);
-       if (hs->rfcomm)
-               headset_set_state(dev, HEADSET_STATE_CONNECTED);
-       else
-               headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-}
-
-static int headset_set_channel(struct headset *headset,
-                               const sdp_record_t *record, uint16_t svc)
-{
-       int ch;
-       sdp_list_t *protos;
-
-       if (sdp_get_access_protos(record, &protos) < 0) {
-               error("Unable to get access protos from headset record");
-               return -1;
-       }
-
-       ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-
-       sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-       sdp_list_free(protos, NULL);
-
-       if (ch <= 0) {
-               error("Unable to get RFCOMM channel from Headset record");
-               return -1;
-       }
-
-       headset->rfcomm_ch = ch;
-
-       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);
-       }
-
-       return 0;
-}
-
-static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
-       struct audio_device *dev = user_data;
-       struct headset *hs = dev->headset;
-       struct pending_connect *p = hs->pending;
-       sdp_record_t *record = NULL;
-       sdp_list_t *r;
-       uuid_t uuid;
-
-       assert(hs->pending != NULL);
-
-       if (err < 0) {
-               error("Unable to get service record: %s (%d)",
-                                                       strerror(-err), -err);
-               p->err = -err;
-               if (p->msg)
-                       error_connect_failed(dev->conn, p->msg, p->err);
-               goto failed;
-       }
-
-       if (!recs || !recs->data) {
-               error("No records found");
-               goto failed_not_supported;
-       }
-
-       sdp_uuid16_create(&uuid, p->svclass);
-
-       for (r = recs; r != NULL; r = r->next) {
-               sdp_list_t *classes;
-               uuid_t class;
-
-               record = r->data;
-
-               if (sdp_get_service_classes(record, &classes) < 0) {
-                       error("Unable to get service classes from record");
-                       continue;
-               }
-
-               memcpy(&class, classes->data, sizeof(uuid));
-
-               sdp_list_free(classes, free);
-
-               if (sdp_uuid_cmp(&class, &uuid) == 0)
-                       break;
-       }
-
-       if (r == NULL) {
-               error("No record found with UUID 0x%04x", p->svclass);
-               goto failed_not_supported;
-       }
-
-       if (headset_set_channel(hs, record, p->svclass) < 0) {
-               error("Unable to extract RFCOMM channel from service record");
-               goto failed_not_supported;
-       }
-
-       /* Set svclass to 0 so we can easily check that SDP is no-longer
-        * going on (to know if bt_cancel_discovery needs to be called) */
-       p->svclass = 0;
-
-       err = rfcomm_connect(dev, NULL, NULL, NULL);
-       if (err < 0) {
-               error("Unable to connect: %s (%d)", strerror(-err), -err);
-               p->err = -err;
-               if (p->msg != NULL)
-                       error_connect_failed(dev->conn, p->msg, p->err);
-               goto failed;
-       }
-
-       return;
-
-failed_not_supported:
-       if (p->svclass == HANDSFREE_SVCLASS_ID &&
-                       get_records(dev, NULL, NULL, NULL) == 0)
-               return;
-       if (p->msg) {
-               DBusMessage *reply = btd_error_not_supported(p->msg);
-               g_dbus_send_message(dev->conn, reply);
-       }
-failed:
-       p->svclass = 0;
-       pending_connect_finalize(dev);
-       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-}
-
-static int get_records(struct audio_device *device, headset_stream_cb_t cb,
-                       void *user_data, unsigned int *cb_id)
-{
-       struct headset *hs = device->headset;
-       uint16_t svclass;
-       uuid_t uuid;
-       int err;
-
-       if (hs->pending && hs->pending->svclass == HANDSFREE_SVCLASS_ID)
-               svclass = HEADSET_SVCLASS_ID;
-       else
-               svclass = hs->search_hfp ? HANDSFREE_SVCLASS_ID :
-                                                       HEADSET_SVCLASS_ID;
-
-       sdp_uuid16_create(&uuid, svclass);
-
-       err = bt_search_service(&device->src, &device->dst, &uuid,
-                                               get_record_cb, device, NULL);
-       if (err < 0)
-               return err;
-
-       if (hs->pending) {
-               hs->pending->svclass = svclass;
-               return 0;
-       }
-
-       headset_set_state(device, HEADSET_STATE_CONNECTING);
-
-       pending_connect_init(hs, HEADSET_STATE_CONNECTED);
-
-       hs->pending->svclass = svclass;
-
-       if (cb) {
-               unsigned int id;
-               id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
-                                       cb, user_data);
-               if (cb_id)
-                       *cb_id = id;
-       }
-
-       return 0;
-}
-
-static int rfcomm_connect(struct audio_device *dev, headset_stream_cb_t cb,
-                               void *user_data, unsigned int *cb_id)
-{
-       struct headset *hs = dev->headset;
-       char address[18];
-       GError *err = NULL;
-
-       if (!manager_allow_headset_connection(dev))
-               return -ECONNREFUSED;
-
-       if (hs->rfcomm_ch < 0)
-               return get_records(dev, cb, user_data, cb_id);
-
-       ba2str(&dev->dst, address);
-
-       DBG("%s: Connecting to %s channel %d", dev->path, address,
-               hs->rfcomm_ch);
-
-       hs->tmp_rfcomm = bt_io_connect(BT_IO_RFCOMM, headset_connect_cb, dev,
-                                       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;
-
-       if (!hs->tmp_rfcomm) {
-               error("%s", err->message);
-               g_error_free(err);
-               return -EIO;
-       }
-
-       hs->hfp_active = hs->hfp_handle != 0 ? TRUE : FALSE;
-       hs->rfcomm_initiator = FALSE;
-
-       headset_set_state(dev, HEADSET_STATE_CONNECTING);
-
-       pending_connect_init(hs, HEADSET_STATE_CONNECTED);
-
-       if (cb) {
-               unsigned int id = connect_cb_new(hs, HEADSET_STATE_CONNECTED,
-                                                       cb, user_data);
-               if (cb_id)
-                       *cb_id = id;
-       }
-
-       return 0;
-}
-
-static DBusMessage *hs_stop(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       DBusMessage *reply = NULL;
-
-       if (hs->state < HEADSET_STATE_PLAY_IN_PROGRESS)
-               return btd_error_not_connected(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       headset_set_state(device, HEADSET_STATE_CONNECTED);
-
-       return reply;
-}
-
-static DBusMessage *hs_is_playing(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       DBusMessage *reply;
-       dbus_bool_t playing;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       playing = (hs->state == HEADSET_STATE_PLAYING);
-
-       dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &playing,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *hs_disconnect(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       char hs_address[18];
-
-       if (hs->state == HEADSET_STATE_DISCONNECTED)
-               return btd_error_not_connected(msg);
-
-       headset_shutdown(device);
-       ba2str(&device->dst, hs_address);
-       info("Disconnected from %s, %s", hs_address, device->path);
-
-       return dbus_message_new_method_return(msg);
-
-}
-
-static DBusMessage *hs_is_connected(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               void *data)
-{
-       struct audio_device *device = data;
-       DBusMessage *reply;
-       dbus_bool_t connected;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       connected = (device->headset->state >= HEADSET_STATE_CONNECTED);
-
-       dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *hs_connect(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       int err;
-
-       if (hs->state == HEADSET_STATE_CONNECTING)
-               return btd_error_in_progress(msg);
-       else if (hs->state > HEADSET_STATE_CONNECTING)
-               return btd_error_already_connected(msg);
-
-       if (hs->hfp_handle && !ag.telephony_ready)
-               return btd_error_not_ready(msg);
-
-       device->auto_connect = FALSE;
-
-       err = rfcomm_connect(device, NULL, NULL, NULL);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       hs->auto_dc = FALSE;
-
-       hs->pending->msg = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-static DBusMessage *hs_ring(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       DBusMessage *reply = NULL;
-       int err;
-
-       if (hs->state < HEADSET_STATE_CONNECTED)
-               return btd_error_not_connected(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       if (ag.ring_timer) {
-               DBG("IndicateCall received when already indicating");
-               return reply;
-       }
-
-       err = headset_send(hs, "\r\nRING\r\n");
-       if (err < 0) {
-               dbus_message_unref(reply);
-               return btd_error_failed(msg, strerror(-err));
-       }
-
-       ring_timer_cb(NULL);
-       ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
-                                               NULL);
-
-       return reply;
-}
-
-static DBusMessage *hs_cancel_call(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       DBusMessage *reply = NULL;
-
-       if (hs->state < HEADSET_STATE_CONNECTED)
-               return btd_error_not_connected(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       if (ag.ring_timer) {
-               g_source_remove(ag.ring_timer);
-               ag.ring_timer = 0;
-       } else
-               DBG("Got CancelCall method call but no call is active");
-
-       return reply;
-}
-
-static DBusMessage *hs_play(DBusConnection *conn, DBusMessage *msg,
-                               void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       int err;
-
-       if (sco_hci) {
-               error("Refusing Headset.Play() because SCO HCI routing "
-                               "is enabled");
-               return btd_error_not_available(msg);
-       }
-
-       switch (hs->state) {
-       case HEADSET_STATE_DISCONNECTED:
-       case HEADSET_STATE_CONNECTING:
-               return btd_error_not_connected(msg);
-       case HEADSET_STATE_PLAY_IN_PROGRESS:
-               if (hs->pending && hs->pending->msg == NULL) {
-                       hs->pending->msg = dbus_message_ref(msg);
-                       return NULL;
-               }
-               return btd_error_busy(msg);
-       case HEADSET_STATE_PLAYING:
-               return btd_error_already_connected(msg);
-       case HEADSET_STATE_CONNECTED:
-       default:
-               break;
-       }
-
-       err = sco_connect(device, NULL, NULL, NULL);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       hs->pending->msg = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-static DBusMessage *hs_get_speaker_gain(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-       DBusMessage *reply;
-       dbus_uint16_t gain;
-
-       if (hs->state < HEADSET_STATE_CONNECTED)
-               return btd_error_not_available(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       gain = (dbus_uint16_t) slc->sp_gain;
-
-       dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *hs_get_mic_gain(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       struct headset_slc *slc = hs->slc;
-       DBusMessage *reply;
-       dbus_uint16_t gain;
-
-       if (hs->state < HEADSET_STATE_CONNECTED || slc == NULL)
-               return btd_error_not_available(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       gain = (dbus_uint16_t) slc->mic_gain;
-
-       dbus_message_append_args(reply, DBUS_TYPE_UINT16, &gain,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *hs_set_gain(DBusConnection *conn,
-                               DBusMessage *msg,
-                               void *data, uint16_t gain,
-                               char type)
-{
-       struct audio_device *device = data;
-       struct headset *hs = device->headset;
-       DBusMessage *reply;
-       int err;
-
-       if (hs->state < HEADSET_STATE_CONNECTED)
-               return btd_error_not_connected(msg);
-
-       err = headset_set_gain(device, gain, type);
-       if (err < 0)
-               return btd_error_invalid_args(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       if (hs->state == HEADSET_STATE_PLAYING) {
-               err = headset_send(hs, "\r\n+VG%c=%u\r\n", type, gain);
-               if (err < 0) {
-                       dbus_message_unref(reply);
-                       return btd_error_failed(msg, strerror(-err));
-               }
-       }
-
-       return reply;
-}
-
-static DBusMessage *hs_set_speaker_gain(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       uint16_t gain;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_SPEAKER);
-}
-
-static DBusMessage *hs_set_mic_gain(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       uint16_t gain;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT16, &gain,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       return hs_set_gain(conn, msg, data, gain, HEADSET_GAIN_MICROPHONE);
-}
-
-static DBusMessage *hs_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       gboolean value;
-       const char *state;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-
-       /* Playing */
-       value = (device->headset->state == HEADSET_STATE_PLAYING);
-       dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value);
-
-       /* State */
-       state = state2str(device->headset->state);
-       if (state)
-               dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
-
-       /* Connected */
-       value = (device->headset->state >= HEADSET_STATE_CONNECTED);
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
-
-       if (!value)
-               goto done;
-
-       /* SpeakerGain */
-       dict_append_entry(&dict, "SpeakerGain",
-                               DBUS_TYPE_UINT16,
-                               &device->headset->slc->sp_gain);
-
-       /* MicrophoneGain */
-       dict_append_entry(&dict, "MicrophoneGain",
-                               DBUS_TYPE_UINT16,
-                               &device->headset->slc->mic_gain);
-
-done:
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static DBusMessage *hs_set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       const char *property;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       uint16_t gain;
-
-       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("SpeakerGain", property)) {
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-                       return btd_error_invalid_args(msg);
-
-               dbus_message_iter_get_basic(&sub, &gain);
-               return hs_set_gain(conn, msg, data, gain,
-                                       HEADSET_GAIN_SPEAKER);
-       } else if (g_str_equal("MicrophoneGain", property)) {
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-                       return btd_error_invalid_args(msg);
-
-               dbus_message_iter_get_basic(&sub, &gain);
-               return hs_set_gain(conn, msg, data, gain,
-                                       HEADSET_GAIN_MICROPHONE);
-       }
-
-       return btd_error_invalid_args(msg);
-}
-
-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) },
-       { }
-};
-
-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,
-                       const char *uuidstr)
-{
-       struct headset *headset = dev->headset;
-       const sdp_record_t *record;
-
-       record = btd_device_get_record(dev->btd_dev, uuidstr);
-       if (!record)
-               return;
-
-       switch (svc) {
-       case HANDSFREE_SVCLASS_ID:
-               if (headset->hfp_handle &&
-                               (headset->hfp_handle != record->handle)) {
-                       error("More than one HFP record found on device");
-                       return;
-               }
-
-               headset->hfp_handle = record->handle;
-               break;
-
-       case HEADSET_SVCLASS_ID:
-               if (headset->hsp_handle &&
-                               (headset->hsp_handle != record->handle)) {
-                       error("More than one HSP record found on device");
-                       return;
-               }
-
-               headset->hsp_handle = record->handle;
-
-               /* Ignore this record if we already have access to HFP */
-               if (headset->hfp_handle)
-                       return;
-
-               break;
-
-       default:
-               DBG("Invalid record passed to headset_update");
-               return;
-       }
-}
-
-static int headset_close_rfcomm(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-       GIOChannel *rfcomm = hs->tmp_rfcomm ? hs->tmp_rfcomm : hs->rfcomm;
-
-       if (rfcomm) {
-               g_io_channel_shutdown(rfcomm, TRUE, NULL);
-               g_io_channel_unref(rfcomm);
-               hs->tmp_rfcomm = NULL;
-               hs->rfcomm = NULL;
-       }
-
-       g_free(hs->slc);
-       hs->slc = NULL;
-
-       return 0;
-}
-
-static void headset_free(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (hs->dc_timer) {
-               g_source_remove(hs->dc_timer);
-               hs->dc_timer = 0;
-       }
-
-       close_sco(dev);
-
-       headset_close_rfcomm(dev);
-
-       g_slist_free_full(hs->nrec_cbs, g_free);
-
-       g_free(hs);
-       dev->headset = NULL;
-}
-
-static void path_unregister(void *data)
-{
-       struct audio_device *dev = data;
-       struct headset *hs = dev->headset;
-
-       if (hs->state > HEADSET_STATE_DISCONNECTED) {
-               DBG("Headset unregistered while device was connected!");
-               headset_shutdown(dev);
-       }
-
-       DBG("Unregistered interface %s on path %s",
-               AUDIO_HEADSET_INTERFACE, dev->path);
-
-       headset_free(dev);
-}
-
-void headset_unregister(struct audio_device *dev)
-{
-       g_dbus_unregister_interface(dev->conn, dev->path,
-               AUDIO_HEADSET_INTERFACE);
-}
-
-struct headset *headset_init(struct audio_device *dev, uint16_t svc,
-                               const char *uuidstr)
-{
-       struct headset *hs;
-       const sdp_record_t *record;
-
-       hs = g_new0(struct headset, 1);
-       hs->rfcomm_ch = -1;
-       hs->search_hfp = server_is_enabled(&dev->src, HANDSFREE_SVCLASS_ID);
-
-       record = btd_device_get_record(dev->btd_dev, uuidstr);
-       if (!record)
-               goto register_iface;
-
-       switch (svc) {
-       case HANDSFREE_SVCLASS_ID:
-               hs->hfp_handle = record->handle;
-               break;
-
-       case HEADSET_SVCLASS_ID:
-               hs->hsp_handle = record->handle;
-               break;
-
-       default:
-               DBG("Invalid record passed to headset_init");
-               g_free(hs);
-               return NULL;
-       }
-
-register_iface:
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE,
-                                       headset_methods, headset_signals, NULL,
-                                       dev, path_unregister)) {
-               g_free(hs);
-               return NULL;
-       }
-
-       DBG("Registered interface %s on path %s",
-               AUDIO_HEADSET_INTERFACE, dev->path);
-
-       return hs;
-}
-
-uint32_t headset_config_init(GKeyFile *config)
-{
-       GError *err = NULL;
-       char *str;
-
-       /* Use the default values if there is no config file */
-       if (config == NULL)
-               return ag.features;
-
-       str = g_key_file_get_string(config, "General", "SCORouting",
-                                       &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               if (strcmp(str, "PCM") == 0)
-                       sco_hci = FALSE;
-               else if (strcmp(str, "HCI") == 0)
-                       sco_hci = TRUE;
-               else
-                       error("Invalid Headset Routing value: %s", str);
-               g_free(str);
-       }
-
-       /* Init fast connectable option */
-       str = g_key_file_get_string(config, "Headset", "FastConnectable",
-                                       &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               fast_connectable = strcmp(str, "true") == 0;
-               if (fast_connectable)
-                       manager_set_fast_connectable(FALSE);
-               g_free(str);
-       }
-
-       return ag.features;
-}
-
-static gboolean hs_dc_timeout(struct audio_device *dev)
-{
-       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-       return FALSE;
-}
-
-gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id)
-{
-       struct headset *hs = dev->headset;
-       struct pending_connect *p = hs->pending;
-       GSList *l;
-       struct connect_cb *cb = NULL;
-
-       if (!p)
-               return FALSE;
-
-       for (l = p->callbacks; l != NULL; l = l->next) {
-               struct connect_cb *tmp = l->data;
-
-               if (tmp->id == id) {
-                       cb = tmp;
-                       break;
-               }
-       }
-
-       if (!cb)
-               return FALSE;
-
-       p->callbacks = g_slist_remove(p->callbacks, cb);
-       g_free(cb);
-
-       if (p->callbacks || p->msg)
-               return TRUE;
-
-       if (hs->auto_dc) {
-               if (hs->rfcomm)
-                       hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,
-                                               (GSourceFunc) hs_dc_timeout,
-                                               dev);
-               else
-                       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-       }
-
-       return TRUE;
-}
-
-static gboolean dummy_connect_complete(struct audio_device *dev)
-{
-       pending_connect_finalize(dev);
-       return FALSE;
-}
-
-unsigned int headset_request_stream(struct audio_device *dev,
-                                       headset_stream_cb_t cb,
-                                       void *user_data)
-{
-       struct headset *hs = dev->headset;
-       unsigned int id;
-
-       if (hs->state == HEADSET_STATE_PLAYING) {
-               id = connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
-               g_idle_add((GSourceFunc) dummy_connect_complete, dev);
-               return id;
-       }
-
-       if (hs->dc_timer) {
-               g_source_remove(hs->dc_timer);
-               hs->dc_timer = 0;
-       }
-
-       if (hs->state == HEADSET_STATE_CONNECTING ||
-                       hs->state == HEADSET_STATE_PLAY_IN_PROGRESS)
-               return connect_cb_new(hs, HEADSET_STATE_PLAYING, cb, user_data);
-
-       if (hs->rfcomm == NULL) {
-               if (rfcomm_connect(dev, cb, user_data, &id) < 0)
-                       return 0;
-               hs->auto_dc = TRUE;
-       } else if (sco_connect(dev, cb, user_data, &id) < 0)
-               return 0;
-
-       hs->pending->target_state = HEADSET_STATE_PLAYING;
-
-       return id;
-}
-
-unsigned int headset_config_stream(struct audio_device *dev,
-                                       gboolean auto_dc,
-                                       headset_stream_cb_t cb,
-                                       void *user_data)
-{
-       struct headset *hs = dev->headset;
-       unsigned int id = 0;
-
-       if (hs->dc_timer) {
-               g_source_remove(hs->dc_timer);
-               hs->dc_timer = 0;
-       }
-
-       if (hs->state == HEADSET_STATE_CONNECTING)
-               return connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb,
-                                       user_data);
-
-       if (hs->rfcomm)
-               goto done;
-
-       if (rfcomm_connect(dev, cb, user_data, &id) < 0)
-               return 0;
-
-       hs->auto_dc = auto_dc;
-       hs->pending->target_state = HEADSET_STATE_CONNECTED;
-
-       return id;
-
-done:
-       id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data);
-       g_idle_add((GSourceFunc) dummy_connect_complete, dev);
-       return id;
-}
-
-unsigned int headset_suspend_stream(struct audio_device *dev,
-                                       headset_stream_cb_t cb,
-                                       void *user_data)
-{
-       struct headset *hs = dev->headset;
-       unsigned int id;
-       int sock;
-
-       if (hs->state == HEADSET_STATE_DISCONNECTED ||
-                               hs->state == HEADSET_STATE_CONNECTING)
-               return 0;
-
-       if (hs->dc_timer) {
-               g_source_remove(hs->dc_timer);
-               hs->dc_timer = 0;
-       }
-
-       if (hs->sco) {
-               sock = g_io_channel_unix_get_fd(hs->sco);
-
-               /* shutdown but leave the socket open and wait for hup */
-               shutdown(sock, SHUT_RDWR);
-       } else {
-               headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
-               g_idle_add((GSourceFunc) dummy_connect_complete, dev);
-       }
-
-       id = connect_cb_new(hs, HEADSET_STATE_CONNECTED, cb, user_data);
-
-       return id;
-}
-
-gboolean headset_get_hfp_active(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->hfp_active;
-}
-
-void headset_set_hfp_active(struct audio_device *dev, gboolean active)
-{
-       struct headset *hs = dev->headset;
-
-       hs->hfp_active = active;
-}
-
-gboolean headset_get_rfcomm_initiator(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->rfcomm_initiator;
-}
-
-void headset_set_rfcomm_initiator(struct audio_device *dev,
-                                       gboolean initiator)
-{
-       struct headset *hs = dev->headset;
-
-       hs->rfcomm_initiator = initiator;
-}
-
-GIOChannel *headset_get_rfcomm(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->tmp_rfcomm;
-}
-
-int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *io)
-{
-       struct headset *hs = dev->headset;
-
-       if (hs->tmp_rfcomm)
-               return -EALREADY;
-
-       hs->tmp_rfcomm = g_io_channel_ref(io);
-
-       return 0;
-}
-
-int headset_connect_sco(struct audio_device *dev, GIOChannel *io)
-{
-       struct headset *hs = dev->headset;
-       struct headset_slc *slc = hs->slc;
-
-       if (hs->sco)
-               return -EISCONN;
-
-       hs->sco = g_io_channel_ref(io);
-
-       if (slc->pending_ring) {
-               ring_timer_cb(NULL);
-               ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL,
-                                               ring_timer_cb,
-                                               NULL);
-               slc->pending_ring = FALSE;
-       }
-
-       return 0;
-}
-
-void headset_set_state(struct audio_device *dev, headset_state_t state)
-{
-       struct headset *hs = dev->headset;
-       struct headset_slc *slc = hs->slc;
-       gboolean value;
-       const char *state_str;
-       headset_state_t old_state = hs->state;
-       GSList *l;
-
-       if (old_state == state)
-               return;
-
-       state_str = state2str(state);
-
-       switch (state) {
-       case HEADSET_STATE_DISCONNECTED:
-               value = FALSE;
-               close_sco(dev);
-               headset_close_rfcomm(dev);
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-               g_dbus_emit_signal(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE,
-                                       "Disconnected",
-                                       DBUS_TYPE_INVALID);
-               if (hs->state > HEADSET_STATE_CONNECTING) {
-                       emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &value);
-                       telephony_device_disconnected(dev);
-               }
-               active_devices = g_slist_remove(active_devices, dev);
-               break;
-       case HEADSET_STATE_CONNECTING:
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-               break;
-       case HEADSET_STATE_CONNECTED:
-               close_sco(dev);
-               if (hs->state != HEADSET_STATE_PLAY_IN_PROGRESS)
-                       emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-               if (hs->state < state) {
-                       if (ag.features & AG_FEATURE_INBAND_RINGTONE)
-                               slc->inband_ring = TRUE;
-                       else
-                               slc->inband_ring = FALSE;
-                       g_dbus_emit_signal(dev->conn, dev->path,
-                                               AUDIO_HEADSET_INTERFACE,
-                                               "Connected",
-                                               DBUS_TYPE_INVALID);
-                       value = TRUE;
-                       emit_property_changed(dev->conn, dev->path,
-                                               AUDIO_HEADSET_INTERFACE,
-                                               "Connected",
-                                               DBUS_TYPE_BOOLEAN, &value);
-                       active_devices = g_slist_append(active_devices, dev);
-                       telephony_device_connected(dev);
-               } else if (hs->state == HEADSET_STATE_PLAYING) {
-                       value = FALSE;
-                       g_dbus_emit_signal(dev->conn, dev->path,
-                                               AUDIO_HEADSET_INTERFACE,
-                                               "Stopped",
-                                               DBUS_TYPE_INVALID);
-                       emit_property_changed(dev->conn, dev->path,
-                                               AUDIO_HEADSET_INTERFACE,
-                                               "Playing",
-                                               DBUS_TYPE_BOOLEAN, &value);
-               }
-               break;
-       case HEADSET_STATE_PLAY_IN_PROGRESS:
-               break;
-       case HEADSET_STATE_PLAYING:
-               value = TRUE;
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-
-               /* Do not watch HUP since we need to know when the link is
-                  really disconnected */
-               hs->sco_id = g_io_add_watch(hs->sco,
-                                       G_IO_ERR | G_IO_NVAL,
-                                       (GIOFunc) sco_cb, dev);
-
-               g_dbus_emit_signal(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "Playing",
-                                       DBUS_TYPE_INVALID);
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_HEADSET_INTERFACE, "Playing",
-                                       DBUS_TYPE_BOOLEAN, &value);
-
-               if (slc->sp_gain >= 0)
-                       headset_send(hs, "\r\n+VGS=%u\r\n", slc->sp_gain);
-               if (slc->mic_gain >= 0)
-                       headset_send(hs, "\r\n+VGM=%u\r\n", slc->mic_gain);
-               break;
-       }
-
-       hs->state = state;
-
-       DBG("State changed %s: %s -> %s", dev->path, str_state[old_state],
-               str_state[state]);
-
-       for (l = headset_callbacks; l != NULL; l = l->next) {
-               struct headset_state_callback *cb = l->data;
-               cb->cb(dev, old_state, state, cb->user_data);
-       }
-}
-
-headset_state_t headset_get_state(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->state;
-}
-
-int headset_get_channel(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->rfcomm_ch;
-}
-
-gboolean headset_is_active(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (hs->state != HEADSET_STATE_DISCONNECTED)
-               return TRUE;
-
-       return FALSE;
-}
-
-headset_lock_t headset_get_lock(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       return hs->lock;
-}
-
-gboolean headset_lock(struct audio_device *dev, headset_lock_t lock)
-{
-       struct headset *hs = dev->headset;
-
-       if (hs->lock & lock)
-               return FALSE;
-
-       hs->lock |= lock;
-
-       return TRUE;
-}
-
-gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock)
-{
-       struct headset *hs = dev->headset;
-
-       if (!(hs->lock & lock))
-               return FALSE;
-
-       hs->lock &= ~lock;
-
-       if (hs->lock)
-               return TRUE;
-
-       if (hs->state == HEADSET_STATE_PLAYING)
-               headset_set_state(dev, HEADSET_STATE_CONNECTED);
-
-       if (hs->auto_dc) {
-               if (hs->state == HEADSET_STATE_CONNECTED)
-                       hs->dc_timer = g_timeout_add_seconds(DC_TIMEOUT,
-                                               (GSourceFunc) hs_dc_timeout,
-                                               dev);
-               else
-                       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-       }
-
-       return TRUE;
-}
-
-gboolean headset_suspend(struct audio_device *dev, void *data)
-{
-       return TRUE;
-}
-
-gboolean headset_play(struct audio_device *dev, void *data)
-{
-       return TRUE;
-}
-
-int headset_get_sco_fd(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (!hs->sco)
-               return -1;
-
-       return g_io_channel_unix_get_fd(hs->sco);
-}
-
-gboolean headset_get_nrec(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (!hs->slc)
-               return TRUE;
-
-       return hs->slc->nrec;
-}
-
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
-                                       headset_nrec_cb cb, void *user_data)
-{
-       struct headset *hs = dev->headset;
-       struct headset_nrec_callback *nrec_cb;
-       static unsigned int id = 0;
-
-       nrec_cb = g_new(struct headset_nrec_callback, 1);
-       nrec_cb->cb = cb;
-       nrec_cb->user_data = user_data;
-       nrec_cb->id = ++id;
-
-       hs->nrec_cbs = g_slist_prepend(hs->nrec_cbs, nrec_cb);
-
-       return nrec_cb->id;
-}
-
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id)
-{
-       struct headset *hs = dev->headset;
-       GSList *l;
-
-       for (l = hs->nrec_cbs; l != NULL; l = l->next) {
-               struct headset_nrec_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       hs->nrec_cbs = g_slist_remove(hs->nrec_cbs, cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
-
-gboolean headset_get_inband(struct audio_device *dev)
-{
-       struct headset *hs = dev->headset;
-
-       if (!hs->slc)
-               return TRUE;
-
-       return hs->slc->inband_ring;
-}
-
-gboolean headset_get_sco_hci(struct audio_device *dev)
-{
-       return sco_hci;
-}
-
-void headset_shutdown(struct audio_device *dev)
-{
-       struct pending_connect *p = dev->headset->pending;
-
-       if (p && p->msg)
-               error_connect_failed(dev->conn, p->msg, ECANCELED);
-
-       pending_connect_finalize(dev);
-       headset_set_state(dev, HEADSET_STATE_DISCONNECTED);
-}
-
-int telephony_event_ind(int index)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       if (!ag.er_ind) {
-               DBG("telephony_report_event called but events are disabled");
-               return -EINVAL;
-       }
-
-       send_foreach_headset(active_devices, hfp_cmp,
-                               "\r\n+CIEV: %d,%d\r\n", index + 1,
-                               ag.indicators[index].val);
-
-       return 0;
-}
-
-int telephony_response_and_hold_ind(int rh)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       ag.rh = rh;
-
-       /* If we aren't in any response and hold state don't send anything */
-       if (ag.rh < 0)
-               return 0;
-
-       send_foreach_headset(active_devices, hfp_cmp, "\r\n+BTRH: %d\r\n",
-                               ag.rh);
-
-       return 0;
-}
-
-int telephony_incoming_call_ind(const char *number, int type)
-{
-       struct audio_device *dev;
-       struct headset *hs;
-       struct headset_slc *slc;
-
-       if (fast_connectable)
-               manager_set_fast_connectable(TRUE);
-
-       if (!active_devices)
-               return -ENODEV;
-
-       /* Get the latest connected device */
-       dev = active_devices->data;
-       hs = dev->headset;
-       slc = hs->slc;
-
-       if (ag.ring_timer) {
-               DBG("telephony_incoming_call_ind: already calling");
-               return -EBUSY;
-       }
-
-       /* With HSP 1.2 the RING messages should *not* be sent if inband
-        * ringtone is being used */
-       if (!hs->hfp_active && slc->inband_ring)
-               return 0;
-
-       g_free(ag.number);
-       ag.number = g_strdup(number);
-       ag.number_type = type;
-
-       if (slc->inband_ring && hs->hfp_active &&
-                                       hs->state != HEADSET_STATE_PLAYING) {
-               slc->pending_ring = TRUE;
-               return 0;
-       }
-
-       ring_timer_cb(NULL);
-       ag.ring_timer = g_timeout_add_seconds(RING_INTERVAL, ring_timer_cb,
-                                               NULL);
-
-       return 0;
-}
-
-int telephony_calling_stopped_ind(void)
-{
-       struct audio_device *dev;
-
-       if (fast_connectable)
-               manager_set_fast_connectable(FALSE);
-
-       if (ag.ring_timer) {
-               g_source_remove(ag.ring_timer);
-               ag.ring_timer = 0;
-       }
-
-       if (!active_devices)
-               return 0;
-
-       /* In case SCO isn't fully up yet */
-       dev = active_devices->data;
-
-       if (!dev->headset->slc->pending_ring && !ag.ring_timer)
-               return -EINVAL;
-
-       dev->headset->slc->pending_ring = FALSE;
-
-       return 0;
-}
-
-int telephony_ready_ind(uint32_t features,
-                       const struct indicator *indicators, int rh,
-                       const char *chld)
-{
-       ag.telephony_ready = TRUE;
-       ag.features = features;
-       ag.indicators = indicators;
-       ag.rh = rh;
-       ag.chld = chld;
-
-       DBG("Telephony plugin initialized");
-
-       print_ag_features(ag.features);
-
-       return 0;
-}
-
-int telephony_deinit(void)
-{
-       g_free(ag.number);
-
-       memset(&ag, 0, sizeof(ag));
-
-       ag.er_mode = 3;
-       ag.rh = BTRH_NOT_SUPPORTED;
-
-       DBG("Telephony deinitialized");
-
-       return 0;
-}
-
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
-                                       int mprty, const char *number,
-                                       int type)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       if (number && strlen(number) > 0)
-               send_foreach_headset(active_devices, hfp_cmp,
-                               "\r\n+CLCC: %d,%d,%d,%d,%d,\"%s\",%d\r\n",
-                               idx, dir, status, mode, mprty, number, type);
-       else
-               send_foreach_headset(active_devices, hfp_cmp,
-                                       "\r\n+CLCC: %d,%d,%d,%d,%d\r\n",
-                                       idx, dir, status, mode, mprty);
-
-       return 0;
-}
-
-int telephony_subscriber_number_ind(const char *number, int type, int service)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       send_foreach_headset(active_devices, hfp_cmp,
-                               "\r\n+CNUM: ,%s,%d,,%d\r\n",
-                               number, type, service);
-
-       return 0;
-}
-
-static int cwa_cmp(struct headset *hs)
-{
-       if (!hs->hfp_active)
-               return -1;
-
-       if (hs->slc->cwa_enabled)
-               return 0;
-       else
-               return -1;
-}
-
-int telephony_call_waiting_ind(const char *number, int type)
-{
-       if (!active_devices)
-               return -ENODEV;
-
-       send_foreach_headset(active_devices, cwa_cmp,
-                               "\r\n+CCWA: \"%s\",%d\r\n",
-                               number, type);
-
-       return 0;
-}
-
-unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data)
-{
-       struct headset_state_callback *state_cb;
-       static unsigned int id = 0;
-
-       state_cb = g_new(struct headset_state_callback, 1);
-       state_cb->cb = cb;
-       state_cb->user_data = user_data;
-       state_cb->id = ++id;
-
-       headset_callbacks = g_slist_append(headset_callbacks, state_cb);
-
-       return state_cb->id;
-}
-
-gboolean headset_remove_state_cb(unsigned int id)
-{
-       GSList *l;
-
-       for (l = headset_callbacks; l != NULL; l = l->next) {
-               struct headset_state_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       headset_callbacks = g_slist_remove(headset_callbacks, cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
diff --git a/audio/headset.h b/audio/headset.h
deleted file mode 100644 (file)
index 465c2d6..0000000
+++ /dev/null
@@ -1,112 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#define AUDIO_HEADSET_INTERFACE "org.bluez.Headset"
-
-#define DEFAULT_HS_AG_CHANNEL 12
-#define DEFAULT_HF_AG_CHANNEL 13
-
-typedef enum {
-       HEADSET_STATE_DISCONNECTED,
-       HEADSET_STATE_CONNECTING,
-       HEADSET_STATE_CONNECTED,
-       HEADSET_STATE_PLAY_IN_PROGRESS,
-       HEADSET_STATE_PLAYING
-} headset_state_t;
-
-typedef enum {
-       HEADSET_LOCK_READ = 1,
-       HEADSET_LOCK_WRITE = 1 << 1,
-} headset_lock_t;
-
-typedef void (*headset_state_cb) (struct audio_device *dev,
-                                       headset_state_t old_state,
-                                       headset_state_t new_state,
-                                       void *user_data);
-typedef void (*headset_nrec_cb) (struct audio_device *dev,
-                                       gboolean nrec,
-                                       void *user_data);
-
-unsigned int headset_add_state_cb(headset_state_cb cb, void *user_data);
-gboolean headset_remove_state_cb(unsigned int id);
-
-typedef void (*headset_stream_cb_t) (struct audio_device *dev, void *user_data);
-
-void headset_connect_cb(GIOChannel *chan, GError *err, gpointer user_data);
-
-GIOChannel *headset_get_rfcomm(struct audio_device *dev);
-
-struct headset *headset_init(struct audio_device *dev, uint16_t svc,
-                               const char *uuidstr);
-
-void headset_unregister(struct audio_device *dev);
-
-uint32_t headset_config_init(GKeyFile *config);
-
-void headset_update(struct audio_device *dev, uint16_t svc,
-                       const char *uuidstr);
-
-unsigned int headset_config_stream(struct audio_device *dev,
-                                       gboolean auto_dc,
-                                       headset_stream_cb_t cb,
-                                       void *user_data);
-unsigned int headset_request_stream(struct audio_device *dev,
-                                       headset_stream_cb_t cb,
-                                       void *user_data);
-unsigned int headset_suspend_stream(struct audio_device *dev,
-                                       headset_stream_cb_t cb,
-                                       void *user_data);
-gboolean headset_cancel_stream(struct audio_device *dev, unsigned int id);
-
-gboolean headset_get_hfp_active(struct audio_device *dev);
-void headset_set_hfp_active(struct audio_device *dev, gboolean active);
-
-gboolean headset_get_rfcomm_initiator(struct audio_device *dev);
-void headset_set_rfcomm_initiator(struct audio_device *dev,
-                                                       gboolean initiator);
-
-int headset_connect_rfcomm(struct audio_device *dev, GIOChannel *chan);
-int headset_connect_sco(struct audio_device *dev, GIOChannel *io);
-
-headset_state_t headset_get_state(struct audio_device *dev);
-void headset_set_state(struct audio_device *dev, headset_state_t state);
-
-int headset_get_channel(struct audio_device *dev);
-
-int headset_get_sco_fd(struct audio_device *dev);
-gboolean headset_get_nrec(struct audio_device *dev);
-unsigned int headset_add_nrec_cb(struct audio_device *dev,
-                                       headset_nrec_cb cb, void *user_data);
-gboolean headset_remove_nrec_cb(struct audio_device *dev, unsigned int id);
-gboolean headset_get_inband(struct audio_device *dev);
-gboolean headset_get_sco_hci(struct audio_device *dev);
-
-gboolean headset_is_active(struct audio_device *dev);
-
-headset_lock_t headset_get_lock(struct audio_device *dev);
-gboolean headset_lock(struct audio_device *dev, headset_lock_t lock);
-gboolean headset_unlock(struct audio_device *dev, headset_lock_t lock);
-gboolean headset_suspend(struct audio_device *dev, void *data);
-gboolean headset_play(struct audio_device *dev, void *data);
-void headset_shutdown(struct audio_device *dev);
diff --git a/audio/ipc.c b/audio/ipc.c
deleted file mode 100644 (file)
index 02d956b..0000000
+++ /dev/null
@@ -1,134 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include "ipc.h"
-
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-/* This table contains the string representation for messages types */
-static const char *strtypes[] = {
-       "BT_REQUEST",
-       "BT_RESPONSE",
-       "BT_INDICATION",
-       "BT_ERROR",
-};
-
-/* This table contains the string representation for messages names */
-static const char *strnames[] = {
-       "BT_GET_CAPABILITIES",
-       "BT_OPEN",
-       "BT_SET_CONFIGURATION",
-       "BT_NEW_STREAM",
-       "BT_START_STREAM",
-       "BT_STOP_STREAM",
-       "BT_SUSPEND_STREAM",
-       "BT_RESUME_STREAM",
-       "BT_CONTROL",
-};
-
-int bt_audio_service_open(void)
-{
-       int sk;
-       int err;
-       struct sockaddr_un addr = {
-               AF_UNIX, BT_IPC_SOCKET_NAME
-       };
-
-       sk = socket(PF_LOCAL, SOCK_STREAM, 0);
-       if (sk < 0) {
-               err = -errno;
-               fprintf(stderr, "%s: Cannot open socket: %s (%d)\n",
-                       __FUNCTION__, strerror(-err), -err);
-               errno = -err;
-               return -1;
-       }
-
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               fprintf(stderr, "%s: connect() failed: %s (%d)\n",
-                       __FUNCTION__, strerror(-err), -err);
-               close(sk);
-               errno = -err;
-               return -1;
-       }
-
-       return sk;
-}
-
-int bt_audio_service_close(int sk)
-{
-       return close(sk);
-}
-
-int bt_audio_service_get_data_fd(int sk)
-{
-       char cmsg_b[CMSG_SPACE(sizeof(int))], m;
-       int err, ret;
-       struct iovec iov = { &m, sizeof(m) };
-       struct msghdr msgh;
-       struct cmsghdr *cmsg;
-
-       memset(&msgh, 0, sizeof(msgh));
-       msgh.msg_iov = &iov;
-       msgh.msg_iovlen = 1;
-       msgh.msg_control = &cmsg_b;
-       msgh.msg_controllen = CMSG_LEN(sizeof(int));
-
-       ret = recvmsg(sk, &msgh, 0);
-       if (ret < 0) {
-               err = -errno;
-               fprintf(stderr, "%s: Unable to receive fd: %s (%d)\n",
-                       __FUNCTION__, strerror(-err), -err);
-               errno = -err;
-               return -1;
-       }
-
-       /* Receive auxiliary data in msgh */
-       for (cmsg = CMSG_FIRSTHDR(&msgh); cmsg != NULL;
-                       cmsg = CMSG_NXTHDR(&msgh, cmsg)) {
-               if (cmsg->cmsg_level == SOL_SOCKET
-                               && cmsg->cmsg_type == SCM_RIGHTS) {
-                       memcpy(&ret, CMSG_DATA(cmsg), sizeof(int));
-                       return ret;
-               }
-       }
-
-       errno = EINVAL;
-       return -1;
-}
-
-const char *bt_audio_strtype(uint8_t type)
-{
-       if (type >= ARRAY_SIZE(strtypes))
-               return NULL;
-
-       return strtypes[type];
-}
-
-const char *bt_audio_strname(uint8_t name)
-{
-       if (name >= ARRAY_SIZE(strnames))
-               return NULL;
-
-       return strnames[name];
-}
diff --git a/audio/ipc.h b/audio/ipc.h
deleted file mode 100644 (file)
index 61ae019..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/*
-  Message sequence chart of streaming sequence for A2DP transport
-
-  Audio daemon                 User
-                               on snd_pcm_open
-                               <--BT_GET_CAPABILITIES_REQ
-
-  BT_GET_CAPABILITIES_RSP-->
-
-                               on snd_pcm_hw_params
-                               <--BT_SETCONFIGURATION_REQ
-
-  BT_SET_CONFIGURATION_RSP-->
-
-                               on snd_pcm_prepare
-                               <--BT_START_STREAM_REQ
-
-  <Moves to streaming state>
-  BT_START_STREAM_RSP-->
-
-  BT_NEW_STREAM_IND -->
-
-                               <  streams data >
-                               ..........
-
-                               on snd_pcm_drop/snd_pcm_drain
-
-                               <--BT_STOP_STREAM_REQ
-
-  <Moves to open state>
-  BT_STOP_STREAM_RSP-->
-
-                               on IPC close or appl crash
-  <Moves to idle>
-
- */
-
-#ifndef BT_AUDIOCLIENT_H
-#define BT_AUDIOCLIENT_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <errno.h>
-
-#define BT_SUGGESTED_BUFFER_SIZE   512
-#define BT_IPC_SOCKET_NAME "\0/org/bluez/audio"
-
-/* Generic message header definition, except for RESPONSE messages */
-typedef struct {
-       uint8_t type;
-       uint8_t name;
-       uint16_t length;
-} __attribute__ ((packed)) bt_audio_msg_header_t;
-
-typedef struct {
-       bt_audio_msg_header_t h;
-       uint8_t posix_errno;
-} __attribute__ ((packed)) bt_audio_error_t;
-
-/* Message types */
-#define BT_REQUEST                     0
-#define BT_RESPONSE                    1
-#define BT_INDICATION                  2
-#define BT_ERROR                       3
-
-/* Messages names */
-#define BT_GET_CAPABILITIES            0
-#define BT_OPEN                                1
-#define BT_SET_CONFIGURATION           2
-#define BT_NEW_STREAM                  3
-#define BT_START_STREAM                        4
-#define BT_STOP_STREAM                 5
-#define BT_CLOSE                       6
-#define BT_CONTROL                     7
-#define BT_DELAY_REPORT                        8
-
-#define BT_CAPABILITIES_TRANSPORT_A2DP 0
-#define BT_CAPABILITIES_TRANSPORT_SCO  1
-#define BT_CAPABILITIES_TRANSPORT_ANY  2
-
-#define BT_CAPABILITIES_ACCESS_MODE_READ       1
-#define BT_CAPABILITIES_ACCESS_MODE_WRITE      2
-#define BT_CAPABILITIES_ACCESS_MODE_READWRITE  3
-
-#define BT_FLAG_AUTOCONNECT    1
-
-struct bt_get_capabilities_req {
-       bt_audio_msg_header_t   h;
-       char                    source[18];     /* Address of the local Device */
-       char                    destination[18];/* Address of the remote Device */
-       char                    object[128];    /* DBus object path */
-       uint8_t                 transport;      /* Requested transport */
-       uint8_t                 flags;          /* Requested flags */
-       uint8_t                 seid;           /* Requested capability configuration */
-} __attribute__ ((packed));
-
-/**
- * SBC Codec parameters as per A2DP profile 1.0 Â§ 4.3
- */
-
-/* A2DP seid are 6 bytes long so HSP/HFP are assigned to 7-8 bits */
-#define BT_A2DP_SEID_RANGE                     (1 << 6) - 1
-
-#define BT_A2DP_SBC_SOURCE                     0x00
-#define BT_A2DP_SBC_SINK                       0x01
-#define BT_A2DP_MPEG12_SOURCE                  0x02
-#define BT_A2DP_MPEG12_SINK                    0x03
-#define BT_A2DP_MPEG24_SOURCE                  0x04
-#define BT_A2DP_MPEG24_SINK                    0x05
-#define BT_A2DP_ATRAC_SOURCE                   0x06
-#define BT_A2DP_ATRAC_SINK                     0x07
-#define BT_A2DP_UNKNOWN_SOURCE                 0x08
-#define BT_A2DP_UNKNOWN_SINK                   0x09
-
-#define BT_SBC_SAMPLING_FREQ_16000             (1 << 3)
-#define BT_SBC_SAMPLING_FREQ_32000             (1 << 2)
-#define BT_SBC_SAMPLING_FREQ_44100             (1 << 1)
-#define BT_SBC_SAMPLING_FREQ_48000             1
-
-#define BT_A2DP_CHANNEL_MODE_MONO              (1 << 3)
-#define BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL      (1 << 2)
-#define BT_A2DP_CHANNEL_MODE_STEREO            (1 << 1)
-#define BT_A2DP_CHANNEL_MODE_JOINT_STEREO      1
-
-#define BT_A2DP_BLOCK_LENGTH_4                 (1 << 3)
-#define BT_A2DP_BLOCK_LENGTH_8                 (1 << 2)
-#define BT_A2DP_BLOCK_LENGTH_12                        (1 << 1)
-#define BT_A2DP_BLOCK_LENGTH_16                        1
-
-#define BT_A2DP_SUBBANDS_4                     (1 << 1)
-#define BT_A2DP_SUBBANDS_8                     1
-
-#define BT_A2DP_ALLOCATION_SNR                 (1 << 1)
-#define BT_A2DP_ALLOCATION_LOUDNESS            1
-
-#define BT_MPEG_SAMPLING_FREQ_16000            (1 << 5)
-#define BT_MPEG_SAMPLING_FREQ_22050            (1 << 4)
-#define BT_MPEG_SAMPLING_FREQ_24000            (1 << 3)
-#define BT_MPEG_SAMPLING_FREQ_32000            (1 << 2)
-#define BT_MPEG_SAMPLING_FREQ_44100            (1 << 1)
-#define BT_MPEG_SAMPLING_FREQ_48000            1
-
-#define BT_MPEG_LAYER_1                                (1 << 2)
-#define BT_MPEG_LAYER_2                                (1 << 1)
-#define BT_MPEG_LAYER_3                                1
-
-#define BT_HFP_CODEC_PCM                       0x00
-
-#define BT_PCM_FLAG_NREC                       0x01
-#define BT_PCM_FLAG_PCM_ROUTING                        0x02
-
-#define BT_WRITE_LOCK                          (1 << 1)
-#define BT_READ_LOCK                           1
-
-typedef struct {
-       uint8_t seid;
-       uint8_t transport;
-       uint8_t type;
-       uint8_t length;
-       uint8_t configured;
-       uint8_t lock;
-       uint8_t data[0];
-} __attribute__ ((packed)) codec_capabilities_t;
-
-typedef struct {
-       codec_capabilities_t capability;
-       uint8_t channel_mode;
-       uint8_t frequency;
-       uint8_t allocation_method;
-       uint8_t subbands;
-       uint8_t block_length;
-       uint8_t min_bitpool;
-       uint8_t max_bitpool;
-} __attribute__ ((packed)) sbc_capabilities_t;
-
-typedef struct {
-       codec_capabilities_t capability;
-       uint8_t channel_mode;
-       uint8_t crc;
-       uint8_t layer;
-       uint8_t frequency;
-       uint8_t mpf;
-       uint16_t bitrate;
-} __attribute__ ((packed)) mpeg_capabilities_t;
-
-typedef struct {
-       codec_capabilities_t capability;
-       uint8_t flags;
-       uint16_t sampling_rate;
-} __attribute__ ((packed)) pcm_capabilities_t;
-
-struct bt_get_capabilities_rsp {
-       bt_audio_msg_header_t   h;
-       char                    source[18];     /* Address of the local Device */
-       char                    destination[18];/* Address of the remote Device */
-       char                    object[128];    /* DBus object path */
-       uint8_t                 data[0];        /* First codec_capabilities_t */
-} __attribute__ ((packed));
-
-struct bt_open_req {
-       bt_audio_msg_header_t   h;
-       char                    source[18];     /* Address of the local Device */
-       char                    destination[18];/* Address of the remote Device */
-       char                    object[128];    /* DBus object path */
-       uint8_t                 seid;           /* Requested capability configuration to lock */
-       uint8_t                 lock;           /* Requested lock */
-} __attribute__ ((packed));
-
-struct bt_open_rsp {
-       bt_audio_msg_header_t   h;
-       char                    source[18];     /* Address of the local Device */
-       char                    destination[18];/* Address of the remote Device */
-       char                    object[128];    /* DBus object path */
-} __attribute__ ((packed));
-
-struct bt_set_configuration_req {
-       bt_audio_msg_header_t   h;
-       codec_capabilities_t    codec;          /* Requested codec */
-} __attribute__ ((packed));
-
-struct bt_set_configuration_rsp {
-       bt_audio_msg_header_t   h;
-       uint16_t                link_mtu;       /* Max length that transport supports */
-} __attribute__ ((packed));
-
-#define BT_STREAM_ACCESS_READ          0
-#define BT_STREAM_ACCESS_WRITE         1
-#define BT_STREAM_ACCESS_READWRITE     2
-struct bt_start_stream_req {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_start_stream_rsp {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-/* This message is followed by one byte of data containing the stream data fd
-   as ancillary data */
-struct bt_new_stream_ind {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_stop_stream_req {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_stop_stream_rsp {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_close_req {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_close_rsp {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_suspend_stream_ind {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-struct bt_resume_stream_ind {
-       bt_audio_msg_header_t   h;
-} __attribute__ ((packed));
-
-#define BT_CONTROL_KEY_POWER                   0x40
-#define BT_CONTROL_KEY_VOL_UP                  0x41
-#define BT_CONTROL_KEY_VOL_DOWN                        0x42
-#define BT_CONTROL_KEY_MUTE                    0x43
-#define BT_CONTROL_KEY_PLAY                    0x44
-#define BT_CONTROL_KEY_STOP                    0x45
-#define BT_CONTROL_KEY_PAUSE                   0x46
-#define BT_CONTROL_KEY_RECORD                  0x47
-#define BT_CONTROL_KEY_REWIND                  0x48
-#define BT_CONTROL_KEY_FAST_FORWARD            0x49
-#define BT_CONTROL_KEY_EJECT                   0x4A
-#define BT_CONTROL_KEY_FORWARD                 0x4B
-#define BT_CONTROL_KEY_BACKWARD                        0x4C
-
-struct bt_control_req {
-       bt_audio_msg_header_t   h;
-       uint8_t                 mode;           /* Control Mode */
-       uint8_t                 key;            /* Control Key */
-} __attribute__ ((packed));
-
-struct bt_control_rsp {
-       bt_audio_msg_header_t   h;
-       uint8_t                 mode;           /* Control Mode */
-       uint8_t                 key;            /* Control Key */
-} __attribute__ ((packed));
-
-struct bt_control_ind {
-       bt_audio_msg_header_t   h;
-       uint8_t                 mode;           /* Control Mode */
-       uint8_t                 key;            /* Control Key */
-} __attribute__ ((packed));
-
-struct bt_delay_report_req {
-       bt_audio_msg_header_t   h;
-       uint16_t                delay;
-} __attribute__ ((packed));
-
-struct bt_delay_report_ind {
-       bt_audio_msg_header_t   h;
-       uint16_t                delay;
-} __attribute__ ((packed));
-
-/* Function declaration */
-
-/* Opens a connection to the audio service: return a socket descriptor */
-int bt_audio_service_open(void);
-
-/* Closes a connection to the audio service */
-int bt_audio_service_close(int sk);
-
-/* Receives stream data file descriptor : must be called after a
-BT_STREAMFD_IND message is returned */
-int bt_audio_service_get_data_fd(int sk);
-
-/* Human readable message type string */
-const char *bt_audio_strtype(uint8_t type);
-
-/* Human readable message name string */
-const char *bt_audio_strname(uint8_t name);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* BT_AUDIOCLIENT_H */
diff --git a/audio/main.c b/audio/main.c
deleted file mode 100644 (file)
index 5c751af..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <sys/socket.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-
-#include "glib-helper.h"
-#include "btio.h"
-#include "plugin.h"
-#include "log.h"
-#include "device.h"
-#include "headset.h"
-#include "manager.h"
-#include "gateway.h"
-
-static GIOChannel *sco_server = NULL;
-
-static GKeyFile *load_config_file(const char *file)
-{
-       GError *err = NULL;
-       GKeyFile *keyfile;
-
-       keyfile = g_key_file_new();
-
-       g_key_file_set_list_separator(keyfile, ',');
-
-       if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
-               error("Parsing %s failed: %s", file, err->message);
-               g_error_free(err);
-               g_key_file_free(keyfile);
-               return NULL;
-       }
-
-       return keyfile;
-}
-
-static void sco_server_cb(GIOChannel *chan, GError *err, gpointer data)
-{
-       int sk;
-       struct audio_device *device;
-       char addr[18];
-       bdaddr_t src, dst;
-
-       if (err) {
-               error("sco_server_cb: %s", err->message);
-               return;
-       }
-
-       bt_io_get(chan, BT_IO_SCO, &err,
-                       BT_IO_OPT_SOURCE_BDADDR, &src,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_DEST, addr,
-                       BT_IO_OPT_INVALID);
-       if (err) {
-               error("bt_io_get: %s", err->message);
-               goto drop;
-       }
-
-       device = manager_find_device(NULL, &src, &dst, AUDIO_HEADSET_INTERFACE,
-                                       FALSE);
-       if (!device)
-               device = manager_find_device(NULL, &src, &dst,
-                                               AUDIO_GATEWAY_INTERFACE,
-                                               FALSE);
-
-       if (!device)
-               goto drop;
-
-       if (device->headset) {
-               if (headset_get_state(device) < HEADSET_STATE_CONNECTED) {
-                       DBG("Refusing SCO from non-connected headset");
-                       goto drop;
-               }
-
-               if (!headset_get_hfp_active(device)) {
-                       error("Refusing non-HFP SCO connect attempt from %s",
-                                                                       addr);
-                       goto drop;
-               }
-
-               if (headset_connect_sco(device, chan) < 0)
-                       goto drop;
-
-               headset_set_state(device, HEADSET_STATE_PLAYING);
-       } else if (device->gateway) {
-               if (!gateway_is_connected(device)) {
-                       DBG("Refusing SCO from non-connected AG");
-                       goto drop;
-               }
-
-               if (gateway_connect_sco(device, chan) < 0)
-                       goto drop;
-       } else
-               goto drop;
-
-       sk = g_io_channel_unix_get_fd(chan);
-       fcntl(sk, F_SETFL, 0);
-
-       DBG("Accepted SCO connection from %s", addr);
-
-       return;
-
-drop:
-       g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static DBusConnection *connection;
-
-static int audio_init(void)
-{
-       GKeyFile *config;
-       gboolean enable_sco;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
-
-       config = load_config_file(CONFIGDIR "/audio.conf");
-
-       if (audio_manager_init(connection, config, &enable_sco) < 0)
-               goto failed;
-
-       if (!enable_sco)
-               return 0;
-
-       sco_server = bt_io_listen(BT_IO_SCO, sco_server_cb, NULL, NULL,
-                                       NULL, NULL,
-                                       BT_IO_OPT_INVALID);
-       if (!sco_server) {
-               error("Unable to start SCO server socket");
-               goto failed;
-       }
-
-       return 0;
-
-failed:
-       audio_manager_exit();
-
-       if (connection) {
-               dbus_connection_unref(connection);
-               connection = NULL;
-       }
-
-       return -EIO;
-}
-
-static void audio_exit(void)
-{
-       if (sco_server) {
-               g_io_channel_shutdown(sco_server, TRUE, NULL);
-               g_io_channel_unref(sco_server);
-               sco_server = NULL;
-       }
-
-       audio_manager_exit();
-
-       dbus_connection_unref(connection);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(audio, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, audio_init, audio_exit)
diff --git a/audio/manager.c b/audio/manager.c
deleted file mode 100644 (file)
index d442d1d..0000000
+++ /dev/null
@@ -1,1456 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <stdlib.h>
-#include <stdarg.h>
-#include <errno.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <sys/stat.h>
-#include <dirent.h>
-#include <ctype.h>
-#include <signal.h>
-
-#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 "glib-helper.h"
-#include "btio.h"
-#include "../src/adapter.h"
-#include "../src/manager.h"
-#include "../src/device.h"
-
-#include "log.h"
-#include "ipc.h"
-#include "device.h"
-#include "error.h"
-#include "avdtp.h"
-#include "media.h"
-#include "a2dp.h"
-#include "headset.h"
-#include "gateway.h"
-#include "sink.h"
-#include "source.h"
-#include "avrcp.h"
-#include "control.h"
-#include "manager.h"
-#include "sdpd.h"
-#include "telephony.h"
-#include "unix.h"
-
-typedef enum {
-       HEADSET = 1 << 0,
-       GATEWAY = 1 << 1,
-       SINK    = 1 << 2,
-       SOURCE  = 1 << 3,
-       CONTROL = 1 << 4,
-       TARGET  = 1 << 5,
-       INVALID = 1 << 6
-} audio_service_type;
-
-typedef enum {
-               GENERIC_AUDIO = 0,
-               ADVANCED_AUDIO,
-               AV_REMOTE,
-               GET_RECORDS
-} audio_sdp_state_t;
-
-struct audio_adapter {
-       struct btd_adapter *btd_adapter;
-       gboolean powered;
-       uint32_t hsp_ag_record_id;
-       uint32_t hfp_ag_record_id;
-       uint32_t hfp_hs_record_id;
-       GIOChannel *hsp_ag_server;
-       GIOChannel *hfp_ag_server;
-       GIOChannel *hfp_hs_server;
-       gint ref;
-};
-
-static gboolean auto_connect = TRUE;
-static int max_connected_headsets = 1;
-static DBusConnection *connection = NULL;
-static GKeyFile *config = NULL;
-static GSList *adapters = NULL;
-static GSList *devices = NULL;
-
-static struct enabled_interfaces enabled = {
-       .hfp            = TRUE,
-       .headset        = TRUE,
-       .gateway        = FALSE,
-       .sink           = TRUE,
-       .source         = FALSE,
-       .control        = TRUE,
-       .socket         = FALSE,
-       .media          = TRUE,
-};
-
-static struct audio_adapter *find_adapter(GSList *list,
-                                       struct btd_adapter *btd_adapter)
-{
-       for (; list; list = list->next) {
-               struct audio_adapter *adapter = list->data;
-
-               if (adapter->btd_adapter == btd_adapter)
-                       return adapter;
-       }
-
-       return NULL;
-}
-
-gboolean server_is_enabled(bdaddr_t *src, uint16_t svc)
-{
-       switch (svc) {
-       case HEADSET_SVCLASS_ID:
-               return enabled.headset;
-       case HEADSET_AGW_SVCLASS_ID:
-               return FALSE;
-       case HANDSFREE_SVCLASS_ID:
-               return enabled.headset && enabled.hfp;
-       case HANDSFREE_AGW_SVCLASS_ID:
-               return enabled.gateway;
-       case AUDIO_SINK_SVCLASS_ID:
-               return enabled.sink;
-       case AUDIO_SOURCE_SVCLASS_ID:
-               return enabled.source;
-       case AV_REMOTE_TARGET_SVCLASS_ID:
-       case AV_REMOTE_SVCLASS_ID:
-               return enabled.control;
-       default:
-               return FALSE;
-       }
-}
-
-static void handle_uuid(const char *uuidstr, struct audio_device *device)
-{
-       uuid_t uuid;
-       uint16_t uuid16;
-
-       if (bt_string2uuid(&uuid, uuidstr) < 0) {
-               error("%s not detected as an UUID-128", uuidstr);
-               return;
-       }
-
-       if (!sdp_uuid128_to_uuid(&uuid) && uuid.type != SDP_UUID16) {
-               error("Could not convert %s to a UUID-16", uuidstr);
-               return;
-       }
-
-       uuid16 = uuid.value.uuid16;
-
-       if (!server_is_enabled(&device->src, uuid16)) {
-               DBG("server not enabled for %s (0x%04x)", uuidstr, uuid16);
-               return;
-       }
-
-       switch (uuid16) {
-       case HEADSET_SVCLASS_ID:
-               DBG("Found Headset record");
-               if (device->headset)
-                       headset_update(device, uuid16, uuidstr);
-               else
-                       device->headset = headset_init(device, uuid16,
-                                                       uuidstr);
-               break;
-       case HEADSET_AGW_SVCLASS_ID:
-               DBG("Found Headset AG record");
-               break;
-       case HANDSFREE_SVCLASS_ID:
-               DBG("Found Handsfree record");
-               if (device->headset)
-                       headset_update(device, uuid16, uuidstr);
-               else
-                       device->headset = headset_init(device, uuid16,
-                                                               uuidstr);
-               break;
-       case HANDSFREE_AGW_SVCLASS_ID:
-               DBG("Found Handsfree AG record");
-               if (enabled.gateway && (device->gateway == NULL))
-                       device->gateway = gateway_init(device);
-               break;
-       case AUDIO_SINK_SVCLASS_ID:
-               DBG("Found Audio Sink");
-               if (device->sink == NULL)
-                       device->sink = sink_init(device);
-               break;
-       case AUDIO_SOURCE_SVCLASS_ID:
-               DBG("Found Audio Source");
-               if (device->source == NULL)
-                       device->source = source_init(device);
-               break;
-       case AV_REMOTE_SVCLASS_ID:
-       case AV_REMOTE_TARGET_SVCLASS_ID:
-               DBG("Found AV %s", uuid16 == AV_REMOTE_SVCLASS_ID ?
-                                                       "Remote" : "Target");
-               if (device->control)
-                       control_update(device->control, uuid16);
-               else
-                       device->control = control_init(device, uuid16);
-
-               if (device->sink && sink_is_active(device))
-                       avrcp_connect(device);
-               break;
-       default:
-               DBG("Unrecognized UUID: 0x%04X", uuid16);
-               break;
-       }
-}
-
-static sdp_record_t *hsp_ag_record(uint8_t ch)
-{
-       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-       uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-       uuid_t l2cap_uuid, rfcomm_uuid;
-       sdp_profile_desc_t profile;
-       sdp_record_t *record;
-       sdp_list_t *aproto, *proto[2];
-       sdp_data_t *channel;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(0, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&svclass_uuid, HEADSET_AGW_SVCLASS_ID);
-       svclass_id = sdp_list_append(0, &svclass_uuid);
-       sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-       svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-       sdp_set_service_classes(record, svclass_id);
-
-       sdp_uuid16_create(&profile.uuid, HEADSET_PROFILE_ID);
-       profile.version = 0x0102;
-       pfseq = sdp_list_append(0, &profile);
-       sdp_set_profile_descs(record, pfseq);
-
-       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-       proto[0] = sdp_list_append(0, &l2cap_uuid);
-       apseq = sdp_list_append(0, proto[0]);
-
-       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-       proto[1] = sdp_list_append(0, &rfcomm_uuid);
-       channel = sdp_data_alloc(SDP_UINT8, &ch);
-       proto[1] = sdp_list_append(proto[1], channel);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_set_info_attr(record, "Headset Audio Gateway", 0, 0);
-
-       sdp_data_free(channel);
-       sdp_list_free(proto[0], 0);
-       sdp_list_free(proto[1], 0);
-       sdp_list_free(apseq, 0);
-       sdp_list_free(pfseq, 0);
-       sdp_list_free(aproto, 0);
-       sdp_list_free(root, 0);
-       sdp_list_free(svclass_id, 0);
-
-       return record;
-}
-
-static sdp_record_t *hfp_hs_record(uint8_t ch)
-{
-       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-       uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-       uuid_t l2cap_uuid, rfcomm_uuid;
-       sdp_profile_desc_t profile;
-       sdp_record_t *record;
-       sdp_list_t *aproto, *proto[2];
-       sdp_data_t *channel;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(0, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&svclass_uuid, HANDSFREE_SVCLASS_ID);
-       svclass_id = sdp_list_append(0, &svclass_uuid);
-       sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-       svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-       sdp_set_service_classes(record, svclass_id);
-
-       sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-       profile.version = 0x0105;
-       pfseq = sdp_list_append(0, &profile);
-       sdp_set_profile_descs(record, pfseq);
-
-       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-       proto[0] = sdp_list_append(0, &l2cap_uuid);
-       apseq = sdp_list_append(0, proto[0]);
-
-       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-       proto[1] = sdp_list_append(0, &rfcomm_uuid);
-       channel = sdp_data_alloc(SDP_UINT8, &ch);
-       proto[1] = sdp_list_append(proto[1], channel);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_set_info_attr(record, "Hands-Free", 0, 0);
-
-       sdp_data_free(channel);
-       sdp_list_free(proto[0], 0);
-       sdp_list_free(proto[1], 0);
-       sdp_list_free(apseq, 0);
-       sdp_list_free(pfseq, 0);
-       sdp_list_free(aproto, 0);
-       sdp_list_free(root, 0);
-       sdp_list_free(svclass_id, 0);
-
-       return record;
-}
-
-static sdp_record_t *hfp_ag_record(uint8_t ch, uint32_t feat)
-{
-       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
-       uuid_t root_uuid, svclass_uuid, ga_svclass_uuid;
-       uuid_t l2cap_uuid, rfcomm_uuid;
-       sdp_profile_desc_t profile;
-       sdp_list_t *aproto, *proto[2];
-       sdp_record_t *record;
-       sdp_data_t *channel, *features;
-       uint8_t netid = 0x01;
-       uint16_t sdpfeat;
-       sdp_data_t *network;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       network = sdp_data_alloc(SDP_UINT8, &netid);
-       if (!network) {
-               sdp_record_free(record);
-               return NULL;
-       }
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(0, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&svclass_uuid, HANDSFREE_AGW_SVCLASS_ID);
-       svclass_id = sdp_list_append(0, &svclass_uuid);
-       sdp_uuid16_create(&ga_svclass_uuid, GENERIC_AUDIO_SVCLASS_ID);
-       svclass_id = sdp_list_append(svclass_id, &ga_svclass_uuid);
-       sdp_set_service_classes(record, svclass_id);
-
-       sdp_uuid16_create(&profile.uuid, HANDSFREE_PROFILE_ID);
-       profile.version = 0x0105;
-       pfseq = sdp_list_append(0, &profile);
-       sdp_set_profile_descs(record, pfseq);
-
-       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
-       proto[0] = sdp_list_append(0, &l2cap_uuid);
-       apseq = sdp_list_append(0, proto[0]);
-
-       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
-       proto[1] = sdp_list_append(0, &rfcomm_uuid);
-       channel = sdp_data_alloc(SDP_UINT8, &ch);
-       proto[1] = sdp_list_append(proto[1], channel);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       sdpfeat = (uint16_t) feat & 0xF;
-       features = sdp_data_alloc(SDP_UINT16, &sdpfeat);
-       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_set_info_attr(record, "Hands-Free Audio Gateway", 0, 0);
-
-       sdp_attr_add(record, SDP_ATTR_EXTERNAL_NETWORK, network);
-
-       sdp_data_free(channel);
-       sdp_list_free(proto[0], 0);
-       sdp_list_free(proto[1], 0);
-       sdp_list_free(apseq, 0);
-       sdp_list_free(pfseq, 0);
-       sdp_list_free(aproto, 0);
-       sdp_list_free(root, 0);
-       sdp_list_free(svclass_id, 0);
-
-       return record;
-}
-
-static void headset_auth_cb(DBusError *derr, void *user_data)
-{
-       struct audio_device *device = user_data;
-       GError *err = NULL;
-       GIOChannel *io;
-
-       if (device->hs_preauth_id) {
-               g_source_remove(device->hs_preauth_id);
-               device->hs_preauth_id = 0;
-       }
-
-       if (derr && dbus_error_is_set(derr)) {
-               error("Access denied: %s", derr->message);
-               headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-               return;
-       }
-
-       io = headset_get_rfcomm(device);
-
-       if (!bt_io_accept(io, headset_connect_cb, device, NULL, &err)) {
-               error("bt_io_accept: %s", err->message);
-               g_error_free(err);
-               headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-               return;
-       }
-}
-
-static gboolean hs_preauth_cb(GIOChannel *chan, GIOCondition cond,
-                                                       gpointer user_data)
-{
-       struct audio_device *device = user_data;
-
-       DBG("Headset disconnected during authorization");
-
-       audio_device_cancel_authorization(device, headset_auth_cb, device);
-
-       headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-
-       device->hs_preauth_id = 0;
-
-       return FALSE;
-}
-
-static void ag_confirm(GIOChannel *chan, gpointer data)
-{
-       const char *server_uuid, *remote_uuid;
-       struct audio_device *device;
-       gboolean hfp_active;
-       bdaddr_t src, dst;
-       int perr;
-       GError *err = NULL;
-       uint8_t ch;
-
-       bt_io_get(chan, BT_IO_RFCOMM, &err,
-                       BT_IO_OPT_SOURCE_BDADDR, &src,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_CHANNEL, &ch,
-                       BT_IO_OPT_INVALID);
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-               goto drop;
-       }
-
-       if (ch == DEFAULT_HS_AG_CHANNEL) {
-               hfp_active = FALSE;
-               server_uuid = HSP_AG_UUID;
-               remote_uuid = HSP_HS_UUID;
-       } else {
-               hfp_active = TRUE;
-               server_uuid = HFP_AG_UUID;
-               remote_uuid = HFP_HS_UUID;
-       }
-
-       device = manager_get_device(&src, &dst, TRUE);
-       if (!device)
-               goto drop;
-
-       if (!manager_allow_headset_connection(device)) {
-               DBG("Refusing headset: too many existing connections");
-               goto drop;
-       }
-
-       if (!device->headset) {
-               btd_device_add_uuid(device->btd_dev, remote_uuid);
-               if (!device->headset)
-                       goto drop;
-       }
-
-       if (headset_get_state(device) > HEADSET_STATE_DISCONNECTED) {
-               DBG("Refusing new connection since one already exists");
-               goto drop;
-       }
-
-       headset_set_hfp_active(device, hfp_active);
-       headset_set_rfcomm_initiator(device, TRUE);
-
-       if (headset_connect_rfcomm(device, chan) < 0) {
-               error("headset_connect_rfcomm failed");
-               goto drop;
-       }
-
-       headset_set_state(device, HEADSET_STATE_CONNECTING);
-
-       perr = audio_device_request_authorization(device, server_uuid,
-                                               headset_auth_cb, device);
-       if (perr < 0) {
-               DBG("Authorization denied: %s", strerror(-perr));
-               headset_set_state(device, HEADSET_STATE_DISCONNECTED);
-               return;
-       }
-
-       device->hs_preauth_id = g_io_add_watch(chan,
-                                       G_IO_NVAL | G_IO_HUP | G_IO_ERR,
-                                       hs_preauth_cb, device);
-
-       device->auto_connect = auto_connect;
-
-       return;
-
-drop:
-       g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static void gateway_auth_cb(DBusError *derr, void *user_data)
-{
-       struct audio_device *device = user_data;
-
-       if (derr && dbus_error_is_set(derr)) {
-               error("Access denied: %s", derr->message);
-               gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
-       } else {
-               char ag_address[18];
-
-               ba2str(&device->dst, ag_address);
-               DBG("Accepted AG connection from %s for %s",
-                       ag_address, device->path);
-
-               gateway_start_service(device);
-       }
-}
-
-static void hf_io_cb(GIOChannel *chan, gpointer data)
-{
-       bdaddr_t src, dst;
-       GError *err = NULL;
-       uint8_t ch;
-       const char *server_uuid, *remote_uuid;
-       struct audio_device *device;
-       int perr;
-
-       bt_io_get(chan, BT_IO_RFCOMM, &err,
-                       BT_IO_OPT_SOURCE_BDADDR, &src,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_CHANNEL, &ch,
-                       BT_IO_OPT_INVALID);
-
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-               return;
-       }
-
-       server_uuid = HFP_HS_UUID;
-       remote_uuid = HFP_AG_UUID;
-
-       device = manager_get_device(&src, &dst, TRUE);
-       if (!device)
-               goto drop;
-
-       if (!device->gateway) {
-               btd_device_add_uuid(device->btd_dev, remote_uuid);
-               if (!device->gateway)
-                       goto drop;
-       }
-
-       if (gateway_is_active(device)) {
-               DBG("Refusing new connection since one already exists");
-               goto drop;
-       }
-
-       if (gateway_connect_rfcomm(device, chan) < 0) {
-               error("Allocating new GIOChannel failed!");
-               goto drop;
-       }
-
-       perr = audio_device_request_authorization(device, server_uuid,
-                                               gateway_auth_cb, device);
-       if (perr < 0) {
-               DBG("Authorization denied: %s", strerror(-perr));
-               gateway_set_state(device, GATEWAY_STATE_DISCONNECTED);
-       }
-
-       return;
-
-drop:
-       g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static int headset_server_init(struct audio_adapter *adapter)
-{
-       uint8_t chan = DEFAULT_HS_AG_CHANNEL;
-       sdp_record_t *record;
-       gboolean master = TRUE;
-       GError *err = NULL;
-       uint32_t features;
-       GIOChannel *io;
-       bdaddr_t src;
-
-       if (config) {
-               gboolean tmp;
-
-               tmp = g_key_file_get_boolean(config, "General", "Master",
-                                               &err);
-               if (err) {
-                       DBG("audio.conf: %s", err->message);
-                       g_clear_error(&err);
-               } else
-                       master = tmp;
-       }
-
-       adapter_get_address(adapter->btd_adapter, &src);
-
-       io =  bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
-                               BT_IO_OPT_CHANNEL, chan,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io)
-               goto failed;
-
-       adapter->hsp_ag_server = io;
-
-       record = hsp_ag_record(chan);
-       if (!record) {
-               error("Unable to allocate new service record");
-               goto failed;
-       }
-
-       if (add_record_to_server(&src, record) < 0) {
-               error("Unable to register HS AG service record");
-               sdp_record_free(record);
-               goto failed;
-       }
-       adapter->hsp_ag_record_id = record->handle;
-
-       features = headset_config_init(config);
-
-       if (!enabled.hfp)
-               return 0;
-
-       chan = DEFAULT_HF_AG_CHANNEL;
-
-       io = bt_io_listen(BT_IO_RFCOMM, NULL, ag_confirm, adapter, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
-                               BT_IO_OPT_CHANNEL, chan,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io)
-               goto failed;
-
-       adapter->hfp_ag_server = io;
-
-       record = hfp_ag_record(chan, features);
-       if (!record) {
-               error("Unable to allocate new service record");
-               goto failed;
-       }
-
-       if (add_record_to_server(&src, record) < 0) {
-               error("Unable to register HF AG service record");
-               sdp_record_free(record);
-               goto failed;
-       }
-       adapter->hfp_ag_record_id = record->handle;
-
-       return 0;
-
-failed:
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-       }
-
-       if (adapter->hsp_ag_server) {
-               g_io_channel_shutdown(adapter->hsp_ag_server, TRUE, NULL);
-               g_io_channel_unref(adapter->hsp_ag_server);
-               adapter->hsp_ag_server = NULL;
-       }
-
-       if (adapter->hfp_ag_server) {
-               g_io_channel_shutdown(adapter->hfp_ag_server, TRUE, NULL);
-               g_io_channel_unref(adapter->hfp_ag_server);
-               adapter->hfp_ag_server = NULL;
-       }
-
-       return -1;
-}
-
-static int gateway_server_init(struct audio_adapter *adapter)
-{
-       uint8_t chan = DEFAULT_HFP_HS_CHANNEL;
-       sdp_record_t *record;
-       gboolean master = TRUE;
-       GError *err = NULL;
-       GIOChannel *io;
-       bdaddr_t src;
-
-       if (config) {
-               gboolean tmp;
-
-               tmp = g_key_file_get_boolean(config, "General", "Master",
-                                               &err);
-               if (err) {
-                       DBG("audio.conf: %s", err->message);
-                       g_clear_error(&err);
-               } else
-                       master = tmp;
-       }
-
-       adapter_get_address(adapter->btd_adapter, &src);
-
-       io = bt_io_listen(BT_IO_RFCOMM, NULL, hf_io_cb, adapter, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
-                               BT_IO_OPT_CHANNEL, chan,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                               BT_IO_OPT_MASTER, master,
-                               BT_IO_OPT_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               g_error_free(err);
-               return -1;
-       }
-
-       adapter->hfp_hs_server = io;
-       record = hfp_hs_record(chan);
-       if (!record) {
-               error("Unable to allocate new service record");
-               goto failed;
-       }
-
-       if (add_record_to_server(&src, record) < 0) {
-               error("Unable to register HFP HS service record");
-               sdp_record_free(record);
-               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)
-{
-       struct btd_adapter *adapter = device_get_adapter(device);
-       bdaddr_t src, dst;
-       struct audio_device *audio_dev;
-
-       adapter_get_address(adapter, &src);
-       device_get_address(device, &dst, NULL);
-
-       audio_dev = manager_get_device(&src, &dst, TRUE);
-       if (!audio_dev) {
-               DBG("unable to get a device object");
-               return -1;
-       }
-
-       g_slist_foreach(uuids, (GFunc) handle_uuid, audio_dev);
-
-       return 0;
-}
-
-static void audio_remove(struct btd_device *device)
-{
-       struct audio_device *dev;
-       const char *path;
-
-       path = device_get_path(device);
-
-       dev = manager_find_device(path, NULL, NULL, NULL, FALSE);
-       if (!dev)
-               return;
-
-       devices = g_slist_remove(devices, dev);
-
-       audio_device_unregister(dev);
-
-}
-
-static struct audio_adapter *audio_adapter_ref(struct audio_adapter *adp)
-{
-       adp->ref++;
-
-       DBG("%p: ref=%d", adp, adp->ref);
-
-       return adp;
-}
-
-static void audio_adapter_unref(struct audio_adapter *adp)
-{
-       adp->ref--;
-
-       DBG("%p: ref=%d", adp, adp->ref);
-
-       if (adp->ref > 0)
-               return;
-
-       adapters = g_slist_remove(adapters, adp);
-       btd_adapter_unref(adp->btd_adapter);
-       g_free(adp);
-}
-
-static struct audio_adapter *audio_adapter_create(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-
-       adp = g_new0(struct audio_adapter, 1);
-       adp->btd_adapter = btd_adapter_ref(adapter);
-
-       return audio_adapter_ref(adp);
-}
-
-static struct audio_adapter *audio_adapter_get(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp) {
-               adp = audio_adapter_create(adapter);
-               adapters = g_slist_append(adapters, adp);
-       } else
-               audio_adapter_ref(adp);
-
-       return adp;
-}
-
-static void state_changed(struct btd_adapter *adapter, gboolean powered)
-{
-       struct audio_adapter *adp;
-       static gboolean telephony = FALSE;
-       GSList *l;
-
-       DBG("%s powered %s", adapter_get_path(adapter),
-                                               powered ? "on" : "off");
-
-       /* ignore powered change, adapter is powering down */
-       if (powered && adapter_powering_down(adapter))
-               return;
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       adp->powered = powered;
-
-       if (powered) {
-               /* telephony driver already initialized*/
-               if (telephony == TRUE)
-                       return;
-               telephony_init();
-               telephony = TRUE;
-               return;
-       }
-
-       /* telephony not initialized just ignore power down */
-       if (telephony == FALSE)
-               return;
-
-       for (l = adapters; l; l = l->next) {
-               adp = l->data;
-
-               if (adp->powered == TRUE)
-                       return;
-       }
-
-       telephony_exit();
-       telephony = FALSE;
-}
-
-static int headset_server_probe(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-       int err;
-
-       DBG("path %s", path);
-
-       adp = audio_adapter_get(adapter);
-       if (!adp)
-               return -EINVAL;
-
-       err = headset_server_init(adp);
-       if (err < 0) {
-               audio_adapter_unref(adp);
-               return err;
-       }
-
-       btd_adapter_register_powered_callback(adapter, state_changed);
-
-       return 0;
-}
-
-static void headset_server_remove(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       btd_adapter_unregister_powered_callback(adapter, state_changed);
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       if (adp->hsp_ag_record_id) {
-               remove_record_from_server(adp->hsp_ag_record_id);
-               adp->hsp_ag_record_id = 0;
-       }
-
-       if (adp->hsp_ag_server) {
-               g_io_channel_shutdown(adp->hsp_ag_server, TRUE, NULL);
-               g_io_channel_unref(adp->hsp_ag_server);
-               adp->hsp_ag_server = NULL;
-       }
-
-       if (adp->hfp_ag_record_id) {
-               remove_record_from_server(adp->hfp_ag_record_id);
-               adp->hfp_ag_record_id = 0;
-       }
-
-       if (adp->hfp_ag_server) {
-               g_io_channel_shutdown(adp->hfp_ag_server, TRUE, NULL);
-               g_io_channel_unref(adp->hfp_ag_server);
-               adp->hfp_ag_server = NULL;
-       }
-
-       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;
-
-       err = gateway_server_init(adp);
-       if (err < 0)
-               audio_adapter_unref(adp);
-
-       return err;
-}
-
-static void gateway_server_remove(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       if (adp->hfp_hs_record_id) {
-               remove_record_from_server(adp->hfp_hs_record_id);
-               adp->hfp_hs_record_id = 0;
-       }
-
-       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;
-       }
-
-       audio_adapter_unref(adp);
-}
-
-static int a2dp_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);
-
-       adp = audio_adapter_get(adapter);
-       if (!adp)
-               return -EINVAL;
-
-       adapter_get_address(adapter, &src);
-
-       err = a2dp_register(connection, &src, config);
-       if (err < 0)
-               audio_adapter_unref(adp);
-
-       return err;
-}
-
-static void a2dp_server_remove(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-       bdaddr_t src;
-
-       DBG("path %s", path);
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       adapter_get_address(adapter, &src);
-       a2dp_unregister(&src);
-       audio_adapter_unref(adp);
-}
-
-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);
-
-       adp = audio_adapter_get(adapter);
-       if (!adp)
-               return -EINVAL;
-
-       adapter_get_address(adapter, &src);
-
-       err = avrcp_register(connection, &src, config);
-       if (err < 0)
-               audio_adapter_unref(adp);
-
-       return err;
-}
-
-static void avrcp_server_remove(struct btd_adapter *adapter)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-       bdaddr_t src;
-
-       DBG("path %s", path);
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       adapter_get_address(adapter, &src);
-       avrcp_unregister(&src);
-       audio_adapter_unref(adp);
-}
-
-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);
-
-       adp = audio_adapter_get(adapter);
-       if (!adp)
-               return -EINVAL;
-
-       adapter_get_address(adapter, &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)
-{
-       struct audio_adapter *adp;
-       const gchar *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       adp = find_adapter(adapters, adapter);
-       if (!adp)
-               return;
-
-       media_unregister(path);
-       audio_adapter_unref(adp);
-}
-
-static struct btd_device_driver audio_driver = {
-       .name   = "audio",
-       .uuids  = BTD_UUIDS(HSP_HS_UUID, HFP_HS_UUID, HSP_AG_UUID, HFP_AG_UUID,
-                       ADVANCED_AUDIO_UUID, A2DP_SOURCE_UUID, A2DP_SINK_UUID,
-                       AVRCP_TARGET_UUID, AVRCP_REMOTE_UUID),
-       .probe  = audio_probe,
-       .remove = audio_remove,
-};
-
-static struct btd_adapter_driver headset_server_driver = {
-       .name   = "audio-headset",
-       .probe  = headset_server_probe,
-       .remove = headset_server_remove,
-};
-
-static struct btd_adapter_driver gateway_server_driver = {
-       .name   = "audio-gateway",
-       .probe  = gateway_server_probe,
-       .remove = gateway_server_remove,
-};
-
-static struct btd_adapter_driver a2dp_server_driver = {
-       .name   = "audio-a2dp",
-       .probe  = a2dp_server_probe,
-       .remove = a2dp_server_remove,
-};
-
-static struct btd_adapter_driver avrcp_server_driver = {
-       .name   = "audio-control",
-       .probe  = avrcp_server_probe,
-       .remove = avrcp_server_remove,
-};
-
-static struct btd_adapter_driver media_server_driver = {
-       .name   = "media",
-       .probe  = media_server_probe,
-       .remove = media_server_remove,
-};
-
-int audio_manager_init(DBusConnection *conn, GKeyFile *conf,
-                                                       gboolean *enable_sco)
-{
-       char **list;
-       int i;
-       gboolean b;
-       GError *err = NULL;
-
-       connection = dbus_connection_ref(conn);
-
-       if (!conf)
-               goto proceed;
-
-       config = conf;
-
-       list = g_key_file_get_string_list(config, "General", "Enable",
-                                               NULL, NULL);
-       for (i = 0; list && list[i] != NULL; i++) {
-               if (g_str_equal(list[i], "Headset"))
-                       enabled.headset = TRUE;
-               else if (g_str_equal(list[i], "Gateway"))
-                       enabled.gateway = TRUE;
-               else if (g_str_equal(list[i], "Sink"))
-                       enabled.sink = TRUE;
-               else if (g_str_equal(list[i], "Source"))
-                       enabled.source = TRUE;
-               else if (g_str_equal(list[i], "Control"))
-                       enabled.control = TRUE;
-               else if (g_str_equal(list[i], "Socket"))
-                       enabled.socket = TRUE;
-               else if (g_str_equal(list[i], "Media"))
-                       enabled.media = TRUE;
-
-       }
-       g_strfreev(list);
-
-       list = g_key_file_get_string_list(config, "General", "Disable",
-                                               NULL, NULL);
-       for (i = 0; list && list[i] != NULL; i++) {
-               if (g_str_equal(list[i], "Headset"))
-                       enabled.headset = FALSE;
-               else if (g_str_equal(list[i], "Gateway"))
-                       enabled.gateway = FALSE;
-               else if (g_str_equal(list[i], "Sink"))
-                       enabled.sink = FALSE;
-               else if (g_str_equal(list[i], "Source"))
-                       enabled.source = FALSE;
-               else if (g_str_equal(list[i], "Control"))
-                       enabled.control = FALSE;
-               else if (g_str_equal(list[i], "Socket"))
-                       enabled.socket = FALSE;
-               else if (g_str_equal(list[i], "Media"))
-                       enabled.media = FALSE;
-       }
-       g_strfreev(list);
-
-       b = g_key_file_get_boolean(config, "General", "AutoConnect", &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else
-               auto_connect = b;
-
-       b = g_key_file_get_boolean(config, "Headset", "HFP",
-                                       &err);
-       if (err)
-               g_clear_error(&err);
-       else
-               enabled.hfp = b;
-
-       err = NULL;
-       i = g_key_file_get_integer(config, "Headset", "MaxConnected",
-                                       &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else
-               max_connected_headsets = i;
-
-proceed:
-       if (enabled.socket)
-               unix_init();
-
-       if (enabled.media)
-               btd_register_adapter_driver(&media_server_driver);
-
-       if (enabled.headset)
-               btd_register_adapter_driver(&headset_server_driver);
-
-       if (enabled.gateway)
-               btd_register_adapter_driver(&gateway_server_driver);
-
-       if (enabled.source || enabled.sink)
-               btd_register_adapter_driver(&a2dp_server_driver);
-
-       if (enabled.control)
-               btd_register_adapter_driver(&avrcp_server_driver);
-
-       btd_register_device_driver(&audio_driver);
-
-       *enable_sco = (enabled.gateway || enabled.headset);
-
-       return 0;
-}
-
-void audio_manager_exit(void)
-{
-       /* Bail out early if we haven't been initialized */
-       if (connection == NULL)
-               return;
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       if (config) {
-               g_key_file_free(config);
-               config = NULL;
-       }
-
-       if (enabled.socket)
-               unix_exit();
-
-       if (enabled.media)
-               btd_unregister_adapter_driver(&media_server_driver);
-
-       if (enabled.headset)
-               btd_unregister_adapter_driver(&headset_server_driver);
-
-       if (enabled.gateway)
-               btd_unregister_adapter_driver(&gateway_server_driver);
-
-       if (enabled.source || enabled.sink)
-               btd_unregister_adapter_driver(&a2dp_server_driver);
-
-       if (enabled.control)
-               btd_unregister_adapter_driver(&avrcp_server_driver);
-
-       btd_unregister_device_driver(&audio_driver);
-}
-
-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) {
-               struct audio_device *dev = l->data;
-
-               if ((path && (strcmp(path, "")) && strcmp(dev->path, path)))
-                       continue;
-
-               if ((src && bacmp(src, BDADDR_ANY)) && bacmp(&dev->src, src))
-                       continue;
-
-               if ((dst && bacmp(dst, BDADDR_ANY)) && bacmp(&dev->dst, dst))
-                       continue;
-
-               if (interface && !strcmp(AUDIO_HEADSET_INTERFACE, interface)
-                               && !dev->headset)
-                       continue;
-
-               if (interface && !strcmp(AUDIO_GATEWAY_INTERFACE, interface)
-                               && !dev->gateway)
-                       continue;
-
-               if (interface && !strcmp(AUDIO_SINK_INTERFACE, interface)
-                               && !dev->sink)
-                       continue;
-
-               if (interface && !strcmp(AUDIO_SOURCE_INTERFACE, interface)
-                               && !dev->source)
-                       continue;
-
-               if (interface && !strcmp(AUDIO_CONTROL_INTERFACE, interface)
-                               && !dev->control)
-                       continue;
-
-               if (connected && !audio_device_is_active(dev, interface))
-                       continue;
-
-               result = g_slist_append(result, dev);
-       }
-
-       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,
-                                       const bdaddr_t *dst,
-                                       gboolean create)
-{
-       struct audio_device *dev;
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       char addr[18];
-       const char *path;
-
-       dev = manager_find_device(NULL, src, dst, NULL, FALSE);
-       if (dev)
-               return dev;
-
-       if (!create)
-               return NULL;
-
-       ba2str(src, addr);
-
-       adapter = manager_find_adapter(src);
-       if (!adapter) {
-               error("Unable to get a btd_adapter object for %s",
-                               addr);
-               return NULL;
-       }
-
-       ba2str(dst, addr);
-
-       device = adapter_get_device(connection, adapter, addr);
-       if (!device) {
-               error("Unable to get btd_device object for %s", addr);
-               return NULL;
-       }
-
-       path = device_get_path(device);
-
-       dev = audio_device_register(connection, device, path, src, dst);
-       if (!dev)
-               return NULL;
-
-       devices = g_slist_append(devices, dev);
-
-       return dev;
-}
-
-gboolean manager_allow_headset_connection(struct audio_device *device)
-{
-       GSList *l;
-       int connected = 0;
-
-       for (l = devices; l != NULL; l = l->next) {
-               struct audio_device *dev = l->data;
-               struct headset *hs = dev->headset;
-
-               if (dev == device)
-                       continue;
-
-               if (device && bacmp(&dev->src, &device->src) != 0)
-                       continue;
-
-               if (!hs)
-                       continue;
-
-               if (headset_get_state(dev) > HEADSET_STATE_DISCONNECTED)
-                       connected++;
-
-               if (connected >= max_connected_headsets)
-                       return FALSE;
-       }
-
-       return TRUE;
-}
-
-void manager_set_fast_connectable(gboolean enable)
-{
-       GSList *l;
-
-       if (enable && !manager_allow_headset_connection(NULL)) {
-               DBG("Refusing enabling fast connectable");
-               return;
-       }
-
-       for (l = adapters; l != NULL; l = l->next) {
-               struct audio_adapter *adapter = l->data;
-
-               if (btd_adapter_set_fast_connectable(adapter->btd_adapter,
-                                                               enable))
-                       error("Changing fast connectable for hci%d failed",
-                               adapter_get_dev_id(adapter->btd_adapter));
-       }
-}
diff --git a/audio/manager.h b/audio/manager.h
deleted file mode 100644 (file)
index f1d3021..0000000
+++ /dev/null
@@ -1,63 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-struct enabled_interfaces {
-       gboolean hfp;
-       gboolean headset;
-       gboolean gateway;
-       gboolean sink;
-       gboolean source;
-       gboolean control;
-       gboolean socket;
-       gboolean media;
-       gboolean media_player;
-};
-
-int audio_manager_init(DBusConnection *conn, GKeyFile *config,
-                                                       gboolean *enable_sco);
-void audio_manager_exit(void);
-
-gboolean server_is_enabled(bdaddr_t *src, uint16_t svc);
-
-struct audio_device *manager_find_device(const char *path,
-                                       const bdaddr_t *src,
-                                       const bdaddr_t *dst,
-                                       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);
-
-gboolean manager_allow_headset_connection(struct audio_device *device);
-
-/* TRUE to enable fast connectable and FALSE to disable fast connectable for all
- * audio adapters. */
-void manager_set_fast_connectable(gboolean enable);
diff --git a/audio/pcm_bluetooth.c b/audio/pcm_bluetooth.c
deleted file mode 100644 (file)
index b9da805..0000000
+++ /dev/null
@@ -1,1785 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <time.h>
-#include <sys/time.h>
-#include <pthread.h>
-#include <signal.h>
-#include <limits.h>
-
-#include <netinet/in.h>
-
-#include <alsa/asoundlib.h>
-#include <alsa/pcm_external.h>
-
-#include "ipc.h"
-#include "sbc.h"
-#include "rtp.h"
-
-/* #define ENABLE_DEBUG */
-
-#define UINT_SECS_MAX (UINT_MAX / 1000000 - 1)
-
-#define MIN_PERIOD_TIME 1
-
-#define BUFFER_SIZE 2048
-
-#ifdef ENABLE_DEBUG
-#define DBG(fmt, arg...)  printf("DEBUG: %s: " fmt "\n" , __FUNCTION__ , ## arg)
-#else
-#define DBG(fmt, arg...)
-#endif
-
-#ifndef SOL_SCO
-#define SOL_SCO 17
-#endif
-
-#ifndef SCO_TXBUFS
-#define SCO_TXBUFS 0x03
-#endif
-
-#ifndef SCO_RXBUFS
-#define SCO_RXBUFS 0x04
-#endif
-
-#ifndef MIN
-# define MIN(x, y) ((x) < (y) ? (x) : (y))
-#endif
-
-#ifndef MAX
-# define MAX(x, y) ((x) > (y) ? (x) : (y))
-#endif
-
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
-
-/* adapted from glibc sys/time.h timersub() macro */
-#define priv_timespecsub(a, b, result)                                 \
-       do {                                                            \
-               (result)->tv_sec = (a)->tv_sec - (b)->tv_sec;           \
-               (result)->tv_nsec = (a)->tv_nsec - (b)->tv_nsec;        \
-               if ((result)->tv_nsec < 0) {                            \
-                       --(result)->tv_sec;                             \
-                       (result)->tv_nsec += 1000000000;                \
-               }                                                       \
-       } while (0)
-
-struct bluetooth_a2dp {
-       sbc_capabilities_t sbc_capabilities;
-       sbc_t sbc;                              /* Codec data */
-       int sbc_initialized;                    /* Keep track if the encoder is initialized */
-       unsigned int codesize;                  /* SBC codesize */
-       int samples;                            /* Number of encoded samples */
-       uint8_t buffer[BUFFER_SIZE];            /* Codec transfer buffer */
-       unsigned int count;                     /* Codec transfer buffer counter */
-
-       int nsamples;                           /* Cumulative number of codec samples */
-       uint16_t seq_num;                       /* Cumulative packet sequence */
-       int frame_count;                        /* Current frames in buffer*/
-};
-
-struct bluetooth_alsa_config {
-       char device[18];                /* Address of the remote Device */
-       int has_device;
-       uint8_t transport;              /* Requested transport */
-       int has_transport;
-       uint16_t rate;
-       int has_rate;
-       uint8_t channel_mode;           /* A2DP only */
-       int has_channel_mode;
-       uint8_t allocation_method;      /* A2DP only */
-       int has_allocation_method;
-       uint8_t subbands;               /* A2DP only */
-       int has_subbands;
-       uint8_t block_length;           /* A2DP only */
-       int has_block_length;
-       uint8_t bitpool;                /* A2DP only */
-       int has_bitpool;
-       int autoconnect;
-};
-
-struct bluetooth_data {
-       snd_pcm_ioplug_t io;
-       struct bluetooth_alsa_config alsa_config;       /* ALSA resource file parameters */
-       volatile snd_pcm_sframes_t hw_ptr;
-       int transport;                                  /* chosen transport SCO or AD2P */
-       unsigned int link_mtu;                          /* MTU for selected transport channel */
-       volatile struct pollfd stream;                  /* Audio stream filedescriptor */
-       struct pollfd server;                           /* Audio daemon filedescriptor */
-       uint8_t buffer[BUFFER_SIZE];            /* Encoded transfer buffer */
-       unsigned int count;                             /* Transfer buffer counter */
-       struct bluetooth_a2dp a2dp;                     /* A2DP data */
-
-       pthread_t hw_thread;                            /* Makes virtual hw pointer move */
-       int pipefd[2];                                  /* Inter thread communication */
-       int stopped;
-       sig_atomic_t reset;                             /* Request XRUN handling */
-};
-
-static int audioservice_send(int sk, const bt_audio_msg_header_t *msg);
-static int audioservice_expect(int sk, bt_audio_msg_header_t *outmsg,
-                                                       int expected_type);
-
-static int bluetooth_start(snd_pcm_ioplug_t *io)
-{
-       DBG("bluetooth_start %p", io);
-
-       return 0;
-}
-
-static int bluetooth_stop(snd_pcm_ioplug_t *io)
-{
-       DBG("bluetooth_stop %p", io);
-
-       return 0;
-}
-
-static void *playback_hw_thread(void *param)
-{
-       struct bluetooth_data *data = param;
-       unsigned int prev_periods;
-       double period_time;
-       struct timespec start;
-       struct pollfd fds[2];
-       int poll_timeout;
-
-       data->server.events = POLLIN;
-       /* note: only errors for data->stream.events */
-
-       fds[0] = data->server;
-       fds[1] = data->stream;
-
-       prev_periods = 0;
-       period_time = 1000000.0 * data->io.period_size / data->io.rate;
-       if (period_time > (int) (MIN_PERIOD_TIME * 1000))
-               poll_timeout = (int) (period_time / 1000.0f);
-       else
-               poll_timeout = MIN_PERIOD_TIME;
-
-       clock_gettime(CLOCK_MONOTONIC, &start);
-
-       while (1) {
-               unsigned int dtime, periods;
-               struct timespec cur, delta;
-               int ret;
-
-               if (data->stopped)
-                       goto iter_sleep;
-
-               if (data->reset) {
-                       DBG("Handle XRUN in hw-thread.");
-                       data->reset = 0;
-                       clock_gettime(CLOCK_MONOTONIC, &start);
-                       prev_periods = 0;
-               }
-
-               clock_gettime(CLOCK_MONOTONIC, &cur);
-
-               priv_timespecsub(&cur, &start, &delta);
-
-               dtime = delta.tv_sec * 1000000 + delta.tv_nsec / 1000;
-               periods = 1.0 * dtime / period_time;
-
-               if (periods > prev_periods) {
-                       char c = 'w';
-                       int frags = periods - prev_periods, n;
-
-                       data->hw_ptr += frags * data->io.period_size;
-                       data->hw_ptr %= data->io.buffer_size;
-
-                       for (n = 0; n < frags; n++) {
-                               /* Notify user that hardware pointer
-                                * has moved * */
-                               if (write(data->pipefd[1], &c, 1) < 0)
-                                       pthread_testcancel();
-                       }
-
-                       /* Reset point of reference to avoid too big values
-                        * that wont fit an unsigned int */
-                       if ((unsigned int) delta.tv_sec < UINT_SECS_MAX)
-                               prev_periods = periods;
-                       else {
-                               prev_periods = 0;
-                               clock_gettime(CLOCK_MONOTONIC, &start);
-                       }
-               }
-
-iter_sleep:
-               /* sleep up to one period interval */
-               ret = poll(fds, 2, poll_timeout);
-
-               if (ret < 0) {
-                       if (errno != EINTR) {
-                               SNDERR("poll error: %s (%d)", strerror(errno),
-                                                               errno);
-                               break;
-                       }
-               } else if (ret > 0) {
-                       ret = (fds[0].revents) ? 0 : 1;
-                       SNDERR("poll fd %d revents %d", ret, fds[ret].revents);
-                       if (fds[ret].revents & (POLLERR | POLLHUP | POLLNVAL))
-                               break;
-               }
-
-               /* Offer opportunity to be canceled by main thread */
-               pthread_testcancel();
-       }
-
-       data->hw_thread = 0;
-       pthread_exit(NULL);
-}
-
-static int bluetooth_playback_start(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-       int err;
-
-       DBG("%p", io);
-
-       data->stopped = 0;
-
-       if (data->hw_thread)
-               return 0;
-
-       err = pthread_create(&data->hw_thread, 0, playback_hw_thread, data);
-
-       return -err;
-}
-
-static int bluetooth_playback_stop(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-
-       DBG("%p", io);
-
-       data->stopped = 1;
-
-       return 0;
-}
-
-static snd_pcm_sframes_t bluetooth_pointer(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-
-       return data->hw_ptr;
-}
-
-static void bluetooth_exit(struct bluetooth_data *data)
-{
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-
-       if (data->server.fd >= 0)
-               bt_audio_service_close(data->server.fd);
-
-       if (data->stream.fd >= 0)
-               close(data->stream.fd);
-
-       if (data->hw_thread) {
-               pthread_cancel(data->hw_thread);
-               pthread_join(data->hw_thread, 0);
-       }
-
-       if (a2dp->sbc_initialized)
-               sbc_finish(&a2dp->sbc);
-
-       if (data->pipefd[0] > 0)
-               close(data->pipefd[0]);
-
-       if (data->pipefd[1] > 0)
-               close(data->pipefd[1]);
-
-       free(data);
-}
-
-static int bluetooth_close(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-
-       DBG("%p", io);
-
-       bluetooth_exit(data);
-
-       return 0;
-}
-
-static int bluetooth_prepare(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-       char c = 'w';
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_start_stream_req *req = (void *) buf;
-       struct bt_start_stream_rsp *rsp = (void *) buf;
-       struct bt_new_stream_ind *ind = (void *) buf;
-       uint32_t period_count = io->buffer_size / io->period_size;
-       int opt_name, err;
-       struct timeval t = { 0, period_count };
-
-       DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
-                                       io->period_size, io->buffer_size);
-
-       data->reset = 0;
-
-       /* As we're gonna receive messages on the server socket, we have to stop the
-          hw thread that is polling on it, if any */
-       if (data->hw_thread) {
-               pthread_cancel(data->hw_thread);
-               pthread_join(data->hw_thread, 0);
-               data->hw_thread = 0;
-       }
-
-       if (io->stream == SND_PCM_STREAM_PLAYBACK)
-               /* If not null for playback, xmms doesn't display time
-                * correctly */
-               data->hw_ptr = 0;
-       else
-               /* ALSA library is really picky on the fact hw_ptr is not null.
-                * If it is, capture won't start */
-               data->hw_ptr = io->period_size;
-
-       /* send start */
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_START_STREAM;
-       req->h.length = sizeof(*req);
-
-       err = audioservice_send(data->server.fd, &req->h);
-       if (err < 0)
-               return err;
-
-       rsp->h.length = sizeof(*rsp);
-       err = audioservice_expect(data->server.fd, &rsp->h,
-                                       BT_START_STREAM);
-       if (err < 0)
-               return err;
-
-       ind->h.length = sizeof(*ind);
-       err = audioservice_expect(data->server.fd, &ind->h,
-                                       BT_NEW_STREAM);
-       if (err < 0)
-               return err;
-
-       if (data->stream.fd >= 0)
-               close(data->stream.fd);
-
-       data->stream.fd = bt_audio_service_get_data_fd(data->server.fd);
-       if (data->stream.fd < 0) {
-               return -errno;
-       }
-
-       if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
-                                               SO_SNDTIMEO : SO_RCVTIMEO;
-
-               if (setsockopt(data->stream.fd, SOL_SOCKET, opt_name, &t,
-                                                       sizeof(t)) < 0)
-                       return -errno;
-       } else {
-               opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
-                                               SCO_TXBUFS : SCO_RXBUFS;
-
-               if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
-                                               sizeof(period_count)) == 0)
-                       return 0;
-
-               opt_name = (io->stream == SND_PCM_STREAM_PLAYBACK) ?
-                                               SO_SNDBUF : SO_RCVBUF;
-
-               if (setsockopt(data->stream.fd, SOL_SCO, opt_name, &period_count,
-                                               sizeof(period_count)) == 0)
-                       return 0;
-
-               /* FIXME : handle error codes */
-       }
-
-       /* wake up any client polling at us */
-       if (write(data->pipefd[1], &c, 1) < 0) {
-               err = -errno;
-               return err;
-       }
-
-       return 0;
-}
-
-static int bluetooth_hsp_hw_params(snd_pcm_ioplug_t *io,
-                                       snd_pcm_hw_params_t *params)
-{
-       struct bluetooth_data *data = io->private_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_open_req *open_req = (void *) buf;
-       struct bt_open_rsp *open_rsp = (void *) buf;
-       struct bt_set_configuration_req *req = (void *) buf;
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-       int err;
-
-       DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
-                                       io->period_size, io->buffer_size);
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       open_req->h.type = BT_REQUEST;
-       open_req->h.name = BT_OPEN;
-       open_req->h.length = sizeof(*open_req);
-
-       strncpy(open_req->destination, data->alsa_config.device, 18);
-       open_req->seid = BT_A2DP_SEID_RANGE + 1;
-       open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ?
-                       BT_WRITE_LOCK : BT_READ_LOCK);
-
-       err = audioservice_send(data->server.fd, &open_req->h);
-       if (err < 0)
-               return err;
-
-       open_rsp->h.length = sizeof(*open_rsp);
-       err = audioservice_expect(data->server.fd, &open_rsp->h,
-                                       BT_OPEN);
-       if (err < 0)
-               return err;
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_SET_CONFIGURATION;
-       req->h.length = sizeof(*req);
-
-       req->codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
-       req->codec.seid = BT_A2DP_SEID_RANGE + 1;
-       req->codec.length = sizeof(pcm_capabilities_t);
-
-       req->h.length += req->codec.length - sizeof(req->codec);
-       err = audioservice_send(data->server.fd, &req->h);
-       if (err < 0)
-               return err;
-
-       rsp->h.length = sizeof(*rsp);
-       err = audioservice_expect(data->server.fd, &rsp->h,
-                                       BT_SET_CONFIGURATION);
-       if (err < 0)
-               return err;
-
-       data->transport = BT_CAPABILITIES_TRANSPORT_SCO;
-       data->link_mtu = rsp->link_mtu;
-
-       return 0;
-}
-
-static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
-{
-       switch (freq) {
-       case BT_SBC_SAMPLING_FREQ_16000:
-       case BT_SBC_SAMPLING_FREQ_32000:
-               return 53;
-       case BT_SBC_SAMPLING_FREQ_44100:
-               switch (mode) {
-               case BT_A2DP_CHANNEL_MODE_MONO:
-               case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 31;
-               case BT_A2DP_CHANNEL_MODE_STEREO:
-               case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
-                       return 53;
-               default:
-                       DBG("Invalid channel mode %u", mode);
-                       return 53;
-               }
-       case BT_SBC_SAMPLING_FREQ_48000:
-               switch (mode) {
-               case BT_A2DP_CHANNEL_MODE_MONO:
-               case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 29;
-               case BT_A2DP_CHANNEL_MODE_STEREO:
-               case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
-                       return 51;
-               default:
-                       DBG("Invalid channel mode %u", mode);
-                       return 51;
-               }
-       default:
-               DBG("Invalid sampling freq %u", freq);
-               return 53;
-       }
-}
-
-static int bluetooth_a2dp_init(struct bluetooth_data *data,
-                                       snd_pcm_hw_params_t *params)
-{
-       struct bluetooth_alsa_config *cfg = &data->alsa_config;
-       sbc_capabilities_t *cap = &data->a2dp.sbc_capabilities;
-       unsigned int max_bitpool, min_bitpool, rate, channels;
-       int dir;
-
-       snd_pcm_hw_params_get_rate(params, &rate, &dir);
-       snd_pcm_hw_params_get_channels(params, &channels);
-
-       switch (rate) {
-       case 48000:
-               cap->frequency = BT_SBC_SAMPLING_FREQ_48000;
-               break;
-       case 44100:
-               cap->frequency = BT_SBC_SAMPLING_FREQ_44100;
-               break;
-       case 32000:
-               cap->frequency = BT_SBC_SAMPLING_FREQ_32000;
-               break;
-       case 16000:
-               cap->frequency = BT_SBC_SAMPLING_FREQ_16000;
-               break;
-       default:
-               DBG("Rate %d not supported", rate);
-               return -1;
-       }
-
-       if (cfg->has_channel_mode)
-               cap->channel_mode = cfg->channel_mode;
-       else if (channels == 2) {
-               if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
-               else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
-               else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
-       } else {
-               if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
-       }
-
-       if (!cap->channel_mode) {
-               DBG("No supported channel modes");
-               return -1;
-       }
-
-       if (cfg->has_block_length)
-               cap->block_length = cfg->block_length;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
-       else {
-               DBG("No supported block lengths");
-               return -1;
-       }
-
-       if (cfg->has_subbands)
-               cap->subbands = cfg->subbands;
-       if (cap->subbands & BT_A2DP_SUBBANDS_8)
-               cap->subbands = BT_A2DP_SUBBANDS_8;
-       else if (cap->subbands & BT_A2DP_SUBBANDS_4)
-               cap->subbands = BT_A2DP_SUBBANDS_4;
-       else {
-               DBG("No supported subbands");
-               return -1;
-       }
-
-       if (cfg->has_allocation_method)
-               cap->allocation_method = cfg->allocation_method;
-       if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
-               cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
-       else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
-               cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
-
-       if (cfg->has_bitpool)
-               min_bitpool = max_bitpool = cfg->bitpool;
-       else {
-               min_bitpool = MAX(MIN_BITPOOL, cap->min_bitpool);
-               max_bitpool = MIN(default_bitpool(cap->frequency,
-                                       cap->channel_mode),
-                                       cap->max_bitpool);
-       }
-
-       cap->min_bitpool = min_bitpool;
-       cap->max_bitpool = max_bitpool;
-
-       return 0;
-}
-
-static void bluetooth_a2dp_setup(struct bluetooth_a2dp *a2dp)
-{
-       sbc_capabilities_t active_capabilities = a2dp->sbc_capabilities;
-
-       if (a2dp->sbc_initialized)
-               sbc_reinit(&a2dp->sbc, 0);
-       else
-               sbc_init(&a2dp->sbc, 0);
-       a2dp->sbc_initialized = 1;
-
-       if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_16000)
-               a2dp->sbc.frequency = SBC_FREQ_16000;
-
-       if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_32000)
-               a2dp->sbc.frequency = SBC_FREQ_32000;
-
-       if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_44100)
-               a2dp->sbc.frequency = SBC_FREQ_44100;
-
-       if (active_capabilities.frequency & BT_SBC_SAMPLING_FREQ_48000)
-               a2dp->sbc.frequency = SBC_FREQ_48000;
-
-       if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_MONO)
-               a2dp->sbc.mode = SBC_MODE_MONO;
-
-       if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
-               a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
-
-       if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
-               a2dp->sbc.mode = SBC_MODE_STEREO;
-
-       if (active_capabilities.channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
-               a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
-
-       a2dp->sbc.allocation = active_capabilities.allocation_method
-                               == BT_A2DP_ALLOCATION_SNR ? SBC_AM_SNR
-                               : SBC_AM_LOUDNESS;
-
-       switch (active_capabilities.subbands) {
-       case BT_A2DP_SUBBANDS_4:
-               a2dp->sbc.subbands = SBC_SB_4;
-               break;
-       case BT_A2DP_SUBBANDS_8:
-               a2dp->sbc.subbands = SBC_SB_8;
-               break;
-       }
-
-       switch (active_capabilities.block_length) {
-       case BT_A2DP_BLOCK_LENGTH_4:
-               a2dp->sbc.blocks = SBC_BLK_4;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_8:
-               a2dp->sbc.blocks = SBC_BLK_8;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_12:
-               a2dp->sbc.blocks = SBC_BLK_12;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_16:
-               a2dp->sbc.blocks = SBC_BLK_16;
-               break;
-       }
-
-       a2dp->sbc.bitpool = active_capabilities.max_bitpool;
-       a2dp->codesize = sbc_get_codesize(&a2dp->sbc);
-       a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
-}
-
-static int bluetooth_a2dp_hw_params(snd_pcm_ioplug_t *io,
-                                       snd_pcm_hw_params_t *params)
-{
-       struct bluetooth_data *data = io->private_data;
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_open_req *open_req = (void *) buf;
-       struct bt_open_rsp *open_rsp = (void *) buf;
-       struct bt_set_configuration_req *req = (void *) buf;
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-       int err;
-
-       DBG("Preparing with io->period_size=%lu io->buffer_size=%lu",
-                                       io->period_size, io->buffer_size);
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       open_req->h.type = BT_REQUEST;
-       open_req->h.name = BT_OPEN;
-       open_req->h.length = sizeof(*open_req);
-
-       strncpy(open_req->destination, data->alsa_config.device, 18);
-       open_req->seid = a2dp->sbc_capabilities.capability.seid;
-       open_req->lock = (io->stream == SND_PCM_STREAM_PLAYBACK ?
-                       BT_WRITE_LOCK : BT_READ_LOCK);
-
-       err = audioservice_send(data->server.fd, &open_req->h);
-       if (err < 0)
-               return err;
-
-       open_rsp->h.length = sizeof(*open_rsp);
-       err = audioservice_expect(data->server.fd, &open_rsp->h,
-                                       BT_OPEN);
-       if (err < 0)
-               return err;
-
-       err = bluetooth_a2dp_init(data, params);
-       if (err < 0)
-               return err;
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_SET_CONFIGURATION;
-       req->h.length = sizeof(*req);
-
-       memcpy(&req->codec, &a2dp->sbc_capabilities,
-                       sizeof(a2dp->sbc_capabilities));
-
-       req->codec.transport = BT_CAPABILITIES_TRANSPORT_A2DP;
-       req->codec.length = sizeof(a2dp->sbc_capabilities);
-       req->h.length += req->codec.length - sizeof(req->codec);
-
-       err = audioservice_send(data->server.fd, &req->h);
-       if (err < 0)
-               return err;
-
-       rsp->h.length = sizeof(*rsp);
-       err = audioservice_expect(data->server.fd, &rsp->h,
-                                       BT_SET_CONFIGURATION);
-       if (err < 0)
-               return err;
-
-       data->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
-       data->link_mtu = rsp->link_mtu;
-
-       /* Setup SBC encoder now we agree on parameters */
-       bluetooth_a2dp_setup(a2dp);
-
-       DBG("\tallocation=%u\n\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
-               a2dp->sbc.allocation, a2dp->sbc.subbands, a2dp->sbc.blocks,
-               a2dp->sbc.bitpool);
-
-       return 0;
-}
-
-static int bluetooth_poll_descriptors(snd_pcm_ioplug_t *io,
-                                       struct pollfd *pfd, unsigned int space)
-{
-       struct bluetooth_data *data = io->private_data;
-
-       assert(io);
-
-       if (space < 1)
-               return 0;
-
-       pfd[0].fd = data->stream.fd;
-       pfd[0].events = POLLIN;
-       pfd[0].revents = 0;
-
-       return 1;
-}
-
-static int bluetooth_poll_revents(snd_pcm_ioplug_t *io ATTRIBUTE_UNUSED,
-                                       struct pollfd *pfds, unsigned int nfds,
-                                       unsigned short *revents)
-{
-       assert(pfds && nfds == 1 && revents);
-
-       *revents = pfds[0].revents;
-
-       return 0;
-}
-
-static int bluetooth_playback_poll_descriptors_count(snd_pcm_ioplug_t *io)
-{
-       return 2;
-}
-
-static int bluetooth_playback_poll_descriptors(snd_pcm_ioplug_t *io,
-                                       struct pollfd *pfd, unsigned int space)
-{
-       struct bluetooth_data *data = io->private_data;
-
-       DBG("");
-
-       assert(data->pipefd[0] >= 0);
-
-       if (space < 2)
-               return 0;
-
-       pfd[0].fd = data->pipefd[0];
-       pfd[0].events = POLLIN;
-       pfd[0].revents = 0;
-       pfd[1].fd = data->stream.fd;
-       pfd[1].events = POLLERR | POLLHUP | POLLNVAL;
-       pfd[1].revents = 0;
-
-       return 2;
-}
-
-static int bluetooth_playback_poll_revents(snd_pcm_ioplug_t *io,
-                                       struct pollfd *pfds, unsigned int nfds,
-                                       unsigned short *revents)
-{
-       static char buf[1];
-
-       DBG("");
-
-       assert(pfds);
-       assert(nfds == 2);
-       assert(revents);
-       assert(pfds[0].fd >= 0);
-       assert(pfds[1].fd >= 0);
-
-       if (io->state != SND_PCM_STATE_PREPARED)
-               if (read(pfds[0].fd, buf, 1) < 0)
-                       SYSERR("read error: %s (%d)", strerror(errno), errno);
-
-       if (pfds[1].revents & (POLLERR | POLLHUP | POLLNVAL))
-               io->state = SND_PCM_STATE_DISCONNECTED;
-
-       *revents = (pfds[0].revents & POLLIN) ? POLLOUT : 0;
-
-       return 0;
-}
-
-
-static snd_pcm_sframes_t bluetooth_hsp_read(snd_pcm_ioplug_t *io,
-                               const snd_pcm_channel_area_t *areas,
-                               snd_pcm_uframes_t offset,
-                               snd_pcm_uframes_t size)
-{
-       struct bluetooth_data *data = io->private_data;
-       snd_pcm_uframes_t frames_to_write, ret;
-       unsigned char *buff;
-       unsigned int frame_size = 0;
-       int nrecv;
-
-       DBG("areas->step=%u areas->first=%u offset=%lu size=%lu io->nonblock=%u",
-                       areas->step, areas->first, offset, size, io->nonblock);
-
-       frame_size = areas->step / 8;
-
-       if (data->count > 0)
-               goto proceed;
-
-       nrecv = recv(data->stream.fd, data->buffer, data->link_mtu,
-                                       io->nonblock ? MSG_DONTWAIT : 0);
-
-       if (nrecv < 0) {
-               ret = (errno == EPIPE) ? -EIO : -errno;
-               goto done;
-       }
-
-       if ((unsigned int) nrecv != data->link_mtu) {
-               ret = -EIO;
-               SNDERR(strerror(-ret));
-               goto done;
-       }
-
-       /* Increment hardware transmition pointer */
-       data->hw_ptr = (data->hw_ptr + data->link_mtu / frame_size) %
-                               io->buffer_size;
-
-proceed:
-       buff = (unsigned char *) areas->addr +
-                       (areas->first + areas->step * offset) / 8;
-
-       if ((data->count + size * frame_size) <= data->link_mtu)
-               frames_to_write = size;
-       else
-               frames_to_write = (data->link_mtu - data->count) / frame_size;
-
-       memcpy(buff, data->buffer + data->count, frame_size * frames_to_write);
-       data->count += (frame_size * frames_to_write);
-       data->count %= data->link_mtu;
-
-       /* Return written frames count */
-       ret = frames_to_write;
-
-done:
-       DBG("returning %lu", ret);
-       return ret;
-}
-
-static snd_pcm_sframes_t bluetooth_hsp_write(snd_pcm_ioplug_t *io,
-                               const snd_pcm_channel_area_t *areas,
-                               snd_pcm_uframes_t offset,
-                               snd_pcm_uframes_t size)
-{
-       struct bluetooth_data *data = io->private_data;
-       snd_pcm_sframes_t ret = 0;
-       snd_pcm_uframes_t frames_to_read;
-       uint8_t *buff;
-       int rsend, frame_size;
-
-       DBG("areas->step=%u areas->first=%u offset=%lu, size=%lu io->nonblock=%u",
-                       areas->step, areas->first, offset, size, io->nonblock);
-
-       if (io->hw_ptr > io->appl_ptr) {
-               ret = bluetooth_playback_stop(io);
-               if (ret == 0)
-                       ret = -EPIPE;
-               goto done;
-       }
-
-       frame_size = areas->step / 8;
-       if ((data->count + size * frame_size) <= data->link_mtu)
-               frames_to_read = size;
-       else
-               frames_to_read = (data->link_mtu - data->count) / frame_size;
-
-       DBG("count=%d frames_to_read=%lu", data->count, frames_to_read);
-
-       /* Ready for more data */
-       buff = (uint8_t *) areas->addr +
-                       (areas->first + areas->step * offset) / 8;
-       memcpy(data->buffer + data->count, buff, frame_size * frames_to_read);
-
-       /* Remember we have some frames in the pipe now */
-       data->count += frames_to_read * frame_size;
-       if (data->count != data->link_mtu) {
-               ret = frames_to_read;
-               goto done;
-       }
-
-       rsend = send(data->stream.fd, data->buffer, data->link_mtu,
-                       io->nonblock ? MSG_DONTWAIT : 0);
-       if (rsend > 0) {
-               /* Reset count pointer */
-               data->count = 0;
-
-               ret = frames_to_read;
-       } else if (rsend < 0)
-               ret = (errno == EPIPE) ? -EIO : -errno;
-       else
-               ret = -EIO;
-
-done:
-       DBG("returning %ld", ret);
-       return ret;
-}
-
-static snd_pcm_sframes_t bluetooth_a2dp_read(snd_pcm_ioplug_t *io,
-                               const snd_pcm_channel_area_t *areas,
-                               snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
-{
-       snd_pcm_uframes_t ret = 0;
-       return ret;
-}
-
-static int avdtp_write(struct bluetooth_data *data)
-{
-       int err;
-       struct rtp_header *header;
-       struct rtp_payload *payload;
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-
-       header = (void *) a2dp->buffer;
-       payload = (void *) (a2dp->buffer + sizeof(*header));
-
-       memset(a2dp->buffer, 0, sizeof(*header) + sizeof(*payload));
-
-       payload->frame_count = a2dp->frame_count;
-       header->v = 2;
-       header->pt = 1;
-       header->sequence_number = htons(a2dp->seq_num);
-       header->timestamp = htonl(a2dp->nsamples);
-       header->ssrc = htonl(1);
-
-       err = send(data->stream.fd, a2dp->buffer, a2dp->count, MSG_DONTWAIT);
-       if (err < 0) {
-               err = -errno;
-               DBG("send failed: %s (%d)", strerror(-err), -err);
-       }
-
-       /* Reset buffer of data to send */
-       a2dp->count = sizeof(struct rtp_header) + sizeof(struct rtp_payload);
-       a2dp->frame_count = 0;
-       a2dp->samples = 0;
-       a2dp->seq_num++;
-
-       return err;
-}
-
-static snd_pcm_sframes_t bluetooth_a2dp_write(snd_pcm_ioplug_t *io,
-                               const snd_pcm_channel_area_t *areas,
-                               snd_pcm_uframes_t offset, snd_pcm_uframes_t size)
-{
-       struct bluetooth_data *data = io->private_data;
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-       snd_pcm_sframes_t ret = 0;
-       unsigned int bytes_left;
-       int frame_size, encoded;
-       ssize_t written;
-       uint8_t *buff;
-
-       DBG("areas->step=%u areas->first=%u offset=%lu size=%lu",
-                               areas->step, areas->first, offset, size);
-       DBG("hw_ptr=%lu appl_ptr=%lu diff=%lu", io->hw_ptr, io->appl_ptr,
-                       io->appl_ptr - io->hw_ptr);
-
-       /* Calutate starting pointers */
-       frame_size = areas->step / 8;
-       bytes_left = size * frame_size;
-       buff = (uint8_t *) areas->addr +
-                               (areas->first + areas->step * (offset)) / 8;
-
-       /* Check for underrun */
-       if (io->hw_ptr > io->appl_ptr) {
-               ret = bluetooth_playback_stop(io);
-               if (ret == 0)
-                       ret = -EPIPE;
-               data->reset = 1;
-               return ret;
-       }
-
-       /* Check if we should autostart */
-       if (io->state == SND_PCM_STATE_PREPARED) {
-               snd_pcm_sw_params_t *swparams;
-               snd_pcm_uframes_t threshold;
-
-               snd_pcm_sw_params_malloc(&swparams);
-               if (!snd_pcm_sw_params_current(io->pcm, swparams) &&
-                               !snd_pcm_sw_params_get_start_threshold(swparams,
-                                                               &threshold)) {
-                       if (io->appl_ptr >= threshold) {
-                               ret = snd_pcm_start(io->pcm);
-                               if (ret != 0)
-                                       return ret;
-                       }
-               }
-
-               snd_pcm_sw_params_free(swparams);
-       }
-
-       /* Check if we have any left over data from the last write */
-       if (data->count > 0) {
-               unsigned int additional_bytes_needed =
-                                               a2dp->codesize - data->count;
-               if (additional_bytes_needed > bytes_left)
-                       goto out;
-
-               memcpy(data->buffer + data->count, buff,
-                                               additional_bytes_needed);
-
-               /* Enough data to encode (sbc wants 1k blocks) */
-               encoded = sbc_encode(&a2dp->sbc, data->buffer, a2dp->codesize,
-                                       a2dp->buffer + a2dp->count,
-                                       sizeof(a2dp->buffer) - a2dp->count,
-                                                               &written);
-               if (encoded <= 0) {
-                       DBG("Encoding error %d", encoded);
-                       goto done;
-               }
-
-               /* Increment a2dp buffers */
-               a2dp->count += written;
-               a2dp->frame_count++;
-               a2dp->samples += encoded / frame_size;
-               a2dp->nsamples += encoded / frame_size;
-
-               /* No space left for another frame then send */
-               if (a2dp->count + written >= data->link_mtu) {
-                       avdtp_write(data);
-                       DBG("sending packet %d, count %d, link_mtu %u",
-                                       a2dp->seq_num, a2dp->count,
-                                                       data->link_mtu);
-               }
-
-               /* Increment up buff pointer to take into account
-                * the data processed */
-               buff += additional_bytes_needed;
-               bytes_left -= additional_bytes_needed;
-
-               /* Since data has been process mark it as zero */
-               data->count = 0;
-       }
-
-
-       /* Process this buffer in full chunks */
-       while (bytes_left >= a2dp->codesize) {
-               /* Enough data to encode (sbc wants 1k blocks) */
-               encoded = sbc_encode(&a2dp->sbc, buff, a2dp->codesize,
-                                       a2dp->buffer + a2dp->count,
-                                       sizeof(a2dp->buffer) - a2dp->count,
-                                                               &written);
-               if (encoded <= 0) {
-                       DBG("Encoding error %d", encoded);
-                       goto done;
-               }
-
-               /* Increment up buff pointer to take into account
-                * the data processed */
-               buff += a2dp->codesize;
-               bytes_left -= a2dp->codesize;
-
-               /* Increment a2dp buffers */
-               a2dp->count += written;
-               a2dp->frame_count++;
-               a2dp->samples += encoded / frame_size;
-               a2dp->nsamples += encoded / frame_size;
-
-               /* No space left for another frame then send */
-               if (a2dp->count + written >= data->link_mtu) {
-                       avdtp_write(data);
-                       DBG("sending packet %d, count %d, link_mtu %u",
-                                               a2dp->seq_num, a2dp->count,
-                                                       data->link_mtu);
-               }
-       }
-
-out:
-       /* Copy the extra to our temp buffer for the next write */
-       if (bytes_left > 0) {
-               memcpy(data->buffer + data->count, buff, bytes_left);
-               data->count += bytes_left;
-               bytes_left = 0;
-       }
-
-done:
-       DBG("returning %ld", size - bytes_left / frame_size);
-
-       return size - bytes_left / frame_size;
-}
-
-static int bluetooth_playback_delay(snd_pcm_ioplug_t *io,
-                                       snd_pcm_sframes_t *delayp)
-{
-       DBG("");
-
-       /* This updates io->hw_ptr value using pointer() function */
-       snd_pcm_hwsync(io->pcm);
-
-       *delayp = io->appl_ptr - io->hw_ptr;
-       if ((io->state == SND_PCM_STATE_RUNNING) && (*delayp < 0)) {
-               io->callback->stop(io);
-               io->state = SND_PCM_STATE_XRUN;
-               *delayp = 0;
-       }
-
-       /* This should never fail, ALSA API is really not
-       prepared to handle a non zero return value */
-       return 0;
-}
-
-static snd_pcm_ioplug_callback_t bluetooth_hsp_playback = {
-       .start                  = bluetooth_playback_start,
-       .stop                   = bluetooth_playback_stop,
-       .pointer                = bluetooth_pointer,
-       .close                  = bluetooth_close,
-       .hw_params              = bluetooth_hsp_hw_params,
-       .prepare                = bluetooth_prepare,
-       .transfer               = bluetooth_hsp_write,
-       .poll_descriptors_count = bluetooth_playback_poll_descriptors_count,
-       .poll_descriptors       = bluetooth_playback_poll_descriptors,
-       .poll_revents           = bluetooth_playback_poll_revents,
-       .delay                  = bluetooth_playback_delay,
-};
-
-static snd_pcm_ioplug_callback_t bluetooth_hsp_capture = {
-       .start                  = bluetooth_start,
-       .stop                   = bluetooth_stop,
-       .pointer                = bluetooth_pointer,
-       .close                  = bluetooth_close,
-       .hw_params              = bluetooth_hsp_hw_params,
-       .prepare                = bluetooth_prepare,
-       .transfer               = bluetooth_hsp_read,
-       .poll_descriptors       = bluetooth_poll_descriptors,
-       .poll_revents           = bluetooth_poll_revents,
-};
-
-static snd_pcm_ioplug_callback_t bluetooth_a2dp_playback = {
-       .start                  = bluetooth_playback_start,
-       .stop                   = bluetooth_playback_stop,
-       .pointer                = bluetooth_pointer,
-       .close                  = bluetooth_close,
-       .hw_params              = bluetooth_a2dp_hw_params,
-       .prepare                = bluetooth_prepare,
-       .transfer               = bluetooth_a2dp_write,
-       .poll_descriptors_count = bluetooth_playback_poll_descriptors_count,
-       .poll_descriptors       = bluetooth_playback_poll_descriptors,
-       .poll_revents           = bluetooth_playback_poll_revents,
-       .delay                  = bluetooth_playback_delay,
-};
-
-static snd_pcm_ioplug_callback_t bluetooth_a2dp_capture = {
-       .start                  = bluetooth_start,
-       .stop                   = bluetooth_stop,
-       .pointer                = bluetooth_pointer,
-       .close                  = bluetooth_close,
-       .hw_params              = bluetooth_a2dp_hw_params,
-       .prepare                = bluetooth_prepare,
-       .transfer               = bluetooth_a2dp_read,
-       .poll_descriptors       = bluetooth_poll_descriptors,
-       .poll_revents           = bluetooth_poll_revents,
-};
-
-#define ARRAY_NELEMS(a) (sizeof((a)) / sizeof((a)[0]))
-
-static int bluetooth_hsp_hw_constraint(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-       snd_pcm_access_t access_list[] = {
-               SND_PCM_ACCESS_RW_INTERLEAVED,
-               /* Mmap access is really useless fo this driver, but we
-                * support it because some pieces of software out there
-                * insist on using it */
-               SND_PCM_ACCESS_MMAP_INTERLEAVED
-       };
-       unsigned int format_list[] = {
-               SND_PCM_FORMAT_S16
-       };
-       int err;
-
-       /* access type */
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
-                                       ARRAY_NELEMS(access_list), access_list);
-       if (err < 0)
-               return err;
-
-       /* supported formats */
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
-                                       ARRAY_NELEMS(format_list), format_list);
-       if (err < 0)
-               return err;
-
-       /* supported channels */
-       err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
-                                                       1, 1);
-       if (err < 0)
-               return err;
-
-       /* supported rate */
-       err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_RATE,
-                                                       8000, 8000);
-       if (err < 0)
-               return err;
-
-       /* supported block size */
-       err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
-                                               data->link_mtu, data->link_mtu);
-       if (err < 0)
-               return err;
-
-       err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_PERIODS,
-                                                                       2, 200);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int bluetooth_a2dp_hw_constraint(snd_pcm_ioplug_t *io)
-{
-       struct bluetooth_data *data = io->private_data;
-       struct bluetooth_a2dp *a2dp = &data->a2dp;
-       struct bluetooth_alsa_config *cfg = &data->alsa_config;
-       snd_pcm_access_t access_list[] = {
-               SND_PCM_ACCESS_RW_INTERLEAVED,
-               /* Mmap access is really useless fo this driver, but we
-                * support it because some pieces of software out there
-                * insist on using it */
-               SND_PCM_ACCESS_MMAP_INTERLEAVED
-       };
-       unsigned int format_list[] = {
-               SND_PCM_FORMAT_S16
-       };
-       unsigned int rate_list[4];
-       unsigned int rate_count;
-       int err, min_channels, max_channels;
-       unsigned int period_list[] = {
-               2048,
-               4096, /* e.g. 23.2msec/period (stereo 16bit at 44.1kHz) */
-               8192
-       };
-
-       /* access type */
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_ACCESS,
-                                       ARRAY_NELEMS(access_list), access_list);
-       if (err < 0)
-               return err;
-
-       /* supported formats */
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_FORMAT,
-                                       ARRAY_NELEMS(format_list), format_list);
-       if (err < 0)
-               return err;
-
-       /* supported channels */
-       if (cfg->has_channel_mode)
-               a2dp->sbc_capabilities.channel_mode = cfg->channel_mode;
-
-       if (a2dp->sbc_capabilities.channel_mode &
-                       BT_A2DP_CHANNEL_MODE_MONO)
-               min_channels = 1;
-       else
-               min_channels = 2;
-
-       if (a2dp->sbc_capabilities.channel_mode &
-                       (~BT_A2DP_CHANNEL_MODE_MONO))
-               max_channels = 2;
-       else
-               max_channels = 1;
-
-       err = snd_pcm_ioplug_set_param_minmax(io, SND_PCM_IOPLUG_HW_CHANNELS,
-                                                       min_channels, max_channels);
-       if (err < 0)
-               return err;
-
-       /* supported buffer sizes
-        * (can be used as 3*8192, 6*4096, 12*2048, ...) */
-       err = snd_pcm_ioplug_set_param_minmax(io,
-                                               SND_PCM_IOPLUG_HW_BUFFER_BYTES,
-                                               8192*3, 8192*3);
-       if (err < 0)
-               return err;
-
-       /* supported block sizes: */
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_PERIOD_BYTES,
-                               ARRAY_NELEMS(period_list), period_list);
-       if (err < 0)
-               return err;
-
-       /* supported rates */
-       rate_count = 0;
-       if (cfg->has_rate) {
-               rate_list[rate_count] = cfg->rate;
-               rate_count++;
-       } else {
-               if (a2dp->sbc_capabilities.frequency &
-                               BT_SBC_SAMPLING_FREQ_16000) {
-                       rate_list[rate_count] = 16000;
-                       rate_count++;
-               }
-
-               if (a2dp->sbc_capabilities.frequency &
-                               BT_SBC_SAMPLING_FREQ_32000) {
-                       rate_list[rate_count] = 32000;
-                       rate_count++;
-               }
-
-               if (a2dp->sbc_capabilities.frequency &
-                               BT_SBC_SAMPLING_FREQ_44100) {
-                       rate_list[rate_count] = 44100;
-                       rate_count++;
-               }
-
-               if (a2dp->sbc_capabilities.frequency &
-                               BT_SBC_SAMPLING_FREQ_48000) {
-                       rate_list[rate_count] = 48000;
-                       rate_count++;
-               }
-       }
-
-       err = snd_pcm_ioplug_set_param_list(io, SND_PCM_IOPLUG_HW_RATE,
-                                               rate_count, rate_list);
-       if (err < 0)
-               return err;
-
-       return 0;
-}
-
-static int bluetooth_parse_config(snd_config_t *conf,
-                               struct bluetooth_alsa_config *bt_config)
-{
-       snd_config_iterator_t i, next;
-
-       memset(bt_config, 0, sizeof(struct bluetooth_alsa_config));
-
-       /* Set defaults */
-       bt_config->autoconnect = 1;
-
-       snd_config_for_each(i, next, conf) {
-               snd_config_t *n = snd_config_iterator_entry(i);
-               const char *id, *value;
-
-               if (snd_config_get_id(n, &id) < 0)
-                       continue;
-
-               if (strcmp(id, "comment") == 0 || strcmp(id, "type") == 0)
-                       continue;
-
-               if (strcmp(id, "autoconnect") == 0) {
-                       int b;
-
-                       b = snd_config_get_bool(n);
-                       if (b < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->autoconnect = b;
-                       continue;
-               }
-
-               if (strcmp(id, "device") == 0 || strcmp(id, "bdaddr") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->has_device = 1;
-                       strncpy(bt_config->device, value, 18);
-                       continue;
-               }
-
-               if (strcmp(id, "profile") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       if (strcmp(value, "auto") == 0) {
-                               bt_config->transport = BT_CAPABILITIES_TRANSPORT_ANY;
-                               bt_config->has_transport = 1;
-                       } else if (strcmp(value, "voice") == 0 ||
-                                               strcmp(value, "hfp") == 0) {
-                               bt_config->transport = BT_CAPABILITIES_TRANSPORT_SCO;
-                               bt_config->has_transport = 1;
-                       } else if (strcmp(value, "hifi") == 0 ||
-                                               strcmp(value, "a2dp") == 0) {
-                               bt_config->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
-                               bt_config->has_transport = 1;
-                       }
-                       continue;
-               }
-
-               if (strcmp(id, "rate") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->rate = atoi(value);
-                       bt_config->has_rate = 1;
-                       continue;
-               }
-
-               if (strcmp(id, "mode") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       if (strcmp(value, "mono") == 0) {
-                               bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
-                               bt_config->has_channel_mode = 1;
-                       } else if (strcmp(value, "dual") == 0) {
-                               bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
-                               bt_config->has_channel_mode = 1;
-                       } else if (strcmp(value, "stereo") == 0) {
-                               bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
-                               bt_config->has_channel_mode = 1;
-                       } else if (strcmp(value, "joint") == 0) {
-                               bt_config->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
-                               bt_config->has_channel_mode = 1;
-                       }
-                       continue;
-               }
-
-               if (strcmp(id, "allocation") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       if (strcmp(value, "loudness") == 0) {
-                               bt_config->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
-                               bt_config->has_allocation_method = 1;
-                       } else if (strcmp(value, "snr") == 0) {
-                               bt_config->allocation_method = BT_A2DP_ALLOCATION_SNR;
-                               bt_config->has_allocation_method = 1;
-                       }
-                       continue;
-               }
-
-               if (strcmp(id, "subbands") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->subbands = atoi(value);
-                       bt_config->has_subbands = 1;
-                       continue;
-               }
-
-               if (strcmp(id, "blocks") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->block_length = atoi(value);
-                       bt_config->has_block_length = 1;
-                       continue;
-               }
-
-               if (strcmp(id, "bitpool") == 0) {
-                       if (snd_config_get_string(n, &value) < 0) {
-                               SNDERR("Invalid type for %s", id);
-                               return -EINVAL;
-                       }
-
-                       bt_config->bitpool = atoi(value);
-                       bt_config->has_bitpool = 1;
-                       continue;
-               }
-
-               SNDERR("Unknown field %s", id);
-               return -EINVAL;
-       }
-
-       return 0;
-}
-
-static int audioservice_send(int sk, const bt_audio_msg_header_t *msg)
-{
-       int err;
-       uint16_t length;
-
-       length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
-
-       DBG("sending %s:%s", bt_audio_strtype(msg->type),
-               bt_audio_strname(msg->name));
-       if (send(sk, msg, length, 0) > 0)
-               err = 0;
-       else {
-               err = -errno;
-               SNDERR("Error sending data to audio service: %s(%d)",
-                       strerror(-err), -err);
-       }
-
-       return err;
-}
-
-static int audioservice_recv(int sk, bt_audio_msg_header_t *inmsg)
-{
-       int err;
-       ssize_t ret;
-       const char *type, *name;
-       uint16_t length;
-
-       length = inmsg->length ? inmsg->length : BT_SUGGESTED_BUFFER_SIZE;
-
-       DBG("trying to receive msg from audio service...");
-
-       ret = recv(sk, inmsg, length, 0);
-       if (ret < 0) {
-               err = -errno;
-               SNDERR("Error receiving IPC data from bluetoothd: %s (%d)",
-                                               strerror(-err), -err);
-       } else if ((size_t) ret < sizeof(bt_audio_msg_header_t)) {
-               SNDERR("Too short (%d bytes) IPC packet from bluetoothd", ret);
-               err = -EINVAL;
-       } else {
-               type = bt_audio_strtype(inmsg->type);
-               name = bt_audio_strname(inmsg->name);
-               if (type && name) {
-                       DBG("Received %s - %s", type, name);
-                       err = 0;
-               } else {
-                       err = -EINVAL;
-                       SNDERR("Bogus message type %d - name %d"
-                                       " received from audio service",
-                                       inmsg->type, inmsg->name);
-               }
-
-       }
-
-       return err;
-}
-
-static int audioservice_expect(int sk, bt_audio_msg_header_t *rsp,
-                                                       int expected_name)
-{
-       bt_audio_error_t *error;
-       int err = audioservice_recv(sk, rsp);
-
-       if (err != 0)
-               return err;
-
-       if (rsp->name != expected_name) {
-               err = -EINVAL;
-               SNDERR("Bogus message %s received while %s was expected",
-                               bt_audio_strname(rsp->name),
-                               bt_audio_strname(expected_name));
-       }
-
-       if (rsp->type == BT_ERROR) {
-               error = (void *) rsp;
-               SNDERR("%s failed : %s(%d)",
-                                       bt_audio_strname(rsp->name),
-                                       strerror(error->posix_errno),
-                                       error->posix_errno);
-               return -error->posix_errno;
-       }
-
-       return err;
-}
-
-static int bluetooth_parse_capabilities(struct bluetooth_data *data,
-                                       struct bt_get_capabilities_rsp *rsp)
-{
-       int bytes_left = rsp->h.length - sizeof(*rsp);
-       codec_capabilities_t *codec = (void *) rsp->data;
-
-       data->transport = codec->transport;
-
-       if (codec->transport != BT_CAPABILITIES_TRANSPORT_A2DP)
-               return 0;
-
-       while (bytes_left > 0) {
-               if ((codec->type == BT_A2DP_SBC_SINK) &&
-                               !(codec->lock & BT_WRITE_LOCK))
-                       break;
-
-               bytes_left -= codec->length;
-               codec = (void *) codec + codec->length;
-       }
-
-       if (bytes_left <= 0 ||
-                       codec->length != sizeof(data->a2dp.sbc_capabilities))
-               return -EINVAL;
-
-       memcpy(&data->a2dp.sbc_capabilities, codec, codec->length);
-
-       return 0;
-}
-
-static int bluetooth_init(struct bluetooth_data *data,
-                               snd_pcm_stream_t stream, snd_config_t *conf)
-{
-       int sk, err;
-       struct bluetooth_alsa_config *alsa_conf = &data->alsa_config;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_get_capabilities_req *req = (void *) buf;
-       struct bt_get_capabilities_rsp *rsp = (void *) buf;
-
-       memset(data, 0, sizeof(struct bluetooth_data));
-
-       err = bluetooth_parse_config(conf, alsa_conf);
-       if (err < 0)
-               return err;
-
-       data->server.fd = -1;
-       data->stream.fd = -1;
-
-       sk = bt_audio_service_open();
-       if (sk < 0) {
-               err = -errno;
-               goto failed;
-       }
-
-       data->server.fd = sk;
-       data->server.events = POLLIN;
-
-       data->pipefd[0] = -1;
-       data->pipefd[1] = -1;
-
-       if (pipe(data->pipefd) < 0) {
-               err = -errno;
-               goto failed;
-       }
-       if (fcntl(data->pipefd[0], F_SETFL, O_NONBLOCK) < 0) {
-               err = -errno;
-               goto failed;
-       }
-       if (fcntl(data->pipefd[1], F_SETFL, O_NONBLOCK) < 0) {
-               err = -errno;
-               goto failed;
-       }
-
-       memset(req, 0, BT_SUGGESTED_BUFFER_SIZE);
-       req->h.type = BT_REQUEST;
-       req->h.name = BT_GET_CAPABILITIES;
-       req->h.length = sizeof(*req);
-
-       if (alsa_conf->autoconnect)
-               req->flags |= BT_FLAG_AUTOCONNECT;
-       strncpy(req->destination, alsa_conf->device, 18);
-       if (alsa_conf->has_transport)
-               req->transport = alsa_conf->transport;
-       else
-               req->transport = BT_CAPABILITIES_TRANSPORT_ANY;
-
-       err = audioservice_send(data->server.fd, &req->h);
-       if (err < 0)
-               goto failed;
-
-       rsp->h.length = 0;
-       err = audioservice_expect(data->server.fd, &rsp->h,
-                                       BT_GET_CAPABILITIES);
-       if (err < 0)
-               goto failed;
-
-       bluetooth_parse_capabilities(data, rsp);
-
-       return 0;
-
-failed:
-       if (sk >= 0)
-               bt_audio_service_close(sk);
-       return err;
-}
-
-SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth);
-
-SND_PCM_PLUGIN_DEFINE_FUNC(bluetooth)
-{
-       struct bluetooth_data *data;
-       int err;
-
-       DBG("Bluetooth PCM plugin (%s)",
-               stream == SND_PCM_STREAM_PLAYBACK ? "Playback" : "Capture");
-
-       data = malloc(sizeof(struct bluetooth_data));
-       if (!data) {
-               err = -ENOMEM;
-               goto error;
-       }
-
-       err = bluetooth_init(data, stream, conf);
-       if (err < 0)
-               goto error;
-
-       data->io.version = SND_PCM_IOPLUG_VERSION;
-       data->io.name = "Bluetooth Audio Device";
-       data->io.mmap_rw = 0; /* No direct mmap communication */
-       data->io.private_data = data;
-
-       if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
-               data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
-                       &bluetooth_a2dp_playback :
-                       &bluetooth_a2dp_capture;
-       else
-               data->io.callback = stream == SND_PCM_STREAM_PLAYBACK ?
-                       &bluetooth_hsp_playback :
-                       &bluetooth_hsp_capture;
-
-       err = snd_pcm_ioplug_create(&data->io, name, stream, mode);
-       if (err < 0)
-               goto error;
-
-       if (data->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
-               err = bluetooth_a2dp_hw_constraint(&data->io);
-       else
-               err = bluetooth_hsp_hw_constraint(&data->io);
-
-       if (err < 0) {
-               snd_pcm_ioplug_delete(&data->io);
-               goto error;
-       }
-
-       *pcmp = data->io.pcm;
-
-       return 0;
-
-error:
-       if (data)
-               bluetooth_exit(data);
-
-       return err;
-}
-
-SND_PCM_PLUGIN_SYMBOL(bluetooth);
diff --git a/audio/rtp.h b/audio/rtp.h
deleted file mode 100644 (file)
index 45fddcf..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct rtp_header {
-       unsigned cc:4;
-       unsigned x:1;
-       unsigned p:1;
-       unsigned v:2;
-
-       unsigned pt:7;
-       unsigned m:1;
-
-       uint16_t sequence_number;
-       uint32_t timestamp;
-       uint32_t ssrc;
-       uint32_t csrc[0];
-} __attribute__ ((packed));
-
-struct rtp_payload {
-       unsigned frame_count:4;
-       unsigned rfa0:1;
-       unsigned is_last_fragment:1;
-       unsigned is_first_fragment:1;
-       unsigned is_fragmented:1;
-} __attribute__ ((packed));
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct rtp_header {
-       unsigned v:2;
-       unsigned p:1;
-       unsigned x:1;
-       unsigned cc:4;
-
-       unsigned m:1;
-       unsigned pt:7;
-
-       uint16_t sequence_number;
-       uint32_t timestamp;
-       uint32_t ssrc;
-       uint32_t csrc[0];
-} __attribute__ ((packed));
-
-struct rtp_payload {
-       unsigned is_fragmented:1;
-       unsigned is_first_fragment:1;
-       unsigned is_last_fragment:1;
-       unsigned rfa0:1;
-       unsigned frame_count:4;
-} __attribute__ ((packed));
-
-#else
-#error "Unknown byte order"
-#endif
diff --git a/audio/sink.c b/audio/sink.c
deleted file mode 100644 (file)
index 6b21e47..0000000
+++ /dev/null
@@ -1,745 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-
-#include "device.h"
-#include "avdtp.h"
-#include "media.h"
-#include "a2dp.h"
-#include "error.h"
-#include "sink.h"
-#include "dbus-common.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#define STREAM_SETUP_RETRY_TIMER 2
-
-struct pending_request {
-       DBusConnection *conn;
-       DBusMessage *msg;
-       unsigned int id;
-};
-
-struct sink {
-       struct audio_device *dev;
-       struct avdtp *session;
-       struct avdtp_stream *stream;
-       unsigned int cb_id;
-       guint retry_id;
-       avdtp_session_state_t session_state;
-       avdtp_state_t stream_state;
-       sink_state_t state;
-       struct pending_request *connect;
-       struct pending_request *disconnect;
-       DBusConnection *conn;
-};
-
-struct sink_state_callback {
-       sink_state_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-static GSList *sink_callbacks = NULL;
-
-static unsigned int avdtp_callback_id = 0;
-
-static char *str_state[] = {
-       "SINK_STATE_DISCONNECTED",
-       "SINK_STATE_CONNECTING",
-       "SINK_STATE_CONNECTED",
-       "SINK_STATE_PLAYING",
-};
-
-static const char *state2str(sink_state_t state)
-{
-       switch (state) {
-       case SINK_STATE_DISCONNECTED:
-               return "disconnected";
-       case SINK_STATE_CONNECTING:
-               return "connecting";
-       case SINK_STATE_CONNECTED:
-               return "connected";
-       case SINK_STATE_PLAYING:
-               return "playing";
-       default:
-               error("Invalid sink state %d", state);
-               return NULL;
-       }
-}
-
-static void sink_set_state(struct audio_device *dev, sink_state_t new_state)
-{
-       struct sink *sink = dev->sink;
-       const char *state_str;
-       sink_state_t old_state = sink->state;
-       GSList *l;
-
-       sink->state = new_state;
-
-       state_str = state2str(new_state);
-       if (state_str)
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_SINK_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-
-       DBG("State changed %s: %s -> %s", dev->path, str_state[old_state],
-               str_state[new_state]);
-
-       for (l = sink_callbacks; l != NULL; l = l->next) {
-               struct sink_state_callback *cb = l->data;
-               cb->cb(dev, old_state, new_state, cb->user_data);
-       }
-}
-
-static void avdtp_state_callback(struct audio_device *dev,
-                                       struct avdtp *session,
-                                       avdtp_session_state_t old_state,
-                                       avdtp_session_state_t new_state,
-                                       void *user_data)
-{
-       struct sink *sink = dev->sink;
-
-       if (sink == NULL)
-               return;
-
-       switch (new_state) {
-       case AVDTP_SESSION_STATE_DISCONNECTED:
-               if (sink->state != SINK_STATE_CONNECTING) {
-                       gboolean value = FALSE;
-                       g_dbus_emit_signal(dev->conn, dev->path,
-                                       AUDIO_SINK_INTERFACE, "Disconnected",
-                                       DBUS_TYPE_INVALID);
-                       emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_SINK_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &value);
-               }
-               sink_set_state(dev, SINK_STATE_DISCONNECTED);
-               break;
-       case AVDTP_SESSION_STATE_CONNECTING:
-               sink_set_state(dev, SINK_STATE_CONNECTING);
-               break;
-       case AVDTP_SESSION_STATE_CONNECTED:
-               break;
-       }
-
-       sink->session_state = new_state;
-}
-
-static void pending_request_free(struct audio_device *dev,
-                                       struct pending_request *pending)
-{
-       if (pending->conn)
-               dbus_connection_unref(pending->conn);
-       if (pending->msg)
-               dbus_message_unref(pending->msg);
-       if (pending->id)
-               a2dp_cancel(dev, pending->id);
-
-       g_free(pending);
-}
-
-static void stream_state_changed(struct avdtp_stream *stream,
-                                       avdtp_state_t old_state,
-                                       avdtp_state_t new_state,
-                                       struct avdtp_error *err,
-                                       void *user_data)
-{
-       struct audio_device *dev = user_data;
-       struct sink *sink = dev->sink;
-       gboolean value;
-
-       if (err)
-               return;
-
-       switch (new_state) {
-       case AVDTP_STATE_IDLE:
-               if (sink->disconnect) {
-                       DBusMessage *reply;
-                       struct pending_request *p;
-
-                       p = sink->disconnect;
-                       sink->disconnect = NULL;
-
-                       reply = dbus_message_new_method_return(p->msg);
-                       g_dbus_send_message(p->conn, reply);
-                       pending_request_free(dev, p);
-               }
-
-               if (sink->session) {
-                       avdtp_unref(sink->session);
-                       sink->session = NULL;
-               }
-               sink->stream = NULL;
-               sink->cb_id = 0;
-               break;
-       case AVDTP_STATE_OPEN:
-               if (old_state == AVDTP_STATE_CONFIGURED &&
-                               sink->state == SINK_STATE_CONNECTING) {
-                       value = TRUE;
-                       g_dbus_emit_signal(dev->conn, dev->path,
-                                               AUDIO_SINK_INTERFACE,
-                                               "Connected",
-                                               DBUS_TYPE_INVALID);
-                       emit_property_changed(dev->conn, dev->path,
-                                               AUDIO_SINK_INTERFACE,
-                                               "Connected",
-                                               DBUS_TYPE_BOOLEAN, &value);
-               } else if (old_state == AVDTP_STATE_STREAMING) {
-                       value = FALSE;
-                       g_dbus_emit_signal(dev->conn, dev->path,
-                                               AUDIO_SINK_INTERFACE,
-                                               "Stopped",
-                                               DBUS_TYPE_INVALID);
-                       emit_property_changed(dev->conn, dev->path,
-                                               AUDIO_SINK_INTERFACE,
-                                               "Playing",
-                                               DBUS_TYPE_BOOLEAN, &value);
-               }
-               sink_set_state(dev, SINK_STATE_CONNECTED);
-               break;
-       case AVDTP_STATE_STREAMING:
-               value = TRUE;
-               g_dbus_emit_signal(dev->conn, dev->path, AUDIO_SINK_INTERFACE,
-                                       "Playing", DBUS_TYPE_INVALID);
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_SINK_INTERFACE, "Playing",
-                                       DBUS_TYPE_BOOLEAN, &value);
-               sink_set_state(dev, SINK_STATE_PLAYING);
-               break;
-       case AVDTP_STATE_CONFIGURED:
-       case AVDTP_STATE_CLOSING:
-       case AVDTP_STATE_ABORTING:
-       default:
-               break;
-       }
-
-       sink->stream_state = new_state;
-}
-
-static void error_failed(DBusConnection *conn, DBusMessage *msg,
-                                                       const char *desc)
-{
-       DBusMessage *reply = btd_error_failed(msg, desc);
-       g_dbus_send_message(conn, reply);
-}
-
-static gboolean stream_setup_retry(gpointer user_data)
-{
-       struct sink *sink = user_data;
-       struct pending_request *pending = sink->connect;
-
-       sink->retry_id = 0;
-
-       if (sink->stream_state >= AVDTP_STATE_OPEN) {
-               DBG("Stream successfully created, after XCASE connect:connect");
-               if (pending->msg) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(pending->msg);
-                       g_dbus_send_message(pending->conn, reply);
-               }
-       } else {
-               DBG("Stream setup failed, after XCASE connect:connect");
-               if (pending->msg)
-                       error_failed(pending->conn, pending->msg, "Stream setup failed");
-       }
-
-       sink->connect = NULL;
-       pending_request_free(sink->dev, pending);
-
-       return FALSE;
-}
-
-static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
-                                       struct avdtp_stream *stream,
-                                       struct avdtp_error *err, void *user_data)
-{
-       struct sink *sink = user_data;
-       struct pending_request *pending;
-
-       pending = sink->connect;
-
-       pending->id = 0;
-
-       if (stream) {
-               DBG("Stream successfully created");
-
-               if (pending->msg) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(pending->msg);
-                       g_dbus_send_message(pending->conn, reply);
-               }
-
-               sink->connect = NULL;
-               pending_request_free(sink->dev, pending);
-
-               return;
-       }
-
-       avdtp_unref(sink->session);
-       sink->session = NULL;
-       if (avdtp_error_category(err) == AVDTP_ERRNO
-                       && avdtp_error_posix_errno(err) != EHOSTDOWN) {
-               DBG("connect:connect XCASE detected");
-               sink->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
-                                                       stream_setup_retry,
-                                                       sink);
-       } else {
-               if (pending->msg)
-                       error_failed(pending->conn, pending->msg, "Stream setup failed");
-               sink->connect = NULL;
-               pending_request_free(sink->dev, pending);
-               DBG("Stream setup failed : %s", avdtp_strerror(err));
-       }
-}
-
-static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
-                       GSList *caps, void *user_data)
-{
-       struct sink *sink = user_data;
-       struct pending_request *pending;
-       int id;
-
-       pending = sink->connect;
-       pending->id = 0;
-
-       id = a2dp_config(session, sep, stream_setup_complete, caps, sink);
-       if (id == 0)
-               goto failed;
-
-       pending->id = id;
-       return;
-
-failed:
-       if (pending->msg)
-               error_failed(pending->conn, pending->msg, "Stream setup failed");
-       pending_request_free(sink->dev, pending);
-       sink->connect = NULL;
-       avdtp_unref(sink->session);
-       sink->session = NULL;
-}
-
-static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
-                               void *user_data)
-{
-       struct sink *sink = user_data;
-       struct pending_request *pending;
-       int id;
-
-       if (!sink->connect) {
-               avdtp_unref(sink->session);
-               sink->session = NULL;
-               return;
-       }
-
-       pending = sink->connect;
-
-       if (err) {
-               avdtp_unref(sink->session);
-               sink->session = NULL;
-               if (avdtp_error_category(err) == AVDTP_ERRNO
-                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
-                       DBG("connect:connect XCASE detected");
-                       sink->retry_id =
-                               g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
-                                                       stream_setup_retry,
-                                                       sink);
-               } else
-                       goto failed;
-               return;
-       }
-
-       DBG("Discovery complete");
-
-       id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
-                                               select_complete, sink);
-       if (id == 0)
-               goto failed;
-
-       pending->id = id;
-       return;
-
-failed:
-       if (pending->msg)
-               error_failed(pending->conn, pending->msg, "Stream setup failed");
-       pending_request_free(sink->dev, pending);
-       sink->connect = NULL;
-       avdtp_unref(sink->session);
-       sink->session = NULL;
-}
-
-gboolean sink_setup_stream(struct sink *sink, struct avdtp *session)
-{
-       if (sink->connect || sink->disconnect)
-               return FALSE;
-
-       if (session && !sink->session)
-               sink->session = avdtp_ref(session);
-
-       if (!sink->session)
-               return FALSE;
-
-       avdtp_set_auto_disconnect(sink->session, FALSE);
-
-       if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
-               return FALSE;
-
-       sink->connect = g_new0(struct pending_request, 1);
-
-       return TRUE;
-}
-
-static DBusMessage *sink_connect(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct audio_device *dev = data;
-       struct sink *sink = dev->sink;
-       struct pending_request *pending;
-
-       if (!sink->session)
-               sink->session = avdtp_get(&dev->src, &dev->dst);
-
-       if (!sink->session)
-               return btd_error_failed(msg, "Unable to get a session");
-
-       if (sink->connect || sink->disconnect)
-               return btd_error_busy(msg);
-
-       if (sink->stream_state >= AVDTP_STATE_OPEN)
-               return btd_error_already_connected(msg);
-
-       if (!sink_setup_stream(sink, NULL))
-               return btd_error_failed(msg, "Failed to create a stream");
-
-       dev->auto_connect = FALSE;
-
-       pending = sink->connect;
-
-       pending->conn = dbus_connection_ref(conn);
-       pending->msg = dbus_message_ref(msg);
-
-       DBG("stream creation in progress");
-
-       return NULL;
-}
-
-static DBusMessage *sink_disconnect(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct sink *sink = device->sink;
-       struct pending_request *pending;
-       int err;
-
-       if (!sink->session)
-               return btd_error_not_connected(msg);
-
-       if (sink->connect || sink->disconnect)
-               return btd_error_busy(msg);
-
-       if (sink->stream_state < AVDTP_STATE_OPEN) {
-               DBusMessage *reply = dbus_message_new_method_return(msg);
-               if (!reply)
-                       return NULL;
-               avdtp_unref(sink->session);
-               sink->session = NULL;
-               return reply;
-       }
-
-       err = avdtp_close(sink->session, sink->stream, FALSE);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       pending = g_new0(struct pending_request, 1);
-       pending->conn = dbus_connection_ref(conn);
-       pending->msg = dbus_message_ref(msg);
-       sink->disconnect = pending;
-
-       return NULL;
-}
-
-static DBusMessage *sink_is_connected(DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       void *data)
-{
-       struct audio_device *device = data;
-       struct sink *sink = device->sink;
-       DBusMessage *reply;
-       dbus_bool_t connected;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       connected = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
-
-       dbus_message_append_args(reply, DBUS_TYPE_BOOLEAN, &connected,
-                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *sink_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct sink *sink = device->sink;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       const char *state;
-       gboolean value;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       /* Playing */
-       value = (sink->stream_state == AVDTP_STATE_STREAMING);
-       dict_append_entry(&dict, "Playing", DBUS_TYPE_BOOLEAN, &value);
-
-       /* Connected */
-       value = (sink->stream_state >= AVDTP_STATE_CONFIGURED);
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &value);
-
-       /* State */
-       state = state2str(sink->state);
-       if (state)
-               dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 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)
-{
-       struct sink *sink = dev->sink;
-
-       if (sink->cb_id)
-               avdtp_stream_remove_cb(sink->session, sink->stream,
-                                       sink->cb_id);
-
-       if (sink->session)
-               avdtp_unref(sink->session);
-
-       if (sink->connect)
-               pending_request_free(dev, sink->connect);
-
-       if (sink->disconnect)
-               pending_request_free(dev, sink->disconnect);
-
-       if (sink->retry_id)
-               g_source_remove(sink->retry_id);
-
-       g_free(sink);
-       dev->sink = NULL;
-}
-
-static void path_unregister(void *data)
-{
-       struct audio_device *dev = data;
-
-       DBG("Unregistered interface %s on path %s",
-               AUDIO_SINK_INTERFACE, dev->path);
-
-       sink_free(dev);
-}
-
-void sink_unregister(struct audio_device *dev)
-{
-       g_dbus_unregister_interface(dev->conn, dev->path,
-               AUDIO_SINK_INTERFACE);
-}
-
-struct sink *sink_init(struct audio_device *dev)
-{
-       struct sink *sink;
-
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_SINK_INTERFACE,
-                                       sink_methods, sink_signals, NULL,
-                                       dev, path_unregister))
-               return NULL;
-
-       DBG("Registered interface %s on path %s",
-               AUDIO_SINK_INTERFACE, dev->path);
-
-       if (avdtp_callback_id == 0)
-               avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
-                                                                       NULL);
-
-       sink = g_new0(struct sink, 1);
-
-       sink->dev = dev;
-
-       return sink;
-}
-
-gboolean sink_is_active(struct audio_device *dev)
-{
-       struct sink *sink = dev->sink;
-
-       if (sink->session)
-               return TRUE;
-
-       return FALSE;
-}
-
-sink_state_t sink_get_state(struct audio_device *dev)
-{
-       struct sink *sink = dev->sink;
-
-       return sink->state;
-}
-
-gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
-                               struct avdtp_stream *stream)
-{
-       struct sink *sink = dev->sink;
-
-       if (sink->stream)
-               return FALSE;
-
-       if (!sink->session)
-               sink->session = avdtp_ref(session);
-
-       sink->stream = stream;
-
-       sink->cb_id = avdtp_stream_add_cb(session, stream,
-                                               stream_state_changed, dev);
-
-       return TRUE;
-}
-
-gboolean sink_shutdown(struct sink *sink)
-{
-       if (!sink->session)
-               return FALSE;
-
-       avdtp_set_device_disconnect(sink->session, TRUE);
-
-       /* cancel pending connect */
-       if (sink->connect) {
-               struct pending_request *pending = sink->connect;
-
-               if (pending->msg)
-                       error_failed(pending->conn, pending->msg,
-                                                       "Stream setup failed");
-               pending_request_free(sink->dev, pending);
-               sink->connect = NULL;
-
-               avdtp_unref(sink->session);
-               sink->session = NULL;
-
-               return TRUE;
-       }
-
-       /* disconnect already ongoing */
-       if (sink->disconnect)
-               return TRUE;
-
-       if (!sink->stream)
-               return FALSE;
-
-       if (avdtp_close(sink->session, sink->stream, FALSE) < 0)
-               return FALSE;
-
-       return TRUE;
-}
-
-unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data)
-{
-       struct sink_state_callback *state_cb;
-       static unsigned int id = 0;
-
-       state_cb = g_new(struct sink_state_callback, 1);
-       state_cb->cb = cb;
-       state_cb->user_data = user_data;
-       state_cb->id = ++id;
-
-       sink_callbacks = g_slist_append(sink_callbacks, state_cb);
-
-       return state_cb->id;
-}
-
-gboolean sink_remove_state_cb(unsigned int id)
-{
-       GSList *l;
-
-       for (l = sink_callbacks; l != NULL; l = l->next) {
-               struct sink_state_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       sink_callbacks = g_slist_remove(sink_callbacks, cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
diff --git a/audio/source.c b/audio/source.c
deleted file mode 100644 (file)
index dbba5b9..0000000
+++ /dev/null
@@ -1,634 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2009  Joao Paulo Rechi Vita
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-
-#include "device.h"
-#include "avdtp.h"
-#include "media.h"
-#include "a2dp.h"
-#include "error.h"
-#include "source.h"
-#include "dbus-common.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#define STREAM_SETUP_RETRY_TIMER 2
-
-struct pending_request {
-       DBusConnection *conn;
-       DBusMessage *msg;
-       unsigned int id;
-};
-
-struct source {
-       struct audio_device *dev;
-       struct avdtp *session;
-       struct avdtp_stream *stream;
-       unsigned int cb_id;
-       guint retry_id;
-       avdtp_session_state_t session_state;
-       avdtp_state_t stream_state;
-       source_state_t state;
-       struct pending_request *connect;
-       struct pending_request *disconnect;
-       DBusConnection *conn;
-};
-
-struct source_state_callback {
-       source_state_cb cb;
-       void *user_data;
-       unsigned int id;
-};
-
-static GSList *source_callbacks = NULL;
-
-static unsigned int avdtp_callback_id = 0;
-
-static const char *state2str(source_state_t state)
-{
-       switch (state) {
-       case SOURCE_STATE_DISCONNECTED:
-               return "disconnected";
-       case SOURCE_STATE_CONNECTING:
-               return "connecting";
-       case SOURCE_STATE_CONNECTED:
-               return "connected";
-       case SOURCE_STATE_PLAYING:
-               return "playing";
-       default:
-               error("Invalid source state %d", state);
-               return NULL;
-       }
-}
-
-static void source_set_state(struct audio_device *dev, source_state_t new_state)
-{
-       struct source *source = dev->source;
-       const char *state_str;
-       source_state_t old_state = source->state;
-       GSList *l;
-
-       source->state = new_state;
-
-       state_str = state2str(new_state);
-       if (state_str)
-               emit_property_changed(dev->conn, dev->path,
-                                       AUDIO_SOURCE_INTERFACE, "State",
-                                       DBUS_TYPE_STRING, &state_str);
-
-       for (l = source_callbacks; l != NULL; l = l->next) {
-               struct source_state_callback *cb = l->data;
-               cb->cb(dev, old_state, new_state, cb->user_data);
-       }
-}
-
-static void avdtp_state_callback(struct audio_device *dev,
-                                       struct avdtp *session,
-                                       avdtp_session_state_t old_state,
-                                       avdtp_session_state_t new_state,
-                                       void *user_data)
-{
-       struct source *source = dev->source;
-
-       if (source == NULL)
-               return;
-
-       switch (new_state) {
-       case AVDTP_SESSION_STATE_DISCONNECTED:
-               source_set_state(dev, SOURCE_STATE_DISCONNECTED);
-               break;
-       case AVDTP_SESSION_STATE_CONNECTING:
-               source_set_state(dev, SOURCE_STATE_CONNECTING);
-               break;
-       case AVDTP_SESSION_STATE_CONNECTED:
-               break;
-       }
-
-       source->session_state = new_state;
-}
-
-static void pending_request_free(struct audio_device *dev,
-                                       struct pending_request *pending)
-{
-       if (pending->conn)
-               dbus_connection_unref(pending->conn);
-       if (pending->msg)
-               dbus_message_unref(pending->msg);
-       if (pending->id)
-               a2dp_cancel(dev, pending->id);
-
-       g_free(pending);
-}
-
-static void stream_state_changed(struct avdtp_stream *stream,
-                                       avdtp_state_t old_state,
-                                       avdtp_state_t new_state,
-                                       struct avdtp_error *err,
-                                       void *user_data)
-{
-       struct audio_device *dev = user_data;
-       struct source *source = dev->source;
-
-       if (err)
-               return;
-
-       switch (new_state) {
-       case AVDTP_STATE_IDLE:
-               if (source->disconnect) {
-                       DBusMessage *reply;
-                       struct pending_request *p;
-
-                       p = source->disconnect;
-                       source->disconnect = NULL;
-
-                       reply = dbus_message_new_method_return(p->msg);
-                       g_dbus_send_message(p->conn, reply);
-                       pending_request_free(dev, p);
-               }
-
-               if (source->session) {
-                       avdtp_unref(source->session);
-                       source->session = NULL;
-               }
-               source->stream = NULL;
-               source->cb_id = 0;
-               break;
-       case AVDTP_STATE_OPEN:
-               source_set_state(dev, SOURCE_STATE_CONNECTED);
-               break;
-       case AVDTP_STATE_STREAMING:
-               source_set_state(dev, SOURCE_STATE_PLAYING);
-               break;
-       case AVDTP_STATE_CONFIGURED:
-       case AVDTP_STATE_CLOSING:
-       case AVDTP_STATE_ABORTING:
-       default:
-               break;
-       }
-
-       source->stream_state = new_state;
-}
-
-static void error_failed(DBusConnection *conn, DBusMessage *msg,
-                                                       const char *desc)
-{
-       DBusMessage *reply = btd_error_failed(msg, desc);
-       g_dbus_send_message(conn, reply);
-}
-
-static gboolean stream_setup_retry(gpointer user_data)
-{
-       struct source *source = user_data;
-       struct pending_request *pending = source->connect;
-
-       source->retry_id = 0;
-
-       if (source->stream_state >= AVDTP_STATE_OPEN) {
-               DBG("Stream successfully created, after XCASE connect:connect");
-               if (pending->msg) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(pending->msg);
-                       g_dbus_send_message(pending->conn, reply);
-               }
-       } else {
-               DBG("Stream setup failed, after XCASE connect:connect");
-               if (pending->msg)
-                       error_failed(pending->conn, pending->msg, "Stream setup failed");
-       }
-
-       source->connect = NULL;
-       pending_request_free(source->dev, pending);
-
-       return FALSE;
-}
-
-static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
-                                       struct avdtp_stream *stream,
-                                       struct avdtp_error *err, void *user_data)
-{
-       struct source *source = user_data;
-       struct pending_request *pending;
-
-       pending = source->connect;
-
-       pending->id = 0;
-
-       if (stream) {
-               DBG("Stream successfully created");
-
-               if (pending->msg) {
-                       DBusMessage *reply;
-                       reply = dbus_message_new_method_return(pending->msg);
-                       g_dbus_send_message(pending->conn, reply);
-               }
-
-               source->connect = NULL;
-               pending_request_free(source->dev, pending);
-
-               return;
-       }
-
-       avdtp_unref(source->session);
-       source->session = NULL;
-       if (avdtp_error_category(err) == AVDTP_ERRNO
-                       && avdtp_error_posix_errno(err) != EHOSTDOWN) {
-               DBG("connect:connect XCASE detected");
-               source->retry_id = g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
-                                                       stream_setup_retry,
-                                                       source);
-       } else {
-               if (pending->msg)
-                       error_failed(pending->conn, pending->msg, "Stream setup failed");
-               source->connect = NULL;
-               pending_request_free(source->dev, pending);
-               DBG("Stream setup failed : %s", avdtp_strerror(err));
-       }
-}
-
-static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
-                       GSList *caps, void *user_data)
-{
-       struct source *source = user_data;
-       struct pending_request *pending;
-       int id;
-
-       pending = source->connect;
-
-       pending->id = 0;
-
-       if (caps == NULL)
-               goto failed;
-
-       id = a2dp_config(session, sep, stream_setup_complete, caps, source);
-       if (id == 0)
-               goto failed;
-
-       pending->id = id;
-       return;
-
-failed:
-       if (pending->msg)
-               error_failed(pending->conn, pending->msg, "Stream setup failed");
-       pending_request_free(source->dev, pending);
-       source->connect = NULL;
-       avdtp_unref(source->session);
-       source->session = NULL;
-}
-
-static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
-                               void *user_data)
-{
-       struct source *source = user_data;
-       struct pending_request *pending;
-       int id;
-
-       pending = source->connect;
-
-       if (err) {
-               avdtp_unref(source->session);
-               source->session = NULL;
-               if (avdtp_error_category(err) == AVDTP_ERRNO
-                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
-                       DBG("connect:connect XCASE detected");
-                       source->retry_id =
-                               g_timeout_add_seconds(STREAM_SETUP_RETRY_TIMER,
-                                                       stream_setup_retry,
-                                                       source);
-               } else
-                       goto failed;
-               return;
-       }
-
-       DBG("Discovery complete");
-
-       id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
-                                               select_complete, source);
-       if (id == 0)
-               goto failed;
-
-       pending->id = id;
-       return;
-
-failed:
-       if (pending->msg)
-               error_failed(pending->conn, pending->msg, "Stream setup failed");
-       pending_request_free(source->dev, pending);
-       source->connect = NULL;
-       avdtp_unref(source->session);
-       source->session = NULL;
-}
-
-gboolean source_setup_stream(struct source *source, struct avdtp *session)
-{
-       if (source->connect || source->disconnect)
-               return FALSE;
-
-       if (session && !source->session)
-               source->session = avdtp_ref(session);
-
-       if (!source->session)
-               return FALSE;
-
-       avdtp_set_auto_disconnect(source->session, FALSE);
-
-       if (avdtp_discover(source->session, discovery_complete, source) < 0)
-               return FALSE;
-
-       source->connect = g_new0(struct pending_request, 1);
-
-       return TRUE;
-}
-
-static DBusMessage *source_connect(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct audio_device *dev = data;
-       struct source *source = dev->source;
-       struct pending_request *pending;
-
-       if (!source->session)
-               source->session = avdtp_get(&dev->src, &dev->dst);
-
-       if (!source->session)
-               return btd_error_failed(msg, "Unable to get a session");
-
-       if (source->connect || source->disconnect)
-               return btd_error_busy(msg);
-
-       if (source->stream_state >= AVDTP_STATE_OPEN)
-               return btd_error_already_connected(msg);
-
-       if (!source_setup_stream(source, NULL))
-               return btd_error_failed(msg, "Failed to create a stream");
-
-       dev->auto_connect = FALSE;
-
-       pending = source->connect;
-
-       pending->conn = dbus_connection_ref(conn);
-       pending->msg = dbus_message_ref(msg);
-
-       DBG("stream creation in progress");
-
-       return NULL;
-}
-
-static DBusMessage *source_disconnect(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct source *source = device->source;
-       struct pending_request *pending;
-       int err;
-
-       if (!source->session)
-               return btd_error_not_connected(msg);
-
-       if (source->connect || source->disconnect)
-               return btd_error_busy(msg);
-
-       if (source->stream_state < AVDTP_STATE_OPEN) {
-               DBusMessage *reply = dbus_message_new_method_return(msg);
-               if (!reply)
-                       return NULL;
-               avdtp_unref(source->session);
-               source->session = NULL;
-               return reply;
-       }
-
-       err = avdtp_close(source->session, source->stream, FALSE);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       pending = g_new0(struct pending_request, 1);
-       pending->conn = dbus_connection_ref(conn);
-       pending->msg = dbus_message_ref(msg);
-       source->disconnect = pending;
-
-       return NULL;
-}
-
-static DBusMessage *source_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct audio_device *device = data;
-       struct source *source = device->source;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       const char *state;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       /* State */
-       state = state2str(source->state);
-       if (state)
-               dict_append_entry(&dict, "State", DBUS_TYPE_STRING, &state);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 const GDBusSignalTable source_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-       { }
-};
-
-static void source_free(struct audio_device *dev)
-{
-       struct source *source = dev->source;
-
-       if (source->cb_id)
-               avdtp_stream_remove_cb(source->session, source->stream,
-                                       source->cb_id);
-
-       if (source->session)
-               avdtp_unref(source->session);
-
-       if (source->connect)
-               pending_request_free(dev, source->connect);
-
-       if (source->disconnect)
-               pending_request_free(dev, source->disconnect);
-
-       if (source->retry_id)
-               g_source_remove(source->retry_id);
-
-       g_free(source);
-       dev->source = NULL;
-}
-
-static void path_unregister(void *data)
-{
-       struct audio_device *dev = data;
-
-       DBG("Unregistered interface %s on path %s",
-               AUDIO_SOURCE_INTERFACE, dev->path);
-
-       source_free(dev);
-}
-
-void source_unregister(struct audio_device *dev)
-{
-       g_dbus_unregister_interface(dev->conn, dev->path,
-               AUDIO_SOURCE_INTERFACE);
-}
-
-struct source *source_init(struct audio_device *dev)
-{
-       struct source *source;
-
-       if (!g_dbus_register_interface(dev->conn, dev->path,
-                                       AUDIO_SOURCE_INTERFACE,
-                                       source_methods, source_signals, NULL,
-                                       dev, path_unregister))
-               return NULL;
-
-       DBG("Registered interface %s on path %s",
-               AUDIO_SOURCE_INTERFACE, dev->path);
-
-       if (avdtp_callback_id == 0)
-               avdtp_callback_id = avdtp_add_state_cb(avdtp_state_callback,
-                                                                       NULL);
-
-       source = g_new0(struct source, 1);
-
-       source->dev = dev;
-
-       return source;
-}
-
-gboolean source_is_active(struct audio_device *dev)
-{
-       struct source *source = dev->source;
-
-       if (source->session)
-               return TRUE;
-
-       return FALSE;
-}
-
-source_state_t source_get_state(struct audio_device *dev)
-{
-       struct source *source = dev->source;
-
-       return source->state;
-}
-
-gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
-                               struct avdtp_stream *stream)
-{
-       struct source *source = dev->source;
-
-       if (source->stream)
-               return FALSE;
-
-       if (!source->session)
-               source->session = avdtp_ref(session);
-
-       source->stream = stream;
-
-       source->cb_id = avdtp_stream_add_cb(session, stream,
-                                               stream_state_changed, dev);
-
-       return TRUE;
-}
-
-gboolean source_shutdown(struct source *source)
-{
-       if (!source->stream)
-               return FALSE;
-
-       if (avdtp_close(source->session, source->stream, FALSE) < 0)
-               return FALSE;
-
-       return TRUE;
-}
-
-unsigned int source_add_state_cb(source_state_cb cb, void *user_data)
-{
-       struct source_state_callback *state_cb;
-       static unsigned int id = 0;
-
-       state_cb = g_new(struct source_state_callback, 1);
-       state_cb->cb = cb;
-       state_cb->user_data = user_data;
-       state_cb->id = ++id;
-
-       source_callbacks = g_slist_append(source_callbacks, state_cb);
-
-       return state_cb->id;
-}
-
-gboolean source_remove_state_cb(unsigned int id)
-{
-       GSList *l;
-
-       for (l = source_callbacks; l != NULL; l = l->next) {
-               struct source_state_callback *cb = l->data;
-               if (cb && cb->id == id) {
-                       source_callbacks = g_slist_remove(source_callbacks, cb);
-                       g_free(cb);
-                       return TRUE;
-               }
-       }
-
-       return FALSE;
-}
diff --git a/audio/telephony-dummy.c b/audio/telephony-dummy.c
deleted file mode 100644 (file)
index 2f89139..0000000
+++ /dev/null
@@ -1,447 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-#define TELEPHONY_DUMMY_IFACE "org.bluez.TelephonyTest"
-#define TELEPHONY_DUMMY_PATH "/org/bluez/test"
-
-static DBusConnection *connection = NULL;
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-static char *active_call_number = NULL;
-static int active_call_status = 0;
-static int active_call_dir = 0;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator dummy_indicators[] =
-{
-       { "battchg",    "0-5",  5,      TRUE },
-       { "signal",     "0-5",  5,      TRUE },
-       { "service",    "0,1",  1,      TRUE },
-       { "call",       "0,1",  0,      TRUE },
-       { "callsetup",  "0-3",  0,      TRUE },
-       { "callheld",   "0-2",  0,      FALSE },
-       { "roam",       "0,1",  0,      TRUE },
-       { NULL }
-};
-
-void telephony_device_connected(void *telephony_device)
-{
-       DBG("telephony-dummy: device %p connected", telephony_device);
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-       DBG("telephony-dummy: device %p disconnected", telephony_device);
-       events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-       events_enabled = ind == 1 ? TRUE : FALSE;
-
-       telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-       telephony_response_and_hold_rsp(telephony_device,
-                                               CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-       telephony_last_dialed_number_rsp(telephony_device, CME_ERROR_NONE);
-
-       /* Notify outgoing call set-up successfully initiated */
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_ALERTING);
-
-       active_call_status = CALL_STATUS_ALERTING;
-       active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-       g_free(active_call_number);
-       active_call_number = NULL;
-
-       telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-
-       if (telephony_get_indicator(dummy_indicators, "callsetup") > 0)
-               telephony_update_indicator(dummy_indicators, "callsetup",
-                                               EV_CALLSETUP_INACTIVE);
-       else
-               telephony_update_indicator(dummy_indicators, "call",
-                                               EV_CALL_INACTIVE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-       telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-
-       telephony_update_indicator(dummy_indicators, "call", EV_CALL_ACTIVE);
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_INACTIVE);
-
-       active_call_status = CALL_STATUS_ACTIVE;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-       g_free(active_call_number);
-       active_call_number = g_strdup(number);
-
-       DBG("telephony-dummy: dial request to %s", active_call_number);
-
-       telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
-       /* Notify outgoing call set-up successfully initiated */
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_ALERTING);
-
-       active_call_status = CALL_STATUS_ALERTING;
-       active_call_dir = CALL_DIR_OUTGOING;
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-       DBG("telephony-dummy: transmit dtmf: %c", tone);
-       telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-       DBG("telephony-dummy: subscriber number request");
-       if (subscriber_number)
-               telephony_subscriber_number_ind(subscriber_number,
-                                               NUMBER_TYPE_TELEPHONY,
-                                               SUBSCRIBER_SERVICE_VOICE);
-       telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-       DBG("telephony-dummy: list current calls request");
-       if (active_call_number)
-               telephony_list_current_call_ind(1, active_call_dir,
-                                               active_call_status,
-                                               CALL_MODE_VOICE,
-                                               CALL_MULTIPARTY_NO,
-                                               active_call_number,
-                                               NUMBER_TYPE_TELEPHONY);
-       telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-       telephony_operator_selection_ind(OPERATOR_MODE_AUTO, "DummyOperator");
-       telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-       DBG("telephony-dymmy: got call hold request %s", cmd);
-       telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-dummy: got %s NR and EC request",
-                       enable ? "enable" : "disable");
-
-       telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-dummy: got %s voice dial request",
-                       enable ? "enable" : "disable");
-
-       g_dbus_emit_signal(connection, TELEPHONY_DUMMY_PATH,
-                       TELEPHONY_DUMMY_IFACE, "VoiceDial",
-                       DBUS_TYPE_INVALID);
-
-       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-       DBG("telephony-dummy: got key press request for %s", keys);
-       telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-/* D-Bus method handlers */
-static DBusMessage *outgoing_call(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       const char *number;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       DBG("telephony-dummy: outgoing call to %s", number);
-
-       g_free(active_call_number);
-       active_call_number = g_strdup(number);
-
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_ALERTING);
-
-       active_call_status = CALL_STATUS_ALERTING;
-       active_call_dir = CALL_DIR_OUTGOING;
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *incoming_call(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       const char *number;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       DBG("telephony-dummy: incoming call to %s", number);
-
-       g_free(active_call_number);
-       active_call_number = g_strdup(number);
-
-       telephony_update_indicator(dummy_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
-
-       active_call_status = CALL_STATUS_INCOMING;
-       active_call_dir = CALL_DIR_INCOMING;
-
-       telephony_incoming_call_ind(number, NUMBER_TYPE_TELEPHONY);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *cancel_call(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       DBG("telephony-dummy: cancel call");
-
-       g_free(active_call_number);
-       active_call_number = NULL;
-
-       if (telephony_get_indicator(dummy_indicators, "callsetup") > 0) {
-               telephony_update_indicator(dummy_indicators, "callsetup",
-                                               EV_CALLSETUP_INACTIVE);
-               telephony_calling_stopped_ind();
-       }
-
-       if (telephony_get_indicator(dummy_indicators, "call") > 0)
-               telephony_update_indicator(dummy_indicators, "call",
-                                               EV_CALL_INACTIVE);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *signal_strength(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       dbus_uint32_t strength;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &strength,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       if (strength > 5)
-               return btd_error_invalid_args(msg);
-
-       telephony_update_indicator(dummy_indicators, "signal", strength);
-
-       DBG("telephony-dummy: signal strength set to %u", strength);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *battery_level(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       dbus_uint32_t level;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &level,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       if (level > 5)
-               return btd_error_invalid_args(msg);
-
-       telephony_update_indicator(dummy_indicators, "battchg", level);
-
-       DBG("telephony-dummy: battery level set to %u", level);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *roaming_status(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       dbus_bool_t roaming;
-       int val;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &roaming,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       val = roaming ? EV_ROAM_ACTIVE : EV_ROAM_INACTIVE;
-
-       telephony_update_indicator(dummy_indicators, "roam", val);
-
-       DBG("telephony-dummy: roaming status set to %d", val);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *registration_status(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       dbus_bool_t registration;
-       int val;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &registration,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       val = registration ? EV_SERVICE_PRESENT : EV_SERVICE_NONE;
-
-       telephony_update_indicator(dummy_indicators, "service", val);
-
-       DBG("telephony-dummy: registration status set to %d", val);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_subscriber_number(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               void *data)
-{
-       const char *number;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &number,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       g_free(subscriber_number);
-       subscriber_number = g_strdup(number);
-
-       DBG("telephony-dummy: subscriber number set to %s", number);
-
-       return dbus_message_new_method_return(msg);
-}
-
-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 const GDBusSignalTable dummy_signals[] = {
-       { GDBUS_SIGNAL("VoiceDial", NULL) },
-       { }
-};
-
-int telephony_init(void)
-{
-       uint32_t features = AG_FEATURE_REJECT_A_CALL |
-                               AG_FEATURE_ENHANCED_CALL_STATUS |
-                               AG_FEATURE_EXTENDED_ERROR_RESULT_CODES;
-
-       DBG("");
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-       if (g_dbus_register_interface(connection, TELEPHONY_DUMMY_PATH,
-                                       TELEPHONY_DUMMY_IFACE,
-                                       dummy_methods, dummy_signals,
-                                       NULL, NULL, NULL) == FALSE) {
-               error("telephony-dummy interface %s init failed on path %s",
-                       TELEPHONY_DUMMY_IFACE, TELEPHONY_DUMMY_PATH);
-               return -1;
-       }
-
-       telephony_ready_ind(features, dummy_indicators, BTRH_NOT_SUPPORTED,
-                                                               chld_str);
-
-       return 0;
-}
-
-void telephony_exit(void)
-{
-       DBG("");
-
-       g_dbus_unregister_interface(connection, TELEPHONY_DUMMY_PATH,
-                                               TELEPHONY_DUMMY_IFACE);
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       telephony_deinit();
-}
diff --git a/audio/telephony-maemo5.c b/audio/telephony-maemo5.c
deleted file mode 100644 (file)
index 8a00296..0000000
+++ /dev/null
@@ -1,2105 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define NETWORK_BUS_NAME               "com.nokia.phone.net"
-#define NETWORK_INTERFACE              "Phone.Net"
-#define NETWORK_PATH                   "/com/nokia/phone/net"
-
-/* Mask bits for supported services */
-#define NETWORK_MASK_GPRS_SUPPORT      0x01
-#define NETWORK_MASK_CS_SERVICES       0x02
-#define NETWORK_MASK_EGPRS_SUPPORT     0x04
-#define NETWORK_MASK_HSDPA_AVAIL       0x08
-#define NETWORK_MASK_HSUPA_AVAIL       0x10
-
-/* network get cell info: cell type */
-#define NETWORK_UNKNOWN_CELL           0
-#define NETWORK_GSM_CELL               1
-#define NETWORK_WCDMA_CELL             2
-
-enum net_registration_status {
-       NETWORK_REG_STATUS_HOME = 0x00,
-       NETWORK_REG_STATUS_ROAM,
-       NETWORK_REG_STATUS_ROAM_BLINK,
-       NETWORK_REG_STATUS_NOSERV,
-       NETWORK_REG_STATUS_NOSERV_SEARCHING,
-       NETWORK_REG_STATUS_NOSERV_NOTSEARCHING,
-       NETWORK_REG_STATUS_NOSERV_NOSIM,
-       NETWORK_REG_STATUS_POWER_OFF = 0x08,
-       NETWORK_REG_STATUS_NSPS,
-       NETWORK_REG_STATUS_NSPS_NO_COVERAGE,
-       NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW
-};
-
-enum network_types {
-       NETWORK_GSM_HOME_PLMN = 0,
-       NETWORK_GSM_PREFERRED_PLMN,
-       NETWORK_GSM_FORBIDDEN_PLMN,
-       NETWORK_GSM_OTHER_PLMN,
-       NETWORK_GSM_NO_PLMN_AVAIL
-};
-
-enum network_alpha_tag_name_type {
-       NETWORK_HARDCODED_LATIN_OPER_NAME = 0,
-       NETWORK_HARDCODED_USC2_OPER_NAME,
-       NETWORK_NITZ_SHORT_OPER_NAME,
-       NETWORK_NITZ_FULL_OPER_NAME,
-};
-
-#define TELEPHONY_MAEMO_PATH           "/com/nokia/MaemoTelephony"
-#define TELEPHONY_MAEMO_INTERFACE      "com.nokia.MaemoTelephony"
-
-#define CALLERID_BASE          "/var/lib/bluetooth/maemo-callerid-"
-#define ALLOWED_FLAG_FILE      "/var/lib/bluetooth/maemo-callerid-allowed"
-#define RESTRICTED_FLAG_FILE   "/var/lib/bluetooth/maemo-callerid-restricted"
-#define NONE_FLAG_FILE         "/var/lib/bluetooth/maemo-callerid-none"
-
-static uint32_t callerid = 0;
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME      "com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE     "com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE      "com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE    "com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH          "/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE                   0
-#define CSD_CALL_STATUS_CREATE                 1
-#define CSD_CALL_STATUS_COMING                 2
-#define CSD_CALL_STATUS_PROCEEDING             3
-#define CSD_CALL_STATUS_MO_ALERTING            4
-#define CSD_CALL_STATUS_MT_ALERTING            5
-#define CSD_CALL_STATUS_WAITING                        6
-#define CSD_CALL_STATUS_ANSWERED               7
-#define CSD_CALL_STATUS_ACTIVE                 8
-#define CSD_CALL_STATUS_MO_RELEASE             9
-#define CSD_CALL_STATUS_MT_RELEASE             10
-#define CSD_CALL_STATUS_HOLD_INITIATED         11
-#define CSD_CALL_STATUS_HOLD                   12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED     13
-#define CSD_CALL_STATUS_RECONNECT_PENDING      14
-#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
-
-/* SIM Phonebook D-Bus definitions */
-#define SIM_PHONEBOOK_BUS_NAME                 "com.nokia.phone.SIM"
-#define SIM_PHONEBOOK_INTERFACE                        "Phone.Sim.Phonebook"
-#define SIM_PHONEBOOK_PATH                     "/com/nokia/phone/SIM/phonebook"
-
-#define PHONEBOOK_INDEX_FIRST_ENTRY            0xFFFF
-#define PHONEBOOK_INDEX_NEXT_FREE_LOCATION     0xFFFE
-
-enum sim_phonebook_type {
-       SIM_PHONEBOOK_TYPE_ADN = 0x0,
-       SIM_PHONEBOOK_TYPE_SDN,
-       SIM_PHONEBOOK_TYPE_FDN,
-       SIM_PHONEBOOK_TYPE_VMBX,
-       SIM_PHONEBOOK_TYPE_MBDN,
-       SIM_PHONEBOOK_TYPE_EN,
-       SIM_PHONEBOOK_TYPE_MSISDN
-};
-
-enum sim_phonebook_location_type {
-       SIM_PHONEBOOK_LOCATION_EXACT = 0x0,
-       SIM_PHONEBOOK_LOCATION_NEXT
-};
-
-struct csd_call {
-       char *object_path;
-       int status;
-       gboolean originating;
-       gboolean emergency;
-       gboolean on_hold;
-       gboolean conference;
-       char *number;
-       gboolean setup;
-};
-
-static struct {
-       uint8_t status;
-       uint16_t lac;
-       uint32_t cell_id;
-       uint32_t operator_code;
-       uint32_t country_code;
-       uint8_t network_type;
-       uint8_t supported_services;
-       uint16_t signals_bar;
-       char *operator_name;
-} net = {
-       .status = NETWORK_REG_STATUS_NOSERV,
-       .lac = 0,
-       .cell_id = 0,
-       .operator_code = 0,
-       .country_code = 0,
-       .network_type = NETWORK_GSM_NO_PLMN_AVAIL,
-       .supported_services = 0,
-       .signals_bar = 0,
-       .operator_name = NULL,
-};
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-static char *msisdn = NULL;    /* Subscriber number */
-static char *vmbx = NULL;      /* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;   /* "battery.charge_level.current" */
-static int battchg_last = -1;  /* "battery.charge_level.last_full" */
-static int battchg_design = -1;        /* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-static char *last_dialed_number = NULL;
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
-       { "battchg",    "0-5",  5,      TRUE },
-       { "signal",     "0-5",  0,      TRUE },
-       { "service",    "0,1",  0,      TRUE },
-       { "call",       "0,1",  0,      TRUE },
-       { "callsetup",  "0-3",  0,      TRUE },
-       { "callheld",   "0-2",  0,      FALSE },
-       { "roam",       "0,1",  0,      TRUE },
-       { NULL }
-};
-
-static char *call_status_str[] = {
-       "IDLE",
-       "CREATE",
-       "COMING",
-       "PROCEEDING",
-       "MO_ALERTING",
-       "MT_ALERTING",
-       "WAITING",
-       "ANSWERED",
-       "ACTIVE",
-       "MO_RELEASE",
-       "MT_RELEASE",
-       "HOLD_INITIATED",
-       "HOLD",
-       "RETRIEVE_INITIATED",
-       "RECONNECT_PENDING",
-       "TERMINATED",
-       "SWAP_INITIATED",
-       "???"
-};
-
-static struct csd_call *find_call(const char *path)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (g_str_equal(call->object_path, path))
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status == CSD_CALL_STATUS_IDLE)
-                       continue;
-
-               if (call->status != CSD_CALL_STATUS_HOLD)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status != CSD_CALL_STATUS_IDLE)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status == status)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static int release_conference(void)
-{
-       DBusMessage *msg;
-
-       DBG("telephony-maemo: releasing conference call");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               CSD_CALL_CONFERENCE_PATH,
-                                               CSD_CALL_INSTANCE,
-                                               "Release");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Release");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Answer");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int swap_calls(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int create_conference(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int call_transfer(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int number_type(const char *number)
-{
-       if (number == NULL)
-               return NUMBER_TYPE_TELEPHONY;
-
-       if (number[0] == '+' || strncmp(number, "00", 2) == 0)
-               return NUMBER_TYPE_INTERNATIONAL;
-
-       return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
-       struct csd_call *coming;
-
-       DBG("telephony-maemo: device %p connected", telephony_device);
-
-       coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-       if (coming) {
-               if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-                       telephony_call_waiting_ind(coming->number,
-                                               number_type(coming->number));
-               else
-                       telephony_incoming_call_ind(coming->number,
-                                               number_type(coming->number));
-       }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-       DBG("telephony-maemo: device %p disconnected", telephony_device);
-       events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-       events_enabled = ind == 1 ? TRUE : FALSE;
-
-       telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-       telephony_response_and_hold_rsp(telephony_device,
-                                               CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-       DBG("telephony-maemo: last dialed number request");
-
-       if (last_dialed_number)
-               telephony_dial_number_req(telephony_device,
-                                               last_dialed_number);
-       else
-               telephony_last_dialed_number_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-       struct csd_call *call;
-       int err;
-
-       call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-       if (!call)
-               call = find_non_idle_call();
-
-       if (!call) {
-               error("No active call");
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       if (call->conference)
-               err = release_conference();
-       else
-               err = release_call(call);
-
-       if (err < 0)
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       else
-               telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-       struct csd_call *call;
-
-       call = find_call_with_status(CSD_CALL_STATUS_COMING);
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-       if (!call) {
-               telephony_answer_call_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       if (answer_call(call) < 0)
-               telephony_answer_call_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       else
-               telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int send_method_call(const char *dest, const char *path,
-                               const char *interface, const char *method,
-                               DBusPendingCallNotifyFunction cb,
-                               void *user_data, int type, ...)
-{
-       DBusMessage *msg;
-       DBusPendingCall *call;
-       va_list args;
-
-       msg = dbus_message_new_method_call(dest, path, interface, method);
-       if (!msg) {
-               error("Unable to allocate new D-Bus %s message", method);
-               return -ENOMEM;
-       }
-
-       va_start(args, type);
-
-       if (!dbus_message_append_args_valist(msg, type, args)) {
-               dbus_message_unref(msg);
-               va_end(args);
-               return -EIO;
-       }
-
-       va_end(args);
-
-       if (!cb) {
-               g_dbus_send_message(connection, msg);
-               return 0;
-       }
-
-       if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-               error("Sending %s failed", method);
-               dbus_message_unref(msg);
-               return -EIO;
-       }
-
-       dbus_pending_call_set_notify(call, cb, user_data, NULL);
-       dbus_pending_call_unref(call);
-       dbus_message_unref(msg);
-
-       return 0;
-}
-
-static const char *memory_dial_lookup(int location)
-{
-       if (location == 1)
-               return vmbx;
-       else
-               return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-       uint32_t flags = callerid;
-       int ret;
-
-       DBG("telephony-maemo: dial request to %s", number);
-
-       if (strncmp(number, "*31#", 4) == 0) {
-               number += 4;
-               flags = CALL_FLAG_PRESENTATION_ALLOWED;
-       } else if (strncmp(number, "#31#", 4) == 0) {
-               number += 4;
-               flags = CALL_FLAG_PRESENTATION_RESTRICTED;
-       } else if (number[0] == '>') {
-               const char *location = &number[1];
-
-               number = memory_dial_lookup(strtol(&number[1], NULL, 0));
-               if (!number) {
-                       error("No number at memory location %s", location);
-                       telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_INVALID_INDEX);
-                       return;
-               }
-       }
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "CreateWith",
-                               NULL, NULL,
-                               DBUS_TYPE_STRING, &number,
-                               DBUS_TYPE_UINT32, &flags,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-       int ret;
-       char buf[2] = { tone, '\0' }, *buf_ptr = buf;
-
-       DBG("telephony-maemo: transmit dtmf: %s", buf);
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "SendDTMF",
-                               NULL, NULL,
-                               DBUS_TYPE_STRING, &buf_ptr,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               telephony_transmit_dtmf_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-       DBG("telephony-maemo: subscriber number request");
-       if (msisdn)
-               telephony_subscriber_number_ind(msisdn,
-                                               number_type(msisdn),
-                                               SUBSCRIBER_SERVICE_VOICE);
-       telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
-       switch (call->status) {
-       case CSD_CALL_STATUS_IDLE:
-       case CSD_CALL_STATUS_MO_RELEASE:
-       case CSD_CALL_STATUS_MT_RELEASE:
-       case CSD_CALL_STATUS_TERMINATED:
-               return -1;
-       case CSD_CALL_STATUS_CREATE:
-               return CALL_STATUS_DIALING;
-       case CSD_CALL_STATUS_WAITING:
-               return CALL_STATUS_WAITING;
-       case CSD_CALL_STATUS_PROCEEDING:
-               /* PROCEEDING can happen in outgoing/incoming */
-               if (call->originating)
-                       return CALL_STATUS_DIALING;
-               else
-                       return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_COMING:
-               return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_MO_ALERTING:
-               return CALL_STATUS_ALERTING;
-       case CSD_CALL_STATUS_MT_ALERTING:
-               return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_ANSWERED:
-       case CSD_CALL_STATUS_ACTIVE:
-       case CSD_CALL_STATUS_RECONNECT_PENDING:
-       case CSD_CALL_STATUS_SWAP_INITIATED:
-       case CSD_CALL_STATUS_HOLD_INITIATED:
-               return CALL_STATUS_ACTIVE;
-       case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-       case CSD_CALL_STATUS_HOLD:
-               return CALL_STATUS_HELD;
-       default:
-               return -1;
-       }
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-       GSList *l;
-       int i;
-
-       DBG("telephony-maemo: 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;
-
-               status = csd_status_to_hfp(call);
-               if (status < 0)
-                       continue;
-
-               direction = call->originating ?
-                               CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-               multiparty = call->conference ?
-                               CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-               telephony_list_current_call_ind(i, direction, status,
-                                               CALL_MODE_VOICE, multiparty,
-                                               call->number,
-                                               number_type(call->number));
-       }
-
-       telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-       telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-                               net.operator_name ? net.operator_name : "");
-       telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-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);
-       }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-       const char *idx;
-       struct csd_call *call;
-       int err = 0;
-
-       DBG("telephony-maemo: got call hold request %s", cmd);
-
-       if (strlen(cmd) > 1)
-               idx = &cmd[1];
-       else
-               idx = NULL;
-
-       if (idx)
-               call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-       else
-               call = NULL;
-
-       switch (cmd[0]) {
-       case '0':
-               foreach_call_with_status(CSD_CALL_STATUS_HOLD, release_call);
-               foreach_call_with_status(CSD_CALL_STATUS_WAITING,
-                                                               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);
-               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);
-                       }
-               }
-               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 (err)
-               telephony_call_hold_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-maemo: got %s NR and EC request",
-                       enable ? "enable" : "disable");
-       telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-       struct csd_call *active, *waiting;
-       int err;
-
-       DBG("telephony-maemo: 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);
-       if (!waiting)
-               waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-       active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
-       if (waiting)
-               err = answer_call(waiting);
-       else if (active)
-               err = release_call(active);
-       else
-               err = 0;
-
-       if (err < 0)
-               telephony_key_press_rsp(telephony_device,
-                                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-maemo: got %s voice dial request",
-                       enable ? "enable" : "disable");
-
-       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
-       const char *number, *call_path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Coming() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       DBG("Incoming call to %s from number %s", call_path, number);
-
-       g_free(call->number);
-       call->number = g_strdup(number);
-
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
-
-       if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-               telephony_call_waiting_ind(call->number,
-                                               number_type(call->number));
-       else
-               telephony_incoming_call_ind(call->number,
-                                               number_type(call->number));
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
-       const char *number, *call_path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Created() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       DBG("Outgoing call from %s to number %s", call_path, number);
-
-       g_free(call->number);
-       call->number = g_strdup(number);
-
-       g_free(last_dialed_number);
-       last_dialed_number = g_strdup(number);
-
-       if (create_request_timer) {
-               g_source_remove(create_request_timer);
-               create_request_timer = 0;
-       }
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_INACTIVE);
-       create_request_timer = 0;
-       return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
-       DBG("Call.CreateRequested()");
-
-       if (create_request_timer)
-               g_source_remove(create_request_timer);
-
-       create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
-       struct csd_call *call;
-       dbus_uint32_t status, cause_type, cause;
-       int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_UINT32, &status,
-                                       DBUS_TYPE_UINT32, &cause_type,
-                                       DBUS_TYPE_UINT32, &cause,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Instance.CallStatus() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       if (status > 16) {
-               error("Invalid call status %u", status);
-               return;
-       }
-
-       DBG("Call %s changed from %s to %s", call_path,
-               call_status_str[call->status], call_status_str[status]);
-
-       if (call->status == (int) status) {
-               DBG("Ignoring CSD Call state change to existing state");
-               return;
-       }
-
-       call->status = (int) status;
-
-       switch (status) {
-       case CSD_CALL_STATUS_IDLE:
-               if (call->setup) {
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-                       if (!call->originating)
-                               telephony_calling_stopped_ind();
-               }
-
-               g_free(call->number);
-               call->number = NULL;
-               call->originating = FALSE;
-               call->emergency = FALSE;
-               call->on_hold = FALSE;
-               call->conference = FALSE;
-               call->setup = FALSE;
-               break;
-       case CSD_CALL_STATUS_CREATE:
-               call->originating = TRUE;
-               call->setup = TRUE;
-               break;
-       case CSD_CALL_STATUS_COMING:
-               call->originating = FALSE;
-               call->setup = TRUE;
-               break;
-       case CSD_CALL_STATUS_PROCEEDING:
-               break;
-       case CSD_CALL_STATUS_MO_ALERTING:
-               telephony_update_indicator(maemo_indicators, "callsetup",
-                                               EV_CALLSETUP_ALERTING);
-               break;
-       case CSD_CALL_STATUS_MT_ALERTING:
-               break;
-       case CSD_CALL_STATUS_WAITING:
-               break;
-       case CSD_CALL_STATUS_ANSWERED:
-               break;
-       case CSD_CALL_STATUS_ACTIVE:
-               if (call->on_hold) {
-                       call->on_hold = FALSE;
-                       if (find_call_with_status(CSD_CALL_STATUS_HOLD))
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-                       else
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_NONE);
-               } else {
-                       if (!g_slist_find(active_calls, call))
-                               active_calls = g_slist_prepend(active_calls, call);
-                       if (g_slist_length(active_calls) == 1)
-                               telephony_update_indicator(maemo_indicators,
-                                                               "call",
-                                                               EV_CALL_ACTIVE);
-                       /* Upgrade callheld status if necessary */
-                       if (callheld == EV_CALLHELD_ON_HOLD)
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-                       if (!call->originating)
-                               telephony_calling_stopped_ind();
-                       call->setup = FALSE;
-               }
-               break;
-       case CSD_CALL_STATUS_MO_RELEASE:
-       case CSD_CALL_STATUS_MT_RELEASE:
-               active_calls = g_slist_remove(active_calls, call);
-               if (g_slist_length(active_calls) == 0)
-                       telephony_update_indicator(maemo_indicators, "call",
-                                                       EV_CALL_INACTIVE);
-               break;
-       case CSD_CALL_STATUS_HOLD_INITIATED:
-               break;
-       case CSD_CALL_STATUS_HOLD:
-               call->on_hold = TRUE;
-               if (find_non_held_call())
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-               else
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_ON_HOLD);
-               break;
-       case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-               break;
-       case CSD_CALL_STATUS_RECONNECT_PENDING:
-               break;
-       case CSD_CALL_STATUS_TERMINATED:
-               if (call->on_hold &&
-                               !find_call_with_status(CSD_CALL_STATUS_HOLD))
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_NONE);
-               else if (callheld == EV_CALLHELD_MULTIPLE &&
-                               find_call_with_status(CSD_CALL_STATUS_HOLD))
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_ON_HOLD);
-               break;
-       case CSD_CALL_STATUS_SWAP_INITIATED:
-               break;
-       default:
-               error("Unknown call status %u", status);
-               break;
-       }
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
-       const char *path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Conference.%s",
-                                       dbus_message_get_member(msg));
-               return;
-       }
-
-       call = find_call(path);
-       if (!call) {
-               error("Conference signal for unknown call %s", path);
-               return;
-       }
-
-       DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
-       call->conference = joined;
-}
-
-static void get_operator_name_reply(DBusPendingCall *pending_call,
-                                       void *user_data)
-{
-       DBusMessage *reply;
-       DBusError err;
-       const char *name;
-       dbus_int32_t net_err;
-
-       reply = dbus_pending_call_steal_reply(pending_call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("get_operator_name failed: %s, %s",
-                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_error_init(&err);
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_INT32, &net_err,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected get_operator_name reply parameters: %s, %s",
-                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       if (net_err != 0) {
-               error("get_operator_name failed with code %d", net_err);
-               goto done;
-       }
-
-       if (strlen(name) == 0)
-               goto done;
-
-       g_free(net.operator_name);
-       net.operator_name = g_strdup(name);
-
-       DBG("telephony-maemo: operator name updated: %s", name);
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void resolve_operator_name(uint32_t operator, uint32_t country)
-{
-       uint8_t name_type = NETWORK_HARDCODED_LATIN_OPER_NAME;
-
-       send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-                               NETWORK_INTERFACE, "get_operator_name",
-                               get_operator_name_reply, NULL,
-                               DBUS_TYPE_BYTE, &name_type,
-                               DBUS_TYPE_UINT32, &operator,
-                               DBUS_TYPE_UINT32, &country,
-                               DBUS_TYPE_INVALID);
-}
-
-static void update_registration_status(uint8_t status, uint16_t lac,
-                                       uint32_t cell_id,
-                                       uint32_t operator_code,
-                                       uint32_t country_code,
-                                       uint8_t network_type,
-                                       uint8_t supported_services)
-{
-       if (net.status != status) {
-               switch (status) {
-               case NETWORK_REG_STATUS_HOME:
-                       telephony_update_indicator(maemo_indicators, "roam",
-                                                       EV_ROAM_INACTIVE);
-                       if (net.status >= NETWORK_REG_STATUS_NOSERV)
-                               telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_PRESENT);
-                       break;
-               case NETWORK_REG_STATUS_ROAM:
-               case NETWORK_REG_STATUS_ROAM_BLINK:
-                       telephony_update_indicator(maemo_indicators, "roam",
-                                                       EV_ROAM_ACTIVE);
-                       if (net.status >= NETWORK_REG_STATUS_NOSERV)
-                               telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_PRESENT);
-                       break;
-               case NETWORK_REG_STATUS_NOSERV:
-               case NETWORK_REG_STATUS_NOSERV_SEARCHING:
-               case NETWORK_REG_STATUS_NOSERV_NOTSEARCHING:
-               case NETWORK_REG_STATUS_NOSERV_NOSIM:
-               case NETWORK_REG_STATUS_POWER_OFF:
-               case NETWORK_REG_STATUS_NSPS:
-               case NETWORK_REG_STATUS_NSPS_NO_COVERAGE:
-               case NETWORK_REG_STATUS_NOSERV_SIM_REJECTED_BY_NW:
-                       if (net.status < NETWORK_REG_STATUS_NOSERV)
-                               telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_NONE);
-                       break;
-               }
-
-               net.status = status;
-       }
-
-       net.lac = lac;
-       net.cell_id = cell_id;
-
-       if (net.operator_code != operator_code ||
-                       net.country_code != country_code) {
-               g_free(net.operator_name);
-               net.operator_name = NULL;
-               resolve_operator_name(operator_code, country_code);
-               net.operator_code = operator_code;
-               net.country_code = country_code;
-       }
-
-       net.network_type = network_type;
-       net.supported_services = supported_services;
-}
-
-static void handle_registration_status_change(DBusMessage *msg)
-{
-       uint8_t status;
-       dbus_uint16_t lac, network_type, supported_services;
-       dbus_uint32_t cell_id, operator_code, country_code;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_BYTE, &status,
-                                       DBUS_TYPE_UINT16, &lac,
-                                       DBUS_TYPE_UINT32, &cell_id,
-                                       DBUS_TYPE_UINT32, &operator_code,
-                                       DBUS_TYPE_UINT32, &country_code,
-                                       DBUS_TYPE_BYTE, &network_type,
-                                       DBUS_TYPE_BYTE, &supported_services,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in registration_status_change");
-               return;
-       }
-
-       update_registration_status(status, lac, cell_id, operator_code,
-                                       country_code, network_type,
-                                       supported_services);
-}
-
-static void update_signal_strength(uint8_t signals_bar)
-{
-       int signal;
-
-       if (signals_bar > 100) {
-               DBG("signals_bar greater than expected: %u", signals_bar);
-               signals_bar = 100;
-       }
-
-       if (net.signals_bar == signals_bar)
-               return;
-
-       /* A simple conversion from 0-100 to 0-5 (used by HFP) */
-       signal = (signals_bar + 20) / 21;
-
-       telephony_update_indicator(maemo_indicators, "signal", signal);
-
-       net.signals_bar = signals_bar;
-
-       DBG("Signal strength updated: %u/100, %d/5", signals_bar, signal);
-}
-
-static void handle_signal_strength_change(DBusMessage *msg)
-{
-       uint8_t signals_bar, rssi_in_dbm;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_BYTE, &signals_bar,
-                                       DBUS_TYPE_BYTE, &rssi_in_dbm,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in signal_strength_change");
-               return;
-       }
-
-       update_signal_strength(signals_bar);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-                                       int first_arg_type, ...)
-{
-       int type;
-       va_list ap;
-
-       va_start(ap, first_arg_type);
-
-       for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-                       type = va_arg(ap, int)) {
-               void *value = va_arg(ap, void *);
-               int real_type = dbus_message_iter_get_arg_type(iter);
-
-               if (real_type != type) {
-                       error("iter_get_basic_args: expected %c but got %c",
-                                       (char) type, (char) real_type);
-                       break;
-               }
-
-               dbus_message_iter_get_basic(iter, value);
-               dbus_message_iter_next(iter);
-       }
-
-       va_end(ap);
-
-       return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       dbus_int32_t level;
-       int *value = user_data;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_error_init(&err);
-       if (dbus_message_get_args(reply, &err,
-                               DBUS_TYPE_INT32, &level,
-                               DBUS_TYPE_INVALID) == FALSE) {
-               error("Unable to parse GetPropertyInteger reply: %s, %s",
-                                                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       *value = (int) level;
-
-       if (value == &battchg_last)
-               DBG("telephony-maemo: battery.charge_level.last_full is %d",
-                               *value);
-       else if (value == &battchg_design)
-               DBG("telephony-maemo: battery.charge_level.design is %d",
-                               *value);
-       else
-               DBG("telephony-maemo: battery.charge_level.current is %d",
-                               *value);
-
-       if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-               int new, max;
-
-               if (battchg_last > 0)
-                       max = battchg_last;
-               else
-                       max = battchg_design;
-
-               new = battchg_cur * 5 / max;
-
-               telephony_update_indicator(maemo_indicators, "battchg", new);
-       }
-done:
-       dbus_message_unref(reply);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-       send_method_call("org.freedesktop.Hal", path,
-                               "org.freedesktop.Hal.Device",
-                               "GetPropertyInteger",
-                               hal_battery_level_reply, user_data,
-                               DBUS_TYPE_STRING, &key,
-                               DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
-       DBusMessageIter iter, array;
-       dbus_int32_t num_changes;
-       const char *path;
-
-       path = dbus_message_get_path(msg);
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return;
-       }
-
-       dbus_message_iter_get_basic(&iter, &num_changes);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return;
-       }
-
-       dbus_message_iter_recurse(&iter, &array);
-
-       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-               DBusMessageIter prop;
-               const char *name;
-               dbus_bool_t added, removed;
-
-               dbus_message_iter_recurse(&array, &prop);
-
-               if (!iter_get_basic_args(&prop,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_BOOLEAN, &added,
-                                       DBUS_TYPE_BOOLEAN, &removed,
-                                       DBUS_TYPE_INVALID)) {
-                       error("Invalid hal PropertyModified parameters");
-                       break;
-               }
-
-               if (g_str_equal(name, "battery.charge_level.last_full"))
-                       hal_get_integer(path, name, &battchg_last);
-               else if (g_str_equal(name, "battery.charge_level.current"))
-                       hal_get_integer(path, name, &battchg_cur);
-               else if (g_str_equal(name, "battery.charge_level.design"))
-                       hal_get_integer(path, name, &battchg_design);
-
-               dbus_message_iter_next(&array);
-       }
-}
-
-static void csd_call_free(struct csd_call *call)
-{
-       if (!call)
-               return;
-
-       g_free(call->object_path);
-       g_free(call->number);
-
-       g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
-       do {
-               DBusMessageIter call_iter;
-               struct csd_call *call;
-               const char *object_path, *number;
-               dbus_uint32_t status;
-               dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
-               if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
-                       error("Unexpected signature in GetCallInfoAll reply");
-                       break;
-               }
-
-               dbus_message_iter_recurse(iter, &call_iter);
-
-               if (!iter_get_basic_args(&call_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &object_path,
-                                       DBUS_TYPE_UINT32, &status,
-                                       DBUS_TYPE_BOOLEAN, &originating,
-                                       DBUS_TYPE_BOOLEAN, &terminating,
-                                       DBUS_TYPE_BOOLEAN, &emerg,
-                                       DBUS_TYPE_BOOLEAN, &on_hold,
-                                       DBUS_TYPE_BOOLEAN, &conf,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-                       error("Parsing call D-Bus parameters failed");
-                       break;
-               }
-
-               call = find_call(object_path);
-               if (!call) {
-                       call = g_new0(struct csd_call, 1);
-                       call->object_path = g_strdup(object_path);
-                       call->status = (int) status;
-                       calls = g_slist_append(calls, call);
-                       DBG("telephony-maemo: new csd call instance at %s",
-                                                               object_path);
-               }
-
-               if (call->status == CSD_CALL_STATUS_IDLE)
-                       continue;
-
-               /* CSD gives incorrect call_hold property sometimes */
-               if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
-                               (call->status == CSD_CALL_STATUS_HOLD &&
-                                                               !on_hold)) {
-                       error("Conflicting call status and on_hold property!");
-                       on_hold = call->status == CSD_CALL_STATUS_HOLD;
-               }
-
-               call->originating = originating;
-               call->on_hold = on_hold;
-               call->conference = conf;
-               g_free(call->number);
-               call->number = g_strdup(number);
-
-       } while (dbus_message_iter_next(iter));
-}
-
-static void signal_strength_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       uint8_t signals_bar, rssi_in_dbm;
-       dbus_int32_t net_err;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("Unable to get signal strength: %s, %s",
-                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_error_init(&err);
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_BYTE, &signals_bar,
-                                       DBUS_TYPE_BYTE, &rssi_in_dbm,
-                                       DBUS_TYPE_INT32, &net_err,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unable to parse signal_strength reply: %s, %s",
-                                                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       if (net_err != 0) {
-               error("get_signal_strength failed with code %d", net_err);
-               goto done;
-       }
-
-       update_signal_strength(signals_bar);
-
-done:
-       dbus_message_unref(reply);
-}
-
-static int get_signal_strength(void)
-{
-       return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-                               NETWORK_INTERFACE, "get_signal_strength",
-                               signal_strength_reply, NULL,
-                               DBUS_TYPE_INVALID);
-}
-
-static void registration_status_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       uint8_t status;
-       dbus_uint16_t lac, network_type, supported_services;
-       dbus_uint32_t cell_id, operator_code, country_code;
-       dbus_int32_t net_err;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("Unable to get registration status: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_error_init(&err);
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_BYTE, &status,
-                                       DBUS_TYPE_UINT16, &lac,
-                                       DBUS_TYPE_UINT32, &cell_id,
-                                       DBUS_TYPE_UINT32, &operator_code,
-                                       DBUS_TYPE_UINT32, &country_code,
-                                       DBUS_TYPE_BYTE, &network_type,
-                                       DBUS_TYPE_BYTE, &supported_services,
-                                       DBUS_TYPE_INT32, &net_err,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unable to parse registration_status_change reply:"
-                                       " %s, %s", err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       if (net_err != 0) {
-               error("get_registration_status failed with code %d", net_err);
-               goto done;
-       }
-
-       update_registration_status(status, lac, cell_id, operator_code,
-                                       country_code, network_type,
-                                       supported_services);
-
-       get_signal_strength();
-
-done:
-       dbus_message_unref(reply);
-}
-
-static int get_registration_status(void)
-{
-       return send_method_call(NETWORK_BUS_NAME, NETWORK_PATH,
-                               NETWORK_INTERFACE, "get_registration_status",
-                               registration_status_reply, NULL,
-                               DBUS_TYPE_INVALID);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, sub;
-
-       get_calls_active = FALSE;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("csd replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in GetCallInfoAll return");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       parse_call_list(&sub);
-
-       get_registration_status();
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, sub;
-       const char *path;
-       char match_string[256];
-       int type;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in FindDeviceByCapability return");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       type = dbus_message_iter_get_arg_type(&sub);
-
-       if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-               error("No hal device with battery capability found");
-               goto done;
-       }
-
-       dbus_message_iter_get_basic(&sub, &path);
-
-       DBG("telephony-maemo: found battery device at %s", path);
-
-       snprintf(match_string, sizeof(match_string),
-                       "type='signal',"
-                       "path='%s',"
-                       "interface='org.freedesktop.Hal.Device',"
-                       "member='PropertyModified'", path);
-       dbus_bus_add_match(connection, match_string, NULL);
-
-       hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-       hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-       hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError derr;
-       DBusMessage *reply;
-       const char *name, *number;
-       char **number_type = user_data;
-       dbus_int32_t current_location, err;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&derr);
-       if (dbus_set_error_from_message(&derr, reply)) {
-               error("SIM.Phonebook replied with an error: %s, %s",
-                               derr.name, derr.message);
-               dbus_error_free(&derr);
-               goto done;
-       }
-
-       dbus_error_init(&derr);
-       if (dbus_message_get_args(reply, &derr,
-                               DBUS_TYPE_STRING, &name,
-                               DBUS_TYPE_STRING, &number,
-                               DBUS_TYPE_INT32, &current_location,
-                               DBUS_TYPE_INT32, &err,
-                               DBUS_TYPE_INVALID) == FALSE) {
-               error("Unable to parse SIM.Phonebook.read arguments: %s, %s",
-                               derr.name, derr.message);
-               dbus_error_free(&derr);
-               goto done;
-       }
-
-       if (err != 0) {
-               error("SIM.Phonebook.read failed with error %d", err);
-               if (number_type == &vmbx)
-                       vmbx = g_strdup(getenv("VMBX_NUMBER"));
-               goto done;
-       }
-
-       if (number_type == &msisdn) {
-               g_free(msisdn);
-               msisdn = g_strdup(number);
-               DBG("Got MSISDN %s (%s)", number, name);
-       } else {
-               g_free(vmbx);
-               vmbx = g_strdup(number);
-               DBG("Got voice mailbox number %s (%s)", number, name);
-       }
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void csd_init(void)
-{
-       dbus_uint32_t location;
-       uint8_t pb_type, location_type;
-       int ret;
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "GetCallInfoAll",
-                               call_info_reply, NULL, DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to sent GetCallInfoAll method call");
-               return;
-       }
-
-       get_calls_active = TRUE;
-
-       pb_type = SIM_PHONEBOOK_TYPE_MSISDN;
-       location = PHONEBOOK_INDEX_FIRST_ENTRY;
-       location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
-       ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-                               SIM_PHONEBOOK_INTERFACE, "read",
-                               phonebook_read_reply, &msisdn,
-                               DBUS_TYPE_BYTE, &pb_type,
-                               DBUS_TYPE_INT32, &location,
-                               DBUS_TYPE_BYTE, &location_type,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-               return;
-       }
-
-       pb_type = SIM_PHONEBOOK_TYPE_MBDN;
-       location = PHONEBOOK_INDEX_FIRST_ENTRY;
-       location_type = SIM_PHONEBOOK_LOCATION_NEXT;
-
-       ret = send_method_call(SIM_PHONEBOOK_BUS_NAME, SIM_PHONEBOOK_PATH,
-                               SIM_PHONEBOOK_INTERFACE, "read",
-                               phonebook_read_reply, &vmbx,
-                               DBUS_TYPE_BYTE, &pb_type,
-                               DBUS_TYPE_INT32, &location,
-                               DBUS_TYPE_BYTE, &location_type,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to send " SIM_PHONEBOOK_INTERFACE ".read()");
-               return;
-       }
-}
-
-static uint32_t get_callflag(const char *callerid_setting)
-{
-       if (callerid_setting != NULL) {
-               if (g_str_equal(callerid_setting, "allowed"))
-                       return CALL_FLAG_PRESENTATION_ALLOWED;
-               else if (g_str_equal(callerid_setting, "restricted"))
-                       return CALL_FLAG_PRESENTATION_RESTRICTED;
-               else
-                       return CALL_FLAG_NONE;
-       } else
-               return CALL_FLAG_NONE;
-}
-
-static void generate_flag_file(const char *filename)
-{
-       int fd;
-
-       if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
-                       g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS) ||
-                       g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-               return;
-
-       fd = open(filename, O_WRONLY | O_CREAT, 0);
-       if (fd >= 0)
-               close(fd);
-}
-
-static void save_callerid_to_file(const char *callerid_setting)
-{
-       char callerid_file[FILENAME_MAX];
-
-       snprintf(callerid_file, sizeof(callerid_file), "%s%s",
-                                       CALLERID_BASE, callerid_setting);
-
-       if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
-               rename(ALLOWED_FLAG_FILE, callerid_file);
-       else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
-               rename(RESTRICTED_FLAG_FILE, callerid_file);
-       else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-               rename(NONE_FLAG_FILE, callerid_file);
-       else
-               generate_flag_file(callerid_file);
-}
-
-static uint32_t callerid_from_file(void)
-{
-       if (g_file_test(ALLOWED_FLAG_FILE, G_FILE_TEST_EXISTS))
-               return CALL_FLAG_PRESENTATION_ALLOWED;
-       else if (g_file_test(RESTRICTED_FLAG_FILE, G_FILE_TEST_EXISTS))
-               return CALL_FLAG_PRESENTATION_RESTRICTED;
-       else if (g_file_test(NONE_FLAG_FILE, G_FILE_TEST_EXISTS))
-               return CALL_FLAG_NONE;
-       else
-               return CALL_FLAG_NONE;
-}
-
-static DBusMessage *set_callerid(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       const char *callerid_setting;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING,
-                                               &callerid_setting,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (g_str_equal(callerid_setting, "allowed") ||
-                       g_str_equal(callerid_setting, "restricted") ||
-                       g_str_equal(callerid_setting, "none")) {
-               save_callerid_to_file(callerid_setting);
-               callerid = get_callflag(callerid_setting);
-               DBG("telephony-maemo setting callerid flag: %s",
-                                                       callerid_setting);
-               return dbus_message_new_method_return(msg);
-       }
-
-       error("telephony-maemo: invalid argument %s for method call"
-                                       " SetCallerId", callerid_setting);
-               return btd_error_invalid_args(msg);
-}
-
-static const GDBusMethodTable telephony_maemo_methods[] = {
-       { GDBUS_ASYNC_METHOD("SetCallerId",
-                               GDBUS_ARGS({ "id", "s" }), NULL,
-                               set_callerid) },
-       { }
-};
-
-static void handle_modem_state(DBusMessage *msg)
-{
-       const char *state;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
-                                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected modem state parameters");
-               return;
-       }
-
-       DBG("SSC modem state: %s", state);
-
-       if (calls != NULL || get_calls_active)
-               return;
-
-       if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
-               csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusMessage *reply = dbus_pending_call_steal_reply(call);
-       DBusError err;
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("get_modem_status: %s, %s", err.name, err.message);
-               dbus_error_free(&err);
-       } else
-               handle_modem_state(reply);
-
-       dbus_message_unref(reply);
-}
-
-static DBusHandlerResult signal_filter(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *path = dbus_message_get_path(msg);
-
-       if (dbus_message_get_type(msg) != DBUS_MESSAGE_TYPE_SIGNAL)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Coming"))
-               handle_incoming_call(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE, "Created"))
-               handle_outgoing_call(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INTERFACE,
-                                                       "CreateRequested"))
-               handle_create_requested(msg);
-       else if (dbus_message_is_signal(msg, CSD_CALL_INSTANCE, "CallStatus"))
-               handle_call_status(msg, path);
-       else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Joined"))
-               handle_conference(msg, TRUE);
-       else if (dbus_message_is_signal(msg, CSD_CALL_CONFERENCE, "Left"))
-               handle_conference(msg, FALSE);
-       else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-                                       "registration_status_change"))
-               handle_registration_status_change(msg);
-       else if (dbus_message_is_signal(msg, NETWORK_INTERFACE,
-                                       "signal_strength_change"))
-               handle_signal_strength_change(msg);
-       else if (dbus_message_is_signal(msg, "org.freedesktop.Hal.Device",
-                                       "PropertyModified"))
-               handle_hal_property_modified(msg);
-       else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
-                                               "modem_state_changed_ind"))
-               handle_modem_state(msg);
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-int telephony_init(void)
-{
-       const char *battery_cap = "battery";
-       uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-                               AG_FEATURE_INBAND_RINGTONE |
-                               AG_FEATURE_REJECT_A_CALL |
-                               AG_FEATURE_ENHANCED_CALL_STATUS |
-                               AG_FEATURE_ENHANCED_CALL_CONTROL |
-                               AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-                               AG_FEATURE_THREE_WAY_CALLING;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-       if (!dbus_connection_add_filter(connection, signal_filter,
-                                               NULL, NULL))
-               error("Can't add signal filter");
-
-       dbus_bus_add_match(connection,
-                       "type=signal,interface=" CSD_CALL_INTERFACE, NULL);
-       dbus_bus_add_match(connection,
-                       "type=signal,interface=" CSD_CALL_INSTANCE, NULL);
-       dbus_bus_add_match(connection,
-                       "type=signal,interface=" CSD_CALL_CONFERENCE, NULL);
-       dbus_bus_add_match(connection,
-                       "type=signal,interface=" NETWORK_INTERFACE, NULL);
-       dbus_bus_add_match(connection,
-                               "type=signal,interface=" SSC_DBUS_IFACE
-                               ",member=modem_state_changed_ind", NULL);
-
-       if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
-                                       "get_modem_state", modem_state_reply,
-                                       NULL, DBUS_TYPE_INVALID) < 0)
-               error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
-       generate_flag_file(NONE_FLAG_FILE);
-       callerid = callerid_from_file();
-
-       if (!g_dbus_register_interface(connection, TELEPHONY_MAEMO_PATH,
-                       TELEPHONY_MAEMO_INTERFACE, telephony_maemo_methods,
-                       NULL, NULL, NULL, NULL)) {
-               error("telephony-maemo interface %s init failed on path %s",
-                       TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-       }
-
-       DBG("telephony-maemo registering %s interface on path %s",
-                       TELEPHONY_MAEMO_INTERFACE, TELEPHONY_MAEMO_PATH);
-
-       telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
-                                                               chld_str);
-       if (send_method_call("org.freedesktop.Hal",
-                               "/org/freedesktop/Hal/Manager",
-                               "org.freedesktop.Hal.Manager",
-                               "FindDeviceByCapability",
-                               hal_find_device_reply, NULL,
-                               DBUS_TYPE_STRING, &battery_cap,
-                               DBUS_TYPE_INVALID) < 0)
-               error("Unable to send HAL method call");
-
-       return 0;
-}
-
-void telephony_exit(void)
-{
-       g_slist_foreach(calls, (GFunc) csd_call_free, NULL);
-       g_slist_free(calls);
-       calls = NULL;
-
-       dbus_connection_remove_filter(connection, signal_filter, NULL);
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       telephony_deinit();
-}
diff --git a/audio/telephony-maemo6.c b/audio/telephony-maemo6.c
deleted file mode 100644 (file)
index 0727ffe..0000000
+++ /dev/null
@@ -1,2200 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "log.h"
-#include "telephony.h"
-#include "error.h"
-
-/* SSC D-Bus definitions */
-#define SSC_DBUS_NAME  "com.nokia.phone.SSC"
-#define SSC_DBUS_IFACE "com.nokia.phone.SSC"
-#define SSC_DBUS_PATH  "/com/nokia/phone/SSC"
-
-/* libcsnet D-Bus definitions */
-#define CSD_CSNET_BUS_NAME     "com.nokia.csd.CSNet"
-#define CSD_CSNET_PATH         "/com/nokia/csd/csnet"
-#define CSD_CSNET_IFACE                "com.nokia.csd.CSNet"
-#define CSD_CSNET_REGISTRATION "com.nokia.csd.CSNet.NetworkRegistration"
-#define CSD_CSNET_OPERATOR     "com.nokia.csd.CSNet.NetworkOperator"
-#define CSD_CSNET_SIGNAL       "com.nokia.csd.CSNet.SignalStrength"
-
-enum net_registration_status {
-       NETWORK_REG_STATUS_HOME,
-       NETWORK_REG_STATUS_ROAMING,
-       NETWORK_REG_STATUS_OFFLINE,
-       NETWORK_REG_STATUS_SEARCHING,
-       NETWORK_REG_STATUS_NO_SIM,
-       NETWORK_REG_STATUS_POWEROFF,
-       NETWORK_REG_STATUS_POWERSAFE,
-       NETWORK_REG_STATUS_NO_COVERAGE,
-       NETWORK_REG_STATUS_REJECTED,
-       NETWORK_REG_STATUS_UNKOWN
-};
-
-/* CSD CALL plugin D-Bus definitions */
-#define CSD_CALL_BUS_NAME      "com.nokia.csd.Call"
-#define CSD_CALL_INTERFACE     "com.nokia.csd.Call"
-#define CSD_CALL_INSTANCE      "com.nokia.csd.Call.Instance"
-#define CSD_CALL_CONFERENCE    "com.nokia.csd.Call.Conference"
-#define CSD_CALL_PATH          "/com/nokia/csd/call"
-#define CSD_CALL_CONFERENCE_PATH "/com/nokia/csd/call/conference"
-
-/* Call status values as exported by the CSD CALL plugin */
-#define CSD_CALL_STATUS_IDLE                   0
-#define CSD_CALL_STATUS_CREATE                 1
-#define CSD_CALL_STATUS_COMING                 2
-#define CSD_CALL_STATUS_PROCEEDING             3
-#define CSD_CALL_STATUS_MO_ALERTING            4
-#define CSD_CALL_STATUS_MT_ALERTING            5
-#define CSD_CALL_STATUS_WAITING                        6
-#define CSD_CALL_STATUS_ANSWERED               7
-#define CSD_CALL_STATUS_ACTIVE                 8
-#define CSD_CALL_STATUS_MO_RELEASE             9
-#define CSD_CALL_STATUS_MT_RELEASE             10
-#define CSD_CALL_STATUS_HOLD_INITIATED         11
-#define CSD_CALL_STATUS_HOLD                   12
-#define CSD_CALL_STATUS_RETRIEVE_INITIATED     13
-#define CSD_CALL_STATUS_RECONNECT_PENDING      14
-#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
-
-/* SIM Phonebook D-Bus definitions */
-#define CSD_SIMPB_BUS_NAME                     "com.nokia.csd.SIM"
-#define CSD_SIMPB_INTERFACE                    "com.nokia.csd.SIM.Phonebook"
-#define CSD_SIMPB_PATH                         "/com/nokia/csd/sim/phonebook"
-
-#define CSD_SIMPB_TYPE_ADN                     "ADN"
-#define CSD_SIMPB_TYPE_FDN                     "FDN"
-#define CSD_SIMPB_TYPE_SDN                     "SDN"
-#define CSD_SIMPB_TYPE_VMBX                    "VMBX"
-#define CSD_SIMPB_TYPE_MBDN                    "MBDN"
-#define CSD_SIMPB_TYPE_EN                      "EN"
-#define CSD_SIMPB_TYPE_MSISDN                  "MSISDN"
-
-/* OHM plugin D-Bus definitions */
-#define OHM_BUS_NAME           "com.nokia.NonGraphicFeedback1"
-#define OHM_INTERFACE          "com.nokia.NonGraphicFeedback1"
-#define OHM_PATH               "/com/nokia/NonGraphicFeedback1"
-
-/* tone-genenerator D-Bus definitions */
-#define TONEGEN_BUS_NAME       "com.Nokia.Telephony.Tones"
-#define TONEGEN_INTERFACE      "com.Nokia.Telephony.Tones"
-#define TONEGEN_PATH           "/com/Nokia/Telephony/Tones"
-
-/* tone-generator DTMF definitions */
-#define DTMF_ASTERISK   10
-#define DTMF_HASHMARK   11
-#define DTMF_A          12
-#define DTMF_B          13
-#define DTMF_C          14
-#define DTMF_D          15
-
-#define FEEDBACK_TONE_DURATION                 200
-
-struct csd_call {
-       char *object_path;
-       int status;
-       gboolean originating;
-       gboolean emergency;
-       gboolean on_hold;
-       gboolean conference;
-       char *number;
-       gboolean setup;
-};
-
-static struct {
-       char *operator_name;
-       uint8_t status;
-       int32_t signal_bars;
-} net = {
-       .operator_name = NULL,
-       .status = NETWORK_REG_STATUS_UNKOWN,
-       /* Init as 0 meaning inactive mode. In modem power off state
-        * can be be -1, but we treat all values as 0s regardless
-        * inactive or power off. */
-       .signal_bars = 0,
-};
-
-struct pending_req {
-       DBusPendingCall *call;
-       void *user_data;
-};
-
-static int get_property(const char *iface, const char *prop);
-
-static DBusConnection *connection = NULL;
-
-static GSList *calls = NULL;
-static GSList *watches = NULL;
-static GSList *pending = NULL;
-
-/* Reference count for determining the call indicator status */
-static GSList *active_calls = NULL;
-
-/* Queue of DTMF tones to play */
-static GSList *tones = NULL;
-static guint create_tones_timer = 0;
-
-static char *msisdn = NULL;    /* Subscriber number */
-static char *vmbx = NULL;      /* Voice mailbox number */
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;   /* "battery.charge_level.current" */
-static int battchg_last = -1;  /* "battery.charge_level.last_full" */
-static int battchg_design = -1;        /* "battery.charge_level.design" */
-
-static gboolean get_calls_active = FALSE;
-
-static gboolean events_enabled = FALSE;
-
-/* Supported set of call hold operations */
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-
-/* Timer for tracking call creation requests */
-static guint create_request_timer = 0;
-
-static struct indicator maemo_indicators[] =
-{
-       { "battchg",    "0-5",  5,      TRUE },
-       /* signal strength in terms of bars */
-       { "signal",     "0-5",  0,      TRUE },
-       { "service",    "0,1",  0,      TRUE },
-       { "call",       "0,1",  0,      TRUE },
-       { "callsetup",  "0-3",  0,      TRUE },
-       { "callheld",   "0-2",  0,      FALSE },
-       { "roam",       "0,1",  0,      TRUE },
-       { NULL }
-};
-
-static char *call_status_str[] = {
-       "IDLE",
-       "CREATE",
-       "COMING",
-       "PROCEEDING",
-       "MO_ALERTING",
-       "MT_ALERTING",
-       "WAITING",
-       "ANSWERED",
-       "ACTIVE",
-       "MO_RELEASE",
-       "MT_RELEASE",
-       "HOLD_INITIATED",
-       "HOLD",
-       "RETRIEVE_INITIATED",
-       "RECONNECT_PENDING",
-       "TERMINATED",
-       "SWAP_INITIATED",
-       "???"
-};
-
-static int send_method_call(const char *dest, const char *path,
-                               const char *interface, const char *method,
-                               DBusPendingCallNotifyFunction cb,
-                               void *user_data, int type, ...)
-{
-       DBusMessage *msg;
-       DBusPendingCall *call;
-       va_list args;
-       struct pending_req *req;
-
-       msg = dbus_message_new_method_call(dest, path, interface, method);
-       if (!msg) {
-               error("Unable to allocate new D-Bus %s message", method);
-               return -ENOMEM;
-       }
-
-       va_start(args, type);
-
-       if (!dbus_message_append_args_valist(msg, type, args)) {
-               dbus_message_unref(msg);
-               va_end(args);
-               return -EIO;
-       }
-
-       va_end(args);
-
-       if (!cb) {
-               g_dbus_send_message(connection, msg);
-               return 0;
-       }
-
-       if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-               error("Sending %s failed", method);
-               dbus_message_unref(msg);
-               return -EIO;
-       }
-
-       dbus_pending_call_set_notify(call, cb, user_data, NULL);
-
-       req = g_new0(struct pending_req, 1);
-       req->call = call;
-       req->user_data = user_data;
-
-       pending = g_slist_prepend(pending, req);
-       dbus_message_unref(msg);
-
-       return 0;
-}
-
-static struct csd_call *find_call(const char *path)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (g_str_equal(call->object_path, path))
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_non_held_call(void)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status == CSD_CALL_STATUS_IDLE)
-                       continue;
-
-               if (call->status != CSD_CALL_STATUS_HOLD)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_non_idle_call(void)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status != CSD_CALL_STATUS_IDLE)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static struct csd_call *find_call_with_status(int status)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct csd_call *call = l->data;
-
-               if (call->status == status)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static int release_conference(void)
-{
-       DBusMessage *msg;
-
-       DBG("telephony-maemo6: releasing conference call");
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               CSD_CALL_CONFERENCE_PATH,
-                                               CSD_CALL_INSTANCE,
-                                               "Release");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int release_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Release");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int answer_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(CSD_CALL_BUS_NAME,
-                                               call->object_path,
-                                               CSD_CALL_INSTANCE,
-                                               "Answer");
-       if (!msg) {
-               error("Unable to allocate new D-Bus message");
-               return -ENOMEM;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static struct pending_req *find_request(const DBusPendingCall *call)
-{
-       GSList *l;
-
-       for (l = pending; l; l = l->next) {
-               struct pending_req *req = l->data;
-
-               if (req->call == call)
-                       return req;
-       }
-
-       return NULL;
-}
-
-static void pending_req_finalize(void *data)
-{
-       struct pending_req *req = data;
-
-       if (!dbus_pending_call_get_completed(req->call))
-               dbus_pending_call_cancel(req->call);
-
-       dbus_pending_call_unref(req->call);
-       g_free(req);
-}
-
-static void remove_pending(DBusPendingCall *call)
-{
-       struct pending_req *req = find_request(call);
-
-       pending = g_slist_remove(pending, req);
-       pending_req_finalize(req);
-}
-
-static void stop_ringtone_reply(DBusPendingCall *call, void *user_data)
-{
-       struct csd_call *coming = user_data;
-
-       remove_pending(call);
-       answer_call(coming);
-}
-
-static int stop_ringtone_and_answer(struct csd_call *call)
-{
-       int ret;
-
-       ret = send_method_call(OHM_BUS_NAME, OHM_PATH,
-                               OHM_INTERFACE, "StopRingtone",
-                               stop_ringtone_reply, call,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0)
-               return answer_call(call);
-
-       return 0;
-}
-
-static int split_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int unhold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int hold_call(struct csd_call *call)
-{
-       DBusMessage *msg;
-
-       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;
-       }
-
-       g_dbus_send_message(connection, msg);
-
-       return 0;
-}
-
-static int swap_calls(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int create_conference(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int call_transfer(void)
-{
-       DBusMessage *msg;
-
-       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(connection, msg);
-
-       return 0;
-}
-
-static int number_type(const char *number)
-{
-       if (number == NULL)
-               return NUMBER_TYPE_TELEPHONY;
-
-       if (number[0] == '+' || strncmp(number, "00", 2) == 0)
-               return NUMBER_TYPE_INTERNATIONAL;
-
-       return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
-       struct csd_call *coming;
-
-       DBG("telephony-maemo6: device %p connected", telephony_device);
-
-       coming = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-       if (coming) {
-               if (find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-                       telephony_call_waiting_ind(coming->number,
-                                               number_type(coming->number));
-               else
-                       telephony_incoming_call_ind(coming->number,
-                                               number_type(coming->number));
-       }
-}
-
-static void remove_pending_by_data(gpointer data, gpointer user_data)
-{
-       struct pending_req *req = data;
-
-       if (req->user_data == user_data) {
-               pending = g_slist_remove(pending, req);
-               pending_req_finalize(req);
-       }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-       DBG("telephony-maemo6: device %p disconnected", telephony_device);
-       events_enabled = FALSE;
-
-       g_slist_foreach(pending, remove_pending_by_data, telephony_device);
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-       events_enabled = ind == 1 ? TRUE : FALSE;
-
-       telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-       telephony_response_and_hold_rsp(telephony_device,
-                                               CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-       struct csd_call *call;
-       struct csd_call *alerting;
-       int err;
-
-       call = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-       if (!call)
-               call = find_non_idle_call();
-
-       if (!call) {
-               error("No active call");
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       alerting = find_call_with_status(CSD_CALL_STATUS_MO_ALERTING);
-       if (call->on_hold && alerting)
-               err = release_call(alerting);
-       else if (call->conference)
-               err = release_conference();
-       else
-               err = release_call(call);
-
-       if (err < 0)
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       else
-               telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-       struct csd_call *call;
-
-       call = find_call_with_status(CSD_CALL_STATUS_COMING);
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_MT_ALERTING);
-
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-       if (!call)
-               call = find_call_with_status(CSD_CALL_STATUS_WAITING);
-
-       if (!call) {
-               telephony_answer_call_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       if (stop_ringtone_and_answer(call) < 0)
-               telephony_answer_call_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       else
-               telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void create_call_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       void *telephony_device = user_data;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("csd replied with an error: %s, %s",
-                               err.name, err.message);
-               if (g_strcmp0(err.name,
-                               "com.nokia.csd.Call.Error.CSInactive") == 0)
-                       telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_NO_NETWORK_SERVICE);
-               else
-                       telephony_dial_number_rsp(telephony_device,
-                                                       CME_ERROR_AG_FAILURE);
-               dbus_error_free(&err);
-       } else
-               telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-       int ret;
-
-       DBG("telephony-maemo6: last dialed number request");
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "CreateFromLast",
-                               create_call_reply, telephony_device,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0)
-               telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-}
-
-static const char *memory_dial_lookup(int location)
-{
-       if (location == 1)
-               return vmbx;
-       else
-               return NULL;
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-       int ret;
-
-       DBG("telephony-maemo6: dial request to %s", number);
-
-       if (strncmp(number, "*31#", 4) == 0)
-               number += 4;
-       else if (strncmp(number, "#31#", 4) == 0)
-               number += 4;
-       else if (number[0] == '>') {
-               const char *location = &number[1];
-
-               number = memory_dial_lookup(strtol(&number[1], NULL, 0));
-               if (!number) {
-                       error("No number at memory location %s", location);
-                       telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_INVALID_INDEX);
-                       return;
-               }
-       }
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "Create",
-                               create_call_reply, telephony_device,
-                               DBUS_TYPE_STRING, &number,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0)
-               telephony_dial_number_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-}
-
-static void start_dtmf_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("csd replied with an error: %s, %s",
-                               err.name, err.message);
-
-               dbus_error_free(&err);
-       } else
-               send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "StopDTMF",
-                               NULL, NULL,
-                               DBUS_TYPE_INVALID);
-
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void start_dtmf(void *telephony_device, char tone)
-{
-       int ret;
-
-       /*
-        * Stop tone immediately, modem will place it in queue and play
-        * required time.
-        */
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "StartDTMF",
-                               start_dtmf_reply, NULL,
-                               DBUS_TYPE_BYTE, &tone,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               telephony_transmit_dtmf_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int tonegen_startevent(char tone)
-{
-       int ret;
-       dbus_uint32_t event_tone;
-       dbus_int32_t dbm0 = -15;
-       dbus_uint32_t duration = 150;
-
-       switch (tone) {
-       case '*':
-               event_tone = DTMF_ASTERISK;
-               break;
-       case '#':
-               event_tone = DTMF_HASHMARK;
-               break;
-       case 'A':
-               event_tone = DTMF_A;
-               break;
-       case 'B':
-               event_tone = DTMF_B;
-               break;
-       case 'C':
-               event_tone = DTMF_C;
-               break;
-       case 'D':
-               event_tone = DTMF_D;
-               break;
-       default:
-               ret = g_ascii_digit_value(tone);
-               if (ret < 0)
-                       return -EINVAL;
-               event_tone = ret;
-       }
-
-       ret = send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-                               TONEGEN_INTERFACE, "StartEventTone",
-                               NULL, NULL,
-                               DBUS_TYPE_UINT32, &event_tone,
-                               DBUS_TYPE_INT32, &dbm0,
-                               DBUS_TYPE_UINT32, &duration,
-                               DBUS_TYPE_INVALID);
-       return ret;
-}
-
-static gboolean stop_feedback_tone(gpointer user_data)
-{
-       if (g_slist_length(tones) > 0) {
-               gpointer ptone;
-               int ret;
-
-               send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-                               TONEGEN_INTERFACE, "StopTone",
-                               NULL, NULL,
-                               DBUS_TYPE_INVALID);
-
-               ptone = g_slist_nth_data(tones, 0);
-               tones = g_slist_remove(tones, ptone);
-
-               ret = tonegen_startevent(GPOINTER_TO_UINT(ptone));
-               if (ret < 0)
-                       goto done;
-
-               return TRUE;
-       }
-done:
-       return FALSE;
-}
-
-static void tones_timer_notify(gpointer data)
-{
-       send_method_call(TONEGEN_BUS_NAME, TONEGEN_PATH,
-                               TONEGEN_INTERFACE, "StopTone",
-                               NULL, NULL,
-                               DBUS_TYPE_INVALID);
-       g_slist_free(tones);
-       tones = NULL;
-
-       create_tones_timer = 0;
-}
-
-static void start_feedback_tone(char tone)
-{
-       if (!create_tones_timer) {
-               int ret;
-
-               ret = tonegen_startevent(tone);
-               if (ret < 0)
-                       return;
-
-               create_tones_timer = g_timeout_add_full(G_PRIORITY_DEFAULT,
-                                               FEEDBACK_TONE_DURATION,
-                                               stop_feedback_tone,
-                                               NULL,
-                                               tones_timer_notify);
-       } else {
-               glong dtmf_tone = tone;
-
-               DBG("add %c to queue", tone);
-               tones = g_slist_append(tones, GUINT_TO_POINTER(dtmf_tone));
-       }
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-       DBG("telephony-maemo6: transmit dtmf: %c", tone);
-
-       start_dtmf(telephony_device, tone);
-
-       if (!find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-               error("No active call");
-       else
-               start_feedback_tone(tone);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-       DBG("telephony-maemo6: subscriber number request");
-       if (msisdn)
-               telephony_subscriber_number_ind(msisdn,
-                                               number_type(msisdn),
-                                               SUBSCRIBER_SERVICE_VOICE);
-       telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static int csd_status_to_hfp(struct csd_call *call)
-{
-       switch (call->status) {
-       case CSD_CALL_STATUS_IDLE:
-       case CSD_CALL_STATUS_MO_RELEASE:
-       case CSD_CALL_STATUS_MT_RELEASE:
-       case CSD_CALL_STATUS_TERMINATED:
-               return -1;
-       case CSD_CALL_STATUS_CREATE:
-               return CALL_STATUS_DIALING;
-       case CSD_CALL_STATUS_WAITING:
-               return CALL_STATUS_WAITING;
-       case CSD_CALL_STATUS_PROCEEDING:
-               /* PROCEEDING can happen in outgoing/incoming */
-               if (call->originating)
-                       return CALL_STATUS_DIALING;
-
-               /*
-                * PROCEEDING is followed by WAITING CSD status, therefore
-                * second incoming call status indication is set immediately
-                * to waiting.
-                */
-               if (g_slist_length(active_calls) > 0)
-                       return CALL_STATUS_WAITING;
-
-               return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_COMING:
-               if (g_slist_length(active_calls) > 0)
-                       return CALL_STATUS_WAITING;
-
-               return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_MO_ALERTING:
-               return CALL_STATUS_ALERTING;
-       case CSD_CALL_STATUS_MT_ALERTING:
-               return CALL_STATUS_INCOMING;
-       case CSD_CALL_STATUS_ANSWERED:
-       case CSD_CALL_STATUS_ACTIVE:
-       case CSD_CALL_STATUS_RECONNECT_PENDING:
-       case CSD_CALL_STATUS_SWAP_INITIATED:
-       case CSD_CALL_STATUS_HOLD_INITIATED:
-               return CALL_STATUS_ACTIVE;
-       case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-       case CSD_CALL_STATUS_HOLD:
-               return CALL_STATUS_HELD;
-       default:
-               return -1;
-       }
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-       GSList *l;
-       int i;
-
-       DBG("telephony-maemo6: 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;
-
-               status = csd_status_to_hfp(call);
-               if (status < 0)
-                       continue;
-
-               direction = call->originating ?
-                               CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-               multiparty = call->conference ?
-                               CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-               telephony_list_current_call_ind(i, direction, status,
-                                               CALL_MODE_VOICE, multiparty,
-                                               call->number,
-                                               number_type(call->number));
-       }
-
-       telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-       telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-                               net.operator_name ? net.operator_name : "");
-       telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-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);
-       }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-       const char *idx;
-       struct csd_call *call;
-       int err = 0;
-
-       DBG("telephony-maemo6: got call hold request %s", cmd);
-
-       if (strlen(cmd) > 1)
-               idx = &cmd[1];
-       else
-               idx = NULL;
-
-       if (idx)
-               call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-       else
-               call = NULL;
-
-       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);
-               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);
-                       }
-               }
-               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 (err)
-               telephony_call_hold_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-maemo6: got %s NR and EC request",
-                       enable ? "enable" : "disable");
-       telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-       struct csd_call *active, *waiting;
-       int err;
-
-       DBG("telephony-maemo6: 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);
-       if (!waiting)
-               waiting = find_call_with_status(CSD_CALL_STATUS_PROCEEDING);
-
-       active = find_call_with_status(CSD_CALL_STATUS_ACTIVE);
-
-       if (waiting)
-               err = answer_call(waiting);
-       else if (active)
-               err = release_call(active);
-       else
-               err = 0;
-
-       if (err < 0)
-               telephony_key_press_rsp(telephony_device,
-                                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-maemo6: got %s voice dial request",
-                       enable ? "enable" : "disable");
-
-       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static void handle_incoming_call(DBusMessage *msg)
-{
-       const char *number, *call_path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Coming() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       DBG("Incoming call to %s from number %s", call_path, number);
-
-       g_free(call->number);
-       call->number = g_strdup(number);
-
-       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));
-       else
-               telephony_incoming_call_ind(call->number,
-                                               number_type(call->number));
-
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
-}
-
-static void handle_outgoing_call(DBusMessage *msg)
-{
-       const char *number, *call_path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &call_path,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Call.Created() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       DBG("Outgoing call from %s to number %s", call_path, number);
-
-       g_free(call->number);
-       call->number = g_strdup(number);
-
-       if (create_request_timer) {
-               g_source_remove(create_request_timer);
-               create_request_timer = 0;
-       }
-}
-
-static gboolean create_timeout(gpointer user_data)
-{
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_INACTIVE);
-       create_request_timer = 0;
-       return FALSE;
-}
-
-static void handle_create_requested(DBusMessage *msg)
-{
-       DBG("Call.CreateRequested()");
-
-       if (create_request_timer)
-               g_source_remove(create_request_timer);
-
-       create_request_timer = g_timeout_add_seconds(5, create_timeout, NULL);
-
-       telephony_update_indicator(maemo_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-}
-
-static void call_set_status(struct csd_call *call, dbus_uint32_t status)
-{
-       dbus_uint32_t prev_status;
-       int callheld = telephony_get_indicator(maemo_indicators, "callheld");
-
-       prev_status = call->status;
-       DBG("Call %s changed from %s to %s", call->object_path,
-               call_status_str[prev_status], call_status_str[status]);
-
-       if (prev_status == status) {
-               DBG("Ignoring CSD Call state change to existing state");
-               return;
-       }
-
-       call->status = (int) status;
-
-       switch (status) {
-       case CSD_CALL_STATUS_IDLE:
-               if (call->setup) {
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-                       if (!call->originating)
-                               telephony_calling_stopped_ind();
-               }
-
-               g_free(call->number);
-               call->number = NULL;
-               call->originating = FALSE;
-               call->emergency = FALSE;
-               call->on_hold = FALSE;
-               call->conference = FALSE;
-               call->setup = FALSE;
-               break;
-       case CSD_CALL_STATUS_CREATE:
-               call->originating = TRUE;
-               call->setup = TRUE;
-               break;
-       case CSD_CALL_STATUS_COMING:
-               call->originating = FALSE;
-               call->setup = TRUE;
-               break;
-       case CSD_CALL_STATUS_PROCEEDING:
-               break;
-       case CSD_CALL_STATUS_MO_ALERTING:
-               telephony_update_indicator(maemo_indicators, "callsetup",
-                                               EV_CALLSETUP_ALERTING);
-               break;
-       case CSD_CALL_STATUS_MT_ALERTING:
-               /* Some headsets expect incoming call notification before they
-                * can send ATA command. When call changed status from waiting
-                * to alerting we need to send missing notification. Otherwise
-                * headsets like Nokia BH-108 or BackBeat 903 are unable to
-                * answer incoming call that was previously waiting. */
-               if (prev_status == CSD_CALL_STATUS_WAITING)
-                       telephony_incoming_call_ind(call->number,
-                                               number_type(call->number));
-               break;
-       case CSD_CALL_STATUS_WAITING:
-               break;
-       case CSD_CALL_STATUS_ANSWERED:
-               break;
-       case CSD_CALL_STATUS_ACTIVE:
-               if (call->on_hold) {
-                       call->on_hold = FALSE;
-                       if (find_call_with_status(CSD_CALL_STATUS_HOLD))
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-                       else
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_NONE);
-               } else {
-                       if (!g_slist_find(active_calls, call))
-                               active_calls = g_slist_prepend(active_calls, call);
-                       if (g_slist_length(active_calls) == 1)
-                               telephony_update_indicator(maemo_indicators,
-                                                               "call",
-                                                               EV_CALL_ACTIVE);
-                       /* Upgrade callheld status if necessary */
-                       if (callheld == EV_CALLHELD_ON_HOLD)
-                               telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-                       if (!call->originating)
-                               telephony_calling_stopped_ind();
-                       call->setup = FALSE;
-               }
-               break;
-       case CSD_CALL_STATUS_MO_RELEASE:
-       case CSD_CALL_STATUS_MT_RELEASE:
-               active_calls = g_slist_remove(active_calls, call);
-               if (g_slist_length(active_calls) == 0)
-                       telephony_update_indicator(maemo_indicators, "call",
-                                                       EV_CALL_INACTIVE);
-
-               if (create_tones_timer)
-                       g_source_remove(create_tones_timer);
-               break;
-       case CSD_CALL_STATUS_HOLD_INITIATED:
-               break;
-       case CSD_CALL_STATUS_HOLD:
-               call->on_hold = TRUE;
-               if (find_non_held_call())
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-               else
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_ON_HOLD);
-               break;
-       case CSD_CALL_STATUS_RETRIEVE_INITIATED:
-               break;
-       case CSD_CALL_STATUS_RECONNECT_PENDING:
-               break;
-       case CSD_CALL_STATUS_TERMINATED:
-               if (call->on_hold &&
-                               !find_call_with_status(CSD_CALL_STATUS_HOLD)) {
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_NONE);
-                       return;
-               }
-
-               if (callheld == EV_CALLHELD_MULTIPLE &&
-                               find_call_with_status(CSD_CALL_STATUS_HOLD) &&
-                               !find_call_with_status(CSD_CALL_STATUS_ACTIVE))
-                       telephony_update_indicator(maemo_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_ON_HOLD);
-               break;
-       case CSD_CALL_STATUS_SWAP_INITIATED:
-               break;
-       default:
-               error("Unknown call status %u", status);
-               break;
-       }
-}
-
-static void handle_call_status(DBusMessage *msg, const char *call_path)
-{
-       struct csd_call *call;
-       dbus_uint32_t status, cause_type, cause;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_UINT32, &status,
-                                       DBUS_TYPE_UINT32, &cause_type,
-                                       DBUS_TYPE_UINT32, &cause,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Instance.CallStatus() signal");
-               return;
-       }
-
-       call = find_call(call_path);
-       if (!call) {
-               error("Didn't find any matching call object for %s",
-                               call_path);
-               return;
-       }
-
-       if (status > 16) {
-               error("Invalid call status %u", status);
-               return;
-       }
-
-       call_set_status(call, status);
-}
-
-static void handle_conference(DBusMessage *msg, gboolean joined)
-{
-       const char *path;
-       struct csd_call *call;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in Conference.%s",
-                                       dbus_message_get_member(msg));
-               return;
-       }
-
-       call = find_call(path);
-       if (!call) {
-               error("Conference signal for unknown call %s", path);
-               return;
-       }
-
-       DBG("Call %s %s the conference", path, joined ? "joined" : "left");
-
-       call->conference = joined;
-}
-
-static uint8_t str2status(const char *state)
-{
-       if (g_strcmp0(state, "Home") == 0)
-               return NETWORK_REG_STATUS_HOME;
-       else if (g_strcmp0(state, "Roaming") == 0)
-               return NETWORK_REG_STATUS_ROAMING;
-       else if (g_strcmp0(state, "Offline") == 0)
-               return NETWORK_REG_STATUS_OFFLINE;
-       else if (g_strcmp0(state, "Searching") == 0)
-               return NETWORK_REG_STATUS_SEARCHING;
-       else if (g_strcmp0(state, "NoSim") == 0)
-               return NETWORK_REG_STATUS_NO_SIM;
-       else if (g_strcmp0(state, "Poweroff") == 0)
-               return NETWORK_REG_STATUS_POWEROFF;
-       else if (g_strcmp0(state, "Powersafe") == 0)
-               return NETWORK_REG_STATUS_POWERSAFE;
-       else if (g_strcmp0(state, "NoCoverage") == 0)
-               return NETWORK_REG_STATUS_NO_COVERAGE;
-       else if (g_strcmp0(state, "Reject") == 0)
-               return NETWORK_REG_STATUS_REJECTED;
-       else
-               return NETWORK_REG_STATUS_UNKOWN;
-}
-
-static void update_registration_status(const char *status)
-{
-       uint8_t new_status;
-
-       new_status = str2status(status);
-
-       if (net.status == new_status)
-               return;
-
-       switch (new_status) {
-       case NETWORK_REG_STATUS_HOME:
-               telephony_update_indicator(maemo_indicators, "roam",
-                                                       EV_ROAM_INACTIVE);
-               if (net.status > NETWORK_REG_STATUS_ROAMING)
-                       telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_PRESENT);
-               break;
-       case NETWORK_REG_STATUS_ROAMING:
-               telephony_update_indicator(maemo_indicators, "roam",
-                                                       EV_ROAM_ACTIVE);
-               if (net.status > NETWORK_REG_STATUS_ROAMING)
-                       telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_PRESENT);
-               break;
-       case NETWORK_REG_STATUS_OFFLINE:
-       case NETWORK_REG_STATUS_SEARCHING:
-       case NETWORK_REG_STATUS_NO_SIM:
-       case NETWORK_REG_STATUS_POWEROFF:
-       case NETWORK_REG_STATUS_POWERSAFE:
-       case NETWORK_REG_STATUS_NO_COVERAGE:
-       case NETWORK_REG_STATUS_REJECTED:
-       case NETWORK_REG_STATUS_UNKOWN:
-               if (net.status < NETWORK_REG_STATUS_OFFLINE)
-                       telephony_update_indicator(maemo_indicators,
-                                                       "service",
-                                                       EV_SERVICE_NONE);
-               break;
-       }
-
-       net.status = new_status;
-
-       DBG("telephony-maemo6: registration status changed: %s", status);
-}
-
-static void handle_registration_changed(DBusMessage *msg)
-{
-       const char *status;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &status,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in RegistrationChanged");
-               return;
-       }
-
-       update_registration_status(status);
-}
-
-static void update_signal_strength(int32_t signal_bars)
-{
-       if (signal_bars < 0) {
-               DBG("signal strength smaller than expected: %d < 0",
-                                                               signal_bars);
-               signal_bars = 0;
-       } else if (signal_bars > 5) {
-               DBG("signal strength greater than expected: %d > 5",
-                                                               signal_bars);
-               signal_bars = 5;
-       }
-
-       if (net.signal_bars == signal_bars)
-               return;
-
-       telephony_update_indicator(maemo_indicators, "signal", signal_bars);
-
-       net.signal_bars = signal_bars;
-       DBG("telephony-maemo6: signal strength updated: %d/5", signal_bars);
-}
-
-static void handle_signal_bars_changed(DBusMessage *msg)
-{
-       int32_t signal_bars;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_INT32, &signal_bars,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in SignalBarsChanged");
-               return;
-       }
-
-       update_signal_strength(signal_bars);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-                                       int first_arg_type, ...)
-{
-       int type;
-       va_list ap;
-
-       va_start(ap, first_arg_type);
-
-       for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-                       type = va_arg(ap, int)) {
-               void *value = va_arg(ap, void *);
-               int real_type = dbus_message_iter_get_arg_type(iter);
-
-               if (real_type != type) {
-                       error("iter_get_basic_args: expected %c but got %c",
-                                       (char) type, (char) real_type);
-                       break;
-               }
-
-               dbus_message_iter_get_basic(iter, value);
-               dbus_message_iter_next(iter);
-       }
-
-       va_end(ap);
-
-       return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       dbus_int32_t level;
-       int *value = user_data;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       if (!dbus_message_get_args(reply, NULL,
-                               DBUS_TYPE_INT32, &level,
-                               DBUS_TYPE_INVALID)) {
-               error("Unexpected args in hald reply");
-               goto done;
-       }
-
-       *value = (int) level;
-
-       if (value == &battchg_last)
-               DBG("telephony-maemo6: battery.charge_level.last_full is %d",
-                               *value);
-       else if (value == &battchg_design)
-               DBG("telephony-maemo6: battery.charge_level.design is %d",
-                               *value);
-       else
-               DBG("telephony-maemo6: battery.charge_level.current is %d",
-                               *value);
-
-       if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-               int new, max;
-
-               if (battchg_last > 0)
-                       max = battchg_last;
-               else
-                       max = battchg_design;
-
-               new = battchg_cur * 5 / max;
-
-               telephony_update_indicator(maemo_indicators, "battchg", new);
-       }
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-       send_method_call("org.freedesktop.Hal", path,
-                               "org.freedesktop.Hal.Device",
-                               "GetPropertyInteger",
-                               hal_battery_level_reply, user_data,
-                               DBUS_TYPE_STRING, &key,
-                               DBUS_TYPE_INVALID);
-}
-
-static void handle_hal_property_modified(DBusMessage *msg)
-{
-       DBusMessageIter iter, array;
-       dbus_int32_t num_changes;
-       const char *path;
-
-       path = dbus_message_get_path(msg);
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return;
-       }
-
-       dbus_message_iter_get_basic(&iter, &num_changes);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return;
-       }
-
-       dbus_message_iter_recurse(&iter, &array);
-
-       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-               DBusMessageIter prop;
-               const char *name;
-               dbus_bool_t added, removed;
-
-               dbus_message_iter_recurse(&array, &prop);
-
-               if (!iter_get_basic_args(&prop,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_BOOLEAN, &added,
-                                       DBUS_TYPE_BOOLEAN, &removed,
-                                       DBUS_TYPE_INVALID)) {
-                       error("Invalid hal PropertyModified parameters");
-                       break;
-               }
-
-               if (g_str_equal(name, "battery.charge_level.last_full"))
-                       hal_get_integer(path, name, &battchg_last);
-               else if (g_str_equal(name, "battery.charge_level.current"))
-                       hal_get_integer(path, name, &battchg_cur);
-               else if (g_str_equal(name, "battery.charge_level.design"))
-                       hal_get_integer(path, name, &battchg_design);
-
-               dbus_message_iter_next(&array);
-       }
-}
-
-static void csd_call_free(void *data)
-{
-       struct csd_call *call = data;
-
-       if (!call)
-               return;
-
-       g_free(call->object_path);
-       g_free(call->number);
-
-       g_slist_foreach(pending, remove_pending_by_data, call);
-
-       g_free(call);
-}
-
-static void parse_call_list(DBusMessageIter *iter)
-{
-       do {
-               DBusMessageIter call_iter;
-               struct csd_call *call;
-               const char *object_path, *number;
-               dbus_uint32_t status;
-               dbus_bool_t originating, terminating, emerg, on_hold, conf;
-
-               if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRUCT) {
-                       error("Unexpected signature in GetCallInfoAll reply");
-                       break;
-               }
-
-               dbus_message_iter_recurse(iter, &call_iter);
-
-               if (!iter_get_basic_args(&call_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &object_path,
-                                       DBUS_TYPE_UINT32, &status,
-                                       DBUS_TYPE_BOOLEAN, &originating,
-                                       DBUS_TYPE_BOOLEAN, &terminating,
-                                       DBUS_TYPE_BOOLEAN, &emerg,
-                                       DBUS_TYPE_BOOLEAN, &on_hold,
-                                       DBUS_TYPE_BOOLEAN, &conf,
-                                       DBUS_TYPE_STRING, &number,
-                                       DBUS_TYPE_INVALID)) {
-                       error("Parsing call D-Bus parameters failed");
-                       break;
-               }
-
-               call = find_call(object_path);
-               if (!call) {
-                       call = g_new0(struct csd_call, 1);
-                       call->object_path = g_strdup(object_path);
-                       calls = g_slist_append(calls, call);
-                       DBG("telephony-maemo6: new csd call instance at %s",
-                                                               object_path);
-               }
-
-               if (status == CSD_CALL_STATUS_IDLE)
-                       continue;
-
-               /* CSD gives incorrect call_hold property sometimes */
-               if ((call->status != CSD_CALL_STATUS_HOLD && on_hold) ||
-                               (call->status == CSD_CALL_STATUS_HOLD &&
-                                                               !on_hold)) {
-                       error("Conflicting call status and on_hold property!");
-                       on_hold = call->status == CSD_CALL_STATUS_HOLD;
-               }
-
-               call->originating = originating;
-               call->on_hold = on_hold;
-               call->conference = conf;
-               g_free(call->number);
-               call->number = g_strdup(number);
-
-               /* Update indicators */
-               call_set_status(call, status);
-
-       } while (dbus_message_iter_next(iter));
-}
-
-static void update_operator_name(const char *name)
-{
-       if (name == NULL)
-               return;
-
-       g_free(net.operator_name);
-       net.operator_name = g_strndup(name, 16);
-       DBG("telephony-maemo6: operator name updated: %s", name);
-}
-
-static void get_property_reply(DBusPendingCall *call, void *user_data)
-{
-       char *prop = user_data;
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, sub;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("csd replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT) {
-               error("Unexpected signature in Get return");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       if (g_strcmp0(prop, "RegistrationStatus") == 0) {
-               const char *status;
-
-               dbus_message_iter_get_basic(&sub, &status);
-               update_registration_status(status);
-
-               get_property(CSD_CSNET_OPERATOR, "OperatorName");
-               get_property(CSD_CSNET_SIGNAL, "SignalBars");
-       } else if (g_strcmp0(prop, "OperatorName") == 0) {
-               const char *name;
-
-               dbus_message_iter_get_basic(&sub, &name);
-               update_operator_name(name);
-       } else if (g_strcmp0(prop, "SignalBars") == 0) {
-               int32_t signal_bars;
-
-               dbus_message_iter_get_basic(&sub, &signal_bars);
-               update_signal_strength(signal_bars);
-       }
-
-done:
-       g_free(prop);
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static int get_property(const char *iface, const char *prop)
-{
-       return send_method_call(CSD_CSNET_BUS_NAME, CSD_CSNET_PATH,
-                               DBUS_INTERFACE_PROPERTIES, "Get",
-                               get_property_reply, g_strdup(prop),
-                               DBUS_TYPE_STRING, &iface,
-                               DBUS_TYPE_STRING, &prop,
-                               DBUS_TYPE_INVALID);
-}
-
-static void handle_operator_name_changed(DBusMessage *msg)
-{
-       const char *name;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected parameters in OperatorNameChanged");
-               return;
-       }
-
-       update_operator_name(name);
-}
-
-static void call_info_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, sub;
-
-       get_calls_active = FALSE;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("csd replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in GetCallInfoAll return");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       parse_call_list(&sub);
-
-       get_property(CSD_CSNET_REGISTRATION, "RegistrationStatus");
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-
-static void phonebook_read_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError derr;
-       DBusMessage *reply;
-       const char *name, *number, *secondname, *additionalnumber, *email;
-       int index;
-       char **number_type = user_data;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&derr);
-       if (dbus_set_error_from_message(&derr, reply)) {
-               error("%s.ReadFirst replied with an error: %s, %s",
-                               CSD_SIMPB_INTERFACE, derr.name, derr.message);
-               dbus_error_free(&derr);
-               if (number_type == &vmbx)
-                       vmbx = g_strdup(getenv("VMBX_NUMBER"));
-               goto done;
-       }
-
-       dbus_error_init(&derr);
-       if (dbus_message_get_args(reply, NULL,
-                               DBUS_TYPE_INT32, &index,
-                               DBUS_TYPE_STRING, &name,
-                               DBUS_TYPE_STRING, &number,
-                               DBUS_TYPE_STRING, &secondname,
-                               DBUS_TYPE_STRING, &additionalnumber,
-                               DBUS_TYPE_STRING, &email,
-                               DBUS_TYPE_INVALID) == FALSE) {
-               error("Unable to parse %s.ReadFirst arguments: %s, %s",
-                               CSD_SIMPB_INTERFACE, derr.name, derr.message);
-               dbus_error_free(&derr);
-               goto done;
-       }
-
-       if (number_type == &msisdn) {
-               g_free(msisdn);
-               msisdn = g_strdup(number);
-               DBG("Got MSISDN %s (%s)", number, name);
-       } else {
-               g_free(vmbx);
-               vmbx = g_strdup(number);
-               DBG("Got voice mailbox number %s (%s)", number, name);
-       }
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void csd_init(void)
-{
-       const char *pb_type;
-       int ret;
-
-       ret = send_method_call(CSD_CALL_BUS_NAME, CSD_CALL_PATH,
-                               CSD_CALL_INTERFACE, "GetCallInfoAll",
-                               call_info_reply, NULL, DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to sent GetCallInfoAll method call");
-               return;
-       }
-
-       get_calls_active = TRUE;
-
-       pb_type = CSD_SIMPB_TYPE_MSISDN;
-
-       ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
-                               CSD_SIMPB_INTERFACE, "ReadFirst",
-                               phonebook_read_reply, &msisdn,
-                               DBUS_TYPE_STRING, &pb_type,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
-               return;
-       }
-
-       /* Voicemail should be in MBDN index 0 */
-       pb_type = CSD_SIMPB_TYPE_MBDN;
-
-       ret = send_method_call(CSD_SIMPB_BUS_NAME, CSD_SIMPB_PATH,
-                               CSD_SIMPB_INTERFACE, "ReadFirst",
-                               phonebook_read_reply, &vmbx,
-                               DBUS_TYPE_STRING, &pb_type,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0) {
-               error("Unable to send " CSD_SIMPB_INTERFACE ".read()");
-               return;
-       }
-}
-
-static void handle_modem_state(DBusMessage *msg)
-{
-       const char *state;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &state,
-                                                       DBUS_TYPE_INVALID)) {
-               error("Unexpected modem state parameters");
-               return;
-       }
-
-       DBG("SSC modem state: %s", state);
-
-       if (calls != NULL || get_calls_active)
-               return;
-
-       if (g_str_equal(state, "cmt_ready") || g_str_equal(state, "online"))
-               csd_init();
-}
-
-static void modem_state_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusMessage *reply = dbus_pending_call_steal_reply(call);
-       DBusError err;
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("get_modem_state: %s, %s", err.name, err.message);
-               dbus_error_free(&err);
-       } else
-               handle_modem_state(reply);
-
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static gboolean signal_filter(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *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, "org.freedesktop.Hal.Device",
-                                       "PropertyModified"))
-               handle_hal_property_modified(msg);
-       else if (dbus_message_is_signal(msg, SSC_DBUS_IFACE,
-                                               "modem_state_changed_ind"))
-               handle_modem_state(msg);
-
-       return TRUE;
-}
-
-static void add_watch(const char *sender, const char *path,
-                               const char *interface, const char *member)
-{
-       guint watch;
-
-       watch = g_dbus_add_signal_watch(connection, sender, path, interface,
-                                       member, signal_filter, NULL, NULL);
-
-       watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, sub;
-       const char *path;
-       int type;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in FindDeviceByCapability return");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       type = dbus_message_iter_get_arg_type(&sub);
-
-       if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-               error("No hal device with battery capability found");
-               goto done;
-       }
-
-       dbus_message_iter_get_basic(&sub, &path);
-
-       DBG("telephony-maemo6: found battery device at %s", path);
-
-       add_watch(NULL, path, "org.freedesktop.Hal.Device",
-                                                       "PropertyModified");
-
-       hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-       hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-       hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-int telephony_init(void)
-{
-       const char *battery_cap = "battery";
-       uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-                               AG_FEATURE_INBAND_RINGTONE |
-                               AG_FEATURE_REJECT_A_CALL |
-                               AG_FEATURE_ENHANCED_CALL_STATUS |
-                               AG_FEATURE_ENHANCED_CALL_CONTROL |
-                               AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-                               AG_FEATURE_THREE_WAY_CALLING;
-       int i;
-
-       DBG("");
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-       add_watch(NULL, NULL, CSD_CALL_INTERFACE, NULL);
-       add_watch(NULL, NULL, CSD_CALL_INSTANCE, NULL);
-       add_watch(NULL, NULL, CSD_CALL_CONFERENCE, NULL);
-       add_watch(NULL, NULL, CSD_CSNET_REGISTRATION, "RegistrationChanged");
-       add_watch(NULL, NULL, CSD_CSNET_OPERATOR, "OperatorNameChanged");
-       add_watch(NULL, NULL, CSD_CSNET_SIGNAL, "SignalBarsChanged");
-       add_watch(NULL, NULL, SSC_DBUS_IFACE, "modem_state_changed_ind");
-
-       if (send_method_call(SSC_DBUS_NAME, SSC_DBUS_PATH, SSC_DBUS_IFACE,
-                                       "get_modem_state", modem_state_reply,
-                                       NULL, DBUS_TYPE_INVALID) < 0)
-               error("Unable to send " SSC_DBUS_IFACE ".get_modem_state()");
-
-       /* Reset indicators */
-       for (i = 0; maemo_indicators[i].desc != NULL; i++) {
-               if (g_str_equal(maemo_indicators[i].desc, "battchg"))
-                       maemo_indicators[i].val = 5;
-               else
-                       maemo_indicators[i].val = 0;
-       }
-
-       telephony_ready_ind(features, maemo_indicators, BTRH_NOT_SUPPORTED,
-                                                               chld_str);
-       if (send_method_call("org.freedesktop.Hal",
-                               "/org/freedesktop/Hal/Manager",
-                               "org.freedesktop.Hal.Manager",
-                               "FindDeviceByCapability",
-                               hal_find_device_reply, NULL,
-                               DBUS_TYPE_STRING, &battery_cap,
-                               DBUS_TYPE_INVALID) < 0)
-               error("Unable to send HAL method call");
-
-       return 0;
-}
-
-static void remove_watch(gpointer data)
-{
-       g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-void telephony_exit(void)
-{
-       DBG("");
-
-       g_free(net.operator_name);
-       net.operator_name = NULL;
-
-       net.status = NETWORK_REG_STATUS_UNKOWN;
-       net.signal_bars = 0;
-
-       g_slist_free(active_calls);
-       active_calls = NULL;
-
-       g_slist_free_full(calls, csd_call_free);
-       calls = NULL;
-
-       g_slist_free_full(pending, pending_req_finalize);
-       pending = NULL;
-
-       g_slist_free_full(watches, remove_watch);
-       watches = NULL;
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       telephony_deinit();
-}
diff --git a/audio/telephony-ofono.c b/audio/telephony-ofono.c
deleted file mode 100644 (file)
index 961fedd..0000000
+++ /dev/null
@@ -1,1637 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2009-2010  Intel Corporation
- *  Copyright (C) 2006-2009  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <stdint.h>
-#include <glib.h>
-#include <dbus/dbus.h>
-#include <gdbus.h>
-
-#include <bluetooth/sdp.h>
-
-#include "log.h"
-#include "telephony.h"
-
-enum net_registration_status {
-       NETWORK_REG_STATUS_HOME = 0x00,
-       NETWORK_REG_STATUS_ROAM,
-       NETWORK_REG_STATUS_NOSERV
-};
-
-struct voice_call {
-       char *obj_path;
-       int status;
-       gboolean originating;
-       gboolean conference;
-       char *number;
-       guint watch;
-};
-
-static DBusConnection *connection = NULL;
-static char *modem_obj_path = NULL;
-static char *last_dialed_number = NULL;
-static GSList *calls = NULL;
-static GSList *watches = NULL;
-static GSList *pending = NULL;
-
-#define OFONO_BUS_NAME "org.ofono"
-#define OFONO_PATH "/"
-#define OFONO_MODEM_INTERFACE "org.ofono.Modem"
-#define OFONO_MANAGER_INTERFACE "org.ofono.Manager"
-#define OFONO_NETWORKREG_INTERFACE "org.ofono.NetworkRegistration"
-#define OFONO_VCMANAGER_INTERFACE "org.ofono.VoiceCallManager"
-#define OFONO_VC_INTERFACE "org.ofono.VoiceCall"
-
-/* HAL battery namespace key values */
-static int battchg_cur = -1;    /* "battery.charge_level.current" */
-static int battchg_last = -1;   /* "battery.charge_level.last_full" */
-static int battchg_design = -1; /* "battery.charge_level.design" */
-
-static struct {
-       uint8_t status;
-       uint32_t signals_bar;
-       char *operator_name;
-} net = {
-       .status = NETWORK_REG_STATUS_NOSERV,
-       .signals_bar = 0,
-       .operator_name = NULL,
-};
-
-static const char *chld_str = "0,1,1x,2,2x,3,4";
-static char *subscriber_number = NULL;
-
-static gboolean events_enabled = FALSE;
-
-static struct indicator ofono_indicators[] =
-{
-       { "battchg",    "0-5",  5,      TRUE },
-       { "signal",     "0-5",  5,      TRUE },
-       { "service",    "0,1",  1,      TRUE },
-       { "call",       "0,1",  0,      TRUE },
-       { "callsetup",  "0-3",  0,      TRUE },
-       { "callheld",   "0-2",  0,      FALSE },
-       { "roam",       "0,1",  0,      TRUE },
-       { NULL }
-};
-
-static struct voice_call *find_vc(const char *path)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct voice_call *vc = l->data;
-
-               if (g_str_equal(vc->obj_path, path))
-                       return vc;
-       }
-
-       return NULL;
-}
-
-static struct voice_call *find_vc_with_status(int status)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct voice_call *vc = l->data;
-
-               if (vc->status == status)
-                       return vc;
-       }
-
-       return NULL;
-}
-
-static struct voice_call *find_vc_without_status(int status)
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct voice_call *call = l->data;
-
-               if (call->status != status)
-                       return call;
-       }
-
-       return NULL;
-}
-
-static int number_type(const char *number)
-{
-       if (number == NULL)
-               return NUMBER_TYPE_TELEPHONY;
-
-       if (number[0] == '+' || strncmp(number, "00", 2) == 0)
-               return NUMBER_TYPE_INTERNATIONAL;
-
-       return NUMBER_TYPE_TELEPHONY;
-}
-
-void telephony_device_connected(void *telephony_device)
-{
-       struct voice_call *coming;
-
-       DBG("telephony-ofono: device %p connected", telephony_device);
-
-       coming = find_vc_with_status(CALL_STATUS_ALERTING);
-       if (coming) {
-               if (find_vc_with_status(CALL_STATUS_ACTIVE))
-                       telephony_call_waiting_ind(coming->number,
-                                               number_type(coming->number));
-               else
-                       telephony_incoming_call_ind(coming->number,
-                                               number_type(coming->number));
-       }
-}
-
-void telephony_device_disconnected(void *telephony_device)
-{
-       DBG("telephony-ofono: device %p disconnected", telephony_device);
-       events_enabled = FALSE;
-}
-
-void telephony_event_reporting_req(void *telephony_device, int ind)
-{
-       events_enabled = ind == 1 ? TRUE : FALSE;
-
-       telephony_event_reporting_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_response_and_hold_req(void *telephony_device, int rh)
-{
-       telephony_response_and_hold_rsp(telephony_device,
-                                               CME_ERROR_NOT_SUPPORTED);
-}
-
-void telephony_last_dialed_number_req(void *telephony_device)
-{
-       DBG("telephony-ofono: last dialed number request");
-
-       if (last_dialed_number)
-               telephony_dial_number_req(telephony_device, last_dialed_number);
-       else
-               telephony_last_dialed_number_rsp(telephony_device,
-                               CME_ERROR_NOT_ALLOWED);
-}
-
-static int send_method_call(const char *dest, const char *path,
-                                const char *interface, const char *method,
-                                DBusPendingCallNotifyFunction cb,
-                                void *user_data, int type, ...)
-{
-       DBusMessage *msg;
-       DBusPendingCall *call;
-       va_list args;
-
-       msg = dbus_message_new_method_call(dest, path, interface, method);
-       if (!msg) {
-               error("Unable to allocate new D-Bus %s message", method);
-               return -ENOMEM;
-       }
-
-       va_start(args, type);
-
-       if (!dbus_message_append_args_valist(msg, type, args)) {
-               dbus_message_unref(msg);
-               va_end(args);
-               return -EIO;
-       }
-
-       va_end(args);
-
-       if (!cb) {
-               g_dbus_send_message(connection, msg);
-               return 0;
-       }
-
-       if (!dbus_connection_send_with_reply(connection, msg, &call, -1)) {
-               error("Sending %s failed", method);
-               dbus_message_unref(msg);
-               return -EIO;
-       }
-
-       dbus_pending_call_set_notify(call, cb, user_data, NULL);
-       pending = g_slist_prepend(pending, call);
-       dbus_message_unref(msg);
-
-       return 0;
-}
-
-static int answer_call(struct voice_call *vc)
-{
-       DBG("%s", vc->number);
-       return send_method_call(OFONO_BUS_NAME, vc->obj_path,
-                                               OFONO_VC_INTERFACE, "Answer",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_call(struct voice_call *vc)
-{
-       DBG("%s", vc->number);
-       return send_method_call(OFONO_BUS_NAME, vc->obj_path,
-                                               OFONO_VC_INTERFACE, "Hangup",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_answer_calls(void)
-{
-       DBG("");
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "ReleaseAndAnswer",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int split_call(struct voice_call *call)
-{
-       DBG("%s", call->number);
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "PrivateChat",
-                                               NULL, NULL,
-                                               DBUS_TYPE_OBJECT_PATH,
-                                               call->obj_path,
-                                               DBUS_TYPE_INVALID);
-       return -1;
-}
-
-static int swap_calls(void)
-{
-       DBG("");
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "SwapCalls",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int create_conference(void)
-{
-       DBG("");
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "CreateMultiparty",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int release_conference(void)
-{
-       DBG("");
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "HangupMultiparty",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-static int call_transfer(void)
-{
-       DBG("");
-       return send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                                               OFONO_VCMANAGER_INTERFACE,
-                                               "Transfer",
-                                               NULL, NULL, DBUS_TYPE_INVALID);
-}
-
-void telephony_terminate_call_req(void *telephony_device)
-{
-       struct voice_call *call;
-       struct voice_call *alerting;
-       int err;
-
-       call = find_vc_with_status(CALL_STATUS_ACTIVE);
-       if (!call)
-               call = calls->data;
-
-       if (!call) {
-               error("No active call");
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       alerting = find_vc_with_status(CALL_STATUS_ALERTING);
-       if (call->status == CALL_STATUS_HELD && alerting)
-               err = release_call(alerting);
-       else if (call->conference)
-               err = release_conference();
-       else
-               err = release_call(call);
-
-       if (err < 0)
-               telephony_terminate_call_rsp(telephony_device,
-                                               CME_ERROR_AG_FAILURE);
-       else
-               telephony_terminate_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_answer_call_req(void *telephony_device)
-{
-       struct voice_call *vc;
-       int ret;
-
-       vc = find_vc_with_status(CALL_STATUS_INCOMING);
-       if (!vc)
-               vc = find_vc_with_status(CALL_STATUS_ALERTING);
-
-       if (!vc)
-               vc = find_vc_with_status(CALL_STATUS_WAITING);
-
-       if (!vc) {
-               telephony_answer_call_rsp(telephony_device,
-                                       CME_ERROR_NOT_ALLOWED);
-               return;
-       }
-
-       ret = answer_call(vc);
-       if (ret < 0) {
-               telephony_answer_call_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       telephony_answer_call_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_dial_number_req(void *telephony_device, const char *number)
-{
-       const char *clir;
-       int ret;
-
-       DBG("telephony-ofono: dial request to %s", number);
-
-       if (!modem_obj_path) {
-               telephony_dial_number_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       if (!strncmp(number, "*31#", 4)) {
-               number += 4;
-               clir = "enabled";
-       } else if (!strncmp(number, "#31#", 4)) {
-               number += 4;
-               clir =  "disabled";
-       } else
-               clir = "default";
-
-       ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                       OFONO_VCMANAGER_INTERFACE,
-                        "Dial", NULL, NULL,
-                       DBUS_TYPE_STRING, &number,
-                       DBUS_TYPE_STRING, &clir,
-                       DBUS_TYPE_INVALID);
-
-       if (ret < 0)
-               telephony_dial_number_rsp(telephony_device,
-                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_dial_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_transmit_dtmf_req(void *telephony_device, char tone)
-{
-       char *tone_string;
-       int ret;
-
-       DBG("telephony-ofono: transmit dtmf: %c", tone);
-
-       if (!modem_obj_path) {
-               telephony_transmit_dtmf_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-               return;
-       }
-
-       tone_string = g_strdup_printf("%c", tone);
-       ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                       OFONO_VCMANAGER_INTERFACE,
-                       "SendTones", NULL, NULL,
-                       DBUS_TYPE_STRING, &tone_string,
-                       DBUS_TYPE_INVALID);
-       g_free(tone_string);
-
-       if (ret < 0)
-               telephony_transmit_dtmf_rsp(telephony_device,
-                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_transmit_dtmf_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_subscriber_number_req(void *telephony_device)
-{
-       DBG("telephony-ofono: subscriber number request");
-
-       if (subscriber_number)
-               telephony_subscriber_number_ind(subscriber_number,
-                                               NUMBER_TYPE_TELEPHONY,
-                                               SUBSCRIBER_SERVICE_VOICE);
-       telephony_subscriber_number_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_list_current_calls_req(void *telephony_device)
-{
-       GSList *l;
-       int i;
-
-       DBG("telephony-ofono: list current calls request");
-
-       for (l = calls, i = 1; l != NULL; l = l->next, i++) {
-               struct voice_call *vc = l->data;
-               int direction, multiparty;
-
-               direction = vc->originating ?
-                               CALL_DIR_OUTGOING : CALL_DIR_INCOMING;
-
-               multiparty = vc->conference ?
-                               CALL_MULTIPARTY_YES : CALL_MULTIPARTY_NO;
-
-               DBG("call %s direction %d multiparty %d", vc->number,
-                                                       direction, multiparty);
-
-               telephony_list_current_call_ind(i, direction, vc->status,
-                                       CALL_MODE_VOICE, multiparty,
-                                       vc->number, number_type(vc->number));
-       }
-
-       telephony_list_current_calls_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_operator_selection_req(void *telephony_device)
-{
-       DBG("telephony-ofono: operator selection request");
-
-       telephony_operator_selection_ind(OPERATOR_MODE_AUTO,
-                               net.operator_name ? net.operator_name : "");
-       telephony_operator_selection_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-static void foreach_vc_with_status(int status,
-                                       int (*func)(struct voice_call *vc))
-{
-       GSList *l;
-
-       for (l = calls; l != NULL; l = l->next) {
-               struct voice_call *call = l->data;
-
-               if (call->status == status)
-                       func(call);
-       }
-}
-
-void telephony_call_hold_req(void *telephony_device, const char *cmd)
-{
-       const char *idx;
-       struct voice_call *call;
-       int err = 0;
-
-       DBG("telephony-ofono: got call hold request %s", cmd);
-
-       if (strlen(cmd) > 1)
-               idx = &cmd[1];
-       else
-               idx = NULL;
-
-       if (idx)
-               call = g_slist_nth_data(calls, strtol(idx, NULL, 0) - 1);
-       else
-               call = NULL;
-
-       switch (cmd[0]) {
-       case '0':
-               if (find_vc_with_status(CALL_STATUS_WAITING))
-                       foreach_vc_with_status(CALL_STATUS_WAITING,
-                                                               release_call);
-               else
-                       foreach_vc_with_status(CALL_STATUS_HELD, release_call);
-               break;
-       case '1':
-               if (idx) {
-                       if (call)
-                               err = release_call(call);
-                       break;
-               }
-               err = release_answer_calls();
-               break;
-       case '2':
-               if (idx) {
-                       if (call)
-                               err = split_call(call);
-               } else {
-                       call = find_vc_with_status(CALL_STATUS_WAITING);
-
-                       if (call)
-                               err = answer_call(call);
-                       else
-                               err = swap_calls();
-               }
-               break;
-       case '3':
-               if (find_vc_with_status(CALL_STATUS_HELD) ||
-                               find_vc_with_status(CALL_STATUS_WAITING))
-                       err = create_conference();
-               break;
-       case '4':
-               err = call_transfer();
-               break;
-       default:
-               DBG("Unknown call hold request");
-               break;
-       }
-
-       if (err)
-               telephony_call_hold_rsp(telephony_device,
-                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_call_hold_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-ofono: got %s NR and EC request",
-                       enable ? "enable" : "disable");
-
-       telephony_nr_and_ec_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_key_press_req(void *telephony_device, const char *keys)
-{
-       struct voice_call *active, *incoming;
-       int err;
-
-       DBG("telephony-ofono: got key press request for %s", keys);
-
-       incoming = find_vc_with_status(CALL_STATUS_INCOMING);
-
-       active = find_vc_with_status(CALL_STATUS_ACTIVE);
-
-       if (incoming)
-               err = answer_call(incoming);
-       else if (active)
-               err = release_call(active);
-       else
-               err = 0;
-
-       if (err < 0)
-               telephony_key_press_rsp(telephony_device,
-                                                       CME_ERROR_AG_FAILURE);
-       else
-               telephony_key_press_rsp(telephony_device, CME_ERROR_NONE);
-}
-
-void telephony_voice_dial_req(void *telephony_device, gboolean enable)
-{
-       DBG("telephony-ofono: got %s voice dial request",
-                       enable ? "enable" : "disable");
-
-       telephony_voice_dial_rsp(telephony_device, CME_ERROR_NOT_SUPPORTED);
-}
-
-static gboolean iter_get_basic_args(DBusMessageIter *iter,
-                                       int first_arg_type, ...)
-{
-       int type;
-       va_list ap;
-
-       va_start(ap, first_arg_type);
-
-       for (type = first_arg_type; type != DBUS_TYPE_INVALID;
-               type = va_arg(ap, int)) {
-               void *value = va_arg(ap, void *);
-               int real_type = dbus_message_iter_get_arg_type(iter);
-
-               if (real_type != type) {
-                       error("iter_get_basic_args: expected %c but got %c",
-                               (char) type, (char) real_type);
-                       break;
-               }
-
-               dbus_message_iter_get_basic(iter, value);
-               dbus_message_iter_next(iter);
-       }
-
-       va_end(ap);
-
-       return type == DBUS_TYPE_INVALID ? TRUE : FALSE;
-}
-
-static void call_free(void *data)
-{
-       struct voice_call *vc = data;
-
-       DBG("%s", vc->obj_path);
-
-       if (vc->status == CALL_STATUS_ACTIVE)
-               telephony_update_indicator(ofono_indicators, "call",
-                                                       EV_CALL_INACTIVE);
-       else
-               telephony_update_indicator(ofono_indicators, "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-
-       if (vc->status == CALL_STATUS_INCOMING)
-               telephony_calling_stopped_ind();
-
-       g_dbus_remove_watch(connection, vc->watch);
-       g_free(vc->obj_path);
-       g_free(vc->number);
-       g_free(vc);
-}
-
-static gboolean handle_vc_property_changed(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct voice_call *vc = data;
-       const char *obj_path = dbus_message_get_path(msg);
-       DBusMessageIter iter, sub;
-       const char *property, *state;
-
-       DBG("path %s", obj_path);
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-               error("Unexpected signature in vc PropertyChanged signal");
-               return TRUE;
-       }
-
-       dbus_message_iter_get_basic(&iter, &property);
-       DBG("property %s", property);
-
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &sub);
-       if (g_str_equal(property, "State")) {
-               dbus_message_iter_get_basic(&sub, &state);
-               DBG("State %s", state);
-               if (g_str_equal(state, "disconnected")) {
-                       calls = g_slist_remove(calls, vc);
-                       call_free(vc);
-               } else if (g_str_equal(state, "active")) {
-                       telephony_update_indicator(ofono_indicators,
-                                                       "call", EV_CALL_ACTIVE);
-                       telephony_update_indicator(ofono_indicators,
-                                                       "callsetup",
-                                                       EV_CALLSETUP_INACTIVE);
-                       if (vc->status == CALL_STATUS_INCOMING)
-                               telephony_calling_stopped_ind();
-                       vc->status = CALL_STATUS_ACTIVE;
-               } else if (g_str_equal(state, "alerting")) {
-                       telephony_update_indicator(ofono_indicators,
-                                       "callsetup", EV_CALLSETUP_ALERTING);
-                       vc->status = CALL_STATUS_ALERTING;
-                       vc->originating = TRUE;
-               } else if (g_str_equal(state, "incoming")) {
-                       /* state change from waiting to incoming */
-                       telephony_update_indicator(ofono_indicators,
-                                       "callsetup", EV_CALLSETUP_INCOMING);
-                       telephony_incoming_call_ind(vc->number,
-                                               NUMBER_TYPE_TELEPHONY);
-                       vc->status = CALL_STATUS_INCOMING;
-                       vc->originating = FALSE;
-               } else if (g_str_equal(state, "held")) {
-                       vc->status = CALL_STATUS_HELD;
-                       if (find_vc_without_status(CALL_STATUS_HELD))
-                               telephony_update_indicator(ofono_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_MULTIPLE);
-                       else
-                               telephony_update_indicator(ofono_indicators,
-                                                       "callheld",
-                                                       EV_CALLHELD_ON_HOLD);
-               }
-       } else if (g_str_equal(property, "Multiparty")) {
-               dbus_bool_t multiparty;
-
-               dbus_message_iter_get_basic(&sub, &multiparty);
-               DBG("Multiparty %s", multiparty ? "True" : "False");
-               vc->conference = multiparty;
-       }
-
-       return TRUE;
-}
-
-static struct voice_call *call_new(const char *path, DBusMessageIter *properties)
-{
-       struct voice_call *vc;
-
-       DBG("%s", path);
-
-       vc = g_new0(struct voice_call, 1);
-       vc->obj_path = g_strdup(path);
-       vc->watch = g_dbus_add_signal_watch(connection, NULL, path,
-                                       OFONO_VC_INTERFACE, "PropertyChanged",
-                                       handle_vc_property_changed, vc, NULL);
-
-       while (dbus_message_iter_get_arg_type(properties)
-                                               == DBUS_TYPE_DICT_ENTRY) {
-               DBusMessageIter entry, value;
-               const char *property, *cli, *state;
-               dbus_bool_t multiparty;
-
-               dbus_message_iter_recurse(properties, &entry);
-               dbus_message_iter_get_basic(&entry, &property);
-
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_recurse(&entry, &value);
-
-               if (g_str_equal(property, "LineIdentification")) {
-                       dbus_message_iter_get_basic(&value, &cli);
-                       DBG("cli %s", cli);
-                       vc->number = g_strdup(cli);
-               } else if (g_str_equal(property, "State")) {
-                       dbus_message_iter_get_basic(&value, &state);
-                       DBG("state %s", state);
-                       if (g_str_equal(state, "incoming"))
-                               vc->status = CALL_STATUS_INCOMING;
-                       else if (g_str_equal(state, "dialing"))
-                               vc->status = CALL_STATUS_DIALING;
-                       else if (g_str_equal(state, "alerting"))
-                               vc->status = CALL_STATUS_ALERTING;
-                       else if (g_str_equal(state, "waiting"))
-                               vc->status = CALL_STATUS_WAITING;
-                       else if (g_str_equal(state, "held"))
-                               vc->status = CALL_STATUS_HELD;
-               } else if (g_str_equal(property, "Multiparty")) {
-                       dbus_message_iter_get_basic(&value, &multiparty);
-                       DBG("Multipary %s", multiparty ? "True" : "False");
-                       vc->conference = multiparty;
-               }
-
-               dbus_message_iter_next(properties);
-       }
-
-       switch (vc->status) {
-       case CALL_STATUS_INCOMING:
-               DBG("CALL_STATUS_INCOMING");
-               vc->originating = FALSE;
-               telephony_update_indicator(ofono_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
-               telephony_incoming_call_ind(vc->number, NUMBER_TYPE_TELEPHONY);
-               break;
-       case CALL_STATUS_DIALING:
-               DBG("CALL_STATUS_DIALING");
-               vc->originating = TRUE;
-               g_free(last_dialed_number);
-               last_dialed_number = g_strdup(vc->number);
-               telephony_update_indicator(ofono_indicators, "callsetup",
-                                       EV_CALLSETUP_OUTGOING);
-               break;
-       case CALL_STATUS_ALERTING:
-               DBG("CALL_STATUS_ALERTING");
-               vc->originating = TRUE;
-               g_free(last_dialed_number);
-               last_dialed_number = g_strdup(vc->number);
-               telephony_update_indicator(ofono_indicators, "callsetup",
-                                       EV_CALLSETUP_ALERTING);
-               break;
-       case CALL_STATUS_WAITING:
-               DBG("CALL_STATUS_WAITING");
-               vc->originating = FALSE;
-               telephony_update_indicator(ofono_indicators, "callsetup",
-                                       EV_CALLSETUP_INCOMING);
-               telephony_call_waiting_ind(vc->number, NUMBER_TYPE_TELEPHONY);
-               break;
-       }
-
-       return vc;
-}
-
-static void remove_pending(DBusPendingCall *call)
-{
-       pending = g_slist_remove(pending, call);
-       dbus_pending_call_unref(call);
-}
-
-static void call_added(const char *path, DBusMessageIter *properties)
-{
-       struct voice_call *vc;
-
-       DBG("%s", path);
-
-       vc = find_vc(path);
-       if (vc)
-               return;
-
-       vc = call_new(path, properties);
-       calls = g_slist_prepend(calls, vc);
-}
-
-static void get_calls_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, entry;
-
-       DBG("");
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("ofono replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &entry);
-
-       while (dbus_message_iter_get_arg_type(&entry)
-                                               == DBUS_TYPE_STRUCT) {
-               const char *path;
-               DBusMessageIter value, properties;
-
-               dbus_message_iter_recurse(&entry, &value);
-               dbus_message_iter_get_basic(&value, &path);
-
-               dbus_message_iter_next(&value);
-               dbus_message_iter_recurse(&value, &properties);
-
-               call_added(path, &properties);
-
-               dbus_message_iter_next(&entry);
-       }
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void handle_network_property(const char *property, DBusMessageIter *variant)
-{
-       const char *status, *operator;
-       unsigned int signals_bar;
-
-       if (g_str_equal(property, "Status")) {
-               dbus_message_iter_get_basic(variant, &status);
-               DBG("Status is %s", status);
-               if (g_str_equal(status, "registered")) {
-                       net.status = NETWORK_REG_STATUS_HOME;
-                       telephony_update_indicator(ofono_indicators,
-                                               "roam", EV_ROAM_INACTIVE);
-                       telephony_update_indicator(ofono_indicators,
-                                               "service", EV_SERVICE_PRESENT);
-               } else if (g_str_equal(status, "roaming")) {
-                       net.status = NETWORK_REG_STATUS_ROAM;
-                       telephony_update_indicator(ofono_indicators,
-                                               "roam", EV_ROAM_ACTIVE);
-                       telephony_update_indicator(ofono_indicators,
-                                               "service", EV_SERVICE_PRESENT);
-               } else {
-                       net.status = NETWORK_REG_STATUS_NOSERV;
-                       telephony_update_indicator(ofono_indicators,
-                                               "roam", EV_ROAM_INACTIVE);
-                       telephony_update_indicator(ofono_indicators,
-                                               "service", EV_SERVICE_NONE);
-               }
-       } else if (g_str_equal(property, "Name")) {
-               dbus_message_iter_get_basic(variant, &operator);
-               DBG("Operator is %s", operator);
-               g_free(net.operator_name);
-               net.operator_name = g_strdup(operator);
-       } else if (g_str_equal(property, "SignalStrength")) {
-               dbus_message_iter_get_basic(variant, &signals_bar);
-               DBG("SignalStrength is %d", signals_bar);
-               net.signals_bar = signals_bar;
-               telephony_update_indicator(ofono_indicators, "signal",
-                                               (signals_bar + 20) / 21);
-       }
-}
-
-static int parse_network_properties(DBusMessageIter *properties)
-{
-       int i;
-
-       /* Reset indicators */
-       for (i = 0; ofono_indicators[i].desc != NULL; i++) {
-               if (g_str_equal(ofono_indicators[i].desc, "battchg"))
-                       ofono_indicators[i].val = 5;
-               else
-                       ofono_indicators[i].val = 0;
-       }
-
-       while (dbus_message_iter_get_arg_type(properties)
-                                               == DBUS_TYPE_DICT_ENTRY) {
-               const char *key;
-               DBusMessageIter value, entry;
-
-               dbus_message_iter_recurse(properties, &entry);
-               dbus_message_iter_get_basic(&entry, &key);
-
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_recurse(&entry, &value);
-
-               handle_network_property(key, &value);
-
-               dbus_message_iter_next(properties);
-       }
-
-       return 0;
-}
-
-static void get_properties_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, properties;
-       int ret = 0;
-
-       DBG("");
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("ofono replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &properties);
-
-       ret = parse_network_properties(&properties);
-       if (ret < 0) {
-               error("Unable to parse %s.GetProperty reply",
-                                               OFONO_NETWORKREG_INTERFACE);
-               goto done;
-       }
-
-       ret = send_method_call(OFONO_BUS_NAME, modem_obj_path,
-                               OFONO_VCMANAGER_INTERFACE, "GetCalls",
-                               get_calls_reply, NULL, DBUS_TYPE_INVALID);
-       if (ret < 0)
-               error("Unable to send %s.GetCalls",
-                                               OFONO_VCMANAGER_INTERFACE);
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void network_found(const char *path)
-{
-       int ret;
-
-       DBG("%s", path);
-
-       modem_obj_path = g_strdup(path);
-
-       ret = send_method_call(OFONO_BUS_NAME, path,
-                               OFONO_NETWORKREG_INTERFACE, "GetProperties",
-                               get_properties_reply, NULL, DBUS_TYPE_INVALID);
-       if (ret < 0)
-               error("Unable to send %s.GetProperties",
-                                               OFONO_NETWORKREG_INTERFACE);
-}
-
-static void modem_removed(const char *path)
-{
-       if (g_strcmp0(modem_obj_path, path) != 0)
-               return;
-
-       DBG("%s", path);
-
-       g_slist_free_full(calls, call_free);
-       calls = NULL;
-
-       g_free(net.operator_name);
-       net.operator_name = NULL;
-       net.status = NETWORK_REG_STATUS_NOSERV;
-       net.signals_bar = 0;
-
-       g_free(modem_obj_path);
-       modem_obj_path = NULL;
-}
-
-static void parse_modem_interfaces(const char *path, DBusMessageIter *ifaces)
-{
-       DBG("%s", path);
-
-       while (dbus_message_iter_get_arg_type(ifaces) == DBUS_TYPE_STRING) {
-               const char *iface;
-
-               dbus_message_iter_get_basic(ifaces, &iface);
-
-               if (g_str_equal(iface, OFONO_NETWORKREG_INTERFACE)) {
-                       network_found(path);
-                       return;
-               }
-
-               dbus_message_iter_next(ifaces);
-       }
-
-       modem_removed(path);
-}
-
-static void modem_added(const char *path, DBusMessageIter *properties)
-{
-       if (modem_obj_path != NULL) {
-               DBG("Ignoring, modem already exist");
-               return;
-       }
-
-       DBG("%s", path);
-
-       while (dbus_message_iter_get_arg_type(properties)
-                                               == DBUS_TYPE_DICT_ENTRY) {
-               const char *key;
-               DBusMessageIter interfaces, value, entry;
-
-               dbus_message_iter_recurse(properties, &entry);
-               dbus_message_iter_get_basic(&entry, &key);
-
-               dbus_message_iter_next(&entry);
-               dbus_message_iter_recurse(&entry, &value);
-
-               if (strcasecmp(key, "Interfaces") != 0)
-                       goto next;
-
-               if (dbus_message_iter_get_arg_type(&value)
-                                                       != DBUS_TYPE_ARRAY) {
-                       error("Invalid Signature");
-                       return;
-               }
-
-               dbus_message_iter_recurse(&value, &interfaces);
-
-               parse_modem_interfaces(path, &interfaces);
-
-               if (modem_obj_path != NULL)
-                       return;
-
-       next:
-               dbus_message_iter_next(properties);
-       }
-}
-
-static void get_modems_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusError err;
-       DBusMessage *reply;
-       DBusMessageIter iter, entry;
-
-       DBG("");
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("ofono replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       /* Skip modem selection if a modem already exist */
-       if (modem_obj_path != NULL)
-               goto done;
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &entry);
-
-       while (dbus_message_iter_get_arg_type(&entry)
-                                               == DBUS_TYPE_STRUCT) {
-               const char *path;
-               DBusMessageIter item, properties;
-
-               dbus_message_iter_recurse(&entry, &item);
-               dbus_message_iter_get_basic(&item, &path);
-
-               dbus_message_iter_next(&item);
-               dbus_message_iter_recurse(&item, &properties);
-
-               modem_added(path, &properties);
-               if (modem_obj_path != NULL)
-                       break;
-
-               dbus_message_iter_next(&entry);
-       }
-
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static gboolean handle_network_property_changed(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessageIter iter, variant;
-       const char *property;
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-               error("Unexpected signature in networkregistration"
-                                       " PropertyChanged signal");
-               return TRUE;
-       }
-       dbus_message_iter_get_basic(&iter, &property);
-       DBG("in handle_registration_property_changed(),"
-                                       " the property is %s", property);
-
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &variant);
-
-       handle_network_property(property, &variant);
-
-       return TRUE;
-}
-
-static void handle_modem_property(const char *path, const char *property,
-                                               DBusMessageIter *variant)
-{
-       DBG("%s", property);
-
-       if (g_str_equal(property, "Interfaces")) {
-               DBusMessageIter interfaces;
-
-               if (dbus_message_iter_get_arg_type(variant)
-                                                       != DBUS_TYPE_ARRAY) {
-                       error("Invalid signature");
-                       return;
-               }
-
-               dbus_message_iter_recurse(variant, &interfaces);
-               parse_modem_interfaces(path, &interfaces);
-       }
-}
-
-static gboolean handle_modem_property_changed(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessageIter iter, variant;
-       const char *property, *path;
-
-       path = dbus_message_get_path(msg);
-
-       /* Ignore if modem already exist and paths doesn't match */
-       if (modem_obj_path != NULL &&
-                               g_str_equal(path, modem_obj_path) == FALSE)
-               return TRUE;
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-               error("Unexpected signature in %s.%s PropertyChanged signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
-       }
-
-       dbus_message_iter_get_basic(&iter, &property);
-
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &variant);
-
-       handle_modem_property(path, property, &variant);
-
-       return TRUE;
-}
-
-static gboolean handle_vcmanager_call_added(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessageIter iter, properties;
-       const char *path = dbus_message_get_path(msg);
-
-       /* Ignore call if modem path doesn't math */
-       if (g_strcmp0(modem_obj_path, path) != 0)
-               return TRUE;
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter)
-                                               != DBUS_TYPE_OBJECT_PATH) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
-       }
-
-       dbus_message_iter_get_basic(&iter, &path);
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &properties);
-
-       call_added(path, &properties);
-
-       return TRUE;
-}
-
-static void call_removed(const char *path)
-{
-       struct voice_call *vc;
-
-       DBG("%s", path);
-
-       vc = find_vc(path);
-       if (vc == NULL)
-               return;
-
-       calls = g_slist_remove(calls, vc);
-       call_free(vc);
-}
-
-static gboolean handle_vcmanager_call_removed(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *path = dbus_message_get_path(msg);
-
-       /* Ignore call if modem path doesn't math */
-       if (g_strcmp0(modem_obj_path, path) != 0)
-               return TRUE;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID)) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
-       }
-
-       call_removed(path);
-
-       return TRUE;
-}
-
-static gboolean handle_manager_modem_added(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessageIter iter, properties;
-       const char *path;
-
-       if (modem_obj_path != NULL)
-               return TRUE;
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter)
-                                               != DBUS_TYPE_OBJECT_PATH) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
-       }
-
-       dbus_message_iter_get_basic(&iter, &path);
-       dbus_message_iter_next(&iter);
-       dbus_message_iter_recurse(&iter, &properties);
-
-       modem_added(path, &properties);
-
-       return TRUE;
-}
-
-static gboolean handle_manager_modem_removed(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *path;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID)) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
-       }
-
-       modem_removed(path);
-
-       return TRUE;
-}
-
-static void hal_battery_level_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusMessage *reply;
-       DBusError err;
-       dbus_int32_t level;
-       int *value = user_data;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_error_init(&err);
-       if (dbus_message_get_args(reply, &err,
-                               DBUS_TYPE_INT32, &level,
-                               DBUS_TYPE_INVALID) == FALSE) {
-               error("Unable to parse GetPropertyInteger reply: %s, %s",
-                                                       err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       *value = (int) level;
-
-       if (value == &battchg_last)
-               DBG("telephony-ofono: battery.charge_level.last_full"
-                                       " is %d", *value);
-       else if (value == &battchg_design)
-               DBG("telephony-ofono: battery.charge_level.design"
-                                       " is %d", *value);
-       else
-               DBG("telephony-ofono: battery.charge_level.current"
-                                       " is %d", *value);
-
-       if ((battchg_design > 0 || battchg_last > 0) && battchg_cur >= 0) {
-               int new, max;
-
-               if (battchg_last > 0)
-                       max = battchg_last;
-               else
-                       max = battchg_design;
-
-               new = battchg_cur * 5 / max;
-
-               telephony_update_indicator(ofono_indicators, "battchg", new);
-       }
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void hal_get_integer(const char *path, const char *key, void *user_data)
-{
-       send_method_call("org.freedesktop.Hal", path,
-                       "org.freedesktop.Hal.Device",
-                       "GetPropertyInteger",
-                       hal_battery_level_reply, user_data,
-                       DBUS_TYPE_STRING, &key,
-                       DBUS_TYPE_INVALID);
-}
-
-static gboolean handle_hal_property_modified(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *path;
-       DBusMessageIter iter, array;
-       dbus_int32_t num_changes;
-
-       path = dbus_message_get_path(msg);
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_INT32) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return TRUE;
-       }
-
-       dbus_message_iter_get_basic(&iter, &num_changes);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in hal PropertyModified signal");
-               return TRUE;
-       }
-
-       dbus_message_iter_recurse(&iter, &array);
-
-       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
-               DBusMessageIter prop;
-               const char *name;
-               dbus_bool_t added, removed;
-
-               dbus_message_iter_recurse(&array, &prop);
-
-               if (!iter_get_basic_args(&prop,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_BOOLEAN, &added,
-                                       DBUS_TYPE_BOOLEAN, &removed,
-                                       DBUS_TYPE_INVALID)) {
-                       error("Invalid hal PropertyModified parameters");
-                       break;
-               }
-
-               if (g_str_equal(name, "battery.charge_level.last_full"))
-                       hal_get_integer(path, name, &battchg_last);
-               else if (g_str_equal(name, "battery.charge_level.current"))
-                       hal_get_integer(path, name, &battchg_cur);
-               else if (g_str_equal(name, "battery.charge_level.design"))
-                       hal_get_integer(path, name, &battchg_design);
-
-               dbus_message_iter_next(&array);
-       }
-
-       return TRUE;
-}
-
-static void add_watch(const char *sender, const char *path,
-                               const char *interface, const char *member,
-                               GDBusSignalFunction function)
-{
-       guint watch;
-
-       watch = g_dbus_add_signal_watch(connection, sender, path, interface,
-                                       member, function, NULL, NULL);
-
-       watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-}
-
-static void hal_find_device_reply(DBusPendingCall *call, void *user_data)
-{
-       DBusMessage *reply;
-       DBusError err;
-       DBusMessageIter iter, sub;
-       int type;
-       const char *path;
-
-       DBG("begin of hal_find_device_reply()");
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&err);
-
-       if (dbus_set_error_from_message(&err, reply)) {
-               error("hald replied with an error: %s, %s",
-                               err.name, err.message);
-               dbus_error_free(&err);
-               goto done;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY) {
-               error("Unexpected signature in hal_find_device_reply()");
-               goto done;
-       }
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       type = dbus_message_iter_get_arg_type(&sub);
-
-       if (type != DBUS_TYPE_OBJECT_PATH && type != DBUS_TYPE_STRING) {
-               error("No hal device with battery capability found");
-               goto done;
-       }
-
-       dbus_message_iter_get_basic(&sub, &path);
-
-       DBG("telephony-ofono: found battery device at %s", path);
-
-       add_watch(NULL, path, "org.freedesktop.Hal.Device",
-                       "PropertyModified", handle_hal_property_modified);
-
-       hal_get_integer(path, "battery.charge_level.last_full", &battchg_last);
-       hal_get_integer(path, "battery.charge_level.current", &battchg_cur);
-       hal_get_integer(path, "battery.charge_level.design", &battchg_design);
-done:
-       dbus_message_unref(reply);
-       remove_pending(call);
-}
-
-static void handle_service_connect(DBusConnection *conn, void *user_data)
-{
-       DBG("telephony-ofono: %s found", OFONO_BUS_NAME);
-
-       send_method_call(OFONO_BUS_NAME, OFONO_PATH,
-                               OFONO_MANAGER_INTERFACE, "GetModems",
-                               get_modems_reply, NULL, DBUS_TYPE_INVALID);
-}
-
-static void handle_service_disconnect(DBusConnection *conn, void *user_data)
-{
-       DBG("telephony-ofono: %s exitted", OFONO_BUS_NAME);
-
-       if (modem_obj_path)
-               modem_removed(modem_obj_path);
-}
-
-int telephony_init(void)
-{
-       uint32_t features = AG_FEATURE_EC_ANDOR_NR |
-                               AG_FEATURE_INBAND_RINGTONE |
-                               AG_FEATURE_REJECT_A_CALL |
-                               AG_FEATURE_ENHANCED_CALL_STATUS |
-                               AG_FEATURE_ENHANCED_CALL_CONTROL |
-                               AG_FEATURE_EXTENDED_ERROR_RESULT_CODES |
-                               AG_FEATURE_THREE_WAY_CALLING;
-       const char *battery_cap = "battery";
-       int ret;
-       guint watch;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_MODEM_INTERFACE,
-                       "PropertyChanged", handle_modem_property_changed);
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_NETWORKREG_INTERFACE,
-                       "PropertyChanged", handle_network_property_changed);
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
-                       "ModemAdded", handle_manager_modem_added);
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_MANAGER_INTERFACE,
-                       "ModemRemoved", handle_manager_modem_removed);
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
-                       "CallAdded", handle_vcmanager_call_added);
-       add_watch(OFONO_BUS_NAME, NULL, OFONO_VCMANAGER_INTERFACE,
-                       "CallRemoved", handle_vcmanager_call_removed);
-
-       watch = g_dbus_add_service_watch(connection, OFONO_BUS_NAME,
-                                               handle_service_connect,
-                                               handle_service_disconnect,
-                                               NULL, NULL);
-       if (watch == 0)
-               return -ENOMEM;
-
-       watches = g_slist_prepend(watches, GUINT_TO_POINTER(watch));
-
-       ret = send_method_call("org.freedesktop.Hal",
-                               "/org/freedesktop/Hal/Manager",
-                               "org.freedesktop.Hal.Manager",
-                               "FindDeviceByCapability",
-                               hal_find_device_reply, NULL,
-                               DBUS_TYPE_STRING, &battery_cap,
-                               DBUS_TYPE_INVALID);
-       if (ret < 0)
-               return ret;
-
-       DBG("telephony_init() successfully");
-
-       telephony_ready_ind(features, ofono_indicators, BTRH_NOT_SUPPORTED,
-                                                               chld_str);
-
-       return ret;
-}
-
-static void remove_watch(gpointer data)
-{
-       g_dbus_remove_watch(connection, GPOINTER_TO_UINT(data));
-}
-
-static void pending_free(void *data)
-{
-       DBusPendingCall *call = data;
-
-       if (!dbus_pending_call_get_completed(call))
-               dbus_pending_call_cancel(call);
-
-       dbus_pending_call_unref(call);
-}
-
-void telephony_exit(void)
-{
-       DBG("");
-
-       g_free(last_dialed_number);
-       last_dialed_number = NULL;
-
-       if (modem_obj_path)
-               modem_removed(modem_obj_path);
-
-       g_slist_free_full(watches, remove_watch);
-       watches = NULL;
-
-       g_slist_free_full(pending, pending_free);
-       pending = NULL;
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       telephony_deinit();
-}
diff --git a/audio/telephony.h b/audio/telephony.h
deleted file mode 100644 (file)
index 73b390c..0000000
+++ /dev/null
@@ -1,244 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <errno.h>
-#include <glib.h>
-
-/* Response and hold values */
-#define BTRH_NOT_SUPPORTED     -2
-#define BTRH_NONE              -1
-#define BTRH_HOLD              0
-#define BTRH_ACCEPT            1
-#define BTRH_REJECT            2
-
-/* HFP feature bits */
-#define AG_FEATURE_THREE_WAY_CALLING           0x0001
-#define AG_FEATURE_EC_ANDOR_NR                 0x0002
-#define AG_FEATURE_VOICE_RECOGNITION           0x0004
-#define AG_FEATURE_INBAND_RINGTONE             0x0008
-#define AG_FEATURE_ATTACH_NUMBER_TO_VOICETAG   0x0010
-#define AG_FEATURE_REJECT_A_CALL               0x0020
-#define AG_FEATURE_ENHANCED_CALL_STATUS                0x0040
-#define AG_FEATURE_ENHANCED_CALL_CONTROL       0x0080
-#define AG_FEATURE_EXTENDED_ERROR_RESULT_CODES 0x0100
-
-#define HF_FEATURE_EC_ANDOR_NR                 0x0001
-#define HF_FEATURE_CALL_WAITING_AND_3WAY       0x0002
-#define HF_FEATURE_CLI_PRESENTATION            0x0004
-#define HF_FEATURE_VOICE_RECOGNITION           0x0008
-#define HF_FEATURE_REMOTE_VOLUME_CONTROL       0x0010
-#define HF_FEATURE_ENHANCED_CALL_STATUS                0x0020
-#define HF_FEATURE_ENHANCED_CALL_CONTROL       0x0040
-
-/* Indicator event values */
-#define EV_SERVICE_NONE                        0
-#define EV_SERVICE_PRESENT             1
-
-#define EV_CALL_INACTIVE               0
-#define EV_CALL_ACTIVE                 1
-
-#define EV_CALLSETUP_INACTIVE          0
-#define EV_CALLSETUP_INCOMING          1
-#define EV_CALLSETUP_OUTGOING          2
-#define EV_CALLSETUP_ALERTING          3
-
-#define EV_CALLHELD_NONE               0
-#define EV_CALLHELD_MULTIPLE           1
-#define EV_CALLHELD_ON_HOLD            2
-
-#define EV_ROAM_INACTIVE               0
-#define EV_ROAM_ACTIVE                 1
-
-/* Call parameters */
-#define CALL_DIR_OUTGOING              0
-#define CALL_DIR_INCOMING              1
-
-#define CALL_STATUS_ACTIVE             0
-#define CALL_STATUS_HELD               1
-#define CALL_STATUS_DIALING            2
-#define CALL_STATUS_ALERTING           3
-#define CALL_STATUS_INCOMING           4
-#define CALL_STATUS_WAITING            5
-
-#define CALL_MODE_VOICE                        0
-#define CALL_MODE_DATA                 1
-#define CALL_MODE_FAX                  2
-
-#define CALL_MULTIPARTY_NO             0
-#define CALL_MULTIPARTY_YES            1
-
-/* Subscriber number parameters */
-#define SUBSCRIBER_SERVICE_VOICE       4
-#define SUBSCRIBER_SERVICE_FAX         5
-
-/* Operator selection mode values */
-#define OPERATOR_MODE_AUTO             0
-#define OPERATOR_MODE_MANUAL           1
-#define OPERATOR_MODE_DEREGISTER       2
-#define OPERATOR_MODE_MANUAL_AUTO      4
-
-/* Some common number types */
-#define NUMBER_TYPE_UNKNOWN            128
-#define NUMBER_TYPE_TELEPHONY          129
-#define NUMBER_TYPE_INTERNATIONAL      145
-#define NUMBER_TYPE_NATIONAL           161
-#define NUMBER_TYPE_VOIP               255
-
-/* Extended Audio Gateway Error Result Codes */
-typedef enum {
-       CME_ERROR_NONE                  = -1,
-       CME_ERROR_AG_FAILURE            = 0,
-       CME_ERROR_NO_PHONE_CONNECTION   = 1,
-       CME_ERROR_NOT_ALLOWED           = 3,
-       CME_ERROR_NOT_SUPPORTED         = 4,
-       CME_ERROR_PH_SIM_PIN_REQUIRED   = 5,
-       CME_ERROR_SIM_NOT_INSERTED      = 10,
-       CME_ERROR_SIM_PIN_REQUIRED      = 11,
-       CME_ERROR_SIM_PUK_REQUIRED      = 12,
-       CME_ERROR_SIM_FAILURE           = 13,
-       CME_ERROR_SIM_BUSY              = 14,
-       CME_ERROR_INCORRECT_PASSWORD    = 16,
-       CME_ERROR_SIM_PIN2_REQUIRED     = 17,
-       CME_ERROR_SIM_PUK2_REQUIRED     = 18,
-       CME_ERROR_MEMORY_FULL           = 20,
-       CME_ERROR_INVALID_INDEX         = 21,
-       CME_ERROR_MEMORY_FAILURE        = 23,
-       CME_ERROR_TEXT_STRING_TOO_LONG  = 24,
-       CME_ERROR_INVALID_TEXT_STRING   = 25,
-       CME_ERROR_DIAL_STRING_TOO_LONG  = 26,
-       CME_ERROR_INVALID_DIAL_STRING   = 27,
-       CME_ERROR_NO_NETWORK_SERVICE    = 30,
-       CME_ERROR_NETWORK_TIMEOUT       = 31,
-       CME_ERROR_NETWORK_NOT_ALLOWED   = 32,
-} cme_error_t;
-
-struct indicator {
-       const char *desc;
-       const char *range;
-       int val;
-       gboolean ignore_redundant;
-};
-
-/* Notify telephony-*.c of connected/disconnected devices. Implemented by
- * telephony-*.c
- */
-void telephony_device_connected(void *telephony_device);
-void telephony_device_disconnected(void *telephony_device);
-
-/* HF requests (sent by the handsfree device). These are implemented by
- * telephony-*.c
- */
-void telephony_event_reporting_req(void *telephony_device, int ind);
-void telephony_response_and_hold_req(void *telephony_device, int rh);
-void telephony_last_dialed_number_req(void *telephony_device);
-void telephony_terminate_call_req(void *telephony_device);
-void telephony_answer_call_req(void *telephony_device);
-void telephony_dial_number_req(void *telephony_device, const char *number);
-void telephony_transmit_dtmf_req(void *telephony_device, char tone);
-void telephony_subscriber_number_req(void *telephony_device);
-void telephony_list_current_calls_req(void *telephony_device);
-void telephony_operator_selection_req(void *telephony_device);
-void telephony_call_hold_req(void *telephony_device, const char *cmd);
-void telephony_nr_and_ec_req(void *telephony_device, gboolean enable);
-void telephony_voice_dial_req(void *telephony_device, gboolean enable);
-void telephony_key_press_req(void *telephony_device, const char *keys);
-
-/* AG responses to HF requests. These are implemented by headset.c */
-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);
-int telephony_last_dialed_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_terminate_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_answer_call_rsp(void *telephony_device, cme_error_t err);
-int telephony_dial_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_transmit_dtmf_rsp(void *telephony_device, cme_error_t err);
-int telephony_subscriber_number_rsp(void *telephony_device, cme_error_t err);
-int telephony_list_current_calls_rsp(void *telephony_device, cme_error_t err);
-int telephony_operator_selection_rsp(void *telephony_device, cme_error_t err);
-int telephony_call_hold_rsp(void *telephony_device, cme_error_t err);
-int telephony_nr_and_ec_rsp(void *telephony_device, cme_error_t err);
-int telephony_voice_dial_rsp(void *telephony_device, cme_error_t err);
-int telephony_key_press_rsp(void *telephony_device, cme_error_t err);
-
-/* Event indications by AG. These are implemented by headset.c */
-int telephony_event_ind(int index);
-int telephony_response_and_hold_ind(int rh);
-int telephony_incoming_call_ind(const char *number, int type);
-int telephony_calling_stopped_ind(void);
-int telephony_ready_ind(uint32_t features, const struct indicator *indicators,
-                       int rh, const char *chld);
-int telephony_deinit(void);
-int telephony_list_current_call_ind(int idx, int dir, int status, int mode,
-                                       int mprty, const char *number,
-                                       int type);
-int telephony_subscriber_number_ind(const char *number, int type,
-                                       int service);
-int telephony_call_waiting_ind(const char *number, int type);
-int telephony_operator_selection_ind(int mode, const char *oper);
-
-/* Helper function for quick indicator updates */
-static inline int telephony_update_indicator(struct indicator *indicators,
-                                               const char *desc,
-                                               int new_val)
-{
-       int i;
-       struct indicator *ind = NULL;
-
-       for (i = 0; indicators[i].desc != NULL; i++) {
-               if (g_str_equal(indicators[i].desc, desc)) {
-                       ind = &indicators[i];
-                       break;
-               }
-       }
-
-       if (!ind)
-               return -ENOENT;
-
-       DBG("Telephony indicator \"%s\" %d->%d", desc, ind->val, new_val);
-
-       if (ind->ignore_redundant && ind->val == new_val) {
-               DBG("Ignoring no-change indication");
-               return 0;
-       }
-
-       ind->val = new_val;
-
-       return telephony_event_ind(i);
-}
-
-static inline int telephony_get_indicator(const struct indicator *indicators,
-                                               const char *desc)
-{
-       int i;
-
-       for (i = 0; indicators[i].desc != NULL; i++) {
-               if (g_str_equal(indicators[i].desc, desc))
-                       return indicators[i].val;
-       }
-
-       return -ENOENT;
-}
-
-int telephony_init(void);
-void telephony_exit(void);
diff --git a/audio/transport.c b/audio/transport.c
deleted file mode 100644 (file)
index b015625..0000000
+++ /dev/null
@@ -1,1147 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2007  Nokia Corporation
- *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/adapter.h"
-#include "../src/dbus-common.h"
-
-#include "log.h"
-#include "error.h"
-#include "device.h"
-#include "avdtp.h"
-#include "media.h"
-#include "transport.h"
-#include "a2dp.h"
-#include "headset.h"
-#include "gateway.h"
-#include "avrcp.h"
-
-#define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport"
-
-struct media_request {
-       DBusMessage             *msg;
-       guint                   id;
-};
-
-struct media_owner {
-       struct media_transport  *transport;
-       struct media_request    *pending;
-       char                    *name;
-       char                    *accesstype;
-       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 media_endpoint   *endpoint;      /* Transport endpoint */
-       GSList                  *owners;        /* Transport owners */
-       uint8_t                 *configuration; /* Transport configuration */
-       int                     size;           /* Transport configuration size */
-       int                     fd;             /* Transport file descriptor */
-       uint16_t                imtu;           /* Transport input mtu */
-       uint16_t                omtu;           /* Transport output mtu */
-       gboolean                read_lock;
-       gboolean                write_lock;
-       gboolean                in_use;
-       guint                   (*resume) (struct media_transport *transport,
-                                       struct media_owner *owner);
-       guint                   (*suspend) (struct media_transport *transport,
-                                       struct media_owner *owner);
-       void                    (*cancel) (struct media_transport *transport,
-                                                               guint id);
-       void                    (*get_properties) (
-                                       struct media_transport *transport,
-                                       DBusMessageIter *dict);
-       int                     (*set_property) (
-                                       struct media_transport *transport,
-                                       const char *property,
-                                       DBusMessageIter *value);
-       GDestroyNotify          destroy;
-       void                    *data;
-};
-
-void media_transport_destroy(struct media_transport *transport)
-{
-       char *path;
-
-       path = g_strdup(transport->path);
-       g_dbus_unregister_interface(transport->conn, path,
-                                               MEDIA_TRANSPORT_INTERFACE);
-
-       g_free(path);
-}
-
-static struct media_request *media_request_create(DBusMessage *msg, guint id)
-{
-       struct media_request *req;
-
-       req = g_new0(struct media_request, 1);
-       req->msg = dbus_message_ref(msg);
-       req->id = id;
-
-       DBG("Request created: method=%s id=%u", dbus_message_get_member(msg),
-                                                                       id);
-
-       return req;
-}
-
-static void media_request_reply(struct media_request *req,
-                                               DBusConnection *conn, int err)
-{
-       DBusMessage *reply;
-
-       DBG("Request %s Reply %s", dbus_message_get_member(req->msg),
-                                                       strerror(err));
-
-       if (!err)
-               reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
-       else
-               reply = g_dbus_create_error(req->msg,
-                                               ERROR_INTERFACE ".Failed",
-                                               "%s", strerror(err));
-
-       g_dbus_send_message(conn, reply);
-}
-
-static gboolean media_transport_release(struct media_transport *transport,
-                                       const char *accesstype)
-{
-       if (g_strstr_len(accesstype, -1, "r") != NULL) {
-               transport->read_lock = FALSE;
-               DBG("Transport %s: read lock released", transport->path);
-       }
-
-       if (g_strstr_len(accesstype, -1, "w") != NULL) {
-               transport->write_lock = FALSE;
-               DBG("Transport %s: write lock released", transport->path);
-       }
-
-       return TRUE;
-}
-
-static void media_owner_remove(struct media_owner *owner)
-{
-       struct media_transport *transport = owner->transport;
-       struct media_request *req = owner->pending;
-
-       if (!req)
-               return;
-
-       DBG("Owner %s Request %s", owner->name,
-                                       dbus_message_get_member(req->msg));
-
-       if (req->id)
-               transport->cancel(transport, req->id);
-
-       owner->pending = NULL;
-       if (req->msg)
-               dbus_message_unref(req->msg);
-
-       g_free(req);
-}
-
-static void media_owner_free(struct media_owner *owner)
-{
-       DBG("Owner %s", owner->name);
-
-       media_owner_remove(owner);
-
-       g_free(owner->name);
-       g_free(owner->accesstype);
-       g_free(owner);
-}
-
-static void media_transport_remove(struct media_transport *transport,
-                                               struct media_owner *owner)
-{
-       DBG("Transport %s Owner %s", transport->path, owner->name);
-
-       media_transport_release(transport, owner->accesstype);
-
-       /* Reply if owner has a pending request */
-       if (owner->pending)
-               media_request_reply(owner->pending, transport->conn, EIO);
-
-       transport->owners = g_slist_remove(transport->owners, owner);
-
-       if (owner->watch)
-               g_dbus_remove_watch(transport->conn, owner->watch);
-
-       media_owner_free(owner);
-
-       /* Suspend if there is no longer any owner */
-       if (transport->owners == NULL && transport->in_use)
-               transport->suspend(transport, NULL);
-}
-
-static gboolean media_transport_set_fd(struct media_transport *transport,
-                                       int fd, uint16_t imtu, uint16_t omtu)
-{
-       if (transport->fd == fd)
-               return TRUE;
-
-       transport->fd = fd;
-       transport->imtu = imtu;
-       transport->omtu = omtu;
-
-       info("%s: fd(%d) ready", transport->path, fd);
-
-       return TRUE;
-}
-
-static void a2dp_resume_complete(struct avdtp *session,
-                               struct avdtp_error *err, void *user_data)
-{
-       struct media_owner *owner = user_data;
-       struct media_request *req = owner->pending;
-       struct media_transport *transport = owner->transport;
-       struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint);
-       struct avdtp_stream *stream;
-       int fd;
-       uint16_t imtu, omtu;
-       gboolean ret;
-
-       req->id = 0;
-
-       if (err)
-               goto fail;
-
-       stream = a2dp_sep_get_stream(sep);
-       if (stream == NULL)
-               goto fail;
-
-       ret = avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, NULL);
-       if (ret == FALSE)
-               goto fail;
-
-       media_transport_set_fd(transport, fd, imtu, omtu);
-
-       if (g_strstr_len(owner->accesstype, -1, "r") == NULL)
-               imtu = 0;
-
-       if (g_strstr_len(owner->accesstype, -1, "w") == NULL)
-               omtu = 0;
-
-       ret = g_dbus_send_reply(transport->conn, req->msg,
-                                               DBUS_TYPE_UNIX_FD, &fd,
-                                               DBUS_TYPE_UINT16, &imtu,
-                                               DBUS_TYPE_UINT16, &omtu,
-                                               DBUS_TYPE_INVALID);
-       if (ret == FALSE)
-               goto fail;
-
-       media_owner_remove(owner);
-
-       return;
-
-fail:
-       media_transport_remove(transport, owner);
-}
-
-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 (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, a2dp->session);
-       if (transport->in_use == FALSE)
-               return 0;
-
-done:
-       return a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner);
-}
-
-static void a2dp_suspend_complete(struct avdtp *session,
-                               struct avdtp_error *err, void *user_data)
-{
-       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 */
-       if (owner->pending) {
-               owner->pending->id = 0;
-               media_request_reply(owner->pending, transport->conn, 0);
-               media_owner_remove(owner);
-       }
-
-       a2dp_sep_unlock(sep, a2dp->session);
-       transport->in_use = FALSE;
-       media_transport_remove(transport, owner);
-}
-
-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, a2dp->session);
-               transport->in_use = FALSE;
-               return 0;
-       }
-
-       return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete, owner);
-}
-
-static void cancel_a2dp(struct media_transport *transport, guint id)
-{
-       a2dp_cancel(transport->device, id);
-}
-
-static void headset_resume_complete(struct audio_device *dev, void *user_data)
-{
-       struct media_owner *owner = user_data;
-       struct media_request *req = owner->pending;
-       struct media_transport *transport = owner->transport;
-       int fd;
-       uint16_t imtu, omtu;
-       gboolean ret;
-
-       req->id = 0;
-
-       if (dev == NULL)
-               goto fail;
-
-       fd = headset_get_sco_fd(dev);
-       if (fd < 0)
-               goto fail;
-
-       imtu = 48;
-       omtu = 48;
-
-       media_transport_set_fd(transport, fd, imtu, omtu);
-
-       if (g_strstr_len(owner->accesstype, -1, "r") == NULL)
-               imtu = 0;
-
-       if (g_strstr_len(owner->accesstype, -1, "w") == NULL)
-               omtu = 0;
-
-       ret = g_dbus_send_reply(transport->conn, req->msg,
-                                               DBUS_TYPE_UNIX_FD, &fd,
-                                               DBUS_TYPE_UINT16, &imtu,
-                                               DBUS_TYPE_UINT16, &omtu,
-                                               DBUS_TYPE_INVALID);
-       if (ret == FALSE)
-               goto fail;
-
-       media_owner_remove(owner);
-
-       return;
-
-fail:
-       media_transport_remove(transport, owner);
-}
-
-static guint resume_headset(struct media_transport *transport,
-                               struct media_owner *owner)
-{
-       struct audio_device *device = transport->device;
-
-       if (transport->in_use == TRUE)
-               goto done;
-
-       transport->in_use = headset_lock(device, HEADSET_LOCK_READ |
-                                               HEADSET_LOCK_WRITE);
-       if (transport->in_use == FALSE)
-               return 0;
-
-done:
-       return headset_request_stream(device, headset_resume_complete,
-                                       owner);
-}
-
-static void headset_suspend_complete(struct audio_device *dev, void *user_data)
-{
-       struct media_owner *owner = user_data;
-       struct media_transport *transport = owner->transport;
-
-       /* Release always succeeds */
-       if (owner->pending) {
-               owner->pending->id = 0;
-               media_request_reply(owner->pending, transport->conn, 0);
-               media_owner_remove(owner);
-       }
-
-       headset_unlock(dev, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE);
-       transport->in_use = FALSE;
-       media_transport_remove(transport, owner);
-}
-
-static guint suspend_headset(struct media_transport *transport,
-                                               struct media_owner *owner)
-{
-       struct audio_device *device = transport->device;
-
-       if (!owner) {
-               headset_unlock(device, HEADSET_LOCK_READ | HEADSET_LOCK_WRITE);
-               transport->in_use = FALSE;
-               return 0;
-       }
-
-       return headset_suspend_stream(device, headset_suspend_complete, owner);
-}
-
-static void cancel_headset(struct media_transport *transport, guint id)
-{
-       headset_cancel_stream(transport->device, id);
-}
-
-static void gateway_resume_complete(struct audio_device *dev, GError *err,
-                                                       void *user_data)
-{
-       struct media_owner *owner = user_data;
-       struct media_request *req = owner->pending;
-       struct media_transport *transport = owner->transport;
-       int fd;
-       uint16_t imtu, omtu;
-       gboolean ret;
-
-       req->id = 0;
-
-       if (dev == NULL)
-               goto fail;
-
-       if (err) {
-               error("Failed to resume gateway: error %s", err->message);
-               goto fail;
-       }
-
-       fd = gateway_get_sco_fd(dev);
-       if (fd < 0)
-               goto fail;
-
-       imtu = 48;
-       omtu = 48;
-
-       media_transport_set_fd(transport, fd, imtu, omtu);
-
-       if (g_strstr_len(owner->accesstype, -1, "r") == NULL)
-               imtu = 0;
-
-       if (g_strstr_len(owner->accesstype, -1, "w") == NULL)
-               omtu = 0;
-
-       ret = g_dbus_send_reply(transport->conn, req->msg,
-                                               DBUS_TYPE_UNIX_FD, &fd,
-                                               DBUS_TYPE_UINT16, &imtu,
-                                               DBUS_TYPE_UINT16, &omtu,
-                                               DBUS_TYPE_INVALID);
-       if (ret == FALSE)
-               goto fail;
-
-       media_owner_remove(owner);
-
-       return;
-
-fail:
-       media_transport_remove(transport, owner);
-}
-
-static guint resume_gateway(struct media_transport *transport,
-                               struct media_owner *owner)
-{
-       struct audio_device *device = transport->device;
-
-       if (transport->in_use == TRUE)
-               goto done;
-
-       transport->in_use = gateway_lock(device, GATEWAY_LOCK_READ |
-                                               GATEWAY_LOCK_WRITE);
-       if (transport->in_use == FALSE)
-               return 0;
-
-done:
-       return gateway_request_stream(device, gateway_resume_complete,
-                                       owner);
-}
-
-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) {
-               owner->pending->id = 0;
-               media_request_reply(owner->pending, transport->conn, 0);
-               media_owner_remove(owner);
-       }
-
-       gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE);
-       transport->in_use = FALSE;
-       media_transport_remove(transport, owner);
-       return FALSE;
-}
-
-static guint suspend_gateway(struct media_transport *transport,
-                                               struct media_owner *owner)
-{
-       struct audio_device *device = transport->device;
-       static int id = 1;
-
-       if (!owner) {
-               gateway_unlock(device, GATEWAY_LOCK_READ | GATEWAY_LOCK_WRITE);
-               transport->in_use = FALSE;
-               return 0;
-       }
-
-       gateway_suspend_stream(device);
-       g_idle_add(gateway_suspend_complete, owner);
-       return id++;
-}
-
-static void cancel_gateway(struct media_transport *transport, guint id)
-{
-       gateway_cancel_stream(transport->device, id);
-}
-
-static void media_owner_exit(DBusConnection *connection, void *user_data)
-{
-       struct media_owner *owner = user_data;
-
-       owner->watch = 0;
-
-       media_owner_remove(owner);
-
-       media_transport_remove(owner->transport, owner);
-}
-
-static gboolean media_transport_acquire(struct media_transport *transport,
-                                                       const char *accesstype)
-{
-       gboolean read_lock = FALSE, write_lock = FALSE;
-
-       if (g_strstr_len(accesstype, -1, "r") != NULL) {
-               if (transport->read_lock == TRUE)
-                       return FALSE;
-               read_lock = TRUE;
-       }
-
-       if (g_strstr_len(accesstype, -1, "w") != NULL) {
-               if (transport->write_lock == TRUE)
-                       return FALSE;
-               write_lock = TRUE;
-       }
-
-       /* Check invalid accesstype */
-       if (read_lock == FALSE && write_lock == FALSE)
-               return FALSE;
-
-       if (read_lock) {
-               transport->read_lock = read_lock;
-               DBG("Transport %s: read lock acquired", transport->path);
-       }
-
-       if (write_lock) {
-               transport->write_lock = write_lock;
-               DBG("Transport %s: write lock acquired", transport->path);
-       }
-
-
-       return TRUE;
-}
-
-static void media_transport_add(struct media_transport *transport,
-                                       struct media_owner *owner)
-{
-       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,
-                                               DBusMessage *msg,
-                                               const char *accesstype)
-{
-       struct media_owner *owner;
-
-       owner = g_new0(struct media_owner, 1);
-       owner->name = g_strdup(dbus_message_get_sender(msg));
-       owner->accesstype = g_strdup(accesstype);
-
-       DBG("Owner created: sender=%s accesstype=%s", owner->name,
-                       accesstype);
-
-       return owner;
-}
-
-static void media_owner_add(struct media_owner *owner,
-                                               struct media_request *req)
-{
-       DBG("Owner %s Request %s", owner->name,
-                                       dbus_message_get_member(req->msg));
-
-       owner->pending = req;
-}
-
-static struct media_owner *media_transport_find_owner(
-                                       struct media_transport *transport,
-                                       const char *name)
-{
-       GSList *l;
-
-       for (l = transport->owners; l; l = l->next) {
-               struct media_owner *owner = l->data;
-
-               if (g_strcmp0(owner->name, name) == 0)
-                       return owner;
-       }
-
-       return NULL;
-}
-
-static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct media_transport *transport = data;
-       struct media_owner *owner;
-       struct media_request *req;
-       const char *accesstype, *sender;
-       guint id;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &accesstype,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       sender = dbus_message_get_sender(msg);
-
-       owner = media_transport_find_owner(transport, sender);
-       if (owner != NULL)
-               return btd_error_not_authorized(msg);
-
-       if (media_transport_acquire(transport, accesstype) == FALSE)
-               return btd_error_not_authorized(msg);
-
-       owner = media_owner_create(conn, msg, accesstype);
-       id = transport->resume(transport, owner);
-       if (id == 0) {
-               media_transport_release(transport, accesstype);
-               media_owner_free(owner);
-               return btd_error_not_authorized(msg);
-       }
-
-       req = media_request_create(msg, id);
-       media_owner_add(owner, req);
-       media_transport_add(transport, owner);
-
-       return NULL;
-}
-
-static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct media_transport *transport = data;
-       struct media_owner *owner;
-       const char *accesstype, *sender;
-       struct media_request *req;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &accesstype,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       sender = dbus_message_get_sender(msg);
-
-       owner = media_transport_find_owner(transport, sender);
-       if (owner == NULL)
-               return btd_error_not_authorized(msg);
-
-       if (g_strcmp0(owner->accesstype, accesstype) == 0) {
-               guint id;
-
-               /* Not the last owner, no need to suspend */
-               if (g_slist_length(transport->owners) != 1) {
-                       media_transport_remove(transport, owner);
-                       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-               }
-
-               if (owner->pending) {
-                       const char *member;
-
-                       member = dbus_message_get_member(owner->pending->msg);
-                       /* Cancel Acquire request if that exist */
-                       if (g_str_equal(member, "Acquire"))
-                               media_owner_remove(owner);
-                       else
-                               return btd_error_in_progress(msg);
-               }
-
-               id = transport->suspend(transport, owner);
-               if (id == 0) {
-                       media_transport_remove(transport, owner);
-                       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-               }
-
-               req = media_request_create(msg, id);
-               media_owner_add(owner, req);
-
-               return NULL;
-       } else if (g_strstr_len(owner->accesstype, -1, accesstype) != NULL) {
-               media_transport_release(transport, accesstype);
-               g_strdelimit(owner->accesstype, accesstype, ' ');
-       } else
-               return btd_error_not_authorized(msg);
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-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, &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;
-}
-
-static int set_property_headset(struct media_transport *transport,
-                                               const char *property,
-                                               DBusMessageIter *value)
-{
-       if (g_strcmp0(property, "NREC") == 0) {
-               gboolean nrec;
-
-               if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
-                       return -EINVAL;
-               dbus_message_iter_get_basic(value, &nrec);
-
-               /* FIXME: set new nrec */
-               return 0;
-       } else if (g_strcmp0(property, "InbandRingtone") == 0) {
-               gboolean inband;
-
-               if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN)
-                       return -EINVAL;
-               dbus_message_iter_get_basic(value, &inband);
-
-               /* FIXME: set new inband */
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static int set_property_gateway(struct media_transport *transport,
-                                               const char *property,
-                                               DBusMessageIter *value)
-{
-       return -EINVAL;
-}
-
-static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct media_transport *transport = data;
-       DBusMessageIter iter;
-       DBusMessageIter value;
-       const char *property, *sender;
-       GSList *l;
-       int err;
-
-       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, &value);
-
-       sender = dbus_message_get_sender(msg);
-       err = -EINVAL;
-
-       /* Check if sender has acquired the transport */
-       for (l = transport->owners; l; l = l->next) {
-               struct media_owner *owner = l->data;
-
-               if (g_strcmp0(owner->name, sender) == 0) {
-                       err = transport->set_property(transport, property,
-                                                               &value);
-                       break;
-               }
-       }
-
-       if (err < 0) {
-               if (err == -EINVAL)
-                       return btd_error_invalid_args(msg);
-               return btd_error_failed(msg, strerror(-err));
-       }
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static void get_properties_a2dp(struct media_transport *transport,
-                                               DBusMessageIter *dict)
-{
-       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,
-                                               DBusMessageIter *dict)
-{
-       gboolean nrec, inband;
-       const char *routing;
-
-       nrec = headset_get_nrec(transport->device);
-       dict_append_entry(dict, "NREC", DBUS_TYPE_BOOLEAN, &nrec);
-
-       inband = headset_get_inband(transport->device);
-       dict_append_entry(dict, "InbandRingtone", DBUS_TYPE_BOOLEAN, &inband);
-
-       routing = headset_get_sco_hci(transport->device) ? "HCI" : "PCM";
-       dict_append_entry(dict, "Routing", DBUS_TYPE_STRING, &routing);
-}
-
-static void get_properties_gateway(struct media_transport *transport,
-                                               DBusMessageIter *dict)
-{
-       /* None */
-}
-
-void transport_get_properties(struct media_transport *transport,
-                                                       DBusMessageIter *iter)
-{
-       DBusMessageIter dict;
-       const char *uuid;
-       uint8_t codec;
-
-       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);
-
-       /* Device */
-       dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH,
-                                               &transport->device->path);
-
-       uuid = media_endpoint_get_uuid(transport->endpoint);
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &uuid);
-
-       codec = media_endpoint_get_codec(transport->endpoint);
-       dict_append_entry(&dict, "Codec", DBUS_TYPE_BYTE, &codec);
-
-       dict_append_array(&dict, "Configuration", DBUS_TYPE_BYTE,
-                               &transport->configuration, transport->size);
-
-       if (transport->get_properties)
-               transport->get_properties(transport, &dict);
-
-       dbus_message_iter_close_container(iter, &dict);
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
-                                       void *data)
-{
-       struct media_transport *transport = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       transport_get_properties(transport, &iter);
-
-       return reply;
-}
-
-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 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;
-       GSList *l = transport->owners;
-
-       while (l) {
-               struct media_owner *owner = l->data;
-               l = l->next;
-               media_transport_remove(transport, owner);
-       }
-
-       g_slist_free(transport->owners);
-
-       if (transport->destroy != NULL)
-               transport->destroy(transport->data);
-
-       if (transport->conn)
-               dbus_connection_unref(transport->conn);
-
-       g_free(transport->configuration);
-       g_free(transport->path);
-       g_free(transport);
-}
-
-static void headset_nrec_changed(struct audio_device *dev, gboolean nrec,
-                                                       void *user_data)
-{
-       struct media_transport *transport = user_data;
-
-       DBG("");
-
-       emit_property_changed(transport->conn, transport->path,
-                               MEDIA_TRANSPORT_INTERFACE, "NREC",
-                               DBUS_TYPE_BOOLEAN, &nrec);
-}
-
-struct media_transport *media_transport_create(DBusConnection *conn,
-                                               struct media_endpoint *endpoint,
-                                               struct audio_device *device,
-                                               uint8_t *configuration,
-                                               size_t size)
-{
-       struct media_transport *transport;
-       const char *uuid;
-       static int fd = 0;
-
-       transport = g_new0(struct media_transport, 1);
-       transport->conn = dbus_connection_ref(conn);
-       transport->device = device;
-       transport->endpoint = endpoint;
-       transport->configuration = g_new(uint8_t, size);
-       memcpy(transport->configuration, configuration, size);
-       transport->size = size;
-       transport->path = g_strdup_printf("%s/fd%d", device->path, fd++);
-       transport->fd = -1;
-
-       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->data = headset;
-               transport->destroy = destroy_headset;
-       } else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
-                       strcasecmp(uuid, HSP_HS_UUID) == 0) {
-               transport->resume = resume_gateway;
-               transport->suspend = suspend_gateway;
-               transport->cancel = cancel_gateway;
-               transport->get_properties = get_properties_gateway;
-               transport->set_property = set_property_gateway;
-       } else
-               goto fail;
-
-       if (g_dbus_register_interface(transport->conn, transport->path,
-                               MEDIA_TRANSPORT_INTERFACE,
-                               transport_methods, transport_signals, NULL,
-                               transport, media_transport_free) == FALSE) {
-               error("Could not register transport %s", transport->path);
-               goto fail;
-       }
-
-       return transport;
-
-fail:
-       media_transport_free(transport);
-       return NULL;
-}
-
-const char *media_transport_get_path(struct media_transport *transport)
-{
-       return transport->path;
-}
-
-void media_transport_update_delay(struct media_transport *transport,
-                                                       uint16_t delay)
-{
-       struct a2dp_transport *a2dp = transport->data;
-
-       /* Check if delay really changed */
-       if (a2dp->delay == delay)
-               return;
-
-       a2dp->delay = delay;
-
-       emit_property_changed(transport->conn, transport->path,
-                               MEDIA_TRANSPORT_INTERFACE, "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);
-}
diff --git a/audio/unix.c b/audio/unix.c
deleted file mode 100644 (file)
index 9a10764..0000000
+++ /dev/null
@@ -1,1909 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <fcntl.h>
-#include <sys/socket.h>
-#include <sys/un.h>
-#include <stdlib.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdint.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <dbus/dbus.h>
-#include <glib.h>
-
-#include "log.h"
-#include "ipc.h"
-#include "device.h"
-#include "manager.h"
-#include "avdtp.h"
-#include "media.h"
-#include "a2dp.h"
-#include "headset.h"
-#include "sink.h"
-#include "source.h"
-#include "gateway.h"
-#include "unix.h"
-
-#define check_nul(str) (str[sizeof(str) - 1] == '\0')
-
-typedef enum {
-       TYPE_NONE,
-       TYPE_HEADSET,
-       TYPE_GATEWAY,
-       TYPE_SINK,
-       TYPE_SOURCE
-} service_type_t;
-
-typedef void (*notify_cb_t) (struct audio_device *dev, void *data);
-
-struct a2dp_data {
-       struct avdtp *session;
-       struct avdtp_stream *stream;
-       struct a2dp_sep *sep;
-};
-
-struct headset_data {
-       gboolean locked;
-};
-
-struct unix_client {
-       struct audio_device *dev;
-       GSList *caps;
-       service_type_t type;
-       char *interface;
-       uint8_t seid;
-       union {
-               struct a2dp_data a2dp;
-               struct headset_data hs;
-       } d;
-       int sock;
-       int lock;
-       int data_fd; /* To be deleted once two phase configuration is fully implemented */
-       unsigned int req_id;
-       unsigned int cb_id;
-       gboolean (*cancel) (struct audio_device *dev, unsigned int id);
-};
-
-static GSList *clients = NULL;
-
-static int unix_sock = -1;
-
-static void client_free(void *data)
-{
-       struct unix_client *client = data;
-
-       DBG("client_free(%p)", client);
-
-       if (client->cancel && client->dev && client->req_id > 0)
-               client->cancel(client->dev, client->req_id);
-
-       if (client->sock >= 0)
-               close(client->sock);
-
-       g_slist_free_full(client->caps, g_free);
-
-       g_free(client->interface);
-       g_free(client);
-}
-
-static int set_nonblocking(int fd)
-{
-       long arg;
-
-       arg = fcntl(fd, F_GETFL);
-       if (arg < 0)
-               return -errno;
-
-       /* Return if already nonblocking */
-       if (arg & O_NONBLOCK)
-               return 0;
-
-       arg |= O_NONBLOCK;
-       if (fcntl(fd, F_SETFL, arg) < 0)
-               return -errno;
-
-       return 0;
-}
-
-/* Pass file descriptor through local domain sockets (AF_LOCAL, formerly
- * AF_UNIX) and the sendmsg() system call with the cmsg_type field of a "struct
- * cmsghdr" set to SCM_RIGHTS and the data being an integer value equal to the
- * handle of the file descriptor to be passed. */
-static int unix_sendmsg_fd(int sock, int fd)
-{
-       char cmsg_b[CMSG_SPACE(sizeof(int))], m = 'm';
-       struct cmsghdr *cmsg;
-       struct iovec iov = { &m, sizeof(m) };
-       struct msghdr msgh;
-
-       memset(&msgh, 0, sizeof(msgh));
-       msgh.msg_iov = &iov;
-       msgh.msg_iovlen = 1;
-       msgh.msg_control = &cmsg_b;
-       msgh.msg_controllen = CMSG_LEN(sizeof(int));
-
-       cmsg = CMSG_FIRSTHDR(&msgh);
-       cmsg->cmsg_level = SOL_SOCKET;
-       cmsg->cmsg_type = SCM_RIGHTS;
-       cmsg->cmsg_len = CMSG_LEN(sizeof(int));
-       /* Initialize the payload */
-       memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
-
-       return sendmsg(sock, &msgh, MSG_NOSIGNAL);
-}
-
-static void unix_ipc_sendmsg(struct unix_client *client,
-                                       const bt_audio_msg_header_t *msg)
-{
-       const char *type = bt_audio_strtype(msg->type);
-       const char *name = bt_audio_strname(msg->name);
-
-       DBG("Audio API: %s -> %s", type, name);
-
-       if (send(client->sock, msg, msg->length, 0) < 0)
-               error("Error %s(%d)", strerror(errno), errno);
-}
-
-static void unix_ipc_error(struct unix_client *client, uint8_t name, int err)
-{
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       bt_audio_error_t *rsp = (void *) buf;
-
-       if (!g_slist_find(clients, client))
-               return;
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_ERROR;
-       rsp->h.name = name;
-       rsp->h.length = sizeof(*rsp);
-
-       rsp->posix_errno = err;
-
-       DBG("sending error %s(%d)", strerror(err), err);
-       unix_ipc_sendmsg(client, &rsp->h);
-}
-
-static service_type_t select_service(struct audio_device *dev, const char *interface)
-{
-       if (!interface) {
-               if (dev->sink && avdtp_is_connected(&dev->src, &dev->dst))
-                       return TYPE_SINK;
-               else if (dev->source && avdtp_is_connected(&dev->src,
-                                                               &dev->dst))
-                       return TYPE_SOURCE;
-               else if (dev->headset && headset_is_active(dev))
-                       return TYPE_HEADSET;
-               else if (dev->sink)
-                       return TYPE_SINK;
-               else if (dev->source)
-                       return TYPE_SOURCE;
-               else if (dev->headset)
-                       return TYPE_HEADSET;
-       } else if (!strcmp(interface, AUDIO_SOURCE_INTERFACE) && dev->source)
-               return TYPE_SOURCE;
-       else if (!strcmp(interface, AUDIO_SINK_INTERFACE) && dev->sink)
-               return TYPE_SINK;
-       else if (!strcmp(interface, AUDIO_HEADSET_INTERFACE) && dev->headset)
-               return TYPE_HEADSET;
-       else if (!strcmp(interface, AUDIO_GATEWAY_INTERFACE) && dev->gateway)
-               return TYPE_GATEWAY;
-
-       return TYPE_NONE;
-}
-
-static void stream_state_changed(struct avdtp_stream *stream,
-                                       avdtp_state_t old_state,
-                                       avdtp_state_t new_state,
-                                       struct avdtp_error *err,
-                                       void *user_data)
-{
-       struct unix_client *client = user_data;
-       struct a2dp_data *a2dp = &client->d.a2dp;
-
-       switch (new_state) {
-       case AVDTP_STATE_IDLE:
-               if (a2dp->sep) {
-                       a2dp_sep_unlock(a2dp->sep, a2dp->session);
-                       a2dp->sep = NULL;
-               }
-               if (a2dp->session) {
-                       avdtp_unref(a2dp->session);
-                       a2dp->session = NULL;
-               }
-               a2dp->stream = NULL;
-               client->cb_id = 0;
-               break;
-       default:
-               break;
-       }
-}
-
-static uint8_t headset_generate_capability(struct audio_device *dev,
-                                               codec_capabilities_t *codec)
-{
-       pcm_capabilities_t *pcm;
-
-       codec->seid = BT_A2DP_SEID_RANGE + 1;
-       codec->transport = BT_CAPABILITIES_TRANSPORT_SCO;
-       codec->type = BT_HFP_CODEC_PCM;
-       codec->length = sizeof(*pcm);
-
-       pcm = (void *) codec;
-       pcm->sampling_rate = 8000;
-       if (dev->headset) {
-               if (headset_get_nrec(dev))
-                       pcm->flags |= BT_PCM_FLAG_NREC;
-               if (!headset_get_sco_hci(dev))
-                       pcm->flags |= BT_PCM_FLAG_PCM_ROUTING;
-               codec->configured = headset_is_active(dev);
-               codec->lock = headset_get_lock(dev);
-       } else {
-               pcm->flags |= BT_PCM_FLAG_NREC;
-               codec->configured = TRUE;
-               codec->lock = 0;
-       }
-
-       return codec->length;
-}
-
-static void headset_discovery_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_get_capabilities_rsp *rsp = (void *) buf;
-       uint8_t length;
-
-       client->req_id = 0;
-
-       if (!dev)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-
-       length = headset_generate_capability(dev, (void *) rsp->data);
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_GET_CAPABILITIES;
-       rsp->h.length = sizeof(*rsp) + length;
-
-       ba2str(&dev->src, rsp->source);
-       ba2str(&dev->dst, rsp->destination);
-       strncpy(rsp->object, dev->path, sizeof(rsp->object));
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       error("discovery failed");
-       unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
-}
-
-static void headset_setup_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-
-       client->req_id = 0;
-
-       if (!dev)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_SET_CONFIGURATION;
-       rsp->h.length = sizeof(*rsp);
-
-       rsp->link_mtu = 48;
-
-       client->data_fd = headset_get_sco_fd(dev);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       error("config failed");
-       unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
-}
-
-static void gateway_setup_complete(struct audio_device *dev, GError *err, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-
-       if (err) {
-               unix_ipc_error(client, BT_SET_CONFIGURATION, err->code);
-               return;
-       }
-
-       client->req_id = 0;
-
-       memset(buf, 0, sizeof(buf));
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_SET_CONFIGURATION;
-       rsp->h.length = sizeof(*rsp);
-
-       rsp->link_mtu = 48;
-
-       client->data_fd = gateway_get_sco_fd(dev);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-}
-
-static void headset_resume_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_start_stream_rsp *rsp = (void *) buf;
-       struct bt_new_stream_ind *ind = (void *) buf;
-
-       client->req_id = 0;
-
-       if (!dev)
-               goto failed;
-
-       client->data_fd = headset_get_sco_fd(dev);
-       if (client->data_fd < 0) {
-               error("Unable to get a SCO fd");
-               goto failed;
-       }
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_START_STREAM;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       memset(buf, 0, sizeof(buf));
-       ind->h.type = BT_INDICATION;
-       ind->h.name = BT_NEW_STREAM;
-       ind->h.length = sizeof(*ind);
-
-       unix_ipc_sendmsg(client, &ind->h);
-
-       if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
-               error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
-               goto failed;
-       }
-
-       return;
-
-failed:
-       error("headset_resume_complete: resume failed");
-       unix_ipc_error(client, BT_START_STREAM, EIO);
-}
-
-static void gateway_resume_complete(struct audio_device *dev, GError *err, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_start_stream_rsp *rsp = (void *) buf;
-       struct bt_new_stream_ind *ind = (void *) buf;
-
-       if (err) {
-               unix_ipc_error(client, BT_START_STREAM, err->code);
-               return;
-       }
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_START_STREAM;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       memset(buf, 0, sizeof(buf));
-       ind->h.type = BT_INDICATION;
-       ind->h.name = BT_NEW_STREAM;
-       ind->h.length = sizeof(*ind);
-
-       unix_ipc_sendmsg(client, &ind->h);
-
-       client->data_fd = gateway_get_sco_fd(dev);
-       if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
-               error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
-               unix_ipc_error(client, BT_START_STREAM, EIO);
-       }
-
-       client->req_id = 0;
-}
-
-static void headset_suspend_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_stop_stream_rsp *rsp = (void *) buf;
-
-       if (!dev)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_STOP_STREAM;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       error("suspend failed");
-       unix_ipc_error(client, BT_STOP_STREAM, EIO);
-}
-
-static void print_mpeg12(struct mpeg_codec_cap *mpeg)
-{
-       DBG("Media Codec: MPEG12"
-               " Channel Modes: %s%s%s%s"
-               " Frequencies: %s%s%s%s%s%s"
-               " Layers: %s%s%s"
-               " CRC: %s",
-               mpeg->channel_mode & MPEG_CHANNEL_MODE_MONO ? "Mono " : "",
-               mpeg->channel_mode & MPEG_CHANNEL_MODE_DUAL_CHANNEL ?
-               "DualChannel " : "",
-               mpeg->channel_mode & MPEG_CHANNEL_MODE_STEREO ? "Stereo " : "",
-               mpeg->channel_mode & MPEG_CHANNEL_MODE_JOINT_STEREO ?
-               "JointStereo " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_16000 ? "16Khz " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_22050 ? "22.05Khz " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_24000 ? "24Khz " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_32000 ? "32Khz " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_44100 ? "44.1Khz " : "",
-               mpeg->frequency & MPEG_SAMPLING_FREQ_48000 ? "48Khz " : "",
-               mpeg->layer & MPEG_LAYER_MP1 ? "1 " : "",
-               mpeg->layer & MPEG_LAYER_MP2 ? "2 " : "",
-               mpeg->layer & MPEG_LAYER_MP3 ? "3 " : "",
-               mpeg->crc ? "Yes" : "No");
-}
-
-static void print_sbc(struct sbc_codec_cap *sbc)
-{
-       DBG("Media Codec: SBC"
-               " Channel Modes: %s%s%s%s"
-               " Frequencies: %s%s%s%s"
-               " Subbands: %s%s"
-               " Blocks: %s%s%s%s"
-               " Bitpool: %d-%d",
-               sbc->channel_mode & SBC_CHANNEL_MODE_MONO ? "Mono " : "",
-               sbc->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL ?
-               "DualChannel " : "",
-               sbc->channel_mode & SBC_CHANNEL_MODE_STEREO ? "Stereo " : "",
-               sbc->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO ? "JointStereo" : "",
-               sbc->frequency & SBC_SAMPLING_FREQ_16000 ? "16Khz " : "",
-               sbc->frequency & SBC_SAMPLING_FREQ_32000 ? "32Khz " : "",
-               sbc->frequency & SBC_SAMPLING_FREQ_44100 ? "44.1Khz " : "",
-               sbc->frequency & SBC_SAMPLING_FREQ_48000 ? "48Khz " : "",
-               sbc->subbands & SBC_SUBBANDS_4 ? "4 " : "",
-               sbc->subbands & SBC_SUBBANDS_8 ? "8 " : "",
-               sbc->block_length & SBC_BLOCK_LENGTH_4 ? "4 " : "",
-               sbc->block_length & SBC_BLOCK_LENGTH_8 ? "8 " : "",
-               sbc->block_length & SBC_BLOCK_LENGTH_12 ? "12 " : "",
-               sbc->block_length & SBC_BLOCK_LENGTH_16 ? "16 " : "",
-               sbc->min_bitpool, sbc->max_bitpool);
-}
-
-static int a2dp_append_codec(struct bt_get_capabilities_rsp *rsp,
-                               struct avdtp_service_capability *cap,
-                               uint8_t seid,
-                               uint8_t type,
-                               uint8_t configured,
-                               uint8_t lock)
-{
-       struct avdtp_media_codec_capability *codec_cap = (void *) cap->data;
-       codec_capabilities_t *codec = (void *) rsp + rsp->h.length;
-       size_t space_left;
-
-       if (rsp->h.length > BT_SUGGESTED_BUFFER_SIZE)
-               return -ENOMEM;
-
-       space_left = BT_SUGGESTED_BUFFER_SIZE - rsp->h.length;
-
-       /* 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;
-
-               if (space_left < sizeof(sbc_capabilities_t))
-                       return -ENOMEM;
-
-               if (type == AVDTP_SEP_TYPE_SINK)
-                       codec->type = BT_A2DP_SBC_SINK;
-               else if (type == AVDTP_SEP_TYPE_SOURCE)
-                       codec->type = BT_A2DP_SBC_SOURCE;
-               else
-                       return -EINVAL;
-
-               codec->length = sizeof(sbc_capabilities_t);
-
-               sbc->channel_mode = sbc_cap->channel_mode;
-               sbc->frequency = sbc_cap->frequency;
-               sbc->allocation_method = sbc_cap->allocation_method;
-               sbc->subbands = sbc_cap->subbands;
-               sbc->block_length = sbc_cap->block_length;
-               sbc->min_bitpool = sbc_cap->min_bitpool;
-               sbc->max_bitpool = sbc_cap->max_bitpool;
-
-               print_sbc(sbc_cap);
-       } else if (codec_cap->media_codec_type == A2DP_CODEC_MPEG12) {
-               struct mpeg_codec_cap *mpeg_cap = (void *) codec_cap;
-               mpeg_capabilities_t *mpeg = (void *) codec;
-
-               if (space_left < sizeof(mpeg_capabilities_t))
-                       return -ENOMEM;
-
-               if (type == AVDTP_SEP_TYPE_SINK)
-                       codec->type = BT_A2DP_MPEG12_SINK;
-               else if (type == AVDTP_SEP_TYPE_SOURCE)
-                       codec->type = BT_A2DP_MPEG12_SOURCE;
-               else
-                       return -EINVAL;
-
-               codec->length = sizeof(mpeg_capabilities_t);
-
-               mpeg->channel_mode = mpeg_cap->channel_mode;
-               mpeg->crc = mpeg_cap->crc;
-               mpeg->layer = mpeg_cap->layer;
-               mpeg->frequency = mpeg_cap->frequency;
-               mpeg->mpf = mpeg_cap->mpf;
-               mpeg->bitrate = mpeg_cap->bitrate;
-
-               print_mpeg12(mpeg_cap);
-       } else {
-               size_t codec_length, type_length, total_length;
-
-               codec_length = cap->length - (sizeof(struct avdtp_service_capability)
-                               + sizeof(struct avdtp_media_codec_capability));
-               type_length = sizeof(codec_cap->media_codec_type);
-               total_length = type_length + codec_length +
-                               sizeof(codec_capabilities_t);
-
-               if (space_left < total_length)
-                       return -ENOMEM;
-
-               if (type == AVDTP_SEP_TYPE_SINK)
-                       codec->type = BT_A2DP_UNKNOWN_SINK;
-               else if (type == AVDTP_SEP_TYPE_SOURCE)
-                       codec->type = BT_A2DP_UNKNOWN_SOURCE;
-               else
-                       return -EINVAL;
-
-               codec->length = total_length;
-               memcpy(codec->data, &codec_cap->media_codec_type, type_length);
-               memcpy(codec->data + type_length, codec_cap->data,
-                       codec_length);
-       }
-
-       codec->seid = seid;
-       codec->configured = configured;
-       codec->lock = lock;
-       rsp->h.length += codec->length;
-
-       DBG("Append %s seid %d - length %d - total %d",
-               configured ? "configured" : "", seid, codec->length,
-               rsp->h.length);
-
-       return 0;
-}
-
-static void a2dp_discovery_complete(struct avdtp *session, GSList *seps,
-                                       struct avdtp_error *err,
-                                       void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_get_capabilities_rsp *rsp = (void *) buf;
-       struct a2dp_data *a2dp = &client->d.a2dp;
-
-       if (!g_slist_find(clients, client)) {
-               DBG("Client disconnected during discovery");
-               return;
-       }
-
-       if (err)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-       client->req_id = 0;
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_GET_CAPABILITIES;
-       rsp->h.length = sizeof(*rsp);
-       ba2str(&client->dev->src, rsp->source);
-       ba2str(&client->dev->dst, rsp->destination);
-       strncpy(rsp->object, client->dev->path, sizeof(rsp->object));
-
-       for (; seps; seps = g_slist_next(seps)) {
-               struct avdtp_remote_sep *rsep = seps->data;
-               struct a2dp_sep *sep;
-               struct avdtp_service_capability *cap;
-               struct avdtp_stream *stream;
-               uint8_t type, seid, configured = 0, lock = 0;
-               GSList *cl;
-
-               type = avdtp_get_type(rsep);
-
-               if (type != AVDTP_SEP_TYPE_SINK &&
-                                               type != AVDTP_SEP_TYPE_SOURCE)
-                       continue;
-
-               cap = avdtp_get_codec(rsep);
-
-               if (cap->category != AVDTP_MEDIA_CODEC)
-                       continue;
-
-               seid = avdtp_get_seid(rsep);
-
-               if (client->seid != 0 && client->seid != seid)
-                       continue;
-
-               stream = avdtp_get_stream(rsep);
-               if (stream) {
-                       configured = 1;
-                       if (client->seid == seid)
-                               cap = avdtp_stream_get_codec(stream);
-               }
-
-               for (cl = clients; cl; cl = cl->next) {
-                       struct unix_client *c = cl->data;
-                       struct a2dp_data *ca2dp = &c->d.a2dp;
-
-                       if (ca2dp->session == session && c->seid == seid) {
-                               lock = c->lock;
-                               break;
-                       }
-               }
-
-               sep = a2dp_get_sep(session, stream);
-               if (sep && a2dp_sep_get_lock(sep))
-                       lock = BT_WRITE_LOCK;
-
-               a2dp_append_codec(rsp, cap, seid, type, configured, lock);
-       }
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       error("discovery failed");
-       unix_ipc_error(client, BT_GET_CAPABILITIES, EIO);
-
-       if (a2dp->sep) {
-               a2dp_sep_unlock(a2dp->sep, a2dp->session);
-               a2dp->sep = NULL;
-       }
-
-       avdtp_unref(a2dp->session);
-       a2dp->session = NULL;
-       a2dp->stream = NULL;
-}
-
-static void a2dp_config_complete(struct avdtp *session, struct a2dp_sep *sep,
-                                       struct avdtp_stream *stream,
-                                       struct avdtp_error *err,
-                                       void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-       struct a2dp_data *a2dp = &client->d.a2dp;
-       uint16_t imtu, omtu;
-       GSList *caps;
-
-       client->req_id = 0;
-
-       if (err)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-
-       if (!stream)
-               goto failed;
-
-       if (client->cb_id > 0)
-               avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
-                                                               client->cb_id);
-
-       a2dp->sep = sep;
-       a2dp->stream = stream;
-
-       if (!avdtp_stream_get_transport(stream, &client->data_fd, &imtu, &omtu,
-                                       &caps)) {
-               error("Unable to get stream transport");
-               goto failed;
-       }
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_SET_CONFIGURATION;
-       rsp->h.length = sizeof(*rsp);
-
-       /* FIXME: Use imtu when fd_opt is CFG_FD_OPT_READ */
-       rsp->link_mtu = omtu;
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       client->cb_id = avdtp_stream_add_cb(session, stream,
-                                               stream_state_changed, client);
-
-       return;
-
-failed:
-       error("config failed");
-
-       unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
-
-       avdtp_unref(a2dp->session);
-
-       a2dp->session = NULL;
-       a2dp->stream = NULL;
-       a2dp->sep = NULL;
-}
-
-static void a2dp_resume_complete(struct avdtp *session,
-                               struct avdtp_error *err, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_start_stream_rsp *rsp = (void *) buf;
-       struct bt_new_stream_ind *ind = (void *) buf;
-       struct a2dp_data *a2dp = &client->d.a2dp;
-
-       if (err)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_START_STREAM;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       memset(buf, 0, sizeof(buf));
-       ind->h.type = BT_RESPONSE;
-       ind->h.name = BT_NEW_STREAM;
-       rsp->h.length = sizeof(*ind);
-
-       unix_ipc_sendmsg(client, &ind->h);
-
-       if (unix_sendmsg_fd(client->sock, client->data_fd) < 0) {
-               error("unix_sendmsg_fd: %s(%d)", strerror(errno), errno);
-               goto failed;
-       }
-
-       return;
-
-failed:
-       error("resume failed");
-
-       unix_ipc_error(client, BT_START_STREAM, EIO);
-
-       if (client->cb_id > 0) {
-               avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
-                                       client->cb_id);
-               client->cb_id = 0;
-       }
-
-       if (a2dp->sep) {
-               a2dp_sep_unlock(a2dp->sep, a2dp->session);
-               a2dp->sep = NULL;
-       }
-
-       avdtp_unref(a2dp->session);
-       a2dp->session = NULL;
-       a2dp->stream = NULL;
-}
-
-static void a2dp_suspend_complete(struct avdtp *session,
-                               struct avdtp_error *err, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_stop_stream_rsp *rsp = (void *) buf;
-
-       if (err)
-               goto failed;
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_STOP_STREAM;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       error("suspend failed");
-
-       unix_ipc_error(client, BT_STOP_STREAM, EIO);
-}
-
-static void start_discovery(struct audio_device *dev, struct unix_client *client)
-{
-       struct a2dp_data *a2dp;
-       int err = 0;
-
-       switch (client->type) {
-       case TYPE_SINK:
-       case TYPE_SOURCE:
-               a2dp = &client->d.a2dp;
-
-               if (!a2dp->session)
-                       a2dp->session = avdtp_get(&dev->src, &dev->dst);
-
-               if (!a2dp->session) {
-                       error("Unable to get a session");
-                       goto failed;
-               }
-
-               err = avdtp_discover(a2dp->session, a2dp_discovery_complete,
-                                       client);
-               if (err) {
-                       if (a2dp->session) {
-                               avdtp_unref(a2dp->session);
-                               a2dp->session = NULL;
-                       }
-                       goto failed;
-               }
-               break;
-
-       case TYPE_HEADSET:
-       case TYPE_GATEWAY:
-               headset_discovery_complete(dev, client);
-               break;
-
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       client->dev = dev;
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_GET_CAPABILITIES, err ? : EIO);
-}
-
-static void open_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_open_rsp *rsp = (void *) buf;
-
-       memset(buf, 0, sizeof(buf));
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_OPEN;
-       rsp->h.length = sizeof(*rsp);
-
-       ba2str(&dev->src, rsp->source);
-       ba2str(&dev->dst, rsp->destination);
-       strncpy(rsp->object, dev->path, sizeof(rsp->object));
-
-       unix_ipc_sendmsg(client, &rsp->h);
-}
-
-static void start_open(struct audio_device *dev, struct unix_client *client)
-{
-       struct a2dp_data *a2dp;
-       struct headset_data *hs;
-       struct avdtp_remote_sep *rsep;
-       gboolean unref_avdtp_on_fail = FALSE;
-
-       switch (client->type) {
-       case TYPE_SINK:
-       case TYPE_SOURCE:
-               a2dp = &client->d.a2dp;
-
-               if (!a2dp->session) {
-                       a2dp->session = avdtp_get(&dev->src, &dev->dst);
-                       unref_avdtp_on_fail = TRUE;
-               }
-
-               if (!a2dp->session) {
-                       error("Unable to get a session");
-                       goto failed;
-               }
-
-               if (a2dp->sep) {
-                       error("Client already has an opened session");
-                       goto failed;
-               }
-
-               rsep = avdtp_get_remote_sep(a2dp->session, client->seid);
-               if (!rsep) {
-                       error("Invalid seid %d", client->seid);
-                       goto failed;
-               }
-
-               a2dp->sep = a2dp_get(a2dp->session, rsep);
-               if (!a2dp->sep) {
-                       error("seid %d not available or locked", client->seid);
-                       goto failed;
-               }
-
-               if (!a2dp_sep_lock(a2dp->sep, a2dp->session)) {
-                       error("Unable to open seid %d", client->seid);
-                       a2dp->sep = NULL;
-                       goto failed;
-               }
-
-               break;
-
-       case TYPE_HEADSET:
-               hs = &client->d.hs;
-
-               if (hs->locked) {
-                       error("Client already has an opened session");
-                       goto failed;
-               }
-
-               hs->locked = headset_lock(dev, client->lock);
-               if (!hs->locked) {
-                       error("Unable to open seid %d", client->seid);
-                       goto failed;
-               }
-               break;
-
-        case TYPE_GATEWAY:
-                break;
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       client->dev = dev;
-
-       open_complete(dev, client);
-
-       return;
-
-failed:
-       if (unref_avdtp_on_fail && a2dp->session) {
-               avdtp_unref(a2dp->session);
-               a2dp->session = NULL;
-       }
-       unix_ipc_error(client, BT_OPEN, EINVAL);
-}
-
-static void start_config(struct audio_device *dev, struct unix_client *client)
-{
-       struct a2dp_data *a2dp;
-       struct headset_data *hs;
-       unsigned int id;
-
-       switch (client->type) {
-       case TYPE_SINK:
-       case TYPE_SOURCE:
-               a2dp = &client->d.a2dp;
-
-               if (!a2dp->session)
-                       a2dp->session = avdtp_get(&dev->src, &dev->dst);
-
-               if (!a2dp->session) {
-                       error("Unable to get a session");
-                       goto failed;
-               }
-
-               if (!a2dp->sep) {
-                       error("seid %d not opened", client->seid);
-                       goto failed;
-               }
-
-               id = a2dp_config(a2dp->session, a2dp->sep, a2dp_config_complete,
-                                       client->caps, client);
-               client->cancel = a2dp_cancel;
-               break;
-
-       case TYPE_HEADSET:
-               hs = &client->d.hs;
-
-               if (!hs->locked) {
-                       error("seid %d not opened", client->seid);
-                       goto failed;
-               }
-
-               id = headset_config_stream(dev, TRUE, headset_setup_complete,
-                                               client);
-               client->cancel = headset_cancel_stream;
-               break;
-       case TYPE_GATEWAY:
-               id = gateway_config_stream(dev, gateway_setup_complete, client);
-               client->cancel = gateway_cancel_stream;
-               break;
-
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       if (id == 0) {
-               error("config failed");
-               goto failed;
-       }
-
-       client->req_id = id;
-       g_slist_free(client->caps);
-       client->caps = NULL;
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_SET_CONFIGURATION, EIO);
-}
-
-static void start_resume(struct audio_device *dev, struct unix_client *client)
-{
-       struct a2dp_data *a2dp = NULL;
-       struct headset_data *hs;
-       unsigned int id;
-       struct avdtp *session = NULL;
-
-       switch (client->type) {
-       case TYPE_SINK:
-       case TYPE_SOURCE:
-               a2dp = &client->d.a2dp;
-
-               if (!a2dp->sep) {
-                       error("seid not opened");
-                       goto failed;
-               }
-
-               if (!a2dp->session) {
-                       session = avdtp_get(&dev->src, &dev->dst);
-                       if (!session) {
-                               error("Unable to get a session");
-                               goto failed;
-                       }
-                       a2dp->session = session;
-               }
-
-               id = a2dp_resume(a2dp->session, a2dp->sep, a2dp_resume_complete,
-                                       client);
-               client->cancel = a2dp_cancel;
-
-               break;
-
-       case TYPE_HEADSET:
-               hs = &client->d.hs;
-
-               if (!hs->locked) {
-                       error("seid not opened");
-                       goto failed;
-               }
-
-               id = headset_request_stream(dev, headset_resume_complete,
-                                               client);
-               client->cancel = headset_cancel_stream;
-               break;
-
-       case TYPE_GATEWAY:
-               id = gateway_request_stream(dev, gateway_resume_complete,
-                                               client);
-               client->cancel = gateway_cancel_stream;
-               break;
-
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       if (id == 0) {
-               error("start_resume: resume failed");
-               goto failed;
-       }
-
-       client->req_id = id;
-
-       return;
-
-failed:
-       if (session) {
-               avdtp_unref(session);
-               a2dp->session = NULL;
-       }
-
-       unix_ipc_error(client, BT_START_STREAM, EIO);
-}
-
-static void start_suspend(struct audio_device *dev, struct unix_client *client)
-{
-       struct a2dp_data *a2dp = NULL;
-       struct headset_data *hs;
-       unsigned int id;
-       struct avdtp *session = NULL;
-
-       switch (client->type) {
-       case TYPE_SINK:
-       case TYPE_SOURCE:
-               a2dp = &client->d.a2dp;
-
-               if (!a2dp->sep) {
-                       error("seid not opened");
-                       goto failed;
-               }
-
-               if (!a2dp->session) {
-                       session = avdtp_get(&dev->src, &dev->dst);
-                       if (!session) {
-                               error("Unable to get a session");
-                               goto failed;
-                       }
-                       a2dp->session = session;
-               }
-
-               if (!a2dp->sep) {
-                       error("Unable to get a sep");
-                       goto failed;
-               }
-
-               id = a2dp_suspend(a2dp->session, a2dp->sep,
-                                       a2dp_suspend_complete, client);
-               client->cancel = a2dp_cancel;
-               break;
-
-       case TYPE_HEADSET:
-               hs = &client->d.hs;
-
-               if (!hs->locked) {
-                       error("seid not opened");
-                       goto failed;
-               }
-
-               id = headset_suspend_stream(dev, headset_suspend_complete,
-                                               client);
-               client->cancel = headset_cancel_stream;
-               break;
-
-       case TYPE_GATEWAY:
-               gateway_suspend_stream(dev);
-               client->cancel = gateway_cancel_stream;
-               headset_suspend_complete(dev, client);
-               id = 1;
-               break;
-
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       if (id == 0) {
-               error("suspend failed");
-               goto failed;
-       }
-
-       return;
-
-failed:
-       if (session) {
-               avdtp_unref(session);
-               a2dp->session = NULL;
-       }
-
-       unix_ipc_error(client, BT_STOP_STREAM, EIO);
-}
-
-static void close_complete(struct audio_device *dev, void *user_data)
-{
-       struct unix_client *client = user_data;
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_close_rsp *rsp = (void *) buf;
-
-       memset(buf, 0, sizeof(buf));
-
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_CLOSE;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-}
-
-static void start_close(struct audio_device *dev, struct unix_client *client,
-                       gboolean reply)
-{
-       struct a2dp_data *a2dp;
-       struct headset_data *hs;
-
-       if (!client->dev)
-               goto failed;
-
-       switch (client->type) {
-       case TYPE_HEADSET:
-               hs = &client->d.hs;
-
-               if (client->dev && hs->locked) {
-                       headset_unlock(client->dev, client->lock);
-                       hs->locked = FALSE;
-               }
-               break;
-        case TYPE_GATEWAY:
-                break;
-       case TYPE_SOURCE:
-       case TYPE_SINK:
-               a2dp = &client->d.a2dp;
-
-               if (client->cb_id > 0) {
-                       avdtp_stream_remove_cb(a2dp->session, a2dp->stream,
-                                                               client->cb_id);
-                       client->cb_id = 0;
-               }
-               if (a2dp->sep) {
-                       a2dp_sep_unlock(a2dp->sep, a2dp->session);
-                       a2dp->sep = NULL;
-               }
-               if (a2dp->session) {
-                       avdtp_unref(a2dp->session);
-                       a2dp->session = NULL;
-               }
-               a2dp->stream = NULL;
-               break;
-       default:
-               error("No known services for device");
-               goto failed;
-       }
-
-       if (!reply)
-               return;
-
-       close_complete(dev, client);
-       client->dev = NULL;
-
-       return;
-
-failed:
-       if (reply)
-               unix_ipc_error(client, BT_STOP_STREAM, EINVAL);
-}
-
-static void handle_getcapabilities_req(struct unix_client *client,
-                                       struct bt_get_capabilities_req *req)
-{
-       struct audio_device *dev;
-       bdaddr_t src, dst;
-       int err = EIO;
-       const char *interface;
-
-       if (!check_nul(req->source) || !check_nul(req->destination) ||
-                       !check_nul(req->object)) {
-               err = EINVAL;
-               goto failed;
-       }
-
-       str2ba(req->source, &src);
-       str2ba(req->destination, &dst);
-
-       if (!manager_find_device(req->object, &src, &dst, NULL, FALSE))
-               goto failed;
-
-       if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
-               interface = AUDIO_HEADSET_INTERFACE;
-       else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
-               interface = AUDIO_SINK_INTERFACE;
-       else
-               interface = client->interface;
-
-       dev = manager_find_device(req->object, &src, &dst, interface, TRUE);
-       if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
-               dev = manager_find_device(req->object, &src, &dst,
-                                                       interface, FALSE);
-
-       if (!dev) {
-               if (req->transport == BT_CAPABILITIES_TRANSPORT_SCO)
-                       interface = AUDIO_GATEWAY_INTERFACE;
-               else if (req->transport == BT_CAPABILITIES_TRANSPORT_A2DP)
-                       interface = AUDIO_SOURCE_INTERFACE;
-               else
-                       interface = NULL;
-               dev = manager_find_device(req->object, &src, &dst,
-                                                       interface, TRUE);
-               if (!dev && (req->flags & BT_FLAG_AUTOCONNECT))
-                       dev = manager_find_device(req->object, &src, &dst,
-                                                       interface, FALSE);
-       }
-
-       if (!dev) {
-               error("Unable to find a matching device");
-               goto failed;
-       }
-
-       client->type = select_service(dev, interface);
-       if (client->type == TYPE_NONE) {
-               error("No matching service found");
-               goto failed;
-       }
-
-       if (g_strcmp0(interface, client->interface) != 0) {
-               g_free(client->interface);
-               client->interface = g_strdup(interface);
-       }
-
-       client->seid = req->seid;
-
-       start_discovery(dev, client);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_GET_CAPABILITIES, err);
-}
-
-static int handle_sco_open(struct unix_client *client, struct bt_open_req *req)
-{
-       if (!client->interface)
-               client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
-       else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) &&
-               !g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
-               return -EIO;
-
-       DBG("open sco - object=%s source=%s destination=%s lock=%s%s",
-                       strcmp(req->object, "") ? req->object : "ANY",
-                       strcmp(req->source, "") ? req->source : "ANY",
-                       strcmp(req->destination, "") ? req->destination : "ANY",
-                       req->lock & BT_READ_LOCK ? "read" : "",
-                       req->lock & BT_WRITE_LOCK ? "write" : "");
-
-       return 0;
-}
-
-static int handle_a2dp_open(struct unix_client *client, struct bt_open_req *req)
-{
-       if (!client->interface)
-               /* FIXME: are we treating a sink or a source? */
-               client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-       else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
-                       !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
-               return -EIO;
-
-       DBG("open a2dp - object=%s source=%s destination=%s lock=%s%s",
-                       strcmp(req->object, "") ? req->object : "ANY",
-                       strcmp(req->source, "") ? req->source : "ANY",
-                       strcmp(req->destination, "") ? req->destination : "ANY",
-                       req->lock & BT_READ_LOCK ? "read" : "",
-                       req->lock & BT_WRITE_LOCK ? "write" : "");
-
-       return 0;
-}
-
-static void handle_open_req(struct unix_client *client, struct bt_open_req *req)
-{
-       struct audio_device *dev;
-       bdaddr_t src, dst;
-       int err = 0;
-
-       if (!check_nul(req->source) || !check_nul(req->destination) ||
-                       !check_nul(req->object)) {
-               err = EINVAL;
-               goto failed;
-       }
-
-       str2ba(req->source, &src);
-       str2ba(req->destination, &dst);
-
-       if (req->seid > BT_A2DP_SEID_RANGE) {
-               err = handle_sco_open(client, req);
-               if (err < 0) {
-                       err = -err;
-                       goto failed;
-               }
-       } else {
-               err = handle_a2dp_open(client, req);
-               if (err < 0) {
-                       err = -err;
-                       goto failed;
-               }
-       }
-
-       if (!manager_find_device(req->object, &src, &dst, NULL, FALSE))
-               goto failed;
-
-       dev = manager_find_device(req->object, &src, &dst, client->interface,
-                               TRUE);
-       if (!dev)
-               dev = manager_find_device(req->object, &src, &dst,
-                                       client->interface, FALSE);
-
-       if (!dev)
-               goto failed;
-
-       client->seid = req->seid;
-       client->lock = req->lock;
-
-       start_open(dev, client);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_OPEN, err ? : EIO);
-}
-
-static int handle_sco_transport(struct unix_client *client,
-                               struct bt_set_configuration_req *req)
-{
-       struct audio_device *dev = client->dev;
-
-       if (!client->interface) {
-               if (dev->headset)
-                       client->interface = g_strdup(AUDIO_HEADSET_INTERFACE);
-               else if (dev->gateway)
-                       client->interface = g_strdup(AUDIO_GATEWAY_INTERFACE);
-               else
-                       return -EIO;
-       } else if (!g_str_equal(client->interface, AUDIO_HEADSET_INTERFACE) &&
-                       !g_str_equal(client->interface, AUDIO_GATEWAY_INTERFACE))
-               return -EIO;
-
-       return 0;
-}
-
-static int handle_a2dp_transport(struct unix_client *client,
-                               struct bt_set_configuration_req *req)
-{
-       struct avdtp_service_capability *media_transport, *media_codec;
-       struct sbc_codec_cap sbc_cap;
-       struct mpeg_codec_cap mpeg_cap;
-
-       if (!client->interface)
-               /* FIXME: are we treating a sink or a source? */
-               client->interface = g_strdup(AUDIO_SINK_INTERFACE);
-       else if (!g_str_equal(client->interface, AUDIO_SINK_INTERFACE) &&
-                       !g_str_equal(client->interface, AUDIO_SOURCE_INTERFACE))
-               return -EIO;
-
-       g_slist_free_full(client->caps, g_free);
-       client->caps = NULL;
-
-       media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-                                               NULL, 0);
-
-       client->caps = g_slist_append(client->caps, media_transport);
-
-       if (req->codec.type == BT_A2DP_MPEG12_SINK ||
-               req->codec.type == BT_A2DP_MPEG12_SOURCE) {
-               mpeg_capabilities_t *mpeg = (void *) &req->codec;
-
-               memset(&mpeg_cap, 0, sizeof(mpeg_cap));
-
-               mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-               mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
-               mpeg_cap.channel_mode = mpeg->channel_mode;
-               mpeg_cap.crc = mpeg->crc;
-               mpeg_cap.layer = mpeg->layer;
-               mpeg_cap.frequency = mpeg->frequency;
-               mpeg_cap.mpf = mpeg->mpf;
-               mpeg_cap.bitrate = mpeg->bitrate;
-
-               media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
-                                                       sizeof(mpeg_cap));
-
-               print_mpeg12(&mpeg_cap);
-       } else if (req->codec.type == BT_A2DP_SBC_SINK ||
-                       req->codec.type == BT_A2DP_SBC_SOURCE) {
-               sbc_capabilities_t *sbc = (void *) &req->codec;
-
-               memset(&sbc_cap, 0, sizeof(sbc_cap));
-
-               sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-               sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
-               sbc_cap.channel_mode = sbc->channel_mode;
-               sbc_cap.frequency = sbc->frequency;
-               sbc_cap.allocation_method = sbc->allocation_method;
-               sbc_cap.subbands = sbc->subbands;
-               sbc_cap.block_length = sbc->block_length;
-               sbc_cap.min_bitpool = sbc->min_bitpool;
-               sbc_cap.max_bitpool = sbc->max_bitpool;
-
-               media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-                                                       sizeof(sbc_cap));
-
-               print_sbc(&sbc_cap);
-       } else
-               return -EINVAL;
-
-       client->caps = g_slist_append(client->caps, media_codec);
-
-       return 0;
-}
-
-static void handle_setconfiguration_req(struct unix_client *client,
-                                       struct bt_set_configuration_req *req)
-{
-       int err = 0;
-
-       if (req->codec.seid != client->seid) {
-               error("Unable to set configuration: seid %d not opened",
-                               req->codec.seid);
-               goto failed;
-       }
-
-       if (!client->dev)
-               goto failed;
-
-       if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_SCO) {
-               err = handle_sco_transport(client, req);
-               if (err < 0) {
-                       err = -err;
-                       goto failed;
-               }
-       } else if (req->codec.transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               err = handle_a2dp_transport(client, req);
-               if (err < 0) {
-                       err = -err;
-                       goto failed;
-               }
-       }
-
-       start_config(client->dev, client);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_SET_CONFIGURATION, err ? : EIO);
-}
-
-static void handle_streamstart_req(struct unix_client *client,
-                                       struct bt_start_stream_req *req)
-{
-       if (!client->dev)
-               goto failed;
-
-       start_resume(client->dev, client);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_START_STREAM, EIO);
-}
-
-static void handle_streamstop_req(struct unix_client *client,
-                                       struct bt_stop_stream_req *req)
-{
-       if (!client->dev)
-               goto failed;
-
-       start_suspend(client->dev, client);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_STOP_STREAM, EIO);
-}
-
-static void handle_close_req(struct unix_client *client,
-                               struct bt_close_req *req)
-{
-       if (!client->dev)
-               goto failed;
-
-       start_close(client->dev, client, TRUE);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_CLOSE, EIO);
-}
-
-static void handle_control_req(struct unix_client *client,
-                                       struct bt_control_req *req)
-{
-       /* FIXME: really implement that */
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_CONTROL;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-}
-
-static void handle_delay_report_req(struct unix_client *client,
-                                       struct bt_delay_report_req *req)
-{
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       struct bt_set_configuration_rsp *rsp = (void *) buf;
-       struct a2dp_data *a2dp;
-       int err;
-
-       if (!client->dev) {
-               err = -ENODEV;
-               goto failed;
-       }
-
-       switch (client->type) {
-       case TYPE_HEADSET:
-        case TYPE_GATEWAY:
-               err = -EINVAL;
-               goto failed;
-       case TYPE_SOURCE:
-       case TYPE_SINK:
-               a2dp = &client->d.a2dp;
-               if (a2dp->session && a2dp->stream) {
-                       err = avdtp_delay_report(a2dp->session, a2dp->stream,
-                                                               req->delay);
-                       if (err < 0)
-                               goto failed;
-               } else {
-                       err = -EINVAL;
-                       goto failed;
-               }
-               break;
-       default:
-               error("No known services for device");
-               err = -EINVAL;
-               goto failed;
-       }
-
-       memset(buf, 0, sizeof(buf));
-       rsp->h.type = BT_RESPONSE;
-       rsp->h.name = BT_DELAY_REPORT;
-       rsp->h.length = sizeof(*rsp);
-
-       unix_ipc_sendmsg(client, &rsp->h);
-
-       return;
-
-failed:
-       unix_ipc_error(client, BT_DELAY_REPORT, -err);
-}
-
-static gboolean client_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       char buf[BT_SUGGESTED_BUFFER_SIZE];
-       bt_audio_msg_header_t *msghdr = (void *) buf;
-       struct unix_client *client = data;
-       int len;
-       const char *type, *name;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       if (cond & (G_IO_HUP | G_IO_ERR)) {
-               DBG("Unix client disconnected (fd=%d)", client->sock);
-
-               goto failed;
-       }
-
-       memset(buf, 0, sizeof(buf));
-
-       len = recv(client->sock, buf, sizeof(buf), 0);
-       if (len < 0) {
-               error("recv: %s (%d)", strerror(errno), errno);
-               goto failed;
-       }
-
-       type = bt_audio_strtype(msghdr->type);
-       name = bt_audio_strname(msghdr->name);
-
-       DBG("Audio API: %s <- %s", type, name);
-
-       if (msghdr->length != len) {
-               error("Invalid message: length mismatch");
-               goto failed;
-       }
-
-       switch (msghdr->name) {
-       case BT_GET_CAPABILITIES:
-               handle_getcapabilities_req(client,
-                               (struct bt_get_capabilities_req *) msghdr);
-               break;
-       case BT_OPEN:
-               handle_open_req(client,
-                               (struct bt_open_req *) msghdr);
-               break;
-       case BT_SET_CONFIGURATION:
-               handle_setconfiguration_req(client,
-                               (struct bt_set_configuration_req *) msghdr);
-               break;
-       case BT_START_STREAM:
-               handle_streamstart_req(client,
-                               (struct bt_start_stream_req *) msghdr);
-               break;
-       case BT_STOP_STREAM:
-               handle_streamstop_req(client,
-                               (struct bt_stop_stream_req *) msghdr);
-               break;
-       case BT_CLOSE:
-               handle_close_req(client,
-                               (struct bt_close_req *) msghdr);
-               break;
-       case BT_CONTROL:
-               handle_control_req(client,
-                               (struct bt_control_req *) msghdr);
-               break;
-       case BT_DELAY_REPORT:
-               handle_delay_report_req(client,
-                               (struct bt_delay_report_req *) msghdr);
-               break;
-       default:
-               error("Audio API: received unexpected message name %d",
-                               msghdr->name);
-       }
-
-       return TRUE;
-
-failed:
-       clients = g_slist_remove(clients, client);
-       start_close(client->dev, client, FALSE);
-       client_free(client);
-       return FALSE;
-}
-
-static gboolean server_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       struct sockaddr_un addr;
-       socklen_t addrlen;
-       int sk, cli_sk;
-       struct unix_client *client;
-       GIOChannel *io;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       if (cond & (G_IO_HUP | G_IO_ERR)) {
-               g_io_channel_shutdown(chan, TRUE, NULL);
-               return FALSE;
-       }
-
-       sk = g_io_channel_unix_get_fd(chan);
-
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-
-       cli_sk = accept(sk, (struct sockaddr *) &addr, &addrlen);
-       if (cli_sk < 0) {
-               error("accept: %s (%d)", strerror(errno), errno);
-               return TRUE;
-       }
-
-       DBG("Accepted new client connection on unix socket (fd=%d)", cli_sk);
-       set_nonblocking(cli_sk);
-
-       client = g_new0(struct unix_client, 1);
-       client->sock = cli_sk;
-       clients = g_slist_append(clients, client);
-
-       io = g_io_channel_unix_new(cli_sk);
-       g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                                       client_cb, client);
-       g_io_channel_unref(io);
-
-       return TRUE;
-}
-
-void unix_device_removed(struct audio_device *dev)
-{
-       GSList *l;
-
-       DBG("unix_device_removed(%p)", dev);
-
-       l = clients;
-       while (l) {
-               struct unix_client *client = l->data;
-
-               l = l->next;
-
-               if (client->dev == dev) {
-                       clients = g_slist_remove(clients, client);
-                       start_close(client->dev, client, FALSE);
-                       client_free(client);
-               }
-       }
-}
-
-void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay)
-{
-       GSList *l;
-       struct bt_delay_report_ind ind;
-
-       DBG("unix_delay_report(%p): %u.%ums", dev, delay / 10, delay % 10);
-
-       memset(&ind, 0, sizeof(ind));
-       ind.h.type = BT_INDICATION;
-       ind.h.name = BT_DELAY_REPORT;
-       ind.h.length = sizeof(ind);
-       ind.delay = delay;
-
-       for (l = clients; l != NULL; l = g_slist_next(l)) {
-               struct unix_client *client = l->data;
-
-               if (client->dev != dev || client->seid != seid)
-                       continue;
-
-               unix_ipc_sendmsg(client, (void *) &ind);
-       }
-}
-
-int unix_init(void)
-{
-       GIOChannel *io;
-       struct sockaddr_un addr = {
-               AF_UNIX, BT_IPC_SOCKET_NAME
-       };
-
-       int sk, err;
-
-       sk = socket(PF_LOCAL, SOCK_STREAM, 0);
-       if (sk < 0) {
-               err = -errno;
-               error("Can't create unix socket: %s (%d)", strerror(-err),
-                                                                       -err);
-               return err;
-       }
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               error("Can't bind unix socket: %s (%d)", strerror(-err),
-                                                                       -err);
-               close(sk);
-               return err;
-       }
-
-       set_nonblocking(sk);
-
-       if (listen(sk, 1) < 0) {
-               err = -errno;
-               error("Can't listen on unix socket: %s (%d)", strerror(-err),
-                                                                       -err);
-               close(sk);
-               return err;
-       }
-
-       unix_sock = sk;
-
-       io = g_io_channel_unix_new(sk);
-       g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                                       server_cb, NULL);
-       g_io_channel_unref(io);
-
-       DBG("Unix socket created: %d", sk);
-
-       return 0;
-}
-
-void unix_exit(void)
-{
-       g_slist_free_full(clients, client_free);
-       if (unix_sock >= 0) {
-               close(unix_sock);
-               unix_sock = -1;
-       }
-}
index e81fb75..f62a533 100644 (file)
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdarg.h>
 #include <stdlib.h>
 #include <unistd.h>
 #endif
 
 #define ERROR_FAILED(gerr, str, err) \
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_FAILED, \
+               g_set_error(gerr, BT_IO_ERROR, err, \
                                str ": %s (%d)", strerror(err), err)
 
 #define DEFAULT_DEFER_TIMEOUT 30
 
+typedef enum {
+       BT_IO_L2CAP,
+       BT_IO_RFCOMM,
+       BT_IO_SCO,
+       BT_IO_INVALID,
+} BtIOType;
+
 struct set_opts {
        bdaddr_t src;
        bdaddr_t dst;
+       BtIOType type;
+       uint8_t src_type;
        uint8_t dst_type;
        int defer;
        int sec_level;
@@ -64,6 +78,7 @@ struct set_opts {
        uint8_t mode;
        int flushable;
        uint32_t priority;
+       uint16_t voice;
 };
 
 struct connect {
@@ -85,6 +100,48 @@ struct server {
        GDestroyNotify destroy;
 };
 
+static BtIOType bt_io_get_type(GIOChannel *io, GError **gerr)
+{
+       int sk = g_io_channel_unix_get_fd(io);
+       int domain, proto, err;
+       socklen_t len;
+
+       domain = 0;
+       len = sizeof(domain);
+       err = getsockopt(sk, SOL_SOCKET, SO_DOMAIN, &domain, &len);
+       if (err < 0) {
+               ERROR_FAILED(gerr, "getsockopt(SO_DOMAIN)", errno);
+               return BT_IO_INVALID;
+       }
+
+       if (domain != AF_BLUETOOTH) {
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                               "BtIO socket domain not AF_BLUETOOTH");
+               return BT_IO_INVALID;
+       }
+
+       proto = 0;
+       len = sizeof(proto);
+       err = getsockopt(sk, SOL_SOCKET, SO_PROTOCOL, &proto, &len);
+       if (err < 0) {
+               ERROR_FAILED(gerr, "getsockopt(SO_PROTOCOL)", errno);
+               return BT_IO_INVALID;
+       }
+
+       switch (proto) {
+       case BTPROTO_RFCOMM:
+               return BT_IO_RFCOMM;
+       case BTPROTO_SCO:
+               return BT_IO_SCO;
+       case BTPROTO_L2CAP:
+               return BT_IO_L2CAP;
+       default:
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                                       "Unknown BtIO socket type");
+               return BT_IO_INVALID;
+       }
+}
+
 static void server_remove(struct server *server)
 {
        if (server->destroy)
@@ -124,19 +181,28 @@ static gboolean accept_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
        struct accept *accept = user_data;
-       GError *err = NULL;
+       GError *gerr = NULL;
 
        /* If the user aborted this accept attempt */
        if ((cond & G_IO_NVAL) || check_nval(io))
                return FALSE;
 
-       if (cond & (G_IO_HUP | G_IO_ERR))
-               g_set_error(&err, BT_IO_ERROR, BT_IO_ERROR_DISCONNECTED,
-                               "HUP or ERR on socket");
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               int err, sk_err, sock = g_io_channel_unix_get_fd(io);
+               socklen_t len = sizeof(sk_err);
+
+               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+                       err = -errno;
+               else
+                       err = -sk_err;
 
-       accept->connect(io, err, accept->user_data);
+               if (err < 0)
+                       ERROR_FAILED(&gerr, "HUP or ERR on socket", -err);
+       }
 
-       g_clear_error(&err);
+       accept->connect(io, gerr, accept->user_data);
+
+       g_clear_error(&gerr);
 
        return FALSE;
 }
@@ -146,32 +212,26 @@ static gboolean connect_cb(GIOChannel *io, GIOCondition cond,
 {
        struct connect *conn = user_data;
        GError *gerr = NULL;
+       int err, sk_err, sock;
+       socklen_t len = sizeof(sk_err);
 
        /* If the user aborted this connect attempt */
        if ((cond & G_IO_NVAL) || check_nval(io))
                return FALSE;
 
-       if (cond & G_IO_OUT) {
-               int err, sk_err = 0, sock = g_io_channel_unix_get_fd(io);
-               socklen_t len = sizeof(sk_err);
+       sock = g_io_channel_unix_get_fd(io);
 
-               if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
-                       err = -errno;
-               else
-                       err = -sk_err;
+       if (getsockopt(sock, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+               err = -errno;
+       else
+               err = -sk_err;
 
-               if (err < 0)
-                       g_set_error(&gerr, BT_IO_ERROR,
-                                       BT_IO_ERROR_CONNECT_FAILED, "%s (%d)",
-                                       strerror(-err), -err);
-       } else if (cond & (G_IO_HUP | G_IO_ERR))
-               g_set_error(&gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-                               "HUP or ERR on socket");
+       if (err < 0)
+               ERROR_FAILED(&gerr, "connect error", -err);
 
        conn->connect(io, gerr, conn->user_data);
 
-       if (gerr)
-               g_error_free(gerr);
+       g_clear_error(&gerr);
 
        return FALSE;
 }
@@ -258,8 +318,8 @@ static void accept_add(GIOChannel *io, BtIOConnect connect, gpointer user_data,
                                        (GDestroyNotify) accept_remove);
 }
 
-static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
-                                               uint16_t cid, GError **err)
+static int l2cap_bind(int sock, const bdaddr_t *src, uint8_t src_type,
+                               uint16_t psm, uint16_t cid, GError **err)
 {
        struct sockaddr_l2 addr;
 
@@ -272,6 +332,8 @@ static int l2cap_bind(int sock, const bdaddr_t *src, uint16_t psm,
        else
                addr.l2_psm = htobs(psm);
 
+       addr.l2_bdaddr_type = src_type;
+
        if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                int error = -errno;
                ERROR_FAILED(err, "l2cap_bind", errno);
@@ -390,7 +452,7 @@ static gboolean set_sec_level(int sock, BtIOType type, int level, GError **err)
        int ret;
 
        if (level < BT_SECURITY_LOW || level > BT_SECURITY_HIGH) {
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+               g_set_error(err, BT_IO_ERROR, EINVAL,
                                "Valid security level range is %d-%d",
                                BT_SECURITY_LOW, BT_SECURITY_HIGH);
                return FALSE;
@@ -662,13 +724,14 @@ static int sco_connect(int sock, const bdaddr_t *dst)
        return 0;
 }
 
-static gboolean sco_set(int sock, uint16_t mtu, GError **err)
+static gboolean sco_set(int sock, uint16_t mtu, uint16_t voice, GError **err)
 {
        struct sco_options sco_opt;
+       struct bt_voice bt_voice;
        socklen_t len;
 
        if (!mtu)
-               return TRUE;
+               goto voice;
 
        len = sizeof(sco_opt);
        memset(&sco_opt, 0, len);
@@ -684,6 +747,17 @@ static gboolean sco_set(int sock, uint16_t mtu, GError **err)
                return FALSE;
        }
 
+voice:
+       if (!voice)
+               return TRUE;
+
+       bt_voice.setting = voice;
+       if (setsockopt(sock, SOL_BLUETOOTH, BT_VOICE, &bt_voice,
+                                               sizeof(bt_voice)) < 0) {
+               ERROR_FAILED(err, "setsockopt(BT_VOICE)", errno);
+               return FALSE;
+       }
+
        return TRUE;
 }
 
@@ -696,11 +770,13 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
        memset(opts, 0, sizeof(*opts));
 
        /* Set defaults */
+       opts->type = BT_IO_SCO;
        opts->defer = DEFAULT_DEFER_TIMEOUT;
        opts->master = -1;
        opts->mode = L2CAP_MODE_BASIC;
        opts->flushable = -1;
        opts->priority = 0;
+       opts->src_type = BDADDR_BREDR;
        opts->dst_type = BDADDR_BREDR;
 
        while (opt != BT_IO_OPT_INVALID) {
@@ -712,6 +788,9 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_SOURCE_BDADDR:
                        bacpy(&opts->src, va_arg(args, const bdaddr_t *));
                        break;
+               case BT_IO_OPT_SOURCE_TYPE:
+                       opts->src_type = va_arg(args, int);
+                       break;
                case BT_IO_OPT_DEST:
                        str2ba(va_arg(args, const char *), &opts->dst);
                        break;
@@ -728,12 +807,15 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                        opts->sec_level = va_arg(args, int);
                        break;
                case BT_IO_OPT_CHANNEL:
+                       opts->type = BT_IO_RFCOMM;
                        opts->channel = va_arg(args, int);
                        break;
                case BT_IO_OPT_PSM:
+                       opts->type = BT_IO_L2CAP;
                        opts->psm = va_arg(args, int);
                        break;
                case BT_IO_OPT_CID:
+                       opts->type = BT_IO_L2CAP;
                        opts->cid = va_arg(args, int);
                        break;
                case BT_IO_OPT_MTU:
@@ -763,8 +845,11 @@ static gboolean parse_set_opts(struct set_opts *opts, GError **err,
                case BT_IO_OPT_PRIORITY:
                        opts->priority = va_arg(args, int);
                        break;
+               case BT_IO_OPT_VOICE:
+                       opts->voice = va_arg(args, int);
+                       break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -883,8 +968,7 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        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");
+                       ERROR_FAILED(err, "Not implemented", EINVAL);
                        return FALSE;
                case BT_IO_OPT_DEFER_TIMEOUT:
                        len = sizeof(int);
@@ -961,7 +1045,7 @@ static gboolean l2cap_get(int sock, GError **err, BtIOOption opt1,
                        *(va_arg(args, uint32_t *)) = priority;
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1068,7 +1152,7 @@ static gboolean rfcomm_get(int sock, GError **err, BtIOOption opt1,
                        memcpy(va_arg(args, uint8_t *), dev_class, 3);
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1151,7 +1235,7 @@ static gboolean sco_get(int sock, GError **err, BtIOOption opt1, va_list args)
                        memcpy(va_arg(args, uint8_t *), dev_class, 3);
                        break;
                default:
-                       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
+                       g_set_error(err, BT_IO_ERROR, EINVAL,
                                        "Unknown option %d", opt);
                        return FALSE;
                }
@@ -1170,19 +1254,17 @@ static gboolean get_valist(GIOChannel *io, BtIOType type, GError **err,
        sock = g_io_channel_unix_get_fd(io);
 
        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);
        case BT_IO_SCO:
                return sco_get(sock, err, opt1, args);
+       default:
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", type);
+               return FALSE;
        }
-
-       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                       "Unknown BtIO type %d", type);
-       return FALSE;
 }
 
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
@@ -1215,13 +1297,13 @@ gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
        return TRUE;
 }
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-                                                       BtIOOption opt1, ...)
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
        va_list args;
        gboolean ret;
        struct set_opts opts;
        int sock;
+       BtIOType type;
 
        va_start(args, opt1);
        ret = parse_set_opts(&opts, err, opt1, args);
@@ -1230,31 +1312,38 @@ gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
        if (!ret)
                return ret;
 
+       type = bt_io_get_type(io, err);
+       if (type == BT_IO_INVALID)
+               return FALSE;
+
        sock = g_io_channel_unix_get_fd(io);
 
        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);
        case BT_IO_RFCOMM:
                return rfcomm_set(sock, opts.sec_level, opts.master, err);
        case BT_IO_SCO:
-               return sco_set(sock, opts.mtu, err);
+               return sco_set(sock, opts.mtu, opts.voice, err);
+       default:
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", type);
+               return FALSE;
        }
 
-       g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                       "Unknown BtIO type %d", type);
-       return FALSE;
 }
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-                                                       BtIOOption opt1, ...)
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...)
 {
        va_list args;
        gboolean ret;
+       BtIOType type;
+
+       type = bt_io_get_type(io, err);
+       if (type == BT_IO_INVALID)
+               return FALSE;
 
        va_start(args, opt1);
        ret = get_valist(io, type, err, opt1, args);
@@ -1263,47 +1352,21 @@ gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
        return ret;
 }
 
-static GIOChannel *create_io(BtIOType type, gboolean server,
-                                       struct set_opts *opts, GError **err)
+static GIOChannel *create_io(gboolean server, struct set_opts *opts,
+                                                               GError **err)
 {
        int sock;
        GIOChannel *io;
 
-       switch (type) {
-       case BT_IO_L2RAW:
-               sock = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_L2CAP);
-               if (sock < 0) {
-                       ERROR_FAILED(err, "socket(RAW, 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, 0, 0, 0, -1, -1, 0, err))
-                       goto failed;
-               break;
+       switch (opts->type) {
        case BT_IO_L2CAP:
                sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
                if (sock < 0) {
                        ERROR_FAILED(err, "socket(SEQPACKET, 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_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)
+               if (l2cap_bind(sock, &opts->src, opts->src_type,
+                               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,
@@ -1330,12 +1393,12 @@ static GIOChannel *create_io(BtIOType type, gboolean server,
                }
                if (sco_bind(sock, &opts->src, err) < 0)
                        goto failed;
-               if (!sco_set(sock, opts->mtu, err))
+               if (!sco_set(sock, opts->mtu, opts->voice, err))
                        goto failed;
                break;
        default:
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                               "Unknown BtIO type %d", type);
+               g_set_error(err, BT_IO_ERROR, EINVAL,
+                               "Unknown BtIO type %d", opts->type);
                return NULL;
        }
 
@@ -1352,9 +1415,9 @@ failed:
        return NULL;
 }
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
-                               gpointer user_data, GDestroyNotify destroy,
-                               GError **gerr, BtIOOption opt1, ...)
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+                               GDestroyNotify destroy, GError **gerr,
+                               BtIOOption opt1, ...)
 {
        GIOChannel *io;
        va_list args;
@@ -1369,19 +1432,14 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
        if (ret == FALSE)
                return NULL;
 
-       io = create_io(type, FALSE, &opts, gerr);
+       io = create_io(FALSE, &opts, gerr);
        if (io == NULL)
                return NULL;
 
        sock = g_io_channel_unix_get_fd(io);
 
-       switch (type) {
-       case BT_IO_L2RAW:
-               err = l2cap_connect(sock, &opts.dst, opts.dst_type, 0,
-                                                               opts.cid);
-               break;
+       switch (opts.type) {
        case BT_IO_L2CAP:
-       case BT_IO_L2ERTM:
                err = l2cap_connect(sock, &opts.dst, opts.dst_type,
                                                        opts.psm, opts.cid);
                break;
@@ -1392,14 +1450,13 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
                err = sco_connect(sock, &opts.dst);
                break;
        default:
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                                               "Unknown BtIO type %d", type);
+               g_set_error(gerr, BT_IO_ERROR, EINVAL,
+                                       "Unknown BtIO type %d", opts.type);
                return NULL;
        }
 
        if (err < 0) {
-               g_set_error(gerr, BT_IO_ERROR, BT_IO_ERROR_CONNECT_FAILED,
-                               "connect: %s (%d)", strerror(-err), -err);
+               ERROR_FAILED(gerr, "connect", -err);
                g_io_channel_unref(io);
                return NULL;
        }
@@ -1409,10 +1466,9 @@ GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
        return io;
 }
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-                               BtIOConfirm confirm, gpointer user_data,
-                               GDestroyNotify destroy, GError **err,
-                               BtIOOption opt1, ...)
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
+                               gpointer user_data, GDestroyNotify destroy,
+                               GError **err, BtIOOption opt1, ...)
 {
        GIOChannel *io;
        va_list args;
@@ -1420,12 +1476,6 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
        int sock;
        gboolean ret;
 
-       if (type == BT_IO_L2RAW) {
-               g_set_error(err, BT_IO_ERROR, BT_IO_ERROR_INVALID_ARGS,
-                               "Server L2CAP RAW sockets not supported");
-               return NULL;
-       }
-
        va_start(args, opt1);
        ret = parse_set_opts(&opts, err, opt1, args);
        va_end(args);
@@ -1433,7 +1483,7 @@ GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
        if (ret == FALSE)
                return NULL;
 
-       io = create_io(type, TRUE, &opts, err);
+       io = create_io(TRUE, &opts, err);
        if (io == NULL)
                return NULL;
 
index cf0e070..2dce9f0 100644 (file)
 
 #include <glib.h>
 
-typedef enum {
-       BT_IO_ERROR_DISCONNECTED,
-       BT_IO_ERROR_CONNECT_FAILED,
-       BT_IO_ERROR_FAILED,
-       BT_IO_ERROR_INVALID_ARGS,
-} BtIOError;
-
 #define BT_IO_ERROR bt_io_error_quark()
 
 GQuark bt_io_error_quark(void);
 
 typedef enum {
-       BT_IO_L2RAW,
-       BT_IO_L2CAP,
-       BT_IO_L2ERTM,
-       BT_IO_RFCOMM,
-       BT_IO_SCO,
-} BtIOType;
-
-typedef enum {
        BT_IO_OPT_INVALID = 0,
        BT_IO_OPT_SOURCE,
        BT_IO_OPT_SOURCE_BDADDR,
+       BT_IO_OPT_SOURCE_TYPE,
        BT_IO_OPT_DEST,
        BT_IO_OPT_DEST_BDADDR,
        BT_IO_OPT_DEST_TYPE,
@@ -69,6 +55,7 @@ typedef enum {
        BT_IO_OPT_MODE,
        BT_IO_OPT_FLUSHABLE,
        BT_IO_OPT_PRIORITY,
+       BT_IO_OPT_VOICE,
 } BtIOOption;
 
 typedef enum {
@@ -93,19 +80,16 @@ typedef void (*BtIOConnect)(GIOChannel *io, GError *err, gpointer user_data);
 gboolean bt_io_accept(GIOChannel *io, BtIOConnect connect, gpointer user_data,
                                        GDestroyNotify destroy, GError **err);
 
-gboolean bt_io_set(GIOChannel *io, BtIOType type, GError **err,
-                                               BtIOOption opt1, ...);
+gboolean bt_io_set(GIOChannel *io, GError **err, BtIOOption opt1, ...);
 
-gboolean bt_io_get(GIOChannel *io, BtIOType type, GError **err,
-                                               BtIOOption opt1, ...);
+gboolean bt_io_get(GIOChannel *io, GError **err, BtIOOption opt1, ...);
 
-GIOChannel *bt_io_connect(BtIOType type, BtIOConnect connect,
+GIOChannel *bt_io_connect(BtIOConnect connect, gpointer user_data,
+                               GDestroyNotify destroy, GError **gerr,
+                               BtIOOption opt1, ...);
+
+GIOChannel *bt_io_listen(BtIOConnect connect, BtIOConfirm confirm,
                                gpointer user_data, GDestroyNotify destroy,
                                GError **err, BtIOOption opt1, ...);
 
-GIOChannel *bt_io_listen(BtIOType type, BtIOConnect connect,
-                               BtIOConfirm confirm, gpointer user_data,
-                               GDestroyNotify destroy, GError **err,
-                               BtIOOption opt1, ...);
-
 #endif
diff --git a/client/agent.c b/client/agent.c
new file mode 100644 (file)
index 0000000..2d9dffd
--- /dev/null
@@ -0,0 +1,486 @@
+/*
+ *
+ *  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 <readline/readline.h>
+#include <gdbus.h>
+
+#include "display.h"
+#include "agent.h"
+
+#define AGENT_PATH "/org/bluez/agent"
+#define AGENT_INTERFACE "org.bluez.Agent1"
+
+#define AGENT_PROMPT   COLOR_RED "[agent]" COLOR_OFF " "
+
+static gboolean agent_registered = FALSE;
+static const char *agent_capability = NULL;
+static DBusMessage *pending_message = NULL;
+static char *agent_saved_prompt = NULL;
+static int agent_saved_point = 0;
+
+static void agent_prompt(const char *msg)
+{
+       char *prompt;
+
+       /* Normal use should not prompt for user input to the agent a second
+        * time before it releases the prompt, but we take a safe action. */
+       if (agent_saved_prompt)
+               return;
+
+       agent_saved_point = rl_point;
+       agent_saved_prompt = g_strdup(rl_prompt);
+
+       rl_set_prompt("");
+       rl_redisplay();
+
+       prompt = g_strdup_printf(AGENT_PROMPT "%s", msg);
+       rl_set_prompt(prompt);
+       g_free(prompt);
+
+       rl_replace_line("", 0);
+       rl_redisplay();
+}
+
+static void agent_release_prompt(void)
+{
+       if (!agent_saved_prompt)
+               return;
+
+       /* This will cause rl_expand_prompt to re-run over the last prompt, but
+        * our prompt doesn't expand anyway. */
+       rl_set_prompt(agent_saved_prompt);
+       rl_replace_line("", 0);
+       rl_point = agent_saved_point;
+       rl_redisplay();
+
+       g_free(agent_saved_prompt);
+       agent_saved_prompt = NULL;
+}
+
+dbus_bool_t agent_completion(void)
+{
+       if (!pending_message)
+               return FALSE;
+
+       return TRUE;
+}
+
+static void pincode_response(DBusConnection *conn, const char *input)
+{
+       g_dbus_send_reply(conn, pending_message, DBUS_TYPE_STRING, &input,
+                                                       DBUS_TYPE_INVALID);
+}
+
+static void passkey_response(DBusConnection *conn, const char *input)
+{
+       dbus_uint32_t passkey;
+       if (sscanf(input, "%u", &passkey) == 1)
+               g_dbus_send_reply(conn, pending_message, DBUS_TYPE_UINT32,
+                                               &passkey, DBUS_TYPE_INVALID);
+       else if (!strcmp(input, "no"))
+               g_dbus_send_error(conn, pending_message,
+                                       "org.bluez.Error.Rejected", NULL);
+       else
+               g_dbus_send_error(conn, pending_message,
+                                       "org.bluez.Error.Canceled", NULL);
+}
+
+static void confirm_response(DBusConnection *conn, const char *input)
+{
+       if (!strcmp(input, "yes"))
+               g_dbus_send_reply(conn, pending_message, DBUS_TYPE_INVALID);
+       else if (!strcmp(input, "no"))
+               g_dbus_send_error(conn, pending_message,
+                                       "org.bluez.Error.Rejected", NULL);
+       else
+               g_dbus_send_error(conn, pending_message,
+                                       "org.bluez.Error.Canceled", NULL);
+}
+
+dbus_bool_t agent_input(DBusConnection *conn, const char *input)
+{
+       const char *member;
+
+       if (!pending_message)
+               return FALSE;
+
+       agent_release_prompt();
+
+       member = dbus_message_get_member(pending_message);
+
+       if (!strcmp(member, "RequestPinCode"))
+               pincode_response(conn, input);
+       else if (!strcmp(member, "RequestPasskey"))
+               passkey_response(conn, input);
+       else if (!strcmp(member, "RequestConfirmation"))
+               confirm_response(conn, input);
+       else if (!strcmp(member, "RequestAuthorization"))
+               confirm_response(conn, input);
+       else if (!strcmp(member, "AuthorizeService"))
+               confirm_response(conn, input);
+       else
+               g_dbus_send_error(conn, pending_message,
+                                       "org.bluez.Error.Canceled", NULL);
+
+       dbus_message_unref(pending_message);
+       pending_message = NULL;
+
+       return TRUE;
+}
+
+static DBusMessage *release_agent(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       agent_registered = FALSE;
+       agent_capability = NULL;
+
+       rl_printf("Agent released\n");
+
+       if (pending_message) {
+               dbus_message_unref(pending_message);
+               pending_message = NULL;
+       }
+
+       agent_release_prompt();
+
+       g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_pincode(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+
+       rl_printf("Request PIN code\n");
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                                                       DBUS_TYPE_INVALID);
+
+       agent_prompt("Enter PIN code: ");
+
+       pending_message = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *display_pincode(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+       const char *pincode;
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                               DBUS_TYPE_STRING, &pincode, DBUS_TYPE_INVALID);
+
+       rl_printf(AGENT_PROMPT "PIN code: %s\n", pincode);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_passkey(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+
+       rl_printf("Request passkey\n");
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                                                       DBUS_TYPE_INVALID);
+
+       agent_prompt("Enter passkey (number in 0-999999): ");
+
+       pending_message = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *display_passkey(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+       dbus_uint32_t passkey;
+       dbus_uint16_t entered;
+       char passkey_full[7];
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                       DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_UINT16, &entered,
+                                                       DBUS_TYPE_INVALID);
+
+       snprintf(passkey_full, sizeof(passkey_full), "%.6u", passkey);
+       passkey_full[6] = '\0';
+
+       if (entered > strlen(passkey_full))
+               entered = strlen(passkey_full);
+
+       rl_printf(AGENT_PROMPT "Passkey: "
+                       COLOR_BOLDGRAY "%.*s" COLOR_BOLDWHITE "%s\n" COLOR_OFF,
+                               entered, passkey_full, passkey_full + entered);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_confirmation(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+       dbus_uint32_t passkey;
+       char *str;
+
+       rl_printf("Request confirmation\n");
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                               DBUS_TYPE_UINT32, &passkey, DBUS_TYPE_INVALID);
+
+       str = g_strdup_printf("Confirm passkey %06u (yes/no): ", passkey);
+       agent_prompt(str);
+       g_free(str);
+
+       pending_message = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *request_authorization(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device;
+
+       rl_printf("Request authorization\n");
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                                                       DBUS_TYPE_INVALID);
+
+       agent_prompt("Accept pairing (yes/no): ");
+
+       pending_message = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *authorize_service(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *device, *uuid;
+       char *str;
+
+       rl_printf("Authorize service\n");
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                               DBUS_TYPE_STRING, &uuid, DBUS_TYPE_INVALID);
+
+       str = g_strdup_printf("Authorize service %s (yes/no): ", uuid);
+       agent_prompt(str);
+       g_free(str);
+
+       pending_message = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static DBusMessage *cancel_request(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       rl_printf("Request canceled\n");
+
+       agent_release_prompt();
+       dbus_message_unref(pending_message);
+       pending_message = NULL;
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+       { GDBUS_METHOD("Release", NULL, NULL, release_agent) },
+       { GDBUS_ASYNC_METHOD("RequestPinCode",
+                       GDBUS_ARGS({ "device", "o" }),
+                       GDBUS_ARGS({ "pincode", "s" }), request_pincode) },
+       { GDBUS_METHOD("DisplayPinCode",
+                       GDBUS_ARGS({ "device", "o" }, { "pincode", "s" }),
+                       NULL, display_pincode) },
+       { GDBUS_ASYNC_METHOD("RequestPasskey",
+                       GDBUS_ARGS({ "device", "o" }),
+                       GDBUS_ARGS({ "passkey", "u" }), request_passkey) },
+       { GDBUS_METHOD("DisplayPasskey",
+                       GDBUS_ARGS({ "device", "o" }, { "passkey", "u" },
+                                                       { "entered", "q" }),
+                       NULL, display_passkey) },
+       { GDBUS_ASYNC_METHOD("RequestConfirmation",
+                       GDBUS_ARGS({ "device", "o" }, { "passkey", "u" }),
+                       NULL, request_confirmation) },
+       { GDBUS_ASYNC_METHOD("RequestAuthorization",
+                       GDBUS_ARGS({ "device", "o" }),
+                       NULL, request_authorization) },
+       { GDBUS_ASYNC_METHOD("AuthorizeService",
+                       GDBUS_ARGS({ "device", "o" }, { "uuid", "s" }),
+                       NULL,  authorize_service) },
+       { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
+       { }
+};
+
+static void register_agent_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = AGENT_PATH;
+       const char *capability = agent_capability;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &capability);
+}
+
+static void register_agent_reply(DBusMessage *message, void *user_data)
+{
+       DBusConnection *conn = user_data;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == FALSE) {
+               agent_registered = TRUE;
+               rl_printf("Agent registered\n");
+       } else {
+               rl_printf("Failed to register agent: %s\n", error.name);
+               dbus_error_free(&error);
+
+               if (g_dbus_unregister_interface(conn, AGENT_PATH,
+                                               AGENT_INTERFACE) == FALSE)
+                       rl_printf("Failed to unregister agent object\n");
+       }
+}
+
+void agent_register(DBusConnection *conn, GDBusProxy *manager,
+                                               const char *capability)
+
+{
+       if (agent_registered == TRUE) {
+               rl_printf("Agent is already registered\n");
+               return;
+       }
+
+       agent_capability = capability;
+
+       if (g_dbus_register_interface(conn, AGENT_PATH,
+                                       AGENT_INTERFACE, methods,
+                                       NULL, NULL, NULL, NULL) == FALSE) {
+               rl_printf("Failed to register agent object\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(manager, "RegisterAgent",
+                                               register_agent_setup,
+                                               register_agent_reply,
+                                               conn, NULL) == FALSE) {
+               rl_printf("Failed to call register agent method\n");
+               return;
+       }
+
+       agent_capability = NULL;
+}
+
+static void unregister_agent_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = AGENT_PATH;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static void unregister_agent_reply(DBusMessage *message, void *user_data)
+{
+       DBusConnection *conn = user_data;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == FALSE) {
+               agent_registered = FALSE;
+               agent_capability = NULL;
+               rl_printf("Agent unregistered\n");
+
+               if (g_dbus_unregister_interface(conn, AGENT_PATH,
+                                               AGENT_INTERFACE) == FALSE)
+                       rl_printf("Failed to unregister agent object\n");
+       } else {
+               rl_printf("Failed to unregister agent: %s\n", error.name);
+               dbus_error_free(&error);
+       }
+}
+
+void agent_unregister(DBusConnection *conn, GDBusProxy *manager)
+{
+       if (agent_registered == FALSE) {
+               rl_printf("No agent is registered\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(manager, "UnregisterAgent",
+                                               unregister_agent_setup,
+                                               unregister_agent_reply,
+                                               conn, NULL) == FALSE) {
+               rl_printf("Failed to call unregister agent method\n");
+               return;
+       }
+}
+
+static void request_default_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = AGENT_PATH;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static void request_default_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to request default agent: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Default agent request successful\n");
+}
+
+void agent_default(DBusConnection *conn, GDBusProxy *manager)
+{
+       if (agent_registered == FALSE) {
+               rl_printf("No agent is registered\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(manager, "RequestDefaultAgent",
+                                               request_default_setup,
+                                               request_default_reply,
+                                               NULL, NULL) == FALSE) {
+               rl_printf("Failed to call request default agent method\n");
+               return;
+       }
+}
similarity index 67%
rename from plugins/storage.c
rename to client/agent.h
index 04a02c7..0fbe8e5 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+void agent_register(DBusConnection *conn, GDBusProxy *manager,
+                                               const char *capability);
+void agent_unregister(DBusConnection *conn, GDBusProxy *manager);
+void agent_default(DBusConnection *conn, GDBusProxy *manager);
 
-#include <bluetooth/bluetooth.h>
-
-#include "plugin.h"
-#include "log.h"
-
-static int storage_init(void)
-{
-       return 0;
-}
-
-static void storage_exit(void)
-{
-}
-
-BLUETOOTH_PLUGIN_DEFINE(storage, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, storage_init, storage_exit)
+dbus_bool_t agent_completion(void);
+dbus_bool_t agent_input(DBusConnection *conn, const char *input);
similarity index 55%
rename from network/main.c
rename to client/display.c
index 88e77ee..bc891af 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
 #include <config.h>
 #endif
 
-#include <errno.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <stdbool.h>
+#include <readline/readline.h>
 
-#include <gdbus.h>
+#include "display.h"
 
-#include "plugin.h"
-#include "manager.h"
-
-static DBusConnection *connection;
-
-static int network_init(void)
+void rl_printf(const char *fmt, ...)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
+       va_list args;
+       bool save_input;
+       char *saved_line;
+       int saved_point;
 
-       if (network_manager_init(connection) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
-       }
+       save_input = !RL_ISSTATE(RL_STATE_DONE);
 
-       return 0;
-}
+       if (save_input) {
+               saved_point = rl_point;
+               saved_line = rl_copy_text(0, rl_end);
+               rl_save_prompt();
+               rl_replace_line("", 0);
+               rl_redisplay();
+       }
 
-static void network_exit(void)
-{
-       network_manager_exit();
+       va_start(args, fmt);
+       vprintf(fmt, args);
+       va_end(args);
 
-       dbus_connection_unref(connection);
+       if (save_input) {
+               rl_restore_prompt();
+               rl_replace_line(saved_line, 0);
+               rl_point = saved_point;
+               rl_redisplay();
+               free(saved_line);
+       }
 }
-
-BLUETOOTH_PLUGIN_DEFINE(network, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, network_init, network_exit)
similarity index 68%
rename from src/oob.h
rename to client/display.h
index 5805082..91a0be9 100644 (file)
--- a/src/oob.h
@@ -2,9 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2011  ST-Ericsson SA
- *
- *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-typedef void (*oob_read_cb_t) (struct btd_adapter *adapter, uint8_t *hash,
-                                                       uint8_t *randomizer);
-
-void oob_register_cb(oob_read_cb_t cb);
+#define COLOR_OFF      "\x1B[0m"
+#define COLOR_RED      "\x1B[0;91m"
+#define COLOR_GREEN    "\x1B[0;92m"
+#define COLOR_YELLOW   "\x1B[0;93m"
+#define COLOR_BLUE     "\x1B[0;94m"
+#define COLOR_BOLDGRAY "\x1B[1;30m"
+#define COLOR_BOLDWHITE        "\x1B[1;37m"
 
-void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-                                                       uint8_t *randomizer);
+void rl_printf(const char *fmt, ...) __attribute__((format(printf, 1, 2)));
diff --git a/client/main.c b/client/main.c
new file mode 100644 (file)
index 0000000..0dd1510
--- /dev/null
@@ -0,0 +1,1390 @@
+/*
+ *
+ *  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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include "monitor/uuid.h"
+#include "agent.h"
+#include "display.h"
+
+/* String display constants */
+#define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
+#define COLORED_DEL    COLOR_RED "DEL" COLOR_OFF
+
+#define PROMPT_ON      COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
+#define PROMPT_OFF     "[bluetooth]# "
+
+static GMainLoop *main_loop;
+static DBusConnection *dbus_conn;
+
+static GDBusProxy *agent_manager;
+static char *auto_register_agent = NULL;
+
+static GDBusProxy *default_ctrl;
+static GList *ctrl_list;
+static GList *dev_list;
+
+static const char * const agent_arguments[] = {
+       "on",
+       "off",
+       "DisplayOnly",
+       "DisplayYesNo",
+       "KeyboardDisplay",
+       "KeyboardOnly",
+       "NoInputNoOutput",
+       NULL
+};
+
+static void proxy_leak(gpointer data)
+{
+       printf("Leaking proxy %p\n", data);
+}
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_ON);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_OFF);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+
+       g_list_free(ctrl_list);
+       ctrl_list = NULL;
+
+       default_ctrl = NULL;
+
+       g_list_free(dev_list);
+       dev_list = NULL;
+}
+
+static void print_adapter(GDBusProxy *proxy, const char *description)
+{
+       DBusMessageIter iter;
+       const char *address, *name;
+
+       if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &address);
+
+       if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
+               dbus_message_iter_get_basic(&iter, &name);
+       else
+               name = "<unknown>";
+
+       rl_printf("%s%s%sController %s %s %s\n",
+                               description ? "[" : "",
+                               description ? : "",
+                               description ? "] " : "",
+                               address, name,
+                               default_ctrl == proxy ? "[default]" : "");
+
+}
+
+static void print_device(GDBusProxy *proxy, const char *description)
+{
+       DBusMessageIter iter;
+       const char *address, *name;
+
+       if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &address);
+
+       if (g_dbus_proxy_get_property(proxy, "Alias", &iter) == TRUE)
+               dbus_message_iter_get_basic(&iter, &name);
+       else
+               name = "<unknown>";
+
+       rl_printf("%s%s%sDevice %s %s\n",
+                               description ? "[" : "",
+                               description ? : "",
+                               description ? "] " : "",
+                               address, name);
+}
+
+static void print_iter(const char *label, const char *name,
+                                               DBusMessageIter *iter)
+{
+       dbus_bool_t valbool;
+       dbus_uint32_t valu32;
+       dbus_uint16_t valu16;
+       dbus_int16_t vals16;
+       const char *valstr;
+
+       if (iter == NULL) {
+               rl_printf("%s%s is nil\n", label, name);
+               return;
+       }
+
+       switch (dbus_message_iter_get_arg_type(iter)) {
+       case DBUS_TYPE_INVALID:
+               rl_printf("%s%s is inavlid\n", label, name);
+               break;
+       case DBUS_TYPE_STRING:
+       case DBUS_TYPE_OBJECT_PATH:
+               dbus_message_iter_get_basic(iter, &valstr);
+               rl_printf("%s%s: %s\n", label, name, valstr);
+               break;
+       case DBUS_TYPE_BOOLEAN:
+               dbus_message_iter_get_basic(iter, &valbool);
+               rl_printf("%s%s: %s\n", label, name,
+                                       valbool == TRUE ? "yes" : "no");
+               break;
+       case DBUS_TYPE_UINT32:
+               dbus_message_iter_get_basic(iter, &valu32);
+               rl_printf("%s%s: 0x%06x\n", label, name, valu32);
+               break;
+       case DBUS_TYPE_UINT16:
+               dbus_message_iter_get_basic(iter, &valu16);
+               rl_printf("%s%s: 0x%04x\n", label, name, valu16);
+               break;
+       case DBUS_TYPE_INT16:
+               dbus_message_iter_get_basic(iter, &vals16);
+               rl_printf("%s%s: %d\n", label, name, vals16);
+               break;
+       default:
+               rl_printf("%s%s has unsupported type\n", label, name);
+               break;
+       }
+}
+
+static void print_property(GDBusProxy *proxy, const char *name)
+{
+       DBusMessageIter iter;
+
+       if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+               return;
+
+       print_iter("\t", name, &iter);
+}
+
+static void print_uuids(GDBusProxy *proxy)
+{
+       DBusMessageIter iter, value;
+
+       if (g_dbus_proxy_get_property(proxy, "UUIDs", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_recurse(&iter, &value);
+
+       while (dbus_message_iter_get_arg_type(&value) == DBUS_TYPE_STRING) {
+               const char *uuid, *text;
+
+               dbus_message_iter_get_basic(&value, &uuid);
+
+               text = uuidstr_to_str(uuid);
+               if (text) {
+                       char str[26];
+                       unsigned int n;
+
+                       str[sizeof(str) - 1] = '\0';
+
+                       n = snprintf(str, sizeof(str), "%s", text);
+                       if (n > sizeof(str) - 1) {
+                               str[sizeof(str) - 2] = '.';
+                               str[sizeof(str) - 3] = '.';
+                               if (str[sizeof(str) - 4] == ' ')
+                                       str[sizeof(str) - 4] = '.';
+
+                               n = sizeof(str) - 1;
+                       }
+
+                       rl_printf("\tUUID: %s%*c(%s)\n",
+                                               str, 26 - n, ' ', uuid);
+               } else
+                       rl_printf("\tUUID: %*c(%s)\n", 26, ' ', uuid);
+
+               dbus_message_iter_next(&value);
+       }
+}
+
+static gboolean device_is_child(GDBusProxy *device, GDBusProxy *master)
+{
+       DBusMessageIter iter;
+       const char *adapter, *path;
+
+       if (!master)
+               return FALSE;
+
+       if (g_dbus_proxy_get_property(device, "Adapter", &iter) == FALSE)
+               return FALSE;
+
+       dbus_message_iter_get_basic(&iter, &adapter);
+       path = g_dbus_proxy_get_path(master);
+
+       if (!strcmp(path, adapter))
+               return TRUE;
+
+       return FALSE;
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, "org.bluez.Device1")) {
+               if (device_is_child(proxy, default_ctrl) == TRUE) {
+                       dev_list = g_list_append(dev_list, proxy);
+
+                       print_device(proxy, COLORED_NEW);
+               }
+       } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+               ctrl_list = g_list_append(ctrl_list, proxy);
+
+               if (!default_ctrl)
+                       default_ctrl = proxy;
+
+               print_adapter(proxy, COLORED_NEW);
+       } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
+               if (!agent_manager) {
+                       agent_manager = proxy;
+
+                       if (auto_register_agent)
+                               agent_register(dbus_conn, agent_manager,
+                                                       auto_register_agent);
+               }
+       }
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, "org.bluez.Device1")) {
+               if (device_is_child(proxy, default_ctrl) == TRUE) {
+                       dev_list = g_list_remove(dev_list, proxy);
+
+                       print_device(proxy, COLORED_DEL);
+               }
+       } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+               ctrl_list = g_list_remove(ctrl_list, proxy);
+
+               print_adapter(proxy, COLORED_DEL);
+
+               if (default_ctrl == proxy) {
+                       default_ctrl = NULL;
+
+                       g_list_free(dev_list);
+                       dev_list = NULL;
+               }
+       } else if (!strcmp(interface, "org.bluez.AgentManager1")) {
+               if (agent_manager == proxy)
+                       agent_manager = NULL;
+       }
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, "org.bluez.Device1")) {
+               if (device_is_child(proxy, default_ctrl) == TRUE) {
+                       DBusMessageIter addr_iter;
+                       char *str;
+
+                       if (g_dbus_proxy_get_property(proxy, "Address",
+                                                       &addr_iter) == TRUE) {
+                               const char *address;
+
+                               dbus_message_iter_get_basic(&addr_iter,
+                                                               &address);
+                               str = g_strdup_printf("[" COLORED_CHG
+                                               "] Device %s ", address);
+                       } else
+                               str = g_strdup("");
+
+                       print_iter(str, name, iter);
+                       g_free(str);
+               }
+       } else if (!strcmp(interface, "org.bluez.Adapter1")) {
+               DBusMessageIter addr_iter;
+               char *str;
+
+               if (g_dbus_proxy_get_property(proxy, "Address",
+                                               &addr_iter) == TRUE) {
+                       const char *address;
+
+                       dbus_message_iter_get_basic(&addr_iter, &address);
+                       str = g_strdup_printf("[" COLORED_CHG
+                                               "] Controller %s ", address);
+               } else
+                       str = g_strdup("");
+
+               print_iter(str, name, iter);
+               g_free(str);
+       }
+}
+
+static void message_handler(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       rl_printf("[SIGNAL] %s.%s\n", dbus_message_get_interface(message),
+                                       dbus_message_get_member(message));
+}
+
+static GDBusProxy *find_proxy_by_address(GList *source, const char *address)
+{
+       GList *list;
+
+       for (list = g_list_first(source); list; list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+               DBusMessageIter iter;
+               const char *str;
+
+               if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+                       continue;
+
+               dbus_message_iter_get_basic(&iter, &str);
+
+               if (!strcmp(str, address))
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static gboolean check_default_ctrl(void)
+{
+       if (!default_ctrl) {
+               rl_printf("No default controller available\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean parse_argument_on_off(const char *arg, dbus_bool_t *value)
+{
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing on/off argument\n");
+               return FALSE;
+       }
+
+       if (!strcmp(arg, "on") || !strcmp(arg, "yes")) {
+               *value = TRUE;
+               return TRUE;
+       }
+
+       if (!strcmp(arg, "off") || !strcmp(arg, "no")) {
+               *value = FALSE;
+               return TRUE;
+       }
+
+       rl_printf("Invalid argument %s\n", arg);
+       return FALSE;
+}
+
+static gboolean parse_argument_agent(const char *arg, dbus_bool_t *value,
+                                                       const char **capability)
+{
+       const char * const *opt;
+
+       if (arg == NULL || strlen(arg) == 0) {
+               rl_printf("Missing on/off/capability argument\n");
+               return FALSE;
+       }
+
+       if (strcmp(arg, "on") == 0 || strcmp(arg, "yes") == 0) {
+               *value = TRUE;
+               *capability = "";
+               return TRUE;
+       }
+
+       if (strcmp(arg, "off") == 0 || strcmp(arg, "no") == 0) {
+               *value = FALSE;
+               return TRUE;
+       }
+
+       for (opt = agent_arguments; *opt; opt++) {
+               if (strcmp(arg, *opt) == 0) {
+                       *value = TRUE;
+                       *capability = *opt;
+                       return TRUE;
+               }
+       }
+
+       rl_printf("Invalid argument %s\n", arg);
+       return FALSE;
+}
+
+static void cmd_list(const char *arg)
+{
+       GList *list;
+
+       for (list = g_list_first(ctrl_list); list; list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+               print_adapter(proxy, NULL);
+       }
+}
+
+static void cmd_show(const char *arg)
+{
+       GDBusProxy *proxy;
+       DBusMessageIter iter;
+       const char *address;
+
+       if (!arg || !strlen(arg)) {
+               if (check_default_ctrl() == FALSE)
+                       return;
+
+               proxy = default_ctrl;
+       } else {
+               proxy = find_proxy_by_address(ctrl_list, arg);
+               if (!proxy) {
+                       rl_printf("Controller %s not available\n", arg);
+                       return;
+               }
+       }
+
+       if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &address);
+       rl_printf("Controller %s\n", address);
+
+       print_property(proxy, "Name");
+       print_property(proxy, "Alias");
+       print_property(proxy, "Class");
+       print_property(proxy, "Powered");
+       print_property(proxy, "Discoverable");
+       print_property(proxy, "Pairable");
+       print_uuids(proxy);
+       print_property(proxy, "Modalias");
+       print_property(proxy, "Discovering");
+}
+
+static void cmd_select(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing controller address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(ctrl_list, arg);
+       if (!proxy) {
+               rl_printf("Controller %s not available\n", arg);
+               return;
+       }
+
+       if (default_ctrl == proxy)
+               return;
+
+       default_ctrl = proxy;
+       print_adapter(proxy, NULL);
+
+       g_list_free(dev_list);
+       dev_list = NULL;
+}
+
+static void cmd_devices(const char *arg)
+{
+       GList *list;
+
+       for (list = g_list_first(dev_list); list; list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+               print_device(proxy, NULL);
+       }
+}
+
+static void generic_callback(const DBusError *error, void *user_data)
+{
+       char *str = user_data;
+
+       if (dbus_error_is_set(error))
+               rl_printf("Failed to set %s: %s\n", str, error->name);
+       else
+               rl_printf("Changing %s succeeded\n", str);
+}
+
+static void cmd_system_alias(const char *arg)
+{
+       char *name;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing name argument\n");
+               return;
+       }
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       name = g_strdup(arg);
+
+       if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
+                                       DBUS_TYPE_STRING, &name,
+                                       generic_callback, name, g_free) == TRUE)
+               return;
+
+       g_free(name);
+}
+
+static void cmd_reset_alias(const char *arg)
+{
+       char *name;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       name = g_strdup("");
+
+       if (g_dbus_proxy_set_property_basic(default_ctrl, "Alias",
+                                       DBUS_TYPE_STRING, &name,
+                                       generic_callback, name, g_free) == TRUE)
+               return;
+
+       g_free(name);
+}
+
+static void cmd_power(const char *arg)
+{
+       dbus_bool_t powered;
+       char *str;
+
+       if (parse_argument_on_off(arg, &powered) == FALSE)
+               return;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       str = g_strdup_printf("power %s", powered == TRUE ? "on" : "off");
+
+       if (g_dbus_proxy_set_property_basic(default_ctrl, "Powered",
+                                       DBUS_TYPE_BOOLEAN, &powered,
+                                       generic_callback, str, g_free) == TRUE)
+               return;
+
+       g_free(str);
+}
+
+static void cmd_pairable(const char *arg)
+{
+       dbus_bool_t pairable;
+       char *str;
+
+       if (parse_argument_on_off(arg, &pairable) == FALSE)
+               return;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       str = g_strdup_printf("pairable %s", pairable == TRUE ? "on" : "off");
+
+       if (g_dbus_proxy_set_property_basic(default_ctrl, "Pairable",
+                                       DBUS_TYPE_BOOLEAN, &pairable,
+                                       generic_callback, str, g_free) == TRUE)
+               return;
+
+       g_free(str);
+}
+
+static void cmd_discoverable(const char *arg)
+{
+       dbus_bool_t discoverable;
+       char *str;
+
+       if (parse_argument_on_off(arg, &discoverable) == FALSE)
+               return;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       str = g_strdup_printf("discoverable %s",
+                               discoverable == TRUE ? "on" : "off");
+
+       if (g_dbus_proxy_set_property_basic(default_ctrl, "Discoverable",
+                                       DBUS_TYPE_BOOLEAN, &discoverable,
+                                       generic_callback, str, g_free) == TRUE)
+               return;
+
+       g_free(str);
+}
+
+static void cmd_agent(const char *arg)
+{
+       dbus_bool_t enable;
+       const char *capability;
+
+       if (parse_argument_agent(arg, &enable, &capability) == FALSE)
+               return;
+
+       if (enable == TRUE) {
+               g_free(auto_register_agent);
+               auto_register_agent = g_strdup(capability);
+
+               if (agent_manager)
+                       agent_register(dbus_conn, agent_manager,
+                                               auto_register_agent);
+               else
+                       rl_printf("Agent registration enabled\n");
+       } else {
+               g_free(auto_register_agent);
+               auto_register_agent = NULL;
+
+               if (agent_manager)
+                       agent_unregister(dbus_conn, agent_manager);
+               else
+                       rl_printf("Agent registration disabled\n");
+       }
+}
+
+static void cmd_default_agent(const char *arg)
+{
+       agent_default(dbus_conn, agent_manager);
+}
+
+static void start_discovery_reply(DBusMessage *message, void *user_data)
+{
+       dbus_bool_t enable = GPOINTER_TO_UINT(user_data);
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to %s discovery: %s\n",
+                               enable == TRUE ? "start" : "stop", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Discovery %s\n", enable == TRUE ? "started" : "stopped");
+}
+
+static void cmd_scan(const char *arg)
+{
+       dbus_bool_t enable;
+       const char *method;
+
+       if (parse_argument_on_off(arg, &enable) == FALSE)
+               return;
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       if (enable == TRUE)
+               method = "StartDiscovery";
+       else
+               method = "StopDiscovery";
+
+       if (g_dbus_proxy_method_call(default_ctrl, method,
+                               NULL, start_discovery_reply,
+                               GUINT_TO_POINTER(enable), NULL) == FALSE) {
+               rl_printf("Failed to %s discovery\n",
+                                       enable == TRUE ? "start" : "stop");
+               return;
+       }
+}
+
+static void cmd_info(const char *arg)
+{
+       GDBusProxy *proxy;
+       DBusMessageIter iter;
+       const char *address;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       if (g_dbus_proxy_get_property(proxy, "Address", &iter) == FALSE)
+               return;
+
+       dbus_message_iter_get_basic(&iter, &address);
+       rl_printf("Device %s\n", address);
+
+       print_property(proxy, "Name");
+       print_property(proxy, "Alias");
+       print_property(proxy, "Class");
+       print_property(proxy, "Appearance");
+       print_property(proxy, "Icon");
+       print_property(proxy, "Paired");
+       print_property(proxy, "Trusted");
+       print_property(proxy, "Blocked");
+       print_property(proxy, "Connected");
+       print_property(proxy, "LegacyPairing");
+       print_uuids(proxy);
+       print_property(proxy, "Modalias");
+}
+
+static void pair_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to pair: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Pairing successful\n");
+}
+
+static void cmd_pair(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Pair", NULL, pair_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to pair\n");
+               return;
+       }
+
+       rl_printf("Attempting to pair with %s\n", arg);
+}
+
+static void cmd_trust(const char *arg)
+{
+       GDBusProxy *proxy;
+       dbus_bool_t trusted;
+       char *str;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       trusted = TRUE;
+
+       str = g_strdup_printf("%s trust", arg);
+
+       if (g_dbus_proxy_set_property_basic(proxy, "Trusted",
+                                       DBUS_TYPE_BOOLEAN, &trusted,
+                                       generic_callback, str, g_free) == TRUE)
+               return;
+
+       g_free(str);
+}
+
+static void remove_device_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to remove device: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Device has been removed\n");
+}
+
+static void remove_device_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static void cmd_remove(const char *arg)
+{
+       GDBusProxy *proxy;
+       char *path;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       if (check_default_ctrl() == FALSE)
+               return;
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       path = g_strdup(g_dbus_proxy_get_path(proxy));
+
+       if (g_dbus_proxy_method_call(default_ctrl, "RemoveDevice",
+                                               remove_device_setup,
+                                               remove_device_reply,
+                                               path, g_free) == FALSE) {
+               rl_printf("Failed to remove device\n");
+               g_free(path);
+               return;
+       }
+}
+
+static void connect_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to connect: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Connection successful\n");
+}
+
+static void cmd_connect(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Connect", NULL, connect_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to connect\n");
+               return;
+       }
+
+       rl_printf("Attempting to connect to %s\n", arg);
+}
+
+static void disconn_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to disconnect: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Successful disconnected\n");
+}
+
+static void cmd_disconn(const char *arg)
+{
+       GDBusProxy *proxy;
+
+       if (!arg || !strlen(arg)) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       proxy = find_proxy_by_address(dev_list, arg);
+       if (!proxy) {
+               rl_printf("Device %s not available\n", arg);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Disconnect", NULL, disconn_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to disconnect\n");
+               return;
+       }
+
+       rl_printf("Attempting to disconnect from %s\n", arg);
+}
+
+static void cmd_version(const char *arg)
+{
+       rl_printf("Version %s\n", VERSION);
+}
+
+static void cmd_quit(const char *arg)
+{
+       g_main_loop_quit(main_loop);
+}
+
+static char *generic_generator(const char *text, int state,
+                                       GList *source, const char *property)
+{
+       static int index, len;
+       GList *list;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       for (list = g_list_nth(source, index); list;
+                                               list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+               DBusMessageIter iter;
+               const char *str;
+
+               index++;
+
+               if (g_dbus_proxy_get_property(proxy, property, &iter) == FALSE)
+                       continue;
+
+               dbus_message_iter_get_basic(&iter, &str);
+
+               if (!strncmp(str, text, len))
+                       return strdup(str);
+        }
+
+       return NULL;
+}
+
+static char *ctrl_generator(const char *text, int state)
+{
+       return generic_generator(text, state, ctrl_list, "Address");
+}
+
+static char *dev_generator(const char *text, int state)
+{
+       return generic_generator(text, state, dev_list, "Address");
+}
+
+static char *capability_generator(const char *text, int state)
+{
+       static int index, len;
+       const char *arg;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       while ((arg = agent_arguments[index])) {
+               index++;
+
+               if (!strncmp(arg, text, len))
+                       return strdup(arg);
+       }
+
+       return NULL;
+}
+
+static const struct {
+       const char *cmd;
+       const char *arg;
+       void (*func) (const char *arg);
+       const char *desc;
+       char * (*gen) (const char *text, int state);
+       void (*disp) (char **matches, int num_matches, int max_length);
+} cmd_table[] = {
+       { "list",         NULL,       cmd_list, "List available controllers" },
+       { "show",         "[ctrl]",   cmd_show, "Controller information",
+                                                       ctrl_generator },
+       { "select",       "<ctrl>",   cmd_select, "Select default controller",
+                                                       ctrl_generator },
+       { "devices",      NULL,       cmd_devices, "List available devices" },
+       { "system-alias", "<name>",   cmd_system_alias },
+       { "reset-alias",  NULL,       cmd_reset_alias },
+       { "power",        "<on/off>", cmd_power, "Set controller power" },
+       { "pairable",     "<on/off>", cmd_pairable,
+                                       "Set controller pairable mode" },
+       { "discoverable", "<on/off>", cmd_discoverable,
+                                       "Set controller discoverable mode" },
+       { "agent",        "<on/off/capability>", cmd_agent,
+                               "Enable/disable agent with given capability",
+                                                       capability_generator},
+       { "default-agent",NULL,       cmd_default_agent,
+                               "Set agent as the default one" },
+       { "scan",         "<on/off>", cmd_scan, "Scan for devices" },
+       { "info",         "<dev>",    cmd_info, "Device information",
+                                                       dev_generator },
+       { "pair",         "<dev>",    cmd_pair, "Pair with device",
+                                                       dev_generator },
+       { "trust",        "<dev>",    cmd_trust, "Trust device",
+                                                       dev_generator },
+       { "remove",       "<dev>",    cmd_remove, "Remove device",
+                                                       dev_generator },
+       { "connect",      "<dev>",    cmd_connect, "Connect device",
+                                                       dev_generator },
+       { "disconnect",   "<dev>",    cmd_disconn, "Disconnect device",
+                                                       dev_generator },
+       { "version",      NULL,       cmd_version, "Display version" },
+       { "quit",         NULL,       cmd_quit, "Quit program" },
+       { "exit",         NULL,       cmd_quit },
+       { "help" },
+       { }
+};
+
+static char *cmd_generator(const char *text, int state)
+{
+       static int index, len;
+       const char *cmd;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       while ((cmd = cmd_table[index].cmd)) {
+               index++;
+
+               if (!strncmp(cmd, text, len))
+                       return strdup(cmd);
+       }
+
+       return NULL;
+}
+
+static char **cmd_completion(const char *text, int start, int end)
+{
+       char **matches = NULL;
+
+       if (agent_completion() == TRUE) {
+               rl_attempted_completion_over = 1;
+               return NULL;
+       }
+
+       if (start > 0) {
+               int i;
+
+               for (i = 0; cmd_table[i].cmd; i++) {
+                       if (strncmp(cmd_table[i].cmd,
+                                       rl_line_buffer, start - 1))
+                               continue;
+
+                       if (!cmd_table[i].gen)
+                               continue;
+
+                       rl_completion_display_matches_hook = cmd_table[i].disp;
+                       matches = rl_completion_matches(text, cmd_table[i].gen);
+                       break;
+               }
+       } else {
+               rl_completion_display_matches_hook = NULL;
+               matches = rl_completion_matches(text, cmd_generator);
+       }
+
+       if (!matches)
+               rl_attempted_completion_over = 1;
+
+       return matches;
+}
+
+static void rl_handler(char *input)
+{
+       char *cmd, *arg;
+       int i;
+
+       if (!input) {
+               rl_insert_text("quit");
+               rl_redisplay();
+               rl_crlf();
+               g_main_loop_quit(main_loop);
+               return;
+       }
+
+       if (!strlen(input))
+               goto done;
+
+       if (agent_input(dbus_conn, input) == TRUE)
+               goto done;
+
+       add_history(input);
+
+       cmd = strtok_r(input, " ", &arg);
+       if (!cmd)
+               goto done;
+
+       if (arg) {
+               int len = strlen(arg);
+               if (len > 0 && arg[len - 1] == ' ')
+                       arg[len - 1] = '\0';
+       }
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (strcmp(cmd, cmd_table[i].cmd))
+                       continue;
+
+               if (cmd_table[i].func) {
+                       cmd_table[i].func(arg);
+                       goto done;
+               }
+       }
+
+       if (strcmp(cmd, "help")) {
+               printf("Invalid command\n");
+               goto done;
+       }
+
+       printf("Available commands:\n");
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (cmd_table[i].desc)
+                       printf("  %s %-*s %s\n", cmd_table[i].cmd,
+                                       (int)(25 - strlen(cmd_table[i].cmd)),
+                                       cmd_table[i].arg ? : "",
+                                       cmd_table[i].desc ? : "");
+       }
+
+done:
+       free(input);
+}
+
+static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       rl_callback_read_char();
+       return TRUE;
+}
+
+static guint setup_standard_input(void)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fileno(stdin));
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               input_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+               rl_replace_line("", 0);
+               rl_crlf();
+               rl_on_new_line();
+               rl_redisplay();
+               break;
+       case SIGTERM:
+               if (__terminated == 0) {
+                       rl_replace_line("", 0);
+                       rl_crlf();
+                       g_main_loop_quit(main_loop);
+               }
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean option_version = FALSE;
+
+static gboolean parse_agent(const char *key, const char *value,
+                                       gpointer user_data, GError **error)
+{
+       if (value)
+               auto_register_agent = g_strdup(value);
+       else
+               auto_register_agent = g_strdup("");
+
+       return TRUE;
+}
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { "agent", 'a', G_OPTION_FLAG_OPTIONAL_ARG,
+                               G_OPTION_ARG_CALLBACK, parse_agent,
+                               "Register agent handler", "CAPABILITY" },
+       { NULL },
+};
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       GDBusClient *client;
+       guint signal, input;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               printf("%s\n", VERSION);
+               exit(0);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+       dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+       rl_attempted_completion_function = cmd_completion;
+
+       rl_erase_empty_line = 1;
+       rl_callback_handler_install(NULL, rl_handler);
+
+       rl_set_prompt(PROMPT_OFF);
+       rl_redisplay();
+
+       input = setup_standard_input();
+       signal = setup_signalfd();
+       client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+       g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+       g_dbus_client_set_signal_watch(client, message_handler, NULL);
+
+       g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+                                                       property_changed, NULL);
+
+       g_main_loop_run(main_loop);
+
+       g_dbus_client_unref(client);
+       g_source_remove(signal);
+       g_source_remove(input);
+
+       rl_message("");
+       rl_callback_handler_remove();
+
+       dbus_connection_unref(dbus_conn);
+       g_main_loop_unref(main_loop);
+
+       g_list_free_full(ctrl_list, proxy_leak);
+       g_list_free_full(dev_list, proxy_leak);
+
+       g_free(auto_register_agent);
+
+       return 0;
+}
diff --git a/compat/bnep.c b/compat/bnep.c
deleted file mode 100644 (file)
index 281350b..0000000
+++ /dev/null
@@ -1,339 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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 <sys/socket.h>
-#include <sys/ioctl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/bnep.h>
-
-#include <netinet/in.h>
-
-#include "pand.h"
-
-static int ctl;
-
-/* Compatibility with old ioctls */
-#define OLD_BNEPCONADD      1
-#define OLD_BNEPCONDEL      2
-#define OLD_BNEPGETCONLIST  3
-#define OLD_BNEPGETCONINFO  4
-
-static unsigned long bnepconnadd;
-static unsigned long bnepconndel;
-static unsigned long bnepgetconnlist;
-static unsigned long bnepgetconninfo;
-
-static struct {
-       char     *str;
-       uint16_t uuid;
-} __svc[] = {
-       { "PANU", BNEP_SVC_PANU },
-       { "NAP",  BNEP_SVC_NAP  },
-       { "GN",   BNEP_SVC_GN   },
-       { NULL }
-};
-
-int bnep_str2svc(char *svc, uint16_t *uuid)
-{
-       int i;
-       for (i = 0; __svc[i].str; i++)
-               if (!strcasecmp(svc, __svc[i].str)) {
-                       *uuid = __svc[i].uuid;
-                       return 0;
-               }
-       return -1;
-}
-
-char *bnep_svc2str(uint16_t uuid)
-{
-       int i;
-       for (i = 0; __svc[i].str; i++)
-               if (__svc[i].uuid == uuid)
-                       return __svc[i].str;
-       return NULL;
-}
-
-int bnep_init(void)
-{
-       ctl = socket(PF_BLUETOOTH, SOCK_RAW, BTPROTO_BNEP);
-       if (ctl < 0) {
-               perror("Failed to open control socket");
-               return 1;
-       }
-
-       /* Temporary ioctl compatibility hack */
-       {
-               struct bnep_connlist_req req;
-               struct bnep_conninfo ci[1];
-
-               req.cnum = 1;
-               req.ci   = ci;
-
-               if (!ioctl(ctl, BNEPGETCONNLIST, &req)) {
-                       /* New ioctls */
-                       bnepconnadd     = BNEPCONNADD;
-                       bnepconndel     = BNEPCONNDEL;
-                       bnepgetconnlist = BNEPGETCONNLIST;
-                       bnepgetconninfo = BNEPGETCONNINFO;
-               } else {
-                       /* Old ioctls */
-                       bnepconnadd     = OLD_BNEPCONADD;
-                       bnepconndel     = OLD_BNEPCONDEL;
-                       bnepgetconnlist = OLD_BNEPGETCONLIST;
-                       bnepgetconninfo = OLD_BNEPGETCONINFO;
-               }
-       }
-
-       return 0;
-}
-
-int bnep_cleanup(void)
-{
-       close(ctl);
-       return 0;
-}
-
-int bnep_show_connections(void)
-{
-       struct bnep_connlist_req req;
-       struct bnep_conninfo ci[48];
-       unsigned int i;
-
-       req.cnum = 48;
-       req.ci   = ci;
-       if (ioctl(ctl, bnepgetconnlist, &req)) {
-               perror("Failed to get connection list");
-               return -1;
-       }
-
-       for (i = 0; i < req.cnum; i++) {
-               char addr[18];
-               ba2str((bdaddr_t *) ci[i].dst, addr);
-               printf("%s %s %s\n", ci[i].device,
-                       addr, bnep_svc2str(ci[i].role));
-       }
-       return 0;
-}
-
-int bnep_kill_connection(uint8_t *dst)
-{
-       struct bnep_conndel_req req;
-
-       memcpy(req.dst, dst, ETH_ALEN);
-       req.flags = 0;
-       if (ioctl(ctl, bnepconndel, &req)) {
-               perror("Failed to kill connection");
-               return -1;
-       }
-       return 0;
-}
-
-int bnep_kill_all_connections(void)
-{
-       struct bnep_connlist_req req;
-       struct bnep_conninfo ci[48];
-       unsigned int i;
-
-       req.cnum = 48;
-       req.ci   = ci;
-       if (ioctl(ctl, bnepgetconnlist, &req)) {
-               perror("Failed to get connection list");
-               return -1;
-       }
-
-       for (i = 0; i < req.cnum; i++) {
-               struct bnep_conndel_req req;
-               memcpy(req.dst, ci[i].dst, ETH_ALEN);
-               req.flags = 0;
-               ioctl(ctl, bnepconndel, &req);
-       }
-       return 0;
-}
-
-static int bnep_connadd(int sk, uint16_t role, char *dev)
-{
-       struct bnep_connadd_req req;
-
-       strncpy(req.device, dev, 16);
-       req.device[15] = '\0';
-       req.sock = sk;
-       req.role = role;
-       if (ioctl(ctl, bnepconnadd, &req))
-               return -1;
-       strncpy(dev, req.device, 16);
-       return 0;
-}
-
-struct __service_16 {
-       uint16_t dst;
-       uint16_t src;
-} __attribute__ ((packed));
-
-struct __service_32 {
-       uint16_t unused1;
-       uint16_t dst;
-       uint16_t unused2;
-       uint16_t src;
-} __attribute__ ((packed));
-
-struct __service_128 {
-       uint16_t unused1;
-       uint16_t dst;
-       uint16_t unused2[8];
-       uint16_t src;
-       uint16_t unused3[7];
-} __attribute__ ((packed));
-
-int bnep_accept_connection(int sk, uint16_t role, char *dev)
-{
-       struct bnep_setup_conn_req *req;
-       struct bnep_control_rsp *rsp;
-       unsigned char pkt[BNEP_MTU];
-       ssize_t r;
-
-       r = recv(sk, pkt, BNEP_MTU, 0);
-       if (r <= 0)
-               return -1;
-
-       errno = EPROTO;
-
-       if ((size_t) r < sizeof(*req))
-               return -1;
-
-       req = (void *) pkt;
-
-       /* Highest known Control command ID
-        * is BNEP_FILTER_MULT_ADDR_RSP = 0x06 */
-       if (req->type == BNEP_CONTROL &&
-                               req->ctrl > BNEP_FILTER_MULT_ADDR_RSP) {
-               uint8_t pkt[3];
-
-               pkt[0] = BNEP_CONTROL;
-               pkt[1] = BNEP_CMD_NOT_UNDERSTOOD;
-               pkt[2] = req->ctrl;
-
-               send(sk, pkt, sizeof(pkt), 0);
-
-               return -1;
-       }
-
-       if (req->type != BNEP_CONTROL || req->ctrl != BNEP_SETUP_CONN_REQ)
-               return -1;
-
-       /* FIXME: Check role UUIDs */
-
-       rsp = (void *) pkt;
-       rsp->type = BNEP_CONTROL;
-       rsp->ctrl = BNEP_SETUP_CONN_RSP;
-       rsp->resp = htons(BNEP_SUCCESS);
-       if (send(sk, rsp, sizeof(*rsp), 0) < 0)
-               return -1;
-
-       return bnep_connadd(sk, role, dev);
-}
-
-/* Create BNEP connection
- * sk      - Connect L2CAP socket
- * role    - Local role
- * service - Remote service
- * dev     - Network device (contains actual dev name on return)
- */
-int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev)
-{
-       struct bnep_setup_conn_req *req;
-       struct bnep_control_rsp *rsp;
-       struct __service_16 *s;
-       struct timeval timeo;
-       unsigned char pkt[BNEP_MTU];
-       ssize_t r;
-
-       /* Send request */
-       req = (void *) pkt;
-       req->type = BNEP_CONTROL;
-       req->ctrl = BNEP_SETUP_CONN_REQ;
-       req->uuid_size = 2;     /* 16bit UUID */
-
-       s = (void *) req->service;
-       s->dst = htons(svc);
-       s->src = htons(role);
-
-       memset(&timeo, 0, sizeof(timeo));
-       timeo.tv_sec = 30;
-
-       setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
-
-       if (send(sk, pkt, sizeof(*req) + sizeof(*s), 0) < 0)
-               return -1;
-
-receive:
-       /* Get response */
-       r = recv(sk, pkt, BNEP_MTU, 0);
-       if (r <= 0)
-               return -1;
-
-       memset(&timeo, 0, sizeof(timeo));
-       timeo.tv_sec = 0;
-
-       setsockopt(sk, SOL_SOCKET, SO_RCVTIMEO, &timeo, sizeof(timeo));
-
-       errno = EPROTO;
-
-       if ((size_t) r < sizeof(*rsp))
-               return -1;
-
-       rsp = (void *) pkt;
-       if (rsp->type != BNEP_CONTROL)
-               return -1;
-
-       if (rsp->ctrl != BNEP_SETUP_CONN_RSP)
-               goto receive;
-
-       r = ntohs(rsp->resp);
-
-       switch (r) {
-       case BNEP_SUCCESS:
-               break;
-
-       case BNEP_CONN_INVALID_DST:
-       case BNEP_CONN_INVALID_SRC:
-       case BNEP_CONN_INVALID_SVC:
-               errno = EPROTO;
-               return -1;
-
-       case BNEP_CONN_NOT_ALLOWED:
-               errno = EACCES;
-               return -1;
-       }
-
-       return bnep_connadd(sk, role, dev);
-}
diff --git a/compat/dun.c b/compat/dun.c
deleted file mode 100644 (file)
index 3f3a0d4..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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 <ctype.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <dirent.h>
-
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <netinet/in.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "dund.h"
-#include "lib.h"
-
-#define PROC_BASE  "/proc"
-
-static int for_each_port(int (*func)(struct rfcomm_dev_info *, unsigned long), unsigned long arg)
-{
-       struct rfcomm_dev_list_req *dl;
-       struct rfcomm_dev_info *di;
-       long r = 0;
-       int  sk, i;
-
-       sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
-       if (sk < 0 ) {
-               perror("Can't open RFCOMM control socket");
-               exit(1);
-       }
-
-       dl = malloc(sizeof(*dl) + RFCOMM_MAX_DEV * sizeof(*di));
-       if (!dl) {
-               perror("Can't allocate request memory");
-               close(sk);
-               exit(1);
-       }
-
-       dl->dev_num = RFCOMM_MAX_DEV;
-       di = dl->dev_info;
-
-       if (ioctl(sk, RFCOMMGETDEVLIST, (void *) dl) < 0) {
-               perror("Can't get device list");
-               exit(1);
-       }
-
-       for (i = 0; i < dl->dev_num; i++) {
-               r = func(di + i, arg);
-               if (r) break;
-       }
-
-       close(sk);
-       free(dl);
-       return r;
-}
-
-static int uses_rfcomm(char *path, char *dev)
-{
-       struct dirent *de;
-       DIR   *dir;
-
-       dir = opendir(path);
-       if (!dir)
-               return 0;
-
-       if (chdir(path) < 0)
-               return 0;
-
-       while ((de = readdir(dir)) != NULL) {
-               char link[PATH_MAX + 1];
-               int  len = readlink(de->d_name, link, PATH_MAX);
-               if (len > 0) {
-                       link[len] = 0;
-                       if (strstr(link, dev)) {
-                               closedir(dir);
-                               return 1;
-                       }
-               }
-       }
-
-       closedir(dir);
-
-       return 0;
-}
-
-static int find_pppd(int id, pid_t *pid)
-{
-       struct dirent *de;
-       char  path[PATH_MAX + 1];
-       char  dev[10];
-       int   empty = 1;
-       DIR   *dir;
-
-       dir = opendir(PROC_BASE);
-       if (!dir) {
-               perror(PROC_BASE);
-               return -1;
-       }
-
-       sprintf(dev, "rfcomm%d", id);
-
-       *pid = 0;
-       while ((de = readdir(dir)) != NULL) {
-               empty = 0;
-               if (isdigit(de->d_name[0])) {
-                       sprintf(path, "%s/%s/fd", PROC_BASE, de->d_name);
-                       if (uses_rfcomm(path, dev)) {
-                               *pid = atoi(de->d_name);
-                               break;
-                       }
-               }
-       }
-       closedir(dir);
-
-       if (empty)
-               fprintf(stderr, "%s is empty (not mounted ?)\n", PROC_BASE);
-
-       return *pid != 0;
-}
-
-static int dun_exec(char *tty, char *prog, char **args)
-{
-       int pid = fork();
-       int fd;
-
-       switch (pid) {
-       case -1:
-               return -1;
-
-       case 0:
-               break;
-
-       default:
-               return pid;
-       }
-
-       setsid();
-
-       /* Close all FDs */
-       for (fd = 3; fd < 20; fd++)
-               close(fd);
-
-       execvp(prog, args);
-
-       syslog(LOG_ERR, "Error while executing %s", prog);
-
-       exit(1);
-}
-
-static int dun_create_tty(int sk, char *tty, int size)
-{
-       struct sockaddr_rc sa;
-       struct stat st;
-       socklen_t alen;
-       int id, try = 30;
-
-       struct rfcomm_dev_req req = {
-               .flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP),
-               .dev_id = -1
-       };
-
-       alen = sizeof(sa);
-       if (getpeername(sk, (struct sockaddr *) &sa, &alen) < 0)
-               return -1;
-       bacpy(&req.dst, &sa.rc_bdaddr);
-
-       alen = sizeof(sa);
-       if (getsockname(sk, (struct sockaddr *) &sa, &alen) < 0)
-               return -1;
-       bacpy(&req.src, &sa.rc_bdaddr);
-       req.channel = sa.rc_channel;
-
-       id = ioctl(sk, RFCOMMCREATEDEV, &req);
-       if (id < 0)
-               return id;
-
-       snprintf(tty, size, "/dev/rfcomm%d", id);
-       while (stat(tty, &st) < 0) {
-               snprintf(tty, size, "/dev/bluetooth/rfcomm/%d", id);
-               if (stat(tty, &st) < 0) {
-                       snprintf(tty, size, "/dev/rfcomm%d", id);
-                       if (try--) {
-                               usleep(100 * 1000);
-                               continue;
-                       }
-
-                       memset(&req, 0, sizeof(req));
-                       req.dev_id = id;
-                       ioctl(sk, RFCOMMRELEASEDEV, &req);
-
-                       return -1;
-               }
-       }
-
-       return id;
-}
-
-int dun_init(void)
-{
-       return 0;
-}
-
-int dun_cleanup(void)
-{
-       return 0;
-}
-
-static int show_conn(struct rfcomm_dev_info *di, unsigned long arg)
-{
-       pid_t pid;
-
-       if (di->state == BT_CONNECTED &&
-               (di->flags & (1<<RFCOMM_REUSE_DLC)) &&
-               (di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
-               (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
-
-               if (find_pppd(di->id, &pid)) {
-                       char dst[18];
-                       ba2str(&di->dst, dst);
-
-                       printf("rfcomm%d: %s channel %d pppd pid %d\n",
-                                       di->id, dst, di->channel, pid);
-               }
-       }
-       return 0;
-}
-
-static int kill_conn(struct rfcomm_dev_info *di, unsigned long arg)
-{
-       bdaddr_t *dst = (bdaddr_t *) arg;
-       pid_t pid;
-
-       if (di->state == BT_CONNECTED &&
-               (di->flags & (1<<RFCOMM_REUSE_DLC)) &&
-               (di->flags & (1<<RFCOMM_TTY_ATTACHED)) &&
-               (di->flags & (1<<RFCOMM_RELEASE_ONHUP))) {
-
-               if (dst && bacmp(&di->dst, dst))
-                       return 0;
-
-               if (find_pppd(di->id, &pid)) {
-                       if (kill(pid, SIGINT) < 0)
-                               perror("Kill");
-
-                       if (!dst)
-                               return 0;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-int dun_show_connections(void)
-{
-       for_each_port(show_conn, 0);
-       return 0;
-}
-
-int dun_kill_connection(uint8_t *dst)
-{
-       for_each_port(kill_conn, (unsigned long) dst);
-       return 0;
-}
-
-int dun_kill_all_connections(void)
-{
-       for_each_port(kill_conn, 0);
-       return 0;
-}
-
-int dun_open_connection(int sk, char *pppd, char **args, int wait)
-{
-       char tty[100];
-       int  pid;
-
-       if (dun_create_tty(sk, tty, sizeof(tty) - 1) < 0) {
-               syslog(LOG_ERR, "RFCOMM TTY creation failed. %s(%d)", strerror(errno), errno);
-               return -1;
-       }
-
-       args[0] = "pppd";
-       args[1] = tty;
-       args[2] = "nodetach";
-
-       pid = dun_exec(tty, pppd, args);
-       if (pid < 0) {
-               syslog(LOG_ERR, "Exec failed. %s(%d)", strerror(errno), errno);
-               return -1;
-       }
-
-       if (wait) {
-               int status;
-               waitpid(pid, &status, 0);
-               /* FIXME: Check for waitpid errors */
-       }
-
-       return 0;
-}
diff --git a/compat/dund.1 b/compat/dund.1
deleted file mode 100644 (file)
index 09fb7f7..0000000
+++ /dev/null
@@ -1,72 +0,0 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.29.
-.TH BlueZ "1" "February 2003" "DUN daemon" "User Commands"
-.SH NAME
-dund \- BlueZ Bluetooth dial-up networking daemon
-.SH DESCRIPTION
-DUN daemon
-.SH SYNOPSIS
-dund <options> [pppd options]
-.SH OPTIONS
-.TP
-\fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR
-Show active DUN connections
-.TP
-\fB\-\-listen\fR \fB\-s\fR
-Listen for DUN connections
-.TP
-\fB\-\-dialup\fR \fB\-u\fR
-Listen for dialup/telephone connections
-.TP
-\fB\-\-connect\fR \fB\-c\fR <bdaddr>
-Create DUN connection
-.TP
-\fB\-\-mrouter\fR \fB\-m\fR <bdaddr>
-Create mRouter connection
-.TP
-\fB\-\-search\fR \fB\-Q[duration]\fR
-Search and connect
-.TP
-\fB\-\-kill\fR \fB\-k\fR <bdaddr>
-Kill DUN connection
-.TP
-\fB\-\-killall\fR \fB\-K\fR
-Kill all DUN connections
-.TP
-\fB\-\-channel\fR \fB\-C\fR <channel>
-RFCOMM channel
-.TP
-\fB\-\-device\fR \fB\-i\fR <bdaddr>
-Source bdaddr
-.TP
-\fB\-\-nosdp\fR \fB\-D\fR
-Disable SDP
-.TP
-\fB\-\-auth\fR \fB\-A\fR
-Enable authentification
-.TP
-\fB\-\-encrypt\fR \fB\-E\fR
-Enable encryption
-.TP
-\fB\-\-secure\fR \fB\-S\fR
-Secure connection
-.TP
-\fB\-\-master\fR \fB\-M\fR
-Become the master of a piconet
-.TP
-\fB\-\-nodetach\fR \fB\-n\fR
-Do not become a daemon
-.TP
-\fB\-\-persist\fR \fB\-p[interval]\fR
-Persist mode
-.TP
-\fB\-\-pppd\fR \fB\-d\fR <pppd>
-Location of the PPP daemon (pppd)
-.TP
-\fB\-\-msdun\fR \fB\-X\fR [timeo]
-Enable Microsoft dialup networking support
-.TP
-\fB\-\-activesync\fR \fB\-a\fR
-Enable Microsoft ActiveSync networking
-.TP
-\fB\-\-cache\fR \fB\-C\fR [valid]
-Enable address cache
diff --git a/compat/dund.c b/compat/dund.c
deleted file mode 100644 (file)
index af1b536..0000000
+++ /dev/null
@@ -1,645 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <getopt.h>
-
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/hidp.h>
-
-#include "sdp.h"
-#include "dund.h"
-#include "lib.h"
-
-volatile sig_atomic_t __io_canceled;
-
-/* MS dialup networking support (i.e. CLIENT / CLIENTSERVER thing) */
-static int msdun = 0;
-
-static char *pppd = "/usr/sbin/pppd";
-static char *pppd_opts[DUN_MAX_PPP_OPTS] =
-       {
-               /* First 3 are reserved */
-               "", "", "",
-               "noauth",
-               "noipdefault",
-               NULL
-       };
-
-static int  detach = 1;
-static int  persist;
-static int  use_sdp = 1;
-static int  auth;
-static int  encrypt;
-static int  secure;
-static int  master;
-static int  type = LANACCESS;
-static int  search_duration = 10;
-static uint use_cache;
-
-static int  channel;
-
-static struct {
-       uint     valid;
-       char     dst[40];
-       bdaddr_t bdaddr;
-       int      channel;
-} cache;
-
-static bdaddr_t src_addr = *BDADDR_ANY;
-static int src_dev = -1;
-
-volatile int terminate;
-
-enum {
-       NONE,
-       SHOW,
-       LISTEN,
-       CONNECT,
-       KILL
-} modes;
-
-static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter);
-
-static int do_listen(void)
-{
-       struct sockaddr_rc sa;
-       int sk, lm;
-
-       if (type == MROUTER) {
-               if (!cache.valid)
-                       return -1;
-
-               if (create_connection(cache.dst, &cache.bdaddr, type) < 0) {
-                       syslog(LOG_ERR, "Cannot connect to mRouter device. %s(%d)",
-                                                               strerror(errno), errno);
-                       return -1;
-               }
-       }
-
-       if (!channel)
-               channel = DUN_DEFAULT_CHANNEL;
-
-       if (use_sdp)
-               dun_sdp_register(&src_addr, channel, type);
-
-       if (type == MROUTER)
-               syslog(LOG_INFO, "Waiting for mRouter callback on channel %d", channel);
-
-       /* Create RFCOMM socket */
-       sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (sk < 0) {
-               syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
-                               strerror(errno), errno);
-               return -1;
-       }
-
-       sa.rc_family  = AF_BLUETOOTH;
-       sa.rc_channel = channel;
-       sa.rc_bdaddr  = src_addr;
-
-       if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
-               syslog(LOG_ERR, "Bind failed. %s(%d)", strerror(errno), errno);
-               return -1;
-       }
-
-       /* Set link mode */
-       lm = 0;
-       if (master)
-               lm |= RFCOMM_LM_MASTER;
-       if (auth)
-               lm |= RFCOMM_LM_AUTH;
-       if (encrypt)
-               lm |= RFCOMM_LM_ENCRYPT;
-       if (secure)
-               lm |= RFCOMM_LM_SECURE;
-
-       if (lm && setsockopt(sk, SOL_RFCOMM, RFCOMM_LM, &lm, sizeof(lm)) < 0) {
-               syslog(LOG_ERR, "Failed to set link mode. %s(%d)", strerror(errno), errno);
-               return -1;
-       }
-
-       listen(sk, 10);
-
-       while (!terminate) {
-               socklen_t alen = sizeof(sa);
-               int nsk;
-               char ba[40];
-               char ch[10];
-
-               nsk = accept(sk, (struct sockaddr *) &sa, &alen);
-               if (nsk < 0) {
-                       syslog(LOG_ERR, "Accept failed. %s(%d)", strerror(errno), errno);
-                       continue;
-               }
-
-               switch (fork()) {
-               case 0:
-                       break;
-               case -1:
-                       syslog(LOG_ERR, "Fork failed. %s(%d)", strerror(errno), errno);
-               default:
-                       close(nsk);
-                       if (type == MROUTER) {
-                               close(sk);
-                               terminate = 1;
-                       }
-                       continue;
-               }
-
-               close(sk);
-
-               if (msdun && ms_dun(nsk, 1, msdun) < 0) {
-                       syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
-                       exit(0);
-               }
-
-               ba2str(&sa.rc_bdaddr, ba);
-               snprintf(ch, sizeof(ch), "%d", channel);
-
-               /* Setup environment */
-               setenv("DUN_BDADDR",  ba, 1);
-               setenv("DUN_CHANNEL", ch, 1);
-
-               if (!dun_open_connection(nsk, pppd, pppd_opts, 0))
-                       syslog(LOG_INFO, "New connection from %s", ba);
-
-               close(nsk);
-               exit(0);
-       }
-
-       if (use_sdp)
-               dun_sdp_unregister();
-       return 0;
-}
-
-/* Connect and initiate RFCOMM session
- * Returns:
- *   -1 - critical error (exit persist mode)
- *   1  - non critical error
- *   0  - success
- */
-static int create_connection(char *dst, bdaddr_t *bdaddr, int mrouter)
-{
-       struct sockaddr_rc sa;
-       int sk, err = 0, ch;
-
-       if (use_cache && cache.valid && cache.channel) {
-               /* Use cached channel */
-               ch = cache.channel;
-
-       } else if (!channel) {
-               syslog(LOG_INFO, "Searching for %s on %s", mrouter ? "SP" : "LAP", dst);
-
-               if (dun_sdp_search(&src_addr, bdaddr, &ch, mrouter) <= 0)
-                       return 0;
-       } else
-               ch = channel;
-
-       syslog(LOG_INFO, "Connecting to %s channel %d", dst, ch);
-
-       sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (sk < 0) {
-               syslog(LOG_ERR, "Cannot create RFCOMM socket. %s(%d)",
-                    strerror(errno), errno);
-               return -1;
-       }
-
-       sa.rc_family  = AF_BLUETOOTH;
-       sa.rc_channel = 0;
-       sa.rc_bdaddr  = src_addr;
-
-       if (bind(sk, (struct sockaddr *) &sa, sizeof(sa)))
-               syslog(LOG_ERR, "Bind failed. %s(%d)",
-                       strerror(errno), errno);
-
-       sa.rc_channel = ch;
-       sa.rc_bdaddr  = *bdaddr;
-
-       if (!connect(sk, (struct sockaddr *) &sa, sizeof(sa)) ) {
-               if (mrouter) {
-                       sleep(1);
-                       close(sk);
-                       return 0;
-               }
-
-               syslog(LOG_INFO, "Connection established");
-
-               if (msdun && ms_dun(sk, 0, msdun) < 0) {
-                       syslog(LOG_ERR, "MSDUN failed. %s(%d)", strerror(errno), errno);
-                       err = 1;
-                       goto out;
-               }
-
-               if (!dun_open_connection(sk, pppd, pppd_opts, (persist > 0)))
-                       err = 0;
-               else
-                       err = 1;
-       } else {
-               syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
-                               dst, strerror(errno), errno);
-               err = 1;
-       }
-
-out:
-       if (use_cache) {
-               if (!err) {
-                       /* Succesesful connection, validate cache */
-                       strcpy(cache.dst, dst);
-                       bacpy(&cache.bdaddr, bdaddr);
-                       cache.channel = ch;
-                       cache.valid   = use_cache;
-               } else {
-                       cache.channel = 0;
-                       cache.valid--;
-               }
-       }
-
-       close(sk);
-       return err;
-}
-
-/* Search and connect
- * Returns:
- *   -1 - critical error (exit persist mode)
- *   1  - non critical error
- *   0  - success
- */
-static int do_connect(void)
-{
-       inquiry_info *ii;
-       int reconnect = 0;
-       int i, n, r = 0;
-
-       do {
-               if (reconnect)
-                       sleep(persist);
-               reconnect = 1;
-
-               if (cache.valid) {
-                       /* Use cached bdaddr */
-                       r = create_connection(cache.dst, &cache.bdaddr, 0);
-                       if (r < 0) {
-                               terminate = 1;
-                               break;
-                       }
-                       continue;
-               }
-
-               syslog(LOG_INFO, "Inquiring");
-
-               /* FIXME: Should we use non general LAP here ? */
-
-               ii = NULL;
-               n  = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
-               if (n < 0) {
-                       syslog(LOG_ERR, "Inquiry failed. %s(%d)", strerror(errno), errno);
-                       continue;
-               }
-
-               for (i = 0; i < n; i++) {
-                       char dst[40];
-                       ba2str(&ii[i].bdaddr, dst);
-
-                       r = create_connection(dst, &ii[i].bdaddr, 0);
-                       if (r < 0) {
-                               terminate = 1;
-                               break;
-                       }
-               }
-               bt_free(ii);
-       } while (!terminate && persist);
-
-       return r;
-}
-
-static void do_show(void)
-{
-       dun_show_connections();
-}
-
-static void do_kill(char *dst)
-{
-       if (dst) {
-               bdaddr_t ba;
-               str2ba(dst, &ba);
-               dun_kill_connection((void *) &ba);
-       } else
-               dun_kill_all_connections();
-}
-
-static void sig_hup(int sig)
-{
-       return;
-}
-
-static void sig_term(int sig)
-{
-       io_cancel();
-       terminate = 1;
-}
-
-static struct option main_lopts[] = {
-       { "help",       0, 0, 'h' },
-       { "listen",     0, 0, 's' },
-       { "connect",    1, 0, 'c' },
-       { "search",     2, 0, 'Q' },
-       { "kill",       1, 0, 'k' },
-       { "killall",    0, 0, 'K' },
-       { "channel",    1, 0, 'P' },
-       { "device",     1, 0, 'i' },
-       { "nosdp",      0, 0, 'D' },
-       { "list",       0, 0, 'l' },
-       { "show",       0, 0, 'l' },
-       { "nodetach",   0, 0, 'n' },
-       { "persist",    2, 0, 'p' },
-       { "auth",       0, 0, 'A' },
-       { "encrypt",    0, 0, 'E' },
-       { "secure",     0, 0, 'S' },
-       { "master",     0, 0, 'M' },
-       { "cache",      0, 0, 'C' },
-       { "pppd",       1, 0, 'd' },
-       { "msdun",      2, 0, 'X' },
-       { "activesync", 0, 0, 'a' },
-       { "mrouter",    1, 0, 'm' },
-       { "dialup",     0, 0, 'u' },
-       { 0, 0, 0, 0 }
-};
-
-static const char *main_sopts = "hsc:k:Kr:i:lnp::DQ::AESMP:C::P:Xam:u";
-
-static const char *main_help =
-       "Bluetooth LAP (LAN Access over PPP) daemon version %s\n"
-       "Usage:\n"
-       "\tdund <options> [pppd options]\n"
-       "Options:\n"
-       "\t--show --list -l          Show active LAP connections\n"
-       "\t--listen -s               Listen for LAP connections\n"
-       "\t--dialup -u               Pretend to be a dialup/telephone\n"
-       "\t--connect -c <bdaddr>     Create LAP connection\n"
-       "\t--mrouter -m <bdaddr>     Create mRouter connection\n"
-       "\t--search -Q[duration]     Search and connect\n"
-       "\t--kill -k <bdaddr>        Kill LAP connection\n"
-       "\t--killall -K              Kill all LAP connections\n"
-       "\t--channel -P <channel>    RFCOMM channel\n"
-       "\t--device -i <bdaddr>      Source bdaddr\n"
-       "\t--nosdp -D                Disable SDP\n"
-       "\t--auth -A                 Enable authentication\n"
-       "\t--encrypt -E              Enable encryption\n"
-       "\t--secure -S               Secure connection\n"
-       "\t--master -M               Become the master of a piconet\n"
-       "\t--nodetach -n             Do not become a daemon\n"
-       "\t--persist -p[interval]    Persist mode\n"
-       "\t--pppd -d <pppd>          Location of the PPP daemon (pppd)\n"
-       "\t--msdun -X[timeo]         Enable Microsoft dialup networking support\n"
-       "\t--activesync -a           Enable Microsoft ActiveSync networking\n"
-       "\t--cache -C[valid]         Enable address cache\n";
-
-int main(int argc, char *argv[])
-{
-       char *dst = NULL, *src = NULL;
-       struct sigaction sa;
-       int mode = NONE;
-       int opt;
-
-       while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
-               switch(opt) {
-               case 'l':
-                       mode = SHOW;
-                       detach = 0;
-                       break;
-
-               case 's':
-                       mode = LISTEN;
-                       type = LANACCESS;
-                       break;
-
-               case 'c':
-                       mode = CONNECT;
-                       dst  = strdup(optarg);
-                       break;
-
-               case 'Q':
-                       mode = CONNECT;
-                       dst  = NULL;
-                       if (optarg)
-                               search_duration = atoi(optarg);
-                       break;
-
-               case 'k':
-                       mode = KILL;
-                       detach = 0;
-                       dst  = strdup(optarg);
-                       break;
-
-               case 'K':
-                       mode = KILL;
-                       detach = 0;
-                       dst  = NULL;
-                       break;
-
-               case 'P':
-                       channel = atoi(optarg);
-                       break;
-
-               case 'i':
-                       src = strdup(optarg);
-                       break;
-
-               case 'D':
-                       use_sdp = 0;
-                       break;
-
-               case 'A':
-                       auth = 1;
-                       break;
-
-               case 'E':
-                       encrypt = 1;
-                       break;
-
-               case 'S':
-                       secure = 1;
-                       break;
-
-               case 'M':
-                       master = 1;
-                       break;
-
-               case 'n':
-                       detach = 0;
-                       break;
-
-               case 'p':
-                       if (optarg)
-                               persist = atoi(optarg);
-                       else
-                               persist = 5;
-                       break;
-
-               case 'C':
-                       if (optarg)
-                               use_cache = atoi(optarg);
-                       else
-                               use_cache = 2;
-                       break;
-
-               case 'd':
-                       pppd  = strdup(optarg);
-                       break;
-
-               case 'X':
-                       if (optarg)
-                               msdun = atoi(optarg);
-                       else
-                               msdun = 10;
-                       break;
-
-               case 'a':
-                       msdun = 10;
-                       type = ACTIVESYNC;
-                       break;
-
-               case 'm':
-                       mode = LISTEN;
-                       dst  = strdup(optarg);
-                       type = MROUTER;
-                       break;
-
-               case 'u':
-                       mode = LISTEN;
-                       type = DIALUP;
-                       break;
-
-               case 'h':
-               default:
-                       printf(main_help, VERSION);
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-
-       /* The rest is pppd options */
-       if (argc > 0) {
-               for (opt = 3; argc && opt < DUN_MAX_PPP_OPTS - 1;
-                                                       argc--, opt++)
-                       pppd_opts[opt] = *argv++;
-               pppd_opts[opt] = NULL;
-       }
-
-       io_init();
-
-       if (dun_init()) {
-               free(dst);
-               return -1;
-       }
-
-       /* Check non daemon modes first */
-       switch (mode) {
-       case SHOW:
-               do_show();
-               free(dst);
-               return 0;
-
-       case KILL:
-               do_kill(dst);
-               free(dst);
-               return 0;
-
-       case NONE:
-               printf(main_help, VERSION);
-               free(dst);
-               return 0;
-       }
-
-       /* Initialize signals */
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       if (detach && daemon(0, 0)) {
-               perror("Can't start daemon");
-               exit(1);
-       }
-
-       openlog("dund", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-       syslog(LOG_INFO, "Bluetooth DUN daemon version %s", VERSION);
-
-       if (src) {
-               src_dev = hci_devid(src);
-               if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
-                       syslog(LOG_ERR, "Invalid source. %s(%d)", strerror(errno), errno);
-                       free(dst);
-                       return -1;
-               }
-       }
-
-       if (dst) {
-               strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
-               str2ba(dst, &cache.bdaddr);
-
-               /* Disable cache invalidation */
-               use_cache = cache.valid = ~0;
-       }
-
-       switch (mode) {
-       case CONNECT:
-               do_connect();
-               break;
-
-       case LISTEN:
-               do_listen();
-               break;
-       }
-
-       free(dst);
-       return 0;
-}
diff --git a/compat/fakehid.c b/compat/fakehid.c
deleted file mode 100644 (file)
index 66161b3..0000000
+++ /dev/null
@@ -1,669 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/hidp.h>
-
-#include "hidd.h"
-#include "uinput.h"
-
-#include <math.h>
-
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
-static volatile sig_atomic_t __io_canceled = 0;
-
-static void sig_hup(int sig)
-{
-}
-
-static void sig_term(int sig)
-{
-       __io_canceled = 1;
-}
-
-static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
-{
-       struct uinput_event event;
-
-       if (fd <= fileno(stderr))
-               return -EINVAL;
-
-       memset(&event, 0, sizeof(event));
-       event.type = type;
-       event.code = code;
-       event.value = value;
-
-       return write(fd, &event, sizeof(event));
-}
-
-static int uinput_create(char *name, int keyboard, int mouse)
-{
-       struct uinput_dev dev;
-       int fd, aux;
-
-       fd = open("/dev/uinput", O_RDWR);
-       if (fd < 0) {
-               fd = open("/dev/input/uinput", O_RDWR);
-               if (fd < 0) {
-                       fd = open("/dev/misc/uinput", O_RDWR);
-                       if (fd < 0) {
-                               fprintf(stderr, "Can't open input device: %s (%d)\n",
-                                                       strerror(errno), errno);
-                               return -1;
-                       }
-               }
-       }
-
-       memset(&dev, 0, sizeof(dev));
-
-       if (name)
-               strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
-
-       dev.id.bustype = BUS_BLUETOOTH;
-       dev.id.vendor  = 0x0000;
-       dev.id.product = 0x0000;
-       dev.id.version = 0x0000;
-
-       if (write(fd, &dev, sizeof(dev)) < 0) {
-               fprintf(stderr, "Can't write device information: %s (%d)\n",
-                                                       strerror(errno), errno);
-               close(fd);
-               return -1;
-       }
-
-       if (mouse) {
-               ioctl(fd, UI_SET_EVBIT, EV_REL);
-
-               for (aux = REL_X; aux <= REL_MISC; aux++)
-                       ioctl(fd, UI_SET_RELBIT, aux);
-       }
-
-       if (keyboard) {
-               ioctl(fd, UI_SET_EVBIT, EV_KEY);
-               ioctl(fd, UI_SET_EVBIT, EV_LED);
-               ioctl(fd, UI_SET_EVBIT, EV_REP);
-
-               for (aux = KEY_RESERVED; aux <= KEY_UNKNOWN; aux++)
-                       ioctl(fd, UI_SET_KEYBIT, aux);
-               /*
-                *for (aux = LED_NUML; aux <= LED_MISC; aux++)
-                *      ioctl(fd, UI_SET_LEDBIT, aux);
-                */
-       }
-
-       if (mouse) {
-               ioctl(fd, UI_SET_EVBIT, EV_KEY);
-
-               for (aux = BTN_LEFT; aux <= BTN_BACK; aux++)
-                       ioctl(fd, UI_SET_KEYBIT, aux);
-       }
-
-       ioctl(fd, UI_DEV_CREATE);
-
-       return fd;
-}
-
-static int rfcomm_connect(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
-{
-       struct sockaddr_rc addr;
-       int sk;
-
-       sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (sk < 0) {
-               fprintf(stderr, "Can't create socket: %s (%d)\n",
-                                                       strerror(errno), errno);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, src);
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "Can't bind socket: %s (%d)\n",
-                                                       strerror(errno), errno);
-               close(sk);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, dst);
-       addr.rc_channel = channel;
-
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "Can't connect: %s (%d)\n",
-                                                       strerror(errno), errno);
-               close(sk);
-               return -1;
-       }
-
-       return sk;
-}
-
-static void func(int fd)
-{
-}
-
-static void back(int fd)
-{
-}
-
-static void next(int fd)
-{
-}
-
-static void button(int fd, unsigned int button, int is_press)
-{
-       switch (button) {
-       case 1:
-               send_event(fd, EV_KEY, BTN_LEFT, is_press);
-               break;
-       case 3:
-               send_event(fd, EV_KEY, BTN_RIGHT, is_press);
-               break;
-       }
-
-       send_event(fd, EV_SYN, SYN_REPORT, 0);
-}
-
-static void move(int fd, unsigned int direction)
-{
-       double angle;
-       int32_t x, y;
-
-       angle = (direction * 22.5) * 3.1415926 / 180;
-       x = (int) (sin(angle) * 8);
-       y = (int) (cos(angle) * -8);
-
-       send_event(fd, EV_REL, REL_X, x);
-       send_event(fd, EV_REL, REL_Y, y);
-
-       send_event(fd, EV_SYN, SYN_REPORT, 0);
-}
-
-static inline void epox_decode(int fd, unsigned char event)
-{
-       switch (event) {
-       case 48:
-               func(fd); break;
-       case 55:
-               back(fd); break;
-       case 56:
-               next(fd); break;
-       case 53:
-               button(fd, 1, 1); break;
-       case 121:
-               button(fd, 1, 0); break;
-       case 113:
-               break;
-       case 54:
-               button(fd, 3, 1); break;
-       case 120:
-               button(fd, 3, 0); break;
-       case 112:
-               break;
-       case 51:
-               move(fd, 0); break;
-       case 97:
-               move(fd, 1); break;
-       case 65:
-               move(fd, 2); break;
-       case 98:
-               move(fd, 3); break;
-       case 50:
-               move(fd, 4); break;
-       case 99:
-               move(fd, 5); break;
-       case 67:
-               move(fd, 6); break;
-       case 101:
-               move(fd, 7); break;
-       case 52:
-               move(fd, 8); break;
-       case 100:
-               move(fd, 9); break;
-       case 66:
-               move(fd, 10); break;
-       case 102:
-               move(fd, 11); break;
-       case 49:
-               move(fd, 12); break;
-       case 103:
-               move(fd, 13); break;
-       case 57:
-               move(fd, 14); break;
-       case 104:
-               move(fd, 15); break;
-       case 69:
-               break;
-       default:
-               printf("Unknown event code %d\n", event);
-               break;
-       }
-}
-
-int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
-{
-       unsigned char buf[16];
-       struct sigaction sa;
-       struct pollfd p;
-       sigset_t sigs;
-       char addr[18];
-       int i, fd, sk, len;
-
-       sk = rfcomm_connect(src, dst, channel);
-       if (sk < 0)
-               return -1;
-
-       fd = uinput_create("Bluetooth Presenter", 0, 1);
-       if (fd < 0) {
-               close(sk);
-               return -1;
-       }
-
-       ba2str(dst, addr);
-
-       printf("Connected to %s on channel %d\n", addr, channel);
-       printf("Press CTRL-C for hangup\n");
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       sigfillset(&sigs);
-       sigdelset(&sigs, SIGCHLD);
-       sigdelset(&sigs, SIGPIPE);
-       sigdelset(&sigs, SIGTERM);
-       sigdelset(&sigs, SIGINT);
-       sigdelset(&sigs, SIGHUP);
-
-       p.fd = sk;
-       p.events = POLLIN | POLLERR | POLLHUP;
-
-       while (!__io_canceled) {
-               p.revents = 0;
-               if (ppoll(&p, 1, NULL, &sigs) < 1)
-                       continue;
-
-               len = read(sk, buf, sizeof(buf));
-               if (len < 0)
-                       break;
-
-               for (i = 0; i < len; i++)
-                       epox_decode(fd, buf[i]);
-       }
-
-       printf("Disconnected\n");
-
-       ioctl(fd, UI_DEV_DESTROY);
-
-       close(fd);
-       close(sk);
-
-       return 0;
-}
-
-int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
-{
-       printf("Not implemented\n");
-       return -1;
-}
-
-/* The strange meta key close to Ctrl has been assigned to Esc,
-   Fn key to CtrlR and the left space to Alt*/
-
-static unsigned char jthree_keycodes[63] = {
-       KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6,
-       KEY_Q, KEY_W, KEY_E, KEY_R, KEY_T,
-       KEY_A, KEY_S, KEY_D, KEY_F, KEY_G,
-       KEY_Z, KEY_X, KEY_C, KEY_V, KEY_B,
-       KEY_LEFTALT, KEY_TAB, KEY_CAPSLOCK, KEY_ESC,
-       KEY_7, KEY_8, KEY_9, KEY_0, KEY_MINUS, KEY_EQUAL, KEY_BACKSPACE,
-       KEY_Y, KEY_U, KEY_I, KEY_O, KEY_P, KEY_LEFTBRACE, KEY_RIGHTBRACE,
-       KEY_H, KEY_J, KEY_K, KEY_L, KEY_SEMICOLON, KEY_APOSTROPHE, KEY_ENTER,
-       KEY_N, KEY_M, KEY_COMMA, KEY_DOT, KEY_SLASH, KEY_UP,
-       KEY_SPACE, KEY_COMPOSE, KEY_LEFT, KEY_DOWN, KEY_RIGHT,
-       KEY_LEFTCTRL, KEY_RIGHTSHIFT, KEY_LEFTSHIFT, KEY_DELETE, KEY_RIGHTCTRL, KEY_RIGHTALT,
-};
-
-static inline void jthree_decode(int fd, unsigned char event)
-{
-       if (event > 63)
-               send_event(fd, EV_KEY, jthree_keycodes[event & 0x3f], 0);
-       else
-               send_event(fd, EV_KEY, jthree_keycodes[event - 1], 1);
-}
-
-int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
-{
-       unsigned char buf[16];
-       struct sigaction sa;
-       struct pollfd p;
-       sigset_t sigs;
-       char addr[18];
-       int i, fd, sk, len;
-
-       sk = rfcomm_connect(src, dst, channel);
-       if (sk < 0)
-               return -1;
-
-       fd = uinput_create("J-Three Keyboard", 1, 0);
-       if (fd < 0) {
-               close(sk);
-               return -1;
-       }
-
-       ba2str(dst, addr);
-
-       printf("Connected to %s on channel %d\n", addr, channel);
-       printf("Press CTRL-C for hangup\n");
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       sigfillset(&sigs);
-       sigdelset(&sigs, SIGCHLD);
-       sigdelset(&sigs, SIGPIPE);
-       sigdelset(&sigs, SIGTERM);
-       sigdelset(&sigs, SIGINT);
-       sigdelset(&sigs, SIGHUP);
-
-       p.fd = sk;
-       p.events = POLLIN | POLLERR | POLLHUP;
-
-       while (!__io_canceled) {
-               p.revents = 0;
-               if (ppoll(&p, 1, NULL, &sigs) < 1)
-                       continue;
-
-               len = read(sk, buf, sizeof(buf));
-               if (len < 0)
-                       break;
-
-               for (i = 0; i < len; i++)
-                       jthree_decode(fd, buf[i]);
-       }
-
-       printf("Disconnected\n");
-
-       ioctl(fd, UI_DEV_DESTROY);
-
-       close(fd);
-       close(sk);
-
-       return 0;
-}
-
-static const int celluon_xlate_num[10] = {
-       KEY_0, KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9
-};
-
-static const int celluon_xlate_char[26] = {
-       KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J,
-       KEY_K, KEY_L, KEY_M, KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T,
-       KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z
-};
-
-static int celluon_xlate(int c)
-{
-       if (c >= '0' && c <= '9')
-               return celluon_xlate_num[c - '0'];
-
-       if (c >= 'A' && c <= 'Z')
-               return celluon_xlate_char[c - 'A'];
-
-       switch (c) {
-       case 0x08:
-               return KEY_BACKSPACE;
-       case 0x09:
-               return KEY_TAB;
-       case 0x0d:
-               return KEY_ENTER;
-       case 0x11:
-               return KEY_LEFTCTRL;
-       case 0x14:
-               return KEY_CAPSLOCK;
-       case 0x20:
-               return KEY_SPACE;
-       case 0x25:
-               return KEY_LEFT;
-       case 0x26:
-               return KEY_UP;
-       case 0x27:
-               return KEY_RIGHT;
-       case 0x28:
-               return KEY_DOWN;
-       case 0x2e:
-               return KEY_DELETE;
-       case 0x5b:
-               return KEY_MENU;
-       case 0xa1:
-               return KEY_RIGHTSHIFT;
-       case 0xa0:
-               return KEY_LEFTSHIFT;
-       case 0xba:
-               return KEY_SEMICOLON;
-       case 0xbd:
-               return KEY_MINUS;
-       case 0xbc:
-               return KEY_COMMA;
-       case 0xbb:
-               return KEY_EQUAL;
-       case 0xbe:
-               return KEY_DOT;
-       case 0xbf:
-               return KEY_SLASH;
-       case 0xc0:
-               return KEY_GRAVE;
-       case 0xdb:
-               return KEY_LEFTBRACE;
-       case 0xdc:
-               return KEY_BACKSLASH;
-       case 0xdd:
-               return KEY_RIGHTBRACE;
-       case 0xde:
-               return KEY_APOSTROPHE;
-       case 0xff03:
-               return KEY_HOMEPAGE;
-       case 0xff04:
-               return KEY_TIME;
-       case 0xff06:
-               return KEY_OPEN;
-       case 0xff07:
-               return KEY_LIST;
-       case 0xff08:
-               return KEY_MAIL;
-       case 0xff30:
-               return KEY_CALC;
-       case 0xff1a: /* Map FN to ALT */
-               return KEY_LEFTALT;
-       case 0xff2f:
-               return KEY_INFO;
-       default:
-               printf("Unknown key %x\n", c);
-               return c;
-       }
-}
-
-struct celluon_state {
-       int len;        /* Expected length of current packet */
-       int count;      /* Number of bytes received */
-       int action;
-       int key;
-};
-
-static void celluon_decode(int fd, struct celluon_state *s, uint8_t c)
-{
-       if (s->count < 2 && c != 0xa5) {
-               /* Lost Sync */
-               s->count = 0;
-               return;
-       }
-
-       switch (s->count) {
-       case 0:
-               /* New packet - Reset state */
-               s->len = 30;
-               s->key = 0;
-               break;
-       case 1:
-               break;
-       case 6:
-               s->action = c;
-               break;
-       case 28:
-               s->key = c;
-               if (c == 0xff)
-                       s->len = 31;
-               break;
-       case 29:
-       case 30:
-               if (s->count == s->len - 1) {
-                       /* TODO: Verify checksum */
-                       if (s->action < 2) {
-                               send_event(fd, EV_KEY, celluon_xlate(s->key),
-                                                               s->action);
-                       }
-                       s->count = -1;
-               } else {
-                       s->key = (s->key << 8) | c;
-               }
-               break;
-       }
-
-       s->count++;
-
-       return;
-}
-
-int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel)
-{
-       unsigned char buf[16];
-       struct sigaction sa;
-       struct pollfd p;
-       sigset_t sigs;
-       char addr[18];
-       int i, fd, sk, len;
-       struct celluon_state s;
-
-       sk = rfcomm_connect(src, dst, channel);
-       if (sk < 0)
-               return -1;
-
-       fd = uinput_create("Celluon Keyboard", 1, 0);
-       if (fd < 0) {
-               close(sk);
-               return -1;
-       }
-
-       ba2str(dst, addr);
-
-       printf("Connected to %s on channel %d\n", addr, channel);
-       printf("Press CTRL-C for hangup\n");
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       sigfillset(&sigs);
-       sigdelset(&sigs, SIGCHLD);
-       sigdelset(&sigs, SIGPIPE);
-       sigdelset(&sigs, SIGTERM);
-       sigdelset(&sigs, SIGINT);
-       sigdelset(&sigs, SIGHUP);
-
-       p.fd = sk;
-       p.events = POLLIN | POLLERR | POLLHUP;
-
-       memset(&s, 0, sizeof(s));
-
-       while (!__io_canceled) {
-               p.revents = 0;
-               if (ppoll(&p, 1, NULL, &sigs) < 1)
-                       continue;
-
-               len = read(sk, buf, sizeof(buf));
-               if (len < 0)
-                       break;
-
-               for (i = 0; i < len; i++)
-                       celluon_decode(fd, &s, buf[i]);
-       }
-
-       printf("Disconnected\n");
-
-       ioctl(fd, UI_DEV_DESTROY);
-
-       close(fd);
-       close(sk);
-
-       return 0;
-}
diff --git a/compat/hidd.1 b/compat/hidd.1
deleted file mode 100644 (file)
index b186ac2..0000000
+++ /dev/null
@@ -1,41 +0,0 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.33.
-.TH HIDD "1" "May 2004" "hidd - Bluetooth HID daemon" "User Commands"
-.SH NAME
-hidd \- Bluetooth HID daemon
-.SH DESCRIPTION
-hidd - Bluetooth HID daemon
-.SS "Usage:"
-.IP
-hidd [options] [commands]
-.SH OPTIONS
-.TP
-\fB\-i\fR <hciX|bdaddr>
-Local HCI device or BD Address
-.TP
-\fB\-t\fR <timeout>
-Set idle timeout (in minutes)
-.TP
-\fB\-n\fR, \fB\-\-nodaemon\fR
-Don't fork daemon to background
-.TP
-\fB\-h\fR, \fB\-\-help\fR
-Display help
-.SS "Commands:"
-.TP
-\fB\-\-server\fR
-Start HID server
-.TP
-\fB\-\-search\fR
-Search for HID devices
-.TP
-\fB\-\-connect\fR <bdaddr>
-Connect remote HID device
-.TP
-\fB\-\-kill\fR <bdaddr>
-Terminate HID connection
-.TP
-\fB\-\-killall\fR
-Terminate all connections
-.TP
-\fB\-\-show\fR
-List current HID connections
diff --git a/compat/hidd.c b/compat/hidd.c
deleted file mode 100644 (file)
index f8a0dfd..0000000
+++ /dev/null
@@ -1,848 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <getopt.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/hidp.h>
-
-#include "sdp.h"
-#include "hidd.h"
-
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
-enum {
-       NONE,
-       SHOW,
-       SERVER,
-       SEARCH,
-       CONNECT,
-       KILL
-};
-
-static volatile sig_atomic_t __io_canceled = 0;
-
-static void sig_hup(int sig)
-{
-}
-
-static void sig_term(int sig)
-{
-       __io_canceled = 1;
-}
-
-static int l2cap_connect(bdaddr_t *src, bdaddr_t *dst, unsigned short psm)
-{
-       struct sockaddr_l2 addr;
-       struct l2cap_options opts;
-       int sk;
-
-       if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
-               return -1;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.l2_family  = AF_BLUETOOTH;
-       bacpy(&addr.l2_bdaddr, src);
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               close(sk);
-               return -1;
-       }
-
-       memset(&opts, 0, sizeof(opts));
-       opts.imtu = HIDP_DEFAULT_MTU;
-       opts.omtu = HIDP_DEFAULT_MTU;
-       opts.flush_to = 0xffff;
-
-       setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
-
-       memset(&addr, 0, sizeof(addr));
-       addr.l2_family  = AF_BLUETOOTH;
-       bacpy(&addr.l2_bdaddr, dst);
-       addr.l2_psm = htobs(psm);
-
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               close(sk);
-               return -1;
-       }
-
-       return sk;
-}
-
-static int l2cap_listen(const bdaddr_t *bdaddr, unsigned short psm, int lm, int backlog)
-{
-       struct sockaddr_l2 addr;
-       struct l2cap_options opts;
-       int sk;
-
-       if ((sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP)) < 0)
-               return -1;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.l2_family = AF_BLUETOOTH;
-       bacpy(&addr.l2_bdaddr, bdaddr);
-       addr.l2_psm = htobs(psm);
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               close(sk);
-               return -1;
-       }
-
-       setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm));
-
-       memset(&opts, 0, sizeof(opts));
-       opts.imtu = HIDP_DEFAULT_MTU;
-       opts.omtu = HIDP_DEFAULT_MTU;
-       opts.flush_to = 0xffff;
-
-       setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &opts, sizeof(opts));
-
-       if (listen(sk, backlog) < 0) {
-               close(sk);
-               return -1;
-       }
-
-       return sk;
-}
-
-static int l2cap_accept(int sk, bdaddr_t *bdaddr)
-{
-       struct sockaddr_l2 addr;
-       socklen_t addrlen;
-       int nsk;
-
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-
-       if ((nsk = accept(sk, (struct sockaddr *) &addr, &addrlen)) < 0)
-               return -1;
-
-       if (bdaddr)
-               bacpy(bdaddr, &addr.l2_bdaddr);
-
-       return nsk;
-}
-
-static int request_authentication(bdaddr_t *src, bdaddr_t *dst)
-{
-       struct hci_conn_info_req *cr;
-       char addr[18];
-       int err, dd, dev_id;
-
-       ba2str(src, addr);
-       dev_id = hci_devid(addr);
-       if (dev_id < 0)
-               return dev_id;
-
-       dd = hci_open_dev(dev_id);
-       if (dd < 0)
-               return dd;
-
-       cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
-       if (!cr)
-               return -ENOMEM;
-
-       bacpy(&cr->bdaddr, dst);
-       cr->type = ACL_LINK;
-       err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);
-       if (err < 0) {
-               free(cr);
-               hci_close_dev(dd);
-               return err;
-       }
-
-       err = hci_authenticate_link(dd, htobs(cr->conn_info->handle), 25000);
-
-       free(cr);
-       hci_close_dev(dd);
-
-       return err;
-}
-
-static int request_encryption(bdaddr_t *src, bdaddr_t *dst)
-{
-       struct hci_conn_info_req *cr;
-       char addr[18];
-       int err, dd, dev_id;
-
-       ba2str(src, addr);
-       dev_id = hci_devid(addr);
-       if (dev_id < 0)
-               return dev_id;
-
-       dd = hci_open_dev(dev_id);
-       if (dd < 0)
-               return dd;
-
-       cr = malloc(sizeof(*cr) + sizeof(struct hci_conn_info));
-       if (!cr)
-               return -ENOMEM;
-
-       bacpy(&cr->bdaddr, dst);
-       cr->type = ACL_LINK;
-       err = ioctl(dd, HCIGETCONNINFO, (unsigned long) cr);
-       if (err < 0) {
-               free(cr);
-               hci_close_dev(dd);
-               return err;
-       }
-
-       err = hci_encrypt_link(dd, htobs(cr->conn_info->handle), 1, 25000);
-
-       free(cr);
-       hci_close_dev(dd);
-
-       return err;
-}
-
-static int create_device(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout)
-{
-       struct hidp_connadd_req req;
-       struct sockaddr_l2 addr;
-       socklen_t addrlen;
-       bdaddr_t src, dst;
-       char bda[18];
-       int err;
-
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-
-       if (getsockname(csk, (struct sockaddr *) &addr, &addrlen) < 0)
-               return -1;
-
-       bacpy(&src, &addr.l2_bdaddr);
-
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-
-       if (getpeername(csk, (struct sockaddr *) &addr, &addrlen) < 0)
-               return -1;
-
-       bacpy(&dst, &addr.l2_bdaddr);
-
-       memset(&req, 0, sizeof(req));
-       req.ctrl_sock = csk;
-       req.intr_sock = isk;
-       req.flags     = 0;
-       req.idle_to   = timeout * 60;
-
-       err = get_stored_device_info(&src, &dst, &req);
-       if (!err)
-               goto create;
-
-       if (!nocheck) {
-               ba2str(&dst, bda);
-               syslog(LOG_ERR, "Rejected connection from unknown device %s", bda);
-               /* Return no error to avoid run_server() complaining too */
-               return 0;
-       }
-
-       if (!nosdp) {
-               err = get_sdp_device_info(&src, &dst, &req);
-               if (err < 0)
-                       goto error;
-       } else {
-               struct l2cap_conninfo conn;
-               socklen_t size;
-               uint8_t class[3];
-
-               memset(&conn, 0, sizeof(conn));
-               size = sizeof(conn);
-               if (getsockopt(csk, SOL_L2CAP, L2CAP_CONNINFO, &conn, &size) < 0)
-                       memset(class, 0, 3);
-               else
-                       memcpy(class, conn.dev_class, 3);
-
-               if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01))
-                       req.subclass = class[0];
-               else
-                       req.subclass = 0xc0;
-       }
-
-create:
-       if (subclass != 0x00)
-               req.subclass = subclass;
-
-       ba2str(&dst, bda);
-       syslog(LOG_INFO, "New HID device %s (%s)", bda, req.name);
-
-       if (encrypt && (req.subclass & 0x40)) {
-               err = request_authentication(&src, &dst);
-               if (err < 0) {
-                       syslog(LOG_ERR, "Authentication for %s failed", bda);
-                       goto error;
-               }
-
-               err = request_encryption(&src, &dst);
-               if (err < 0)
-                       syslog(LOG_ERR, "Encryption for %s failed", bda);
-       }
-
-       if (bootonly) {
-               req.rd_size = 0;
-               req.flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
-       }
-
-       err = ioctl(ctl, HIDPCONNADD, &req);
-
-error:
-       free(req.rd_data);
-
-       return err;
-}
-
-static void run_server(int ctl, int csk, int isk, uint8_t subclass, int nosdp, int nocheck, int bootonly, int encrypt, int timeout)
-{
-       struct pollfd p[2];
-       sigset_t sigs;
-       short events;
-       int err, ncsk, nisk;
-
-       sigfillset(&sigs);
-       sigdelset(&sigs, SIGCHLD);
-       sigdelset(&sigs, SIGPIPE);
-       sigdelset(&sigs, SIGTERM);
-       sigdelset(&sigs, SIGINT);
-       sigdelset(&sigs, SIGHUP);
-
-       p[0].fd = csk;
-       p[0].events = POLLIN | POLLERR | POLLHUP;
-
-       p[1].fd = isk;
-       p[1].events = POLLIN | POLLERR | POLLHUP;
-
-       while (!__io_canceled) {
-               p[0].revents = 0;
-               p[1].revents = 0;
-
-               if (ppoll(p, 2, NULL, &sigs) < 1)
-                       continue;
-
-               events = p[0].revents | p[1].revents;
-
-               if (events & POLLIN) {
-                       ncsk = l2cap_accept(csk, NULL);
-                       nisk = l2cap_accept(isk, NULL);
-
-                       err = create_device(ctl, ncsk, nisk, subclass, nosdp, nocheck, bootonly, encrypt, timeout);
-                       if (err < 0)
-                               syslog(LOG_ERR, "HID create error %d (%s)",
-                                               errno, strerror(errno));
-
-                       close(nisk);
-                       sleep(1);
-                       close(ncsk);
-               }
-       }
-}
-
-static char *hidp_state[] = {
-       "unknown",
-       "connected",
-       "open",
-       "bound",
-       "listening",
-       "connecting",
-       "connecting",
-       "config",
-       "disconnecting",
-       "closed"
-};
-
-static char *hidp_flagstostr(uint32_t flags)
-{
-       static char str[100];
-       str[0] = 0;
-
-       strcat(str, "[");
-
-       if (flags & (1 << HIDP_BOOT_PROTOCOL_MODE))
-               strcat(str, "boot-protocol");
-
-       strcat(str, "]");
-
-       return str;
-}
-
-static void do_show(int ctl)
-{
-       struct hidp_connlist_req req;
-       struct hidp_conninfo ci[16];
-       char addr[18];
-       unsigned int i;
-
-       req.cnum = 16;
-       req.ci   = ci;
-
-       if (ioctl(ctl, HIDPGETCONNLIST, &req) < 0) {
-               perror("Can't get connection list");
-               close(ctl);
-               exit(1);
-       }
-
-       for (i = 0; i < req.cnum; i++) {
-               ba2str(&ci[i].bdaddr, addr);
-               printf("%s %s [%04x:%04x] %s %s\n", addr, ci[i].name,
-                       ci[i].vendor, ci[i].product, hidp_state[ci[i].state],
-                       ci[i].flags ? hidp_flagstostr(ci[i].flags) : "");
-       }
-}
-
-static void do_connect(int ctl, bdaddr_t *src, bdaddr_t *dst, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout)
-{
-       struct hidp_connadd_req req;
-       uint16_t uuid = HID_SVCLASS_ID;
-       uint8_t channel = 0;
-       char name[256];
-       int csk, isk, err;
-
-       memset(&req, 0, sizeof(req));
-       name[0] = '\0';
-
-       err = get_sdp_device_info(src, dst, &req);
-       if (err < 0 && fakehid)
-               err = get_alternate_device_info(src, dst,
-                               &uuid, &channel, name, sizeof(name) - 1);
-
-       if (err < 0) {
-               perror("Can't get device information");
-               close(ctl);
-               exit(1);
-       }
-
-       switch (uuid) {
-       case HID_SVCLASS_ID:
-               goto connect;
-
-       case SERIAL_PORT_SVCLASS_ID:
-               if (subclass == 0x40 || !strcmp(name, "Cable Replacement")) {
-                       if (epox_presenter(src, dst, channel) < 0) {
-                               close(ctl);
-                               exit(1);
-                       }
-                       break;
-               }
-               if (subclass == 0x1f || !strcmp(name, "SPP slave")) {
-                       if (jthree_keyboard(src, dst, channel) < 0) {
-                               close(ctl);
-                               exit(1);
-                       }
-                       break;
-               }
-               if (subclass == 0x02 || !strcmp(name, "Serial Port")) {
-                       if (celluon_keyboard(src, dst, channel) < 0) {
-                               close(ctl);
-                               exit(1);
-                       }
-                       break;
-               }
-               break;
-
-       case HEADSET_SVCLASS_ID:
-       case HANDSFREE_SVCLASS_ID:
-               if (headset_presenter(src, dst, channel) < 0) {
-                       close(ctl);
-                       exit(1);
-               }
-               break;
-       }
-
-       return;
-
-connect:
-       csk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_CTRL);
-       if (csk < 0) {
-               perror("Can't create HID control channel");
-               close(ctl);
-               exit(1);
-       }
-
-       isk = l2cap_connect(src, dst, L2CAP_PSM_HIDP_INTR);
-       if (isk < 0) {
-               perror("Can't create HID interrupt channel");
-               close(csk);
-               close(ctl);
-               exit(1);
-       }
-
-       err = create_device(ctl, csk, isk, subclass, 1, 1, bootonly, encrypt, timeout);
-       if (err < 0) {
-               fprintf(stderr, "HID create error %d (%s)\n",
-                                               errno, strerror(errno));
-               close(isk);
-               sleep(1);
-               close(csk);
-               close(ctl);
-               exit(1);
-       }
-}
-
-static void do_search(int ctl, bdaddr_t *bdaddr, uint8_t subclass, int fakehid, int bootonly, int encrypt, int timeout)
-{
-       inquiry_info *info = NULL;
-       bdaddr_t src, dst;
-       int i, dev_id, num_rsp, length, flags;
-       char addr[18];
-       uint8_t class[3];
-
-       ba2str(bdaddr, addr);
-       dev_id = hci_devid(addr);
-       if (dev_id < 0) {
-               dev_id = hci_get_route(NULL);
-               hci_devba(dev_id, &src);
-       } else
-               bacpy(&src, bdaddr);
-
-       length  = 8;    /* ~10 seconds */
-       num_rsp = 0;
-       flags   = IREQ_CACHE_FLUSH;
-
-       printf("Searching ...\n");
-
-       num_rsp = hci_inquiry(dev_id, length, num_rsp, NULL, &info, flags);
-
-       for (i = 0; i < num_rsp; i++) {
-               memcpy(class, (info+i)->dev_class, 3);
-               if (class[1] == 0x25 && (class[2] == 0x00 || class[2] == 0x01)) {
-                       bacpy(&dst, &(info+i)->bdaddr);
-                       ba2str(&dst, addr);
-
-                       printf("\tConnecting to device %s\n", addr);
-                       do_connect(ctl, &src, &dst, subclass, fakehid, bootonly, encrypt, timeout);
-               }
-       }
-
-       if (!fakehid)
-               goto done;
-
-       for (i = 0; i < num_rsp; i++) {
-               memcpy(class, (info+i)->dev_class, 3);
-               if ((class[0] == 0x00 && class[2] == 0x00 &&
-                               (class[1] == 0x40 || class[1] == 0x1f)) ||
-                               (class[0] == 0x10 && class[1] == 0x02 && class[2] == 0x40)) {
-                       bacpy(&dst, &(info+i)->bdaddr);
-                       ba2str(&dst, addr);
-
-                       printf("\tConnecting to device %s\n", addr);
-                       do_connect(ctl, &src, &dst, subclass, 1, bootonly, 0, timeout);
-               }
-       }
-
-done:
-       bt_free(info);
-
-       if (!num_rsp) {
-               fprintf(stderr, "\tNo devices in range or visible\n");
-               close(ctl);
-               exit(1);
-       }
-}
-
-static void do_kill(int ctl, bdaddr_t *bdaddr, uint32_t flags)
-{
-       struct hidp_conndel_req req;
-       struct hidp_connlist_req cl;
-       struct hidp_conninfo ci[16];
-       unsigned int i;
-
-       if (!bacmp(bdaddr, BDADDR_ALL)) {
-               cl.cnum = 16;
-               cl.ci   = ci;
-
-               if (ioctl(ctl, HIDPGETCONNLIST, &cl) < 0) {
-                       perror("Can't get connection list");
-                       close(ctl);
-                       exit(1);
-               }
-
-               for (i = 0; i < cl.cnum; i++) {
-                       bacpy(&req.bdaddr, &ci[i].bdaddr);
-                       req.flags = flags;
-
-                       if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
-                               perror("Can't release connection");
-                               close(ctl);
-                               exit(1);
-                       }
-               }
-
-       } else {
-               bacpy(&req.bdaddr, bdaddr);
-               req.flags = flags;
-
-               if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
-                       perror("Can't release connection");
-                       close(ctl);
-                       exit(1);
-               }
-       }
-}
-
-static void usage(void)
-{
-       printf("hidd - Bluetooth HID daemon version %s\n\n", VERSION);
-
-       printf("Usage:\n"
-               "\thidd [options] [commands]\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-i <hciX|bdaddr>     Local HCI device or BD Address\n"
-               "\t-t <timeout>         Set idle timeout (in minutes)\n"
-               "\t-b <subclass>        Overwrite the boot mode subclass\n"
-               "\t-n, --nodaemon       Don't fork daemon to background\n"
-               "\t-h, --help           Display help\n"
-               "\n");
-
-       printf("Commands:\n"
-               "\t--server             Start HID server\n"
-               "\t--search             Search for HID devices\n"
-               "\t--connect <bdaddr>   Connect remote HID device\n"
-               "\t--unplug <bdaddr>    Unplug the HID connection\n"
-               "\t--kill <bdaddr>      Terminate HID connection\n"
-               "\t--killall            Terminate all connections\n"
-               "\t--show               List current HID connections\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "nodaemon",   0, 0, 'n' },
-       { "subclass",   1, 0, 'b' },
-       { "timeout",    1, 0, 't' },
-       { "device",     1, 0, 'i' },
-       { "master",     0, 0, 'M' },
-       { "encrypt",    0, 0, 'E' },
-       { "nosdp",      0, 0, 'D' },
-       { "nocheck",    0, 0, 'Z' },
-       { "bootonly",   0, 0, 'B' },
-       { "hidonly",    0, 0, 'H' },
-       { "show",       0, 0, 'l' },
-       { "list",       0, 0, 'l' },
-       { "server",     0, 0, 'd' },
-       { "listen",     0, 0, 'd' },
-       { "search",     0, 0, 's' },
-       { "create",     1, 0, 'c' },
-       { "connect",    1, 0, 'c' },
-       { "disconnect", 1, 0, 'k' },
-       { "terminate",  1, 0, 'k' },
-       { "release",    1, 0, 'k' },
-       { "kill",       1, 0, 'k' },
-       { "killall",    0, 0, 'K' },
-       { "unplug",     1, 0, 'u' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       struct sigaction sa;
-       bdaddr_t bdaddr, dev;
-       uint32_t flags = 0;
-       uint8_t subclass = 0x00;
-       char addr[18];
-       int log_option = LOG_NDELAY | LOG_PID;
-       int opt, ctl, csk, isk;
-       int mode = SHOW, detach = 1, nosdp = 0, nocheck = 0, bootonly = 0;
-       int fakehid = 1, encrypt = 0, timeout = 30, lm = 0;
-
-       bacpy(&bdaddr, BDADDR_ANY);
-
-       while ((opt = getopt_long(argc, argv, "+i:nt:b:MEDZBHldsc:k:Ku:h", main_options, NULL)) != -1) {
-               switch(opt) {
-               case 'i':
-                       if (!strncasecmp(optarg, "hci", 3))
-                               hci_devba(atoi(optarg + 3), &bdaddr);
-                       else
-                               str2ba(optarg, &bdaddr);
-                       break;
-               case 'n':
-                       detach = 0;
-                       break;
-               case 't':
-                       timeout = atoi(optarg);
-                       break;
-               case 'b':
-                       if (!strncasecmp(optarg, "0x", 2))
-                               subclass = (uint8_t) strtol(optarg, NULL, 16);
-                       else
-                               subclass = atoi(optarg);
-                       break;
-               case 'M':
-                       lm |= L2CAP_LM_MASTER;
-                       break;
-               case 'E':
-                       encrypt = 1;
-                       break;
-               case 'D':
-                       nosdp = 1;
-                       break;
-               case 'Z':
-                       nocheck = 1;
-                       break;
-               case 'B':
-                       bootonly = 1;
-                       break;
-               case 'H':
-                       fakehid = 0;
-                       break;
-               case 'l':
-                       mode = SHOW;
-                       break;
-               case 'd':
-                       mode = SERVER;
-                       break;
-               case 's':
-                       mode = SEARCH;
-                       break;
-               case 'c':
-                       str2ba(optarg, &dev);
-                       mode = CONNECT;
-                       break;
-               case 'k':
-                       str2ba(optarg, &dev);
-                       mode = KILL;
-                       break;
-               case 'K':
-                       bacpy(&dev, BDADDR_ALL);
-                       mode = KILL;
-                       break;
-               case 'u':
-                       str2ba(optarg, &dev);
-                       flags = (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
-                       mode = KILL;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       exit(0);
-               }
-       }
-
-       ba2str(&bdaddr, addr);
-
-       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-       if (ctl < 0) {
-               perror("Can't open HIDP control socket");
-               exit(1);
-       }
-
-       switch (mode) {
-       case SERVER:
-               csk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_CTRL, lm, 10);
-               if (csk < 0) {
-                       perror("Can't listen on HID control channel");
-                       close(ctl);
-                       exit(1);
-               }
-
-               isk = l2cap_listen(&bdaddr, L2CAP_PSM_HIDP_INTR, lm, 10);
-               if (isk < 0) {
-                       perror("Can't listen on HID interrupt channel");
-                       close(ctl);
-                       close(csk);
-                       exit(1);
-               }
-               break;
-
-       case SEARCH:
-               do_search(ctl, &bdaddr, subclass, fakehid, bootonly, encrypt, timeout);
-               close(ctl);
-               exit(0);
-
-       case CONNECT:
-               do_connect(ctl, &bdaddr, &dev, subclass, fakehid, bootonly, encrypt, timeout);
-               close(ctl);
-               exit(0);
-
-       case KILL:
-               do_kill(ctl, &dev, flags);
-               close(ctl);
-               exit(0);
-
-       default:
-               do_show(ctl);
-               close(ctl);
-               exit(0);
-       }
-
-        if (detach) {
-               if (daemon(0, 0)) {
-                       perror("Can't start daemon");
-                       exit(1);
-               }
-       } else
-               log_option |= LOG_PERROR;
-
-       openlog("hidd", log_option, LOG_DAEMON);
-
-       if (bacmp(&bdaddr, BDADDR_ANY))
-               syslog(LOG_INFO, "Bluetooth HID daemon (%s)", addr);
-       else
-               syslog(LOG_INFO, "Bluetooth HID daemon");
-
-       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_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       run_server(ctl, csk, isk, subclass, nosdp, nocheck, bootonly, encrypt, timeout);
-
-       syslog(LOG_INFO, "Exit");
-
-       close(csk);
-       close(isk);
-       close(ctl);
-
-       return 0;
-}
diff --git a/compat/hidd.h b/compat/hidd.h
deleted file mode 100644 (file)
index 0536967..0000000
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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
- *
- */
-
-#define L2CAP_PSM_HIDP_CTRL 0x11
-#define L2CAP_PSM_HIDP_INTR 0x13
-
-int epox_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
-int headset_presenter(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
-int jthree_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
-int celluon_keyboard(const bdaddr_t *src, const bdaddr_t *dst, uint8_t channel);
diff --git a/compat/lib.h b/compat/lib.h
deleted file mode 100644 (file)
index 3b3aeb5..0000000
+++ /dev/null
@@ -1,86 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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 <sys/types.h>
-#include <errno.h>
-#include <signal.h>
-
-#ifndef min
-#define min(a,b)    ( (a)<(b) ? (a):(b) )
-#endif
-
-/* IO cancelation */
-extern volatile sig_atomic_t __io_canceled;
-
-static inline void io_init(void)
-{
-       __io_canceled = 0;
-}
-
-static inline void io_cancel(void)
-{
-       __io_canceled = 1;
-}
-
-/* Read exactly len bytes (Signal safe)*/
-static inline int read_n(int fd, char *buf, int len)
-{
-       register int t = 0, w;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = read(fd, buf, len)) < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w;
-               buf += w;
-               t += w;
-       }
-
-       return t;
-}
-
-/* Write exactly len bytes (Signal safe)*/
-static inline int write_n(int fd, char *buf, int len)
-{
-       register int t = 0, w;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = write(fd, buf, len)) < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w;
-               buf += w;
-               t += w;
-       }
-
-       return t;
-}
diff --git a/compat/msdun.c b/compat/msdun.c
deleted file mode 100644 (file)
index ae88c0c..0000000
+++ /dev/null
@@ -1,153 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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 <fcntl.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <syslog.h>
-#include <setjmp.h>
-#include <string.h>
-
-#include "lib.h"
-#include "dund.h"
-
-#define MS_PPP      2
-#define MS_SUCCESS  1
-#define MS_FAILED  -1
-#define MS_TIMEOUT -2
-
-static sigjmp_buf jmp;
-static int        retry;
-static int        timeout;
-
-static void sig_alarm(int sig)
-{
-       siglongjmp(jmp, MS_TIMEOUT);
-}
-
-static int w4_str(int fd, char *str)
-{
-       char buf[40];
-       unsigned len = 0;
-       int r;
-
-       while (1) {
-               r = read(fd, buf + len, sizeof(buf) - len - 1);
-               if (r < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-                       break;
-               }
-               if (!r)
-                       break;
-
-               len += r;
-
-               if (len < strlen(str))
-                       continue;
-               buf[len] = 0;
-
-               if (strstr(buf, str))
-                       return MS_SUCCESS;
-
-               /* Detect PPP */
-               if (strchr(buf, '~'))
-                       return MS_PPP;
-       }
-       return MS_FAILED;
-}
-
-static int ms_server(int fd)
-{
-       switch (w4_str(fd, "CLIENT")) {
-       case MS_SUCCESS:
-               write_n(fd, "CLIENTSERVER", 12);
-       case MS_PPP:
-               return MS_SUCCESS;
-       default:
-               return MS_FAILED;
-       }
-}
-
-static int ms_client(int fd)
-{
-       write_n(fd, "CLIENT", 6);
-       return w4_str(fd, "CLIENTSERVER");
-}
-
-int ms_dun(int fd, int server, int timeo)
-{
-       sig_t osig;
-
-       retry    = 4;
-       timeout  = timeo;
-
-       if (!server)
-               timeout /= retry;
-
-       osig = signal(SIGALRM, sig_alarm);
-
-       while (1) {
-               int r = sigsetjmp(jmp, 1);
-               if (r) {
-                       if (r == MS_TIMEOUT && !server && --retry)
-                               continue;
-
-                       alarm(0);
-                       signal(SIGALRM, osig);
-
-                       switch (r) {
-                       case MS_SUCCESS:
-                       case MS_PPP:
-                               errno = 0;
-                               return 0;
-
-                       case MS_FAILED:
-                               errno = EPROTO;
-                               break;
-
-                       case MS_TIMEOUT:
-                               errno = ETIMEDOUT;
-                               break;
-                       }
-                       return -1;
-               }
-
-               alarm(timeout);
-
-               if (server)
-                       r = ms_server(fd);
-               else
-                       r = ms_client(fd);
-
-               siglongjmp(jmp, r);
-       }
-}
diff --git a/compat/pand.1 b/compat/pand.1
deleted file mode 100644 (file)
index 4603b8b..0000000
+++ /dev/null
@@ -1,77 +0,0 @@
-.\" DO NOT MODIFY THIS FILE!  It was generated by help2man 1.29.
-.TH BlueZ "1" "February 2003" "PAN daemon" "User Commands"
-.SH NAME
-pand \- BlueZ Bluetooth PAN daemon
-.SH DESCRIPTION
-The pand PAN daemon allows your computer to connect to ethernet
-networks using Bluetooth.
-.SH SYNPOSIS
-pand <options>
-.SH OPTIONS
-.TP
-\fB\-\-show\fR \fB\-\-list\fR \fB\-l\fR
-Show active PAN connections
-.TP
-\fB\-\-listen\fR \fB\-s\fR
-Listen for PAN connections
-.TP
-\fB\-\-connect\fR \fB\-c\fR <bdaddr>
-Create PAN connection
-.TP
-\fB\-\-search\fR \fB\-Q[duration]\fR
-Search and connect
-.TP
-\fB\-\-kill\fR \fB\-k\fR <bdaddr>
-Kill PAN connection
-.TP
-\fB\-\-killall\fR \fB\-K\fR
-Kill all PAN connections
-.TP
-\fB\-\-role\fR \fB\-r\fR <role>
-Local PAN role (PANU, NAP, GN)
-.TP
-\fB\-\-service\fR \fB\-d\fR <role>
-Remote PAN service (PANU, NAP, GN)
-.TP
-\fB\-\-ethernet\fR \fB\-e\fR <name>
-Network interface name
-.TP
-\fB\-\-device\fR \fB\-i\fR <bdaddr>
-Source bdaddr
-.TP
-\fB\-\-nosdp\fR \fB\-D\fR
-Disable SDP
-.TP
-\fB\-\-encrypt\fR \fB\-E\fR
-Enable encryption
-.TP
-\fB\-\-secure\fR \fB\-S\fR
-Secure connection
-.TP
-\fB\-\-master\fR \fB\-M\fR
-Become the master of a piconet
-.TP
-\fB\-\-nodetach\fR \fB\-n\fR
-Do not become a daemon
-.TP
-\fB\-\-persist\fR \fB\-p[interval]\fR
-Persist mode
-.TP
-\fB\-\-cache\fR \fB\-C[valid]\fR
-Cache addresses
-.TP
-\fB\-\-pidfile\fR \fB\-P <pidfile>\fR
-Create PID file
-.TP
-\fB\-\-devup\fR \fB\-u <script>\fR
-Script to run when interface comes up
-.TP
-\fB\-\-devdown\fR \fB\-o <script>\fR
-Script to run when interface comes down
-.TP
-\fB\-\-autozap\fR \fB\-z\fR
-Disconnect automatically on exit
-
-.SH SCRIPTS
-The devup/devdown script will be called with bluetooth device as first argument
-and bluetooth destination address as second argument.
diff --git a/compat/pand.c b/compat/pand.c
deleted file mode 100644 (file)
index b82650e..0000000
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  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
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <signal.h>
-#include <getopt.h>
-#include <sys/poll.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/bnep.h>
-#include <bluetooth/hidp.h>
-
-#include "sdp.h"
-#include "pand.h"
-
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
-static uint16_t role    = BNEP_SVC_PANU;       /* Local role (ie service) */
-static uint16_t service = BNEP_SVC_NAP;                /* Remote service */
-
-static int detach = 1;
-static int persist;
-static int use_sdp = 1;
-static int use_cache;
-static int link_mode = 0;
-static int cleanup;
-static int search_duration = 10;
-
-static struct {
-       int      valid;
-       char     dst[40];
-       bdaddr_t bdaddr;
-} cache;
-
-static char netdev[16] = "bnep%d";
-static char *pidfile = NULL;
-static char *devupcmd = NULL;
-static char *devdowncmd = NULL;
-
-static bdaddr_t src_addr = *BDADDR_ANY;
-static int src_dev = -1;
-
-static volatile int terminate;
-
-static void do_kill(char *dst);
-
-enum {
-       NONE,
-       SHOW,
-       LISTEN,
-       CONNECT,
-       KILL
-} modes;
-
-struct script_arg {
-       char    dev[20];
-       char    dst[20];
-       int     sk;
-       int     nsk;
-};
-
-static void run_script(char *script, char *dev, char *dst, int sk, int nsk)
-{
-       char *argv[4];
-       struct sigaction sa;
-
-       if (!script)
-               return;
-
-       if (access(script, R_OK | X_OK))
-               return;
-
-       if (fork())
-               return;
-
-       if (sk >= 0)
-               close(sk);
-
-       if (nsk >= 0)
-               close(nsk);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_handler = SIG_DFL;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       argv[0] = script;
-       argv[1] = dev;
-       argv[2] = dst;
-       argv[3] = NULL;
-
-       execv(script, argv);
-
-       exit(1);
-}
-
-/* Wait for disconnect or error condition on the socket */
-static int w4_hup(int sk, struct script_arg *down_cmd)
-{
-       struct pollfd pf;
-       sigset_t sigs;
-       int n;
-
-       sigfillset(&sigs);
-       sigdelset(&sigs, SIGCHLD);
-       sigdelset(&sigs, SIGPIPE);
-       sigdelset(&sigs, SIGTERM);
-       sigdelset(&sigs, SIGINT);
-       sigdelset(&sigs, SIGHUP);
-
-       while (!terminate) {
-               pf.fd = sk;
-               pf.events = POLLERR | POLLHUP;
-
-               n = ppoll(&pf, 1, NULL, &sigs);
-
-               if (n < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-
-                       syslog(LOG_ERR, "Poll failed. %s(%d)",
-                                               strerror(errno), errno);
-
-                       return 1;
-               }
-
-               if (n) {
-                       int err = 0;
-                       socklen_t olen = sizeof(err);
-
-                       getsockopt(sk, SOL_SOCKET, SO_ERROR, &err, &olen);
-
-                       syslog(LOG_INFO, "%s disconnected%s%s", netdev,
-                               err ? " : " : "", err ? strerror(err) : "");
-
-                       if (down_cmd)
-                               run_script(devdowncmd,
-                                               down_cmd->dev, down_cmd->dst,
-                                               down_cmd->sk, down_cmd->nsk);
-
-                       close(sk);
-
-                       return 0;
-               }
-       }
-
-       return 0;
-}
-
-static int do_listen(void)
-{
-       struct l2cap_options l2o;
-       struct sockaddr_l2 l2a;
-       socklen_t olen;
-       int sk, lm;
-
-       if (use_sdp)
-               bnep_sdp_register(&src_addr, role);
-
-       /* Create L2CAP socket and bind it to PSM BNEP */
-       sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-       if (sk < 0) {
-               syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       memset(&l2a, 0, sizeof(l2a));
-       l2a.l2_family = AF_BLUETOOTH;
-       bacpy(&l2a.l2_bdaddr, &src_addr);
-       l2a.l2_psm = htobs(BNEP_PSM);
-
-       if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a))) {
-               syslog(LOG_ERR, "Bind failed. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       /* Setup L2CAP options according to BNEP spec */
-       memset(&l2o, 0, sizeof(l2o));
-       olen = sizeof(l2o);
-       if (getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen) < 0) {
-               syslog(LOG_ERR, "Failed to get L2CAP options. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       l2o.imtu = l2o.omtu = BNEP_MTU;
-       if (setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o)) < 0) {
-               syslog(LOG_ERR, "Failed to set L2CAP options. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       /* Set link mode */
-       lm = link_mode;
-       if (lm && setsockopt(sk, SOL_L2CAP, L2CAP_LM, &lm, sizeof(lm)) < 0) {
-               syslog(LOG_ERR, "Failed to set link mode. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       listen(sk, 10);
-
-       while (!terminate) {
-               socklen_t alen = sizeof(l2a);
-               char devname[16];
-               int nsk;
-
-               nsk = accept(sk, (struct sockaddr *) &l2a, &alen);
-               if (nsk < 0) {
-                       syslog(LOG_ERR, "Accept failed. %s(%d)",
-                                               strerror(errno), errno);
-                       continue;
-               }
-
-               switch (fork()) {
-               case 0:
-                       break;
-               case -1:
-                       syslog(LOG_ERR, "Fork failed. %s(%d)",
-                                               strerror(errno), errno);
-               default:
-                       close(nsk);
-                       continue;
-               }
-
-               strncpy(devname, netdev, 16);
-               devname[15] = '\0';
-
-               if (!bnep_accept_connection(nsk, role, devname)) {
-                       char str[40];
-                       struct script_arg down_cmd;
-
-                       ba2str(&l2a.l2_bdaddr, str);
-
-                       syslog(LOG_INFO, "New connection from %s at %s",
-                                                               str, devname);
-
-                       run_script(devupcmd, devname, str, sk, nsk);
-
-                       memset(&down_cmd, 0, sizeof(struct script_arg));
-                       strncpy(down_cmd.dev, devname, strlen(devname) + 1);
-                       strncpy(down_cmd.dst, str, strlen(str) + 1);
-                       down_cmd.sk = sk;
-                       down_cmd.nsk = nsk;
-                       w4_hup(nsk, &down_cmd);
-               } else {
-                       syslog(LOG_ERR, "Connection failed. %s(%d)",
-                                               strerror(errno), errno);
-               }
-
-               close(nsk);
-               exit(0);
-       }
-
-       if (use_sdp)
-               bnep_sdp_unregister();
-
-       return 0;
-}
-
-/* Connect and initiate BNEP session
- * Returns:
- *   -1 - critical error (exit persist mode)
- *   1  - non critical error
- *   0  - success
- */
-static int create_connection(char *dst, bdaddr_t *bdaddr)
-{
-       struct l2cap_options l2o;
-       struct sockaddr_l2 l2a;
-       socklen_t olen;
-       int sk, r = 0;
-       struct script_arg down_cmd;
-
-       syslog(LOG_INFO, "Connecting to %s", dst);
-
-       sk = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
-       if (sk < 0) {
-               syslog(LOG_ERR, "Cannot create L2CAP socket. %s(%d)",
-                                               strerror(errno), errno);
-               return -1;
-       }
-
-       /* Setup L2CAP options according to BNEP spec */
-       memset(&l2o, 0, sizeof(l2o));
-       olen = sizeof(l2o);
-       getsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, &olen);
-       l2o.imtu = l2o.omtu = BNEP_MTU;
-       setsockopt(sk, SOL_L2CAP, L2CAP_OPTIONS, &l2o, sizeof(l2o));
-
-       memset(&l2a, 0, sizeof(l2a));
-       l2a.l2_family = AF_BLUETOOTH;
-       bacpy(&l2a.l2_bdaddr, &src_addr);
-
-       if (bind(sk, (struct sockaddr *) &l2a, sizeof(l2a)))
-               syslog(LOG_ERR, "Bind failed. %s(%d)",
-                                               strerror(errno), errno);
-
-       memset(&l2a, 0, sizeof(l2a));
-       l2a.l2_family = AF_BLUETOOTH;
-       bacpy(&l2a.l2_bdaddr, bdaddr);
-       l2a.l2_psm = htobs(BNEP_PSM);
-
-       if (!connect(sk, (struct sockaddr *) &l2a, sizeof(l2a)) &&
-                       !bnep_create_connection(sk, role, service, netdev)) {
-
-               syslog(LOG_INFO, "%s connected", netdev);
-
-               run_script(devupcmd, netdev, dst, sk, -1);
-
-               if (persist || devdowncmd) {
-                               memset(&down_cmd, 0, sizeof(struct script_arg));
-                               strncpy(down_cmd.dev, netdev, strlen(netdev) + 1);
-                               strncpy(down_cmd.dst, dst, strlen(dst) + 1);
-                               down_cmd.sk = sk;
-                               down_cmd.nsk = -1;
-                               w4_hup(sk, &down_cmd);
-
-                       if (terminate && cleanup) {
-                               syslog(LOG_INFO, "Disconnecting from %s.", dst);
-                               do_kill(dst);
-                       }
-               }
-
-               r = 0;
-       } else {
-               syslog(LOG_ERR, "Connect to %s failed. %s(%d)",
-                                               dst, strerror(errno), errno);
-               r = 1;
-       }
-
-       close(sk);
-
-       if (use_cache) {
-               if (!r) {
-                       /* Succesesful connection, validate cache */
-                       strcpy(cache.dst, dst);
-                       bacpy(&cache.bdaddr, bdaddr);
-                       cache.valid = use_cache;
-               } else
-                       cache.valid--;
-       }
-
-       return r;
-}
-
-/* Search and connect
- * Returns:
- *   -1 - critical error (exit persist mode)
- *   1  - non critical error
- *   0  - success
- */
-static int do_connect(void)
-{
-       inquiry_info *ii;
-       int reconnect = 0;
-       int i, n, r = 0;
-
-       do {
-               if (reconnect)
-                       sleep(persist);
-               reconnect = 1;
-
-               if (cache.valid > 0) {
-                       /* Use cached bdaddr */
-                       r = create_connection(cache.dst, &cache.bdaddr);
-                       if (r < 0) {
-                               terminate = 1;
-                               break;
-                       }
-                       continue;
-               }
-
-               syslog(LOG_INFO, "Inquiring");
-
-               /* FIXME: Should we use non general LAP here ? */
-
-               ii = NULL;
-               n  = hci_inquiry(src_dev, search_duration, 0, NULL, &ii, 0);
-               if (n < 0) {
-                       syslog(LOG_ERR, "Inquiry failed. %s(%d)",
-                                               strerror(errno), errno);
-                       continue;
-               }
-
-               for (i = 0; i < n; i++) {
-                       char dst[40];
-                       ba2str(&ii[i].bdaddr, dst);
-
-                       if (use_sdp) {
-                               syslog(LOG_INFO, "Searching for %s on %s",
-                                               bnep_svc2str(service), dst);
-
-                               if (bnep_sdp_search(&src_addr, &ii[i].bdaddr, service) <= 0)
-                                       continue;
-                       }
-
-                       r = create_connection(dst, &ii[i].bdaddr);
-                       if (r < 0) {
-                               terminate = 1;
-                               break;
-                       }
-               }
-               bt_free(ii);
-       } while (!terminate && persist);
-
-       return r;
-}
-
-static void do_show(void)
-{
-       bnep_show_connections();
-}
-
-static void do_kill(char *dst)
-{
-       if (dst) {
-               bdaddr_t *ba = strtoba(dst);
-               bnep_kill_connection((void *) ba);
-               free(ba);
-       } else {
-               bnep_kill_all_connections();
-       }
-}
-
-static void sig_hup(int sig)
-{
-       return;
-}
-
-static void sig_term(int sig)
-{
-       terminate = 1;
-}
-
-static int write_pidfile(void)
-{
-       int fd;
-       FILE *f;
-       pid_t pid;
-
-       do {
-               fd = open(pidfile, O_WRONLY|O_TRUNC|O_CREAT|O_EXCL, 0644);
-               if (fd == -1) {
-                       /* Try to open the file for read. */
-                       fd = open(pidfile, O_RDONLY);
-                       if (fd < 0) {
-                               syslog(LOG_ERR, "Could not read old pidfile: %s(%d)",
-                                                       strerror(errno), errno);
-                               return -1;
-                       }
-
-                       /* We're already running; send a SIGHUP (we presume that they
-                        * are calling ifup for a reason, so they probably want to
-                        * rescan) and then exit cleanly and let things go on in the
-                        * background.  Muck with the filename so that we don't go
-                        * deleting the pid file for the already-running instance.
-                        */
-                       f = fdopen(fd, "r");
-                       if (!f) {
-                               syslog(LOG_ERR, "Could not fdopen old pidfile: %s(%d)",
-                                                       strerror(errno), errno);
-                               close(fd);
-                               return -1;
-                       }
-
-                       pid = 0;
-                       if (fscanf(f, "%d", &pid) != 1)
-                               pid = 0;
-                       fclose(f);
-
-                       if (pid) {
-                               /* Try to kill it. */
-                               if (kill(pid, SIGHUP) == -1) {
-                                       /* No such pid; remove the bogus pid file. */
-                                       syslog(LOG_INFO, "Removing stale pidfile");
-                                       unlink(pidfile);
-                                       fd = -1;
-                               } else {
-                                       /* Got it.  Don't mess with the pid file on
-                                        * our way out. */
-                                       syslog(LOG_INFO, "Signalling existing process %d and exiting\n", pid);
-                                       pidfile = NULL;
-                                       return -1;
-                               }
-                       }
-               }
-       } while(fd == -1);
-
-       f = fdopen(fd, "w");
-       if (!f) {
-               syslog(LOG_ERR, "Could not fdopen new pidfile: %s(%d)",
-                                               strerror(errno), errno);
-               close(fd);
-               unlink(pidfile);
-               return -1;
-       }
-
-       fprintf(f, "%d\n", getpid());
-       fclose(f);
-
-       return 0;
-}
-
-static struct option main_lopts[] = {
-       { "help",     0, 0, 'h' },
-       { "listen",   0, 0, 's' },
-       { "connect",  1, 0, 'c' },
-       { "search",   2, 0, 'Q' },
-       { "kill",     1, 0, 'k' },
-       { "killall",  0, 0, 'K' },
-       { "role",     1, 0, 'r' },
-       { "service",  1, 0, 'd' },
-       { "ethernet", 1, 0, 'e' },
-       { "device",   1, 0, 'i' },
-       { "nosdp",    0, 0, 'D' },
-       { "list",     0, 0, 'l' },
-       { "show",     0, 0, 'l' },
-       { "nodetach", 0, 0, 'n' },
-       { "persist",  2, 0, 'p' },
-       { "auth",     0, 0, 'A' },
-       { "encrypt",  0, 0, 'E' },
-       { "secure",   0, 0, 'S' },
-       { "master",   0, 0, 'M' },
-       { "cache",    0, 0, 'C' },
-       { "pidfile",  1, 0, 'P' },
-       { "devup",    1, 0, 'u' },
-       { "devdown",  1, 0, 'o' },
-       { "autozap",  0, 0, 'z' },
-       { 0, 0, 0, 0 }
-};
-
-static const char *main_sopts = "hsc:k:Kr:d:e:i:lnp::DQ::AESMC::P:u:o:z";
-
-static const char *main_help =
-       "Bluetooth PAN daemon version %s\n"
-       "Usage:\n"
-       "\tpand <options>\n"
-       "Options:\n"
-       "\t--show --list -l          Show active PAN connections\n"
-       "\t--listen -s               Listen for PAN connections\n"
-       "\t--connect -c <bdaddr>     Create PAN connection\n"
-       "\t--autozap -z              Disconnect automatically on exit\n"
-       "\t--search -Q[duration]     Search and connect\n"
-       "\t--kill -k <bdaddr>        Kill PAN connection\n"
-       "\t--killall -K              Kill all PAN connections\n"
-       "\t--role -r <role>          Local PAN role (PANU, NAP, GN)\n"
-       "\t--service -d <role>       Remote PAN service (PANU, NAP, GN)\n"
-       "\t--ethernet -e <name>      Network interface name\n"
-       "\t--device -i <bdaddr>      Source bdaddr\n"
-       "\t--nosdp -D                Disable SDP\n"
-       "\t--auth -A                 Enable authentication\n"
-       "\t--encrypt -E              Enable encryption\n"
-       "\t--secure -S               Secure connection\n"
-       "\t--master -M               Become the master of a piconet\n"
-       "\t--nodetach -n             Do not become a daemon\n"
-       "\t--persist -p[interval]    Persist mode\n"
-       "\t--cache -C[valid]         Cache addresses\n"
-       "\t--pidfile -P <pidfile>    Create PID file\n"
-       "\t--devup -u <script>       Script to run when interface comes up\n"
-       "\t--devdown -o <script>     Script to run when interface comes down\n";
-
-int main(int argc, char *argv[])
-{
-       char *dst = NULL, *src = NULL;
-       struct sigaction sa;
-       int mode = NONE;
-       int opt;
-
-       while ((opt=getopt_long(argc, argv, main_sopts, main_lopts, NULL)) != -1) {
-               switch(opt) {
-               case 'l':
-                       mode = SHOW;
-                       detach = 0;
-                       break;
-
-               case 's':
-                       mode = LISTEN;
-                       break;
-
-               case 'c':
-                       mode = CONNECT;
-                       dst  = strdup(optarg);
-                       break;
-
-               case 'Q':
-                       mode = CONNECT;
-                       if (optarg)
-                               search_duration = atoi(optarg);
-                       break;
-
-               case 'k':
-                       mode = KILL;
-                       detach = 0;
-                       dst  = strdup(optarg);
-                       break;
-
-               case 'K':
-                       mode = KILL;
-                       detach = 0;
-                       break;
-
-               case 'i':
-                       src = strdup(optarg);
-                       break;
-
-               case 'r':
-                       bnep_str2svc(optarg, &role);
-                       break;
-
-               case 'd':
-                       bnep_str2svc(optarg, &service);
-                       break;
-
-               case 'D':
-                       use_sdp = 0;
-                       break;
-
-               case 'A':
-                       link_mode |= L2CAP_LM_AUTH;
-                       break;
-
-               case 'E':
-                       link_mode |= L2CAP_LM_ENCRYPT;
-                       break;
-
-               case 'S':
-                       link_mode |= L2CAP_LM_SECURE;
-                       break;
-
-               case 'M':
-                       link_mode |= L2CAP_LM_MASTER;
-                       break;
-
-               case 'e':
-                       strncpy(netdev, optarg, 16);
-                       netdev[15] = '\0';
-                       break;
-
-               case 'n':
-                       detach = 0;
-                       break;
-
-               case 'p':
-                       if (optarg)
-                               persist = atoi(optarg);
-                       else
-                               persist = 5;
-                       break;
-
-               case 'C':
-                       if (optarg)
-                               use_cache = atoi(optarg);
-                       else
-                               use_cache = 2;
-                       break;
-
-               case 'P':
-                       pidfile = strdup(optarg);
-                       break;
-
-               case 'u':
-                       devupcmd = strdup(optarg);
-                       break;
-
-               case 'o':
-                       devdowncmd = strdup(optarg);
-                       break;
-
-               case 'z':
-                       cleanup = 1;
-                       break;
-
-               case 'h':
-               default:
-                       printf(main_help, VERSION);
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (bnep_init()) {
-               free(dst);
-               return -1;
-       }
-
-       /* Check non daemon modes first */
-       switch (mode) {
-       case SHOW:
-               do_show();
-               free(dst);
-               return 0;
-
-       case KILL:
-               do_kill(dst);
-               free(dst);
-               return 0;
-
-       case NONE:
-               printf(main_help, VERSION);
-               free(dst);
-               return 0;
-       }
-
-       /* Initialize signals */
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       if (detach && daemon(0, 0)) {
-               perror("Can't start daemon");
-               exit(1);
-       }
-
-       openlog("pand", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-       syslog(LOG_INFO, "Bluetooth PAN daemon version %s", VERSION);
-
-       if (src) {
-               src_dev = hci_devid(src);
-               if (src_dev < 0 || hci_devba(src_dev, &src_addr) < 0) {
-                       syslog(LOG_ERR, "Invalid source. %s(%d)",
-                                               strerror(errno), errno);
-                       free(dst);
-                       return -1;
-               }
-       }
-
-       if (pidfile && write_pidfile()) {
-               free(dst);
-               return -1;
-       }
-
-       if (dst) {
-               /* Disable cache invalidation */
-               use_cache = 0;
-
-               strncpy(cache.dst, dst, sizeof(cache.dst) - 1);
-               str2ba(dst, &cache.bdaddr);
-               cache.valid = 1;
-               free(dst);
-       }
-
-       switch (mode) {
-       case CONNECT:
-               do_connect();
-               break;
-
-       case LISTEN:
-               do_listen();
-               break;
-       }
-
-       if (pidfile)
-               unlink(pidfile);
-
-       return 0;
-}
diff --git a/compat/sdp.c b/compat/sdp.c
deleted file mode 100644 (file)
index 9ad8333..0000000
+++ /dev/null
@@ -1,706 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <syslog.h>
-#include <limits.h>
-#include <sys/stat.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/hidp.h>
-#include <bluetooth/bnep.h>
-
-#include "textfile.h"
-#include "sdp.h"
-
-static sdp_record_t *record = NULL;
-static sdp_session_t *session = NULL;
-
-static void epox_endian_quirk(unsigned char *data, int size)
-{
-       /* USAGE_PAGE (Keyboard)        05 07
-        * USAGE_MINIMUM (0)            19 00
-        * USAGE_MAXIMUM (65280)        2A 00 FF   <= must be FF 00
-        * LOGICAL_MINIMUM (0)          15 00
-        * LOGICAL_MAXIMUM (65280)      26 00 FF   <= must be FF 00
-        */
-       unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
-                                               0x15, 0x00, 0x26, 0x00, 0xff };
-       unsigned int i;
-
-       if (!data)
-               return;
-
-       for (i = 0; i < size - sizeof(pattern); i++) {
-               if (!memcmp(data + i, pattern, sizeof(pattern))) {
-                       data[i + 5] = 0xff;
-                       data[i + 6] = 0x00;
-                       data[i + 10] = 0xff;
-                       data[i + 11] = 0x00;
-               }
-       }
-}
-
-static int store_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
-{
-       char filename[PATH_MAX + 1], addr[18], *str, *desc;
-       int i, err, size;
-
-       ba2str(src, addr);
-       create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd");
-
-       size = 15 + 3 + 3 + 5 + (req->rd_size * 2) + 1 + 9 + strlen(req->name) + 2;
-       str = malloc(size);
-       if (!str)
-               return -ENOMEM;
-
-       desc = malloc((req->rd_size * 2) + 1);
-       if (!desc) {
-               free(str);
-               return -ENOMEM;
-       }
-
-       memset(desc, 0, (req->rd_size * 2) + 1);
-       for (i = 0; i < req->rd_size; i++)
-               sprintf(desc + (i * 2), "%2.2X", req->rd_data[i]);
-
-       snprintf(str, size - 1, "%04X:%04X:%04X %02X %02X %04X %s %08X %s",
-                       req->vendor, req->product, req->version,
-                       req->subclass, req->country, req->parser, desc,
-                       req->flags, req->name);
-
-       free(desc);
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(dst, addr);
-       err = textfile_put(filename, addr, str);
-
-       free(str);
-
-       return err;
-}
-
-int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
-{
-       char filename[PATH_MAX + 1], addr[18], tmp[3], *str, *desc;
-       unsigned int vendor, product, version, subclass, country, parser, pos;
-       int i;
-
-       desc = malloc(4096);
-       if (!desc)
-               return -ENOMEM;
-
-       memset(desc, 0, 4096);
-
-       ba2str(src, addr);
-       create_name(filename, PATH_MAX, STORAGEDIR, addr, "hidd");
-
-       ba2str(dst, addr);
-       str = textfile_get(filename, addr);
-       if (!str) {
-               free(desc);
-               return -EIO;
-       }
-
-       sscanf(str, "%04X:%04X:%04X %02X %02X %04X %4095s %08X %n",
-                       &vendor, &product, &version, &subclass, &country,
-                       &parser, desc, &req->flags, &pos);
-
-
-       req->vendor   = vendor;
-       req->product  = product;
-       req->version  = version;
-       req->subclass = subclass;
-       req->country  = country;
-       req->parser   = parser;
-
-       snprintf(req->name, 128, "%s", str + pos);
-
-       free(str);
-       req->rd_size = strlen(desc) / 2;
-       req->rd_data = malloc(req->rd_size);
-       if (!req->rd_data) {
-               free(desc);
-               return -ENOMEM;
-       }
-
-       memset(tmp, 0, sizeof(tmp));
-       for (i = 0; i < req->rd_size; i++) {
-               memcpy(tmp, desc + (i * 2), 2);
-               req->rd_data[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
-
-       free(desc);
-
-       return 0;
-}
-
-int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req)
-{
-       struct sockaddr_l2 addr;
-       socklen_t addrlen;
-       bdaddr_t bdaddr;
-       uint32_t range = 0x0000ffff;
-       sdp_session_t *s;
-       sdp_list_t *search, *attrid, *pnp_rsp, *hid_rsp;
-       sdp_record_t *rec;
-       sdp_data_t *pdlist, *pdlist2;
-       uuid_t svclass;
-       int err;
-
-       s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
-       if (!s)
-               return -1;
-
-       sdp_uuid16_create(&svclass, PNP_INFO_SVCLASS_ID);
-       search = sdp_list_append(NULL, &svclass);
-       attrid = sdp_list_append(NULL, &range);
-
-       err = sdp_service_search_attr_req(s, search,
-                                       SDP_ATTR_REQ_RANGE, attrid, &pnp_rsp);
-
-       sdp_list_free(search, NULL);
-       sdp_list_free(attrid, NULL);
-
-       sdp_uuid16_create(&svclass, HID_SVCLASS_ID);
-       search = sdp_list_append(NULL, &svclass);
-       attrid = sdp_list_append(NULL, &range);
-
-       err = sdp_service_search_attr_req(s, search,
-                                       SDP_ATTR_REQ_RANGE, attrid, &hid_rsp);
-
-       sdp_list_free(search, NULL);
-       sdp_list_free(attrid, NULL);
-
-       memset(&addr, 0, sizeof(addr));
-       addrlen = sizeof(addr);
-
-       if (getsockname(s->sock, (struct sockaddr *) &addr, &addrlen) < 0)
-               bacpy(&bdaddr, src);
-       else
-               bacpy(&bdaddr, &addr.l2_bdaddr);
-
-       sdp_close(s);
-
-       if (err || !hid_rsp)
-               return -1;
-
-       if (pnp_rsp) {
-               rec = (sdp_record_t *) pnp_rsp->data;
-
-               pdlist = sdp_data_get(rec, 0x0201);
-               req->vendor = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               pdlist = sdp_data_get(rec, 0x0202);
-               req->product = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               pdlist = sdp_data_get(rec, 0x0203);
-               req->version = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               sdp_record_free(rec);
-       }
-
-       rec = (sdp_record_t *) hid_rsp->data;
-
-       pdlist2 = sdp_data_get(rec, 0x0100);
-       if (pdlist2)
-               strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1);
-       else {
-               pdlist = sdp_data_get(rec, 0x0101);
-               pdlist2 = sdp_data_get(rec, 0x0102);
-               if (pdlist) {
-                       if (pdlist2) {
-                               if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
-                                       strncpy(req->name, pdlist2->val.str, sizeof(req->name) - 1);
-                                       strcat(req->name, " ");
-                               }
-                               strncat(req->name, pdlist->val.str,
-                                               sizeof(req->name) - strlen(req->name));
-                       } else
-                               strncpy(req->name, pdlist->val.str, sizeof(req->name) - 1);
-               }
-       }
-
-       pdlist = sdp_data_get(rec, 0x0201);
-       req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
-
-       pdlist = sdp_data_get(rec, 0x0202);
-       req->subclass = pdlist ? pdlist->val.uint8 : 0;
-
-       pdlist = sdp_data_get(rec, 0x0203);
-       req->country = pdlist ? pdlist->val.uint8 : 0;
-
-       pdlist = sdp_data_get(rec, 0x0206);
-       if (pdlist) {
-               pdlist = pdlist->val.dataseq;
-               pdlist = pdlist->val.dataseq;
-               pdlist = pdlist->next;
-
-               req->rd_data = malloc(pdlist->unitSize);
-               if (req->rd_data) {
-                       memcpy(req->rd_data, (unsigned char *) pdlist->val.str, pdlist->unitSize);
-                       req->rd_size = pdlist->unitSize;
-                       epox_endian_quirk(req->rd_data, req->rd_size);
-               }
-       }
-
-       sdp_record_free(rec);
-
-       if (bacmp(&bdaddr, BDADDR_ANY))
-               store_device_info(&bdaddr, dst, req);
-
-       return 0;
-}
-
-int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len)
-{
-       uint16_t attr1 = SDP_ATTR_PROTO_DESC_LIST;
-       uint16_t attr2 = SDP_ATTR_SVCNAME_PRIMARY;
-       sdp_session_t *s;
-       sdp_list_t *search, *attrid, *rsp;
-       uuid_t svclass;
-       int err;
-
-       s = sdp_connect(src, dst, SDP_RETRY_IF_BUSY | SDP_WAIT_ON_CLOSE);
-       if (!s)
-               return -1;
-
-       sdp_uuid16_create(&svclass, HEADSET_SVCLASS_ID);
-       search = sdp_list_append(NULL, &svclass);
-       attrid = sdp_list_append(NULL, &attr1);
-       attrid = sdp_list_append(attrid, &attr2);
-
-       err = sdp_service_search_attr_req(s, search,
-                                       SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp);
-
-       sdp_list_free(search, NULL);
-       sdp_list_free(attrid, NULL);
-
-       if (err <= 0) {
-               sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
-               search = sdp_list_append(NULL, &svclass);
-               attrid = sdp_list_append(NULL, &attr1);
-               attrid = sdp_list_append(attrid, &attr2);
-
-               err = sdp_service_search_attr_req(s, search,
-                                       SDP_ATTR_REQ_INDIVIDUAL, attrid, &rsp);
-
-               sdp_list_free(search, NULL);
-               sdp_list_free(attrid, NULL);
-
-               if (err < 0) {
-                       sdp_close(s);
-                       return err;
-               }
-
-               if (uuid)
-                       *uuid = SERIAL_PORT_SVCLASS_ID;
-       } else {
-               if (uuid)
-                       *uuid = HEADSET_SVCLASS_ID;
-       }
-
-       sdp_close(s);
-
-       for (; rsp; rsp = rsp->next) {
-               sdp_record_t *rec = (sdp_record_t *) rsp->data;
-               sdp_list_t *protos;
-
-               sdp_get_service_name(rec, name, len);
-
-               if (!sdp_get_access_protos(rec, &protos)) {
-                       uint8_t ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-                       if (ch > 0) {
-                               if (channel)
-                                       *channel = ch;
-                               return 0;
-                       }
-               }
-
-               sdp_record_free(rec);
-       }
-
-       return -EIO;
-}
-
-void bnep_sdp_unregister(void)
-{
-       if (record && sdp_record_unregister(session, record))
-               syslog(LOG_ERR, "Service record unregistration failed.");
-
-       sdp_close(session);
-}
-
-int bnep_sdp_register(bdaddr_t *device, uint16_t role)
-{
-       sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
-       uuid_t root_uuid, pan, l2cap, bnep;
-       sdp_profile_desc_t profile[1];
-       sdp_list_t *proto[2];
-       sdp_data_t *v, *p;
-       uint16_t psm = 15, version = 0x0100;
-       uint16_t security_desc = 0;
-       uint16_t net_access_type = 0xfffe;
-       uint32_t max_net_access_rate = 0;
-       char *name = "BlueZ PAN";
-       char *desc = "BlueZ PAN Service";
-       int status;
-
-       session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
-       if (!session) {
-               syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
-                                                       strerror(errno), errno);
-               return -1;
-       }
-
-       record = sdp_record_alloc();
-       if (!record) {
-               syslog(LOG_ERR, "Failed to allocate service record %s(%d)",
-                                                       strerror(errno), errno);
-               sdp_close(session);
-               return -1;
-       }
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(NULL, &root_uuid);
-       sdp_set_browse_groups(record, root);
-       sdp_list_free(root, 0);
-
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(NULL, &l2cap);
-       p = sdp_data_alloc(SDP_UINT16, &psm);
-       proto[0] = sdp_list_append(proto[0], p);
-       apseq    = sdp_list_append(NULL, proto[0]);
-
-       sdp_uuid16_create(&bnep, BNEP_UUID);
-       proto[1] = sdp_list_append(NULL, &bnep);
-       v = sdp_data_alloc(SDP_UINT16, &version);
-       proto[1] = sdp_list_append(proto[1], v);
-
-       /* Supported protocols */
-       {
-               uint16_t ptype[4] = {
-                       0x0800,  /* IPv4 */
-                       0x0806,  /* ARP */
-               };
-               sdp_data_t *head, *pseq;
-               int p;
-
-               for (p = 0, head = NULL; p < 2; p++) {
-                       sdp_data_t *data = sdp_data_alloc(SDP_UINT16, &ptype[p]);
-                       if (head)
-                               sdp_seq_append(head, data);
-                       else
-                               head = data;
-               }
-               pseq = sdp_data_alloc(SDP_SEQ16, head);
-               proto[1] = sdp_list_append(proto[1], pseq);
-       }
-
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(NULL, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_add_lang_attr(record);
-
-       sdp_list_free(proto[0], NULL);
-       sdp_list_free(proto[1], NULL);
-       sdp_list_free(apseq, NULL);
-       sdp_list_free(aproto, NULL);
-       sdp_data_free(p);
-       sdp_data_free(v);
-       sdp_attr_add_new(record, SDP_ATTR_SECURITY_DESC, SDP_UINT16, &security_desc);
-
-       switch (role) {
-       case BNEP_SVC_NAP:
-               sdp_uuid16_create(&pan, NAP_SVCLASS_ID);
-               svclass = sdp_list_append(NULL, &pan);
-               sdp_set_service_classes(record, svclass);
-
-               sdp_uuid16_create(&profile[0].uuid, NAP_PROFILE_ID);
-               profile[0].version = 0x0100;
-               pfseq = sdp_list_append(NULL, &profile[0]);
-               sdp_set_profile_descs(record, pfseq);
-
-               sdp_set_info_attr(record, "Network Access Point", name, desc);
-
-               sdp_attr_add_new(record, SDP_ATTR_NET_ACCESS_TYPE, SDP_UINT16, &net_access_type);
-               sdp_attr_add_new(record, SDP_ATTR_MAX_NET_ACCESSRATE, SDP_UINT32, &max_net_access_rate);
-               break;
-
-       case BNEP_SVC_GN:
-               sdp_uuid16_create(&pan, GN_SVCLASS_ID);
-               svclass = sdp_list_append(NULL, &pan);
-               sdp_set_service_classes(record, svclass);
-
-               sdp_uuid16_create(&profile[0].uuid, GN_PROFILE_ID);
-               profile[0].version = 0x0100;
-               pfseq = sdp_list_append(NULL, &profile[0]);
-               sdp_set_profile_descs(record, pfseq);
-
-               sdp_set_info_attr(record, "Group Network Service", name, desc);
-               break;
-
-       case BNEP_SVC_PANU:
-               sdp_uuid16_create(&pan, PANU_SVCLASS_ID);
-               svclass = sdp_list_append(NULL, &pan);
-               sdp_set_service_classes(record, svclass);
-               sdp_list_free(svclass, 0);
-
-               sdp_uuid16_create(&profile[0].uuid, PANU_PROFILE_ID);
-               profile[0].version = 0x0100;
-               pfseq = sdp_list_append(NULL, &profile[0]);
-               sdp_set_profile_descs(record, pfseq);
-               sdp_list_free(pfseq, 0);
-
-               sdp_set_info_attr(record, "PAN User", name, desc);
-               break;
-       }
-
-       status = sdp_device_record_register(session, device, record, 0);
-       if (status) {
-               syslog(LOG_ERR, "SDP registration failed.");
-               sdp_record_free(record); record = NULL;
-               sdp_close(session);
-               return -1;
-       }
-
-       return 0;
-}
-
-/* Search for PAN service.
- * Returns 1 if service is found and 0 otherwise. */
-int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service)
-{
-       sdp_list_t *srch, *rsp = NULL;
-       sdp_session_t *s;
-       uuid_t svclass;
-       int err;
-
-       switch (service) {
-       case BNEP_SVC_PANU:
-               sdp_uuid16_create(&svclass, PANU_SVCLASS_ID);
-               break;
-       case BNEP_SVC_NAP:
-               sdp_uuid16_create(&svclass, NAP_SVCLASS_ID);
-               break;
-       case BNEP_SVC_GN:
-               sdp_uuid16_create(&svclass, GN_SVCLASS_ID);
-               break;
-       }
-
-       srch = sdp_list_append(NULL, &svclass);
-
-       s = sdp_connect(src, dst, 0);
-       if (!s) {
-               syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
-                                                       strerror(errno), errno);
-               return 0;
-       }
-
-       err = sdp_service_search_req(s, srch, 1, &rsp);
-       sdp_close(s);
-
-       /* Assume that search is successeful
-        * if at least one record is found */
-       if (!err && sdp_list_len(rsp))
-               return 1;
-
-       return 0;
-}
-
-static unsigned char async_uuid[] = {  0x03, 0x50, 0x27, 0x8F, 0x3D, 0xCA, 0x4E, 0x62,
-                                       0x83, 0x1D, 0xA4, 0x11, 0x65, 0xFF, 0x90, 0x6C };
-
-void dun_sdp_unregister(void)
-{
-       if (record && sdp_record_unregister(session, record))
-               syslog(LOG_ERR, "Service record unregistration failed.");
-       sdp_close(session);
-}
-
-int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type)
-{
-       sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
-       uuid_t root_uuid, l2cap, rfcomm, dun;
-       sdp_profile_desc_t profile[1];
-       sdp_list_t *proto[2];
-       int status;
-
-       session = sdp_connect(BDADDR_ANY, BDADDR_LOCAL, 0);
-       if (!session) {
-               syslog(LOG_ERR, "Failed to connect to the local SDP server. %s(%d)",
-                               strerror(errno), errno);
-               return -1;
-       }
-
-       record = sdp_record_alloc();
-       if (!record) {
-               syslog(LOG_ERR, "Failed to alloc service record");
-               return -1;
-       }
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(NULL, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(NULL, &l2cap);
-       apseq    = sdp_list_append(NULL, proto[0]);
-
-       sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-       proto[1] = sdp_list_append(NULL, &rfcomm);
-       proto[1] = sdp_list_append(proto[1], sdp_data_alloc(SDP_UINT8, &channel));
-       apseq    = sdp_list_append(apseq, proto[1]);
-
-       aproto   = sdp_list_append(NULL, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       switch (type) {
-       case MROUTER:
-               sdp_uuid16_create(&dun, SERIAL_PORT_SVCLASS_ID);
-               break;
-       case ACTIVESYNC:
-               sdp_uuid128_create(&dun, (void *) async_uuid);
-               break;
-       case DIALUP:
-               sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
-               break;
-       default:
-               sdp_uuid16_create(&dun, LAN_ACCESS_SVCLASS_ID);
-               break;
-       }
-
-       svclass = sdp_list_append(NULL, &dun);
-       sdp_set_service_classes(record, svclass);
-
-       switch (type) {
-       case LANACCESS:
-               sdp_uuid16_create(&profile[0].uuid, LAN_ACCESS_PROFILE_ID);
-               profile[0].version = 0x0100;
-               pfseq = sdp_list_append(NULL, &profile[0]);
-               sdp_set_profile_descs(record, pfseq);
-               break;
-       case DIALUP:
-               sdp_uuid16_create(&profile[0].uuid, DIALUP_NET_PROFILE_ID);
-               profile[0].version = 0x0100;
-               pfseq = sdp_list_append(NULL, &profile[0]);
-               sdp_set_profile_descs(record, pfseq);
-               break;
-       }
-
-       switch (type) {
-       case MROUTER:
-               sdp_set_info_attr(record, "mRouter", NULL, NULL);
-               break;
-       case ACTIVESYNC:
-               sdp_set_info_attr(record, "ActiveSync", NULL, NULL);
-               break;
-       case DIALUP:
-               sdp_set_info_attr(record, "Dialup Networking", NULL, NULL);
-               break;
-       default:
-               sdp_set_info_attr(record, "LAN Access Point", NULL, NULL);
-               break;
-       }
-
-       status = sdp_device_record_register(session, device, record, 0);
-       if (status) {
-               syslog(LOG_ERR, "SDP registration failed.");
-               sdp_record_free(record);
-               record = NULL;
-               return -1;
-       }
-       return 0;
-}
-
-int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type)
-{
-       sdp_session_t *s;
-       sdp_list_t *srch, *attrs, *rsp;
-       uuid_t svclass;
-       uint16_t attr;
-       int err;
-
-       s = sdp_connect(src, dst, 0);
-       if (!s) {
-               syslog(LOG_ERR, "Failed to connect to the SDP server. %s(%d)",
-                               strerror(errno), errno);
-               return -1;
-       }
-
-       switch (type) {
-       case MROUTER:
-               sdp_uuid16_create(&svclass, SERIAL_PORT_SVCLASS_ID);
-               break;
-       case ACTIVESYNC:
-               sdp_uuid128_create(&svclass, (void *) async_uuid);
-               break;
-       case DIALUP:
-               sdp_uuid16_create(&svclass, DIALUP_NET_SVCLASS_ID);
-               break;
-       default:
-               sdp_uuid16_create(&svclass, LAN_ACCESS_SVCLASS_ID);
-               break;
-       }
-
-       srch  = sdp_list_append(NULL, &svclass);
-
-       attr  = SDP_ATTR_PROTO_DESC_LIST;
-       attrs = sdp_list_append(NULL, &attr);
-
-       err = sdp_service_search_attr_req(s, srch, SDP_ATTR_REQ_INDIVIDUAL, attrs, &rsp);
-
-       sdp_close(s);
-
-       if (err)
-               return 0;
-
-       for(; rsp; rsp = rsp->next) {
-               sdp_record_t *rec = (sdp_record_t *) rsp->data;
-               sdp_list_t *protos;
-
-               if (!sdp_get_access_protos(rec, &protos)) {
-                       int ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-                       if (ch > 0) {
-                               *channel = ch;
-                               return 1;
-                       }
-               }
-       }
-
-       return 0;
-}
diff --git a/compat/sdp.h b/compat/sdp.h
deleted file mode 100644 (file)
index 6ca975f..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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
- *
- */
-
-#define LANACCESS      0
-#define MROUTER                1
-#define ACTIVESYNC     2
-#define DIALUP         3
-
-int get_stored_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req);
-int get_sdp_device_info(const bdaddr_t *src, const bdaddr_t *dst, struct hidp_connadd_req *req);
-int get_alternate_device_info(const bdaddr_t *src, const bdaddr_t *dst, uint16_t *uuid, uint8_t *channel, char *name, size_t len);
-
-int bnep_sdp_search(bdaddr_t *src, bdaddr_t *dst, uint16_t service);
-int bnep_sdp_register(bdaddr_t *device, uint16_t role);
-void bnep_sdp_unregister(void);
-
-int dun_sdp_search(bdaddr_t *src, bdaddr_t *dst, int *channel, int type);
-int dun_sdp_register(bdaddr_t *device, uint8_t channel, int type);
-void dun_sdp_unregister(void);
diff --git a/compile b/compile
index b1f4749..862a14e 100755 (executable)
--- a/compile
+++ b/compile
@@ -1,7 +1,7 @@
 #! /bin/sh
 # Wrapper for compilers which do not understand '-c -o'.
 
-scriptversion=2012-01-04.17; # UTC
+scriptversion=2012-03-05.13; # UTC
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2009, 2010, 2012 Free
 # Software Foundation, Inc.
@@ -79,6 +79,48 @@ func_file_conv ()
   esac
 }
 
+# func_cl_dashL linkdir
+# Make cl look for libraries in LINKDIR
+func_cl_dashL ()
+{
+  func_file_conv "$1"
+  if test -z "$lib_path"; then
+    lib_path=$file
+  else
+    lib_path="$lib_path;$file"
+  fi
+  linker_opts="$linker_opts -LIBPATH:$file"
+}
+
+# func_cl_dashl library
+# Do a library search-path lookup for cl
+func_cl_dashl ()
+{
+  lib=$1
+  found=no
+  save_IFS=$IFS
+  IFS=';'
+  for dir in $lib_path $LIB
+  do
+    IFS=$save_IFS
+    if $shared && test -f "$dir/$lib.dll.lib"; then
+      found=yes
+      lib=$dir/$lib.dll.lib
+      break
+    fi
+    if test -f "$dir/$lib.lib"; then
+      found=yes
+      lib=$dir/$lib.lib
+      break
+    fi
+  done
+  IFS=$save_IFS
+
+  if test "$found" != yes; then
+    lib=$lib.lib
+  fi
+}
+
 # func_cl_wrapper cl arg...
 # Adjust compile command to suit cl
 func_cl_wrapper ()
@@ -109,43 +151,34 @@ func_cl_wrapper ()
              ;;
          esac
          ;;
+       -I)
+         eat=1
+         func_file_conv "$2" mingw
+         set x "$@" -I"$file"
+         shift
+         ;;
        -I*)
          func_file_conv "${1#-I}" mingw
          set x "$@" -I"$file"
          shift
          ;;
+       -l)
+         eat=1
+         func_cl_dashl "$2"
+         set x "$@" "$lib"
+         shift
+         ;;
        -l*)
-         lib=${1#-l}
-         found=no
-         save_IFS=$IFS
-         IFS=';'
-         for dir in $lib_path $LIB
-         do
-           IFS=$save_IFS
-           if $shared && test -f "$dir/$lib.dll.lib"; then
-             found=yes
-             set x "$@" "$dir/$lib.dll.lib"
-             break
-           fi
-           if test -f "$dir/$lib.lib"; then
-             found=yes
-             set x "$@" "$dir/$lib.lib"
-             break
-           fi
-         done
-         IFS=$save_IFS
-
-         test "$found" != yes && set x "$@" "$lib.lib"
+         func_cl_dashl "${1#-l}"
+         set x "$@" "$lib"
          shift
          ;;
+       -L)
+         eat=1
+         func_cl_dashL "$2"
+         ;;
        -L*)
-         func_file_conv "${1#-L}"
-         if test -z "$lib_path"; then
-           lib_path=$file
-         else
-           lib_path="$lib_path;$file"
-         fi
-         linker_opts="$linker_opts -LIBPATH:$file"
+         func_cl_dashL "${1#-L}"
          ;;
        -static)
          shared=false
index ef188ba..9f1f690 100644 (file)
@@ -9,12 +9,12 @@
 /* Define to 1 if you have the <inttypes.h> header file. */
 #undef HAVE_INTTYPES_H
 
-/* Define to 1 if you have USB library. */
-#undef HAVE_LIBUSB
-
 /* Define to 1 if you have the <memory.h> header file. */
 #undef HAVE_MEMORY_H
 
+/* Define to 1 if you have the <readline/readline.h> header file. */
+#undef HAVE_READLINE_READLINE_H
+
 /* Define to 1 if you have the <stdint.h> header file. */
 #undef HAVE_STDINT_H
 
 /* Define to 1 if you have the <string.h> header file. */
 #undef HAVE_STRING_H
 
-/* Define to 1 if you have <sys/inotify.h>. */
-#undef HAVE_SYS_INOTIFY_H
-
 /* Define to 1 if you have the <sys/stat.h> header file. */
 #undef HAVE_SYS_STAT_H
 
 /* Define to 1 if you have the <sys/types.h> header file. */
 #undef HAVE_SYS_TYPES_H
 
+/* Define to 1 if you have the udev_hwdb_new() function. */
+#undef HAVE_UDEV_HWDB_NEW
+
 /* Define to 1 if you have the <unistd.h> header file. */
 #undef HAVE_UNISTD_H
 
    */
 #undef LT_OBJDIR
 
-/* Define to 1 if you need the ppoll() function. */
-#undef NEED_PPOLL
-
-/* Define to 1 if you need the usb_get_busses() function. */
-#undef NEED_USB_GET_BUSSES
-
-/* Define to 1 if you need the usb_interrupt_read() function. */
-#undef NEED_USB_INTERRUPT_READ
+/* Define if threading support is required */
+#undef NEED_THREADS
 
 /* Define to 1 if your C compiler doesn't accept -c and -o together. */
 #undef NO_MINUS_C_MINUS_O
 
-/* Define the OUI file path */
-#undef OUIFILE
-
 /* Name of package */
 #undef PACKAGE
 
 /* Directory for the storage files */
 #undef STORAGEDIR
 
+/* Enable extensions on AIX 3, Interix.  */
+#ifndef _ALL_SOURCE
+# undef _ALL_SOURCE
+#endif
+/* Enable GNU extensions on systems that have them.  */
+#ifndef _GNU_SOURCE
+# undef _GNU_SOURCE
+#endif
+/* Enable threading extensions on Solaris.  */
+#ifndef _POSIX_PTHREAD_SEMANTICS
+# undef _POSIX_PTHREAD_SEMANTICS
+#endif
+/* Enable extensions on HP NonStop.  */
+#ifndef _TANDEM_SOURCE
+# undef _TANDEM_SOURCE
+#endif
+/* Enable general extensions on Solaris.  */
+#ifndef __EXTENSIONS__
+# undef __EXTENSIONS__
+#endif
+
+
 /* Version number of package */
 #undef VERSION
 
-/* Define to 1 if `lex' declares `yytext' as a `char *' by default, not a
-   `char[]'. */
-#undef YYTEXT_POINTER
+/* Define to 1 if on MINIX. */
+#undef _MINIX
+
+/* Define to 2 if the system does not provide POSIX.1 features except with
+   this defined. */
+#undef _POSIX_1_SOURCE
+
+/* Define to 1 if you need to in order for `stat' and other things to work. */
+#undef _POSIX_SOURCE
+
+/* Define to the equivalent of the C99 'restrict' keyword, or to
+   nothing if this is not supported.  Do not define if restrict is
+   supported directly.  */
+#undef restrict
+/* Work around a bug in Sun C++: it does not support _Restrict or
+   __restrict__, even though the corresponding Sun C compiler ends up with
+   "#define restrict _Restrict" or "#define restrict __restrict__" in the
+   previous line.  Perhaps some future version of Sun C++ will work with
+   restrict; if so, hopefully it defines __RESTRICT like Sun C does.  */
+#if defined __SUNPRO_CC && !defined __RESTRICT
+# define _Restrict
+# define __restrict__
+#endif
index c894da4..6205f84 100755 (executable)
@@ -4,7 +4,7 @@
 #   2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008, 2009, 2010,
 #   2011, 2012 Free Software Foundation, Inc.
 
-timestamp='2012-02-10'
+timestamp='2012-04-18'
 
 # This file is (in principle) common to ALL GNU software.
 # The presence of a machine in this file suggests that SOME GNU software
@@ -225,6 +225,12 @@ case $os in
        -isc*)
                basic_machine=`echo $1 | sed -e 's/86-.*/86-pc/'`
                ;;
+       -lynx*178)
+               os=-lynxos178
+               ;;
+       -lynx*5)
+               os=-lynxos5
+               ;;
        -lynx*)
                os=-lynxos
                ;;
@@ -1537,6 +1543,9 @@ case $basic_machine in
        c4x-* | tic4x-*)
                os=-coff
                ;;
+       hexagon-*)
+               os=-elf
+               ;;
        tic54x-*)
                os=-coff
                ;;
index 22a9b13..2bb5b0f 100755 (executable)
--- a/configure
+++ b/configure
@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.69 for bluez 4.101.
+# Generated by GNU Autoconf 2.69 for bluez 5.10.
 #
 #
 # Copyright (C) 1992-1996, 1998-2012 Free Software Foundation, Inc.
@@ -196,6 +196,7 @@ test -x / || exit 1"
   as_lineno_2=";as_suggested=$as_suggested$LINENO;as_suggested=$as_suggested" as_lineno_2a=\$LINENO
   eval 'test \"x\$as_lineno_1'\$as_run'\" != \"x\$as_lineno_2'\$as_run'\" &&
   test \"x\`expr \$as_lineno_1'\$as_run' + 1\`\" = \"x\$as_lineno_2'\$as_run'\"' || exit 1
+test \$(( 1 + 1 )) = 2 || exit 1
 
   test -n \"\${ZSH_VERSION+set}\${BASH_VERSION+set}\" || (
     ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
@@ -203,8 +204,7 @@ test -x / || exit 1"
     ECHO=\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO\$ECHO
     PATH=/empty FPATH=/empty; export PATH FPATH
     test \"X\`printf %s \$ECHO\`\" = \"X\$ECHO\" \\
-      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1
-test \$(( 1 + 1 )) = 2 || exit 1"
+      || test \"X\`print -r -- \$ECHO\`\" = \"X\$ECHO\" ) || exit 1"
   if (eval "$as_required") 2>/dev/null; then :
   as_have_required=yes
 else
@@ -587,12 +587,11 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='bluez'
 PACKAGE_TARNAME='bluez'
-PACKAGE_VERSION='4.101'
-PACKAGE_STRING='bluez 4.101'
+PACKAGE_VERSION='5.10'
+PACKAGE_STRING='bluez 5.10'
 PACKAGE_BUGREPORT=''
 PACKAGE_URL=''
 
-ac_default_prefix=/usr/local
 # Factoring default headers for most tests.
 ac_includes_default="\
 #include <stdio.h>
@@ -629,98 +628,58 @@ ac_includes_default="\
 # include <unistd.h>
 #endif"
 
+ac_default_prefix=/usr/local
 ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
-SYSTEMD_FALSE
-SYSTEMD_TRUE
-SYSTEMD_UNITDIR
-GATTMODULES_FALSE
-GATTMODULES_TRUE
-WIIMOTEPLUGIN_FALSE
-WIIMOTEPLUGIN_TRUE
-DBUSOOBPLUGIN_FALSE
-DBUSOOBPLUGIN_TRUE
-MAEMO6PLUGIN_FALSE
-MAEMO6PLUGIN_TRUE
+ANDROID_FALSE
+ANDROID_TRUE
+CONFIGDIR
+EXPERIMENTAL_FALSE
+EXPERIMENTAL_TRUE
 DATAFILES_FALSE
 DATAFILES_TRUE
-DFUTOOL_FALSE
-DFUTOOL_TRUE
+SYSTEMD_USERUNITDIR
+SYSTEMD_SYSTEMUNITDIR
+SYSTEMD_FALSE
+SYSTEMD_TRUE
+READLINE_FALSE
+READLINE_TRUE
+CLIENT_FALSE
+CLIENT_TRUE
+OBEX_FALSE
+OBEX_TRUE
+ICAL_LIBS
+ICAL_CFLAGS
+CUPS_FALSE
+CUPS_TRUE
 HID2HCI_FALSE
 HID2HCI_TRUE
-PCMCIA_FALSE
-PCMCIA_TRUE
-BCCMD_FALSE
-BCCMD_TRUE
+UDEV_DIR
+UDEV_FALSE
+UDEV_TRUE
+UDEV_LIBS
+UDEV_CFLAGS
+MONITOR_FALSE
+MONITOR_TRUE
 TOOLS_FALSE
 TOOLS_TRUE
 TEST_FALSE
 TEST_TRUE
-CUPS_FALSE
-CUPS_TRUE
-DUND_FALSE
-DUND_TRUE
-PAND_FALSE
-PAND_TRUE
-HIDD_FALSE
-HIDD_TRUE
-PNATPLUGIN_FALSE
-PNATPLUGIN_TRUE
-READLINE_FALSE
-READLINE_TRUE
-HAL_FALSE
-HAL_TRUE
-MCAP_FALSE
-MCAP_TRUE
-HEALTHPLUGIN_FALSE
-HEALTHPLUGIN_TRUE
-SERVICEPLUGIN_FALSE
-SERVICEPLUGIN_TRUE
-SAPPLUGIN_FALSE
-SAPPLUGIN_TRUE
-NETWORKPLUGIN_FALSE
-NETWORKPLUGIN_TRUE
-SERIALPLUGIN_FALSE
-SERIALPLUGIN_TRUE
-INPUTPLUGIN_FALSE
-INPUTPLUGIN_TRUE
-AUDIOPLUGIN_FALSE
-AUDIOPLUGIN_TRUE
-GSTREAMER_FALSE
-GSTREAMER_TRUE
-ALSA_FALSE
-ALSA_TRUE
-SBC_FALSE
-SBC_TRUE
-USB_FALSE
-USB_TRUE
-SNDFILE_FALSE
-SNDFILE_TRUE
-MISC_LDFLAGS
-MISC_CFLAGS
-TELEPHONY_DRIVER
-SAP_DRIVER
-CHECK_LIBS
-CHECK_CFLAGS
-READLINE_LIBS
-SNDFILE_LIBS
-SNDFILE_CFLAGS
-UDEV_LIBS
-UDEV_CFLAGS
-USB_LIBS
-USB_CFLAGS
-GSTREAMER_PLUGINSDIR
-GSTREAMER_LIBS
-GSTREAMER_CFLAGS
-ALSA_LIBS
-ALSA_CFLAGS
-GLIB_LIBS
-GLIB_CFLAGS
+LIBRARY_FALSE
+LIBRARY_TRUE
+DBUS_SESSIONBUSDIR
+DBUS_SYSTEMBUSDIR
+DBUS_CONFDIR
 DBUS_LIBS
 DBUS_CFLAGS
-CPP
+GTHREAD_LIBS
+GTHREAD_CFLAGS
+GLIB_LIBS
+GLIB_CFLAGS
+MISC_LDFLAGS
+MISC_CFLAGS
 OTOOL64
 OTOOL
 LIPO
@@ -738,8 +697,6 @@ ac_ct_DUMPBIN
 DUMPBIN
 LD
 FGREP
-EGREP
-GREP
 SED
 host_os
 host_vendor
@@ -750,11 +707,16 @@ build_vendor
 build_cpu
 build
 LIBTOOL
-LEXLIB
-LEX_OUTPUT_ROOT
-LEX
-YFLAGS
-YACC
+WARNING_CFLAGS
+PKG_CONFIG_LIBDIR
+PKG_CONFIG_PATH
+PKG_CONFIG
+MAINT
+MAINTAINER_MODE_FALSE
+MAINTAINER_MODE_TRUE
+EGREP
+GREP
+CPP
 am__fastdepCC_FALSE
 am__fastdepCC_TRUE
 CCDEPMODE
@@ -772,16 +734,6 @@ CPPFLAGS
 LDFLAGS
 CFLAGS
 CC
-WARNING_CFLAGS
-UDEV_DIR
-STORAGEDIR
-CONFIGDIR
-PKG_CONFIG_LIBDIR
-PKG_CONFIG_PATH
-PKG_CONFIG
-MAINT
-MAINTAINER_MODE_FALSE
-MAINTAINER_MODE_TRUE
 AM_BACKSLASH
 AM_DEFAULT_VERBOSITY
 AM_DEFAULT_V
@@ -851,8 +803,8 @@ ac_subst_files=''
 ac_user_opts='
 enable_option_checking
 enable_silent_rules
-enable_maintainer_mode
 enable_dependency_tracking
+enable_maintainer_mode
 enable_static
 enable_shared
 with_pic
@@ -860,72 +812,51 @@ enable_fast_install
 with_gnu_ld
 with_sysroot
 enable_libtool_lock
-with_ouifile
 enable_optimization
-enable_fortify
+enable_debug
 enable_pie
-enable_network
-enable_sap
-with_sap
-enable_serial
-enable_input
-enable_audio
-enable_service
-enable_health
-enable_pnat
-enable_gstreamer
-enable_alsa
-enable_usb
+enable_threads
+with_dbusconfdir
+with_dbussystembusdir
+with_dbussessionbusdir
+enable_library
+enable_test
 enable_tools
-enable_bccmd
-enable_pcmcia
-enable_hid2hci
-enable_dfutool
-enable_hidd
-enable_pand
-enable_dund
+enable_monitor
+enable_udev
+with_udevdir
 enable_cups
-enable_test
+enable_obex
+enable_client
+enable_systemd
+with_systemdsystemunitdir
+with_systemduserunitdir
 enable_datafiles
-enable_debug
-with_telephony
-enable_maemo6
-enable_dbusoob
-enable_wiimote
-enable_hal
-enable_gatt
-with_systemdunitdir
+enable_experimental
+enable_android
 '
       ac_precious_vars='build_alias
 host_alias
 target_alias
-PKG_CONFIG
-PKG_CONFIG_PATH
-PKG_CONFIG_LIBDIR
 CC
 CFLAGS
 LDFLAGS
 LIBS
 CPPFLAGS
-YACC
-YFLAGS
 CPP
-DBUS_CFLAGS
-DBUS_LIBS
+PKG_CONFIG
+PKG_CONFIG_PATH
+PKG_CONFIG_LIBDIR
 GLIB_CFLAGS
 GLIB_LIBS
-ALSA_CFLAGS
-ALSA_LIBS
-GSTREAMER_CFLAGS
-GSTREAMER_LIBS
-USB_CFLAGS
-USB_LIBS
+GTHREAD_CFLAGS
+GTHREAD_LIBS
+DBUS_CFLAGS
+DBUS_LIBS
 UDEV_CFLAGS
 UDEV_LIBS
-SNDFILE_CFLAGS
-SNDFILE_LIBS
-CHECK_CFLAGS
-CHECK_LIBS'
+ICAL_CFLAGS
+ICAL_LIBS'
 
 
 # Initialize some variables set by options.
@@ -1466,7 +1397,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures bluez 4.101 to adapt to many kinds of systems.
+\`configure' configures bluez 5.10 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1536,7 +1467,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of bluez 4.101:";;
+     short | recursive ) echo "Configuration of bluez 5.10:";;
    esac
   cat <<\_ACEOF
 
@@ -1546,46 +1477,31 @@ Optional Features:
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
   --enable-silent-rules          less verbose build output (undo: `make V=1')
   --disable-silent-rules         verbose build output (undo: `make V=0')
-  --enable-maintainer-mode  enable make rules and dependencies not useful
-                         (and sometimes confusing) to the casual installer
   --disable-dependency-tracking  speeds up one-time build
   --enable-dependency-tracking   do not reject slow dependency extractors
+  --enable-maintainer-mode  enable make rules and dependencies not useful
+                         (and sometimes confusing) to the casual installer
   --enable-static[=PKGS]  build static libraries [default=no]
   --enable-shared[=PKGS]  build shared libraries [default=yes]
   --enable-fast-install[=PKGS]
                           optimize for fast installation [default=yes]
   --disable-libtool-lock  avoid locking (might break parallel builds)
-  --disable-optimization  disable code optimization
-  --disable-fortify       disable compile time buffer checks
-  --disable-pie           disable position independent executables flag
-  --disable-network       disable network plugin
-  --enable-sap            enable sap plugin
-  --disable-serial        disable serial plugin
-  --disable-input         disable input plugin
-  --disable-audio         disable audio plugin
-  --disable-service       disable service plugin
-  --enable-health         enable health plugin
-  --enable-pnat           enable pnat plugin
-  --enable-gstreamer      enable GStreamer support
-  --enable-alsa           enable ALSA support
-  --enable-usb            enable USB support
-  --enable-tools          install Bluetooth utilities
-  --enable-bccmd          install BCCMD interface utility
-  --enable-pcmcia         install PCMCIA serial script
-  --enable-hid2hci        install HID mode switching utility
-  --enable-dfutool        install DFU firmware upgrade utility
-  --enable-hidd           install HID daemon
-  --enable-pand           install PAN daemon
-  --enable-dund           install DUN daemon
-  --enable-cups           install CUPS backend support
-  --enable-test           install test programs
-  --enable-datafiles      install Bluetooth configuration and data files
+  --disable-optimization  disable code optimization through compiler
   --enable-debug          enable compiling with debugging information
-  --enable-maemo6         compile with maemo6 plugin
-  --enable-dbusoob        compile with D-Bus OOB plugin
-  --enable-wiimote        compile with Wii Remote plugin
-  --enable-hal            Use HAL to determine adapter class
-  --enable-gatt           enable gatt module
+  --enable-pie            enable position independent executables flag
+  --enable-threads        enable threading support
+  --enable-library        install Bluetooth library
+  --enable-test           enable test/example scripts
+  --disable-tools         disable Bluetooth tools
+  --disable-monitor       disable Bluetooth monitor
+  --disable-udev          disable udev device support
+  --disable-cups          disable CUPS printer support
+  --disable-obex          disable OBEX profile support
+  --disable-client        disable command line client
+  --disable-systemd       disable systemd integration
+  --disable-datafiles     do not install configuration and data files
+  --enable-experimental   enable experimental plugins (SAP, NFC, ...)
+  --enable-android        enable BlueZ for Android
 
 Optional Packages:
   --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
@@ -1595,18 +1511,18 @@ Optional Packages:
   --with-gnu-ld           assume the C compiler uses GNU ld [default=no]
   --with-sysroot=DIR Search for dependent libraries within DIR
                         (or the compiler's sysroot if not specified).
-  --with-ouifile=PATH     Path to the oui.txt file [auto]
-  --with-sap=DRIVER       select SAP driver
-  --with-telephony=DRIVER select telephony driver
-  --with-systemdunitdir=DIR
-                          path to systemd system service directory
+  --with-dbusconfdir=DIR  path to D-Bus configuration directory
+  --with-dbussystembusdir=DIR
+                          path to D-Bus system bus services directory
+  --with-dbussessionbusdir=DIR
+                          path to D-Bus session bus services directory
+  --with-udevdir=DIR      path to udev directory
+  --with-systemdsystemunitdir=DIR
+                          path to systemd system unit directory
+  --with-systemduserunitdir=DIR
+                          path to systemd user unit directory
 
 Some influential environment variables:
-  PKG_CONFIG  path to pkg-config utility
-  PKG_CONFIG_PATH
-              directories to add to pkg-config's search path
-  PKG_CONFIG_LIBDIR
-              path overriding pkg-config's built-in search path
   CC          C compiler command
   CFLAGS      C compiler flags
   LDFLAGS     linker flags, e.g. -L<lib dir> if you have libraries in a
@@ -1614,34 +1530,24 @@ Some influential environment variables:
   LIBS        libraries to pass to the linker, e.g. -l<library>
   CPPFLAGS    (Objective) C/C++ preprocessor flags, e.g. -I<include dir> if
               you have headers in a nonstandard directory <include dir>
-  YACC        The `Yet Another Compiler Compiler' implementation to use.
-              Defaults to the first program found out of: `bison -y', `byacc',
-              `yacc'.
-  YFLAGS      The list of arguments that will be passed by default to $YACC.
-              This script will default YFLAGS to the empty string to avoid a
-              default value of `-d' given by some make applications.
   CPP         C preprocessor
-  DBUS_CFLAGS C compiler flags for DBUS, overriding pkg-config
-  DBUS_LIBS   linker flags for DBUS, overriding pkg-config
+  PKG_CONFIG  path to pkg-config utility
+  PKG_CONFIG_PATH
+              directories to add to pkg-config's search path
+  PKG_CONFIG_LIBDIR
+              path overriding pkg-config's built-in search path
   GLIB_CFLAGS C compiler flags for GLIB, overriding pkg-config
   GLIB_LIBS   linker flags for GLIB, overriding pkg-config
-  ALSA_CFLAGS C compiler flags for ALSA, overriding pkg-config
-  ALSA_LIBS   linker flags for ALSA, overriding pkg-config
-  GSTREAMER_CFLAGS
-              C compiler flags for GSTREAMER, overriding pkg-config
-  GSTREAMER_LIBS
-              linker flags for GSTREAMER, overriding pkg-config
-  USB_CFLAGS  C compiler flags for USB, overriding pkg-config
-  USB_LIBS    linker flags for USB, overriding pkg-config
+  GTHREAD_CFLAGS
+              C compiler flags for GTHREAD, overriding pkg-config
+  GTHREAD_LIBS
+              linker flags for GTHREAD, overriding pkg-config
+  DBUS_CFLAGS C compiler flags for DBUS, overriding pkg-config
+  DBUS_LIBS   linker flags for DBUS, overriding pkg-config
   UDEV_CFLAGS C compiler flags for UDEV, overriding pkg-config
   UDEV_LIBS   linker flags for UDEV, overriding pkg-config
-  SNDFILE_CFLAGS
-              C compiler flags for SNDFILE, overriding pkg-config
-  SNDFILE_LIBS
-              linker flags for SNDFILE, overriding pkg-config
-  CHECK_CFLAGS
-              C compiler flags for CHECK, overriding pkg-config
-  CHECK_LIBS  linker flags for CHECK, overriding pkg-config
+  ICAL_CFLAGS C compiler flags for ICAL, overriding pkg-config
+  ICAL_LIBS   linker flags for ICAL, overriding pkg-config
 
 Use these variables to override the choices made by `configure' or to help
 it to find libraries and programs with nonstandard names/locations.
@@ -1709,7 +1615,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-bluez configure 4.101
+bluez configure 5.10
 generated by GNU Autoconf 2.69
 
 Copyright (C) 2012 Free Software Foundation, Inc.
@@ -1761,21 +1667,20 @@ fi
 
 } # ac_fn_c_try_compile
 
-# ac_fn_c_try_link LINENO
-# -----------------------
-# Try to link conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_link ()
+# ac_fn_c_try_cpp LINENO
+# ----------------------
+# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_cpp ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  rm -f conftest.$ac_objext conftest$ac_exeext
-  if { { ac_try="$ac_link"
+  if { { ac_try="$ac_cpp conftest.$ac_ext"
 case "(($ac_try" in
   *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
   *) ac_try_echo=$ac_try;;
 esac
 eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
 $as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_link") 2>conftest.err
+  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
   ac_status=$?
   if test -s conftest.err; then
     grep -v '^ *+' conftest.err >conftest.er1
@@ -1783,97 +1688,108 @@ $as_echo "$ac_try_echo"; } >&5
     mv -f conftest.er1 conftest.err
   fi
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } && {
-        test -z "$ac_c_werror_flag" ||
+  test $ac_status = 0; } > conftest.i && {
+        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
         test ! -s conftest.err
-       } && test -s conftest$ac_exeext && {
-        test "$cross_compiling" = yes ||
-        test -x conftest$ac_exeext
        }; then :
   ac_retval=0
 else
   $as_echo "$as_me: failed program was:" >&5
 sed 's/^/| /' conftest.$ac_ext >&5
 
-       ac_retval=1
+    ac_retval=1
 fi
-  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
-  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
-  # interfere with the next link command; also delete a directory that is
-  # left behind by Apple's compiler.  We do this before executing the actions.
-  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
   as_fn_set_status $ac_retval
 
-} # ac_fn_c_try_link
+} # ac_fn_c_try_cpp
 
-# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
 # -------------------------------------------------------
-# Tests whether HEADER exists and can be compiled using the include files in
-# INCLUDES, setting the cache variable VAR accordingly.
-ac_fn_c_check_header_compile ()
+# Tests whether HEADER exists, giving a warning if it cannot be compiled using
+# the include files in INCLUDES and setting the cache variable VAR
+# accordingly.
+ac_fn_c_check_header_mongrel ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  if eval \${$3+:} false; then :
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
 $as_echo_n "checking for $2... " >&6; }
 if eval \${$3+:} false; then :
   $as_echo_n "(cached) " >&6
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
 else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+  # Is the header compilable?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
+$as_echo_n "checking $2 usability... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 $4
 #include <$2>
 _ACEOF
 if ac_fn_c_try_compile "$LINENO"; then :
-  eval "$3=yes"
+  ac_header_compiler=yes
 else
-  eval "$3=no"
+  ac_header_compiler=no
 fi
 rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
+$as_echo "$ac_header_compiler" >&6; }
 
-} # ac_fn_c_check_header_compile
+# Is the header present?
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
+$as_echo_n "checking $2 presence... " >&6; }
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <$2>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  ac_header_preproc=yes
+else
+  ac_header_preproc=no
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
+$as_echo "$ac_header_preproc" >&6; }
 
-# ac_fn_c_try_cpp LINENO
-# ----------------------
-# Try to preprocess conftest.$ac_ext, and return whether this succeeded.
-ac_fn_c_try_cpp ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if { { ac_try="$ac_cpp conftest.$ac_ext"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+# So?  What about this header?
+case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
+  yes:no: )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
+$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
+  no:yes:* )
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
+$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
+$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
+$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
+$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
+$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
+    ;;
 esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_cpp conftest.$ac_ext") 2>conftest.err
-  ac_status=$?
-  if test -s conftest.err; then
-    grep -v '^ *+' conftest.err >conftest.er1
-    cat conftest.er1 >&5
-    mv -f conftest.er1 conftest.err
-  fi
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } > conftest.i && {
-        test -z "$ac_c_preproc_warn_flag$ac_c_werror_flag" ||
-        test ! -s conftest.err
-       }; then :
-  ac_retval=0
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  $as_echo "$as_me: failed program was:" >&5
-sed 's/^/| /' conftest.$ac_ext >&5
-
-    ac_retval=1
+  eval "$3=\$ac_header_compiler"
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
 fi
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-  as_fn_set_status $ac_retval
 
-} # ac_fn_c_try_cpp
+} # ac_fn_c_check_header_mongrel
 
 # ac_fn_c_try_run LINENO
 # ----------------------
@@ -1917,10 +1833,11 @@ fi
 
 } # ac_fn_c_try_run
 
-# ac_fn_c_check_func LINENO FUNC VAR
-# ----------------------------------
-# Tests whether FUNC exists, setting the cache variable VAR accordingly
-ac_fn_c_check_func ()
+# ac_fn_c_check_header_compile LINENO HEADER VAR INCLUDES
+# -------------------------------------------------------
+# Tests whether HEADER exists and can be compiled using the include files in
+# INCLUDES, setting the cache variable VAR accordingly.
+ac_fn_c_check_header_compile ()
 {
   as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
   { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
@@ -1930,20 +1847,96 @@ if eval \${$3+:} false; then :
 else
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
-   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
-#define $2 innocuous_$2
+$4
+#include <$2>
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  eval "$3=yes"
+else
+  eval "$3=no"
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+eval ac_res=\$$3
+              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
+$as_echo "$ac_res" >&6; }
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
-/* System header to define __stub macros and hopefully few prototypes,
-    which can conflict with char $2 (); below.
-    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-    <limits.h> exists even on freestanding compilers.  */
+} # ac_fn_c_check_header_compile
 
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
+# ac_fn_c_try_link LINENO
+# -----------------------
+# Try to link conftest.$ac_ext, and return whether this succeeded.
+ac_fn_c_try_link ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  rm -f conftest.$ac_objext conftest$ac_exeext
+  if { { ac_try="$ac_link"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_link") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    grep -v '^ *+' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+    mv -f conftest.er1 conftest.err
+  fi
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } && {
+        test -z "$ac_c_werror_flag" ||
+        test ! -s conftest.err
+       } && test -s conftest$ac_exeext && {
+        test "$cross_compiling" = yes ||
+        test -x conftest$ac_exeext
+       }; then :
+  ac_retval=0
+else
+  $as_echo "$as_me: failed program was:" >&5
+sed 's/^/| /' conftest.$ac_ext >&5
+
+       ac_retval=1
+fi
+  # Delete the IPA/IPO (Inter Procedural Analysis/Optimization) information
+  # created by the PGI compiler (conftest_ipa8_conftest.oo), as it would
+  # interfere with the next link command; also delete a directory that is
+  # left behind by Apple's compiler.  We do this before executing the actions.
+  rm -rf conftest.dSYM conftest_ipa8_conftest.oo
+  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
+  as_fn_set_status $ac_retval
+
+} # ac_fn_c_try_link
+
+# ac_fn_c_check_func LINENO FUNC VAR
+# ----------------------------------
+# Tests whether FUNC exists, setting the cache variable VAR accordingly
+ac_fn_c_check_func ()
+{
+  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
+$as_echo_n "checking for $2... " >&6; }
+if eval \${$3+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+/* Define $2 to an innocuous variant, in case <limits.h> declares $2.
+   For example, HP-UX 11i <limits.h> declares gettimeofday.  */
+#define $2 innocuous_$2
+
+/* System header to define __stub macros and hopefully few prototypes,
+    which can conflict with char $2 (); below.
+    Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+    <limits.h> exists even on freestanding compilers.  */
+
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
 
 #undef $2
 
@@ -1983,98 +1976,11 @@ $as_echo "$ac_res" >&6; }
   eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
 
 } # ac_fn_c_check_func
-
-# ac_fn_c_check_header_mongrel LINENO HEADER VAR INCLUDES
-# -------------------------------------------------------
-# Tests whether HEADER exists, giving a warning if it cannot be compiled using
-# the include files in INCLUDES and setting the cache variable VAR
-# accordingly.
-ac_fn_c_check_header_mongrel ()
-{
-  as_lineno=${as_lineno-"$1"} as_lineno_stack=as_lineno_stack=$as_lineno_stack
-  if eval \${$3+:} false; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-else
-  # Is the header compilable?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 usability" >&5
-$as_echo_n "checking $2 usability... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-$4
-#include <$2>
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_header_compiler=yes
-else
-  ac_header_compiler=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_compiler" >&5
-$as_echo "$ac_header_compiler" >&6; }
-
-# Is the header present?
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking $2 presence" >&5
-$as_echo_n "checking $2 presence... " >&6; }
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <$2>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  ac_header_preproc=yes
-else
-  ac_header_preproc=no
-fi
-rm -f conftest.err conftest.i conftest.$ac_ext
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_header_preproc" >&5
-$as_echo "$ac_header_preproc" >&6; }
-
-# So?  What about this header?
-case $ac_header_compiler:$ac_header_preproc:$ac_c_preproc_warn_flag in #((
-  yes:no: )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&5
-$as_echo "$as_me: WARNING: $2: accepted by the compiler, rejected by the preprocessor!" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-  no:yes:* )
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: present but cannot be compiled" >&5
-$as_echo "$as_me: WARNING: $2: present but cannot be compiled" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     check for missing prerequisite headers?" >&5
-$as_echo "$as_me: WARNING: $2:     check for missing prerequisite headers?" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: see the Autoconf documentation" >&5
-$as_echo "$as_me: WARNING: $2: see the Autoconf documentation" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&5
-$as_echo "$as_me: WARNING: $2:     section \"Present But Cannot Be Compiled\"" >&2;}
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: $2: proceeding with the compiler's result" >&5
-$as_echo "$as_me: WARNING: $2: proceeding with the compiler's result" >&2;}
-    ;;
-esac
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $2" >&5
-$as_echo_n "checking for $2... " >&6; }
-if eval \${$3+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  eval "$3=\$ac_header_compiler"
-fi
-eval ac_res=\$$3
-              { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_res" >&5
-$as_echo "$ac_res" >&6; }
-fi
-  eval $as_lineno_stack; ${as_lineno_stack:+:} unset as_lineno
-
-} # ac_fn_c_check_header_mongrel
 cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by bluez $as_me 4.101, which was
+It was created by bluez $as_me 5.10, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   $ $0 $@
@@ -2868,6 +2774,45 @@ else
 fi
 rmdir .tst 2>/dev/null
 
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
+fi
+
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no)  AM_DEFAULT_VERBOSITY=1;;
+*)   AM_DEFAULT_VERBOSITY=1;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+       @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
+else
+  am_cv_make_support_nested_variables=no
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
 if test "`cd $srcdir && pwd`" != "`pwd`"; then
   # Use -I$(srcdir) only when $(srcdir) != ., so that make's output
   # is not polluted with repeated "-I."
@@ -2890,7 +2835,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='bluez'
- VERSION='4.101'
+ VERSION='5.10'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -2924,7 +2869,88 @@ MAKEINFO=${MAKEINFO-"${am_missing_run}makeinfo"}
 # in the wild :-(  We should find a proper way to deprecate it ...
 AMTAR='$${TAR-tar}'
 
-am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to create a pax tar archive" >&5
+$as_echo_n "checking how to create a pax tar archive... " >&6; }
+# Loop over all known methods to create a tar archive until one works.
+_am_tools='gnutar  pax cpio none'
+_am_tools=${am_cv_prog_tar_pax-$_am_tools}
+# Do not fold the above two line into one, because Tru64 sh and
+# Solaris sh will not grok spaces in the rhs of `-'.
+for _am_tool in $_am_tools
+do
+  case $_am_tool in
+  gnutar)
+    for _am_tar in tar gnutar gtar;
+    do
+      { echo "$as_me:$LINENO: $_am_tar --version" >&5
+   ($_am_tar --version) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); } && break
+    done
+    am__tar="$_am_tar --format=posix -chf - "'"$$tardir"'
+    am__tar_="$_am_tar --format=posix -chf - "'"$tardir"'
+    am__untar="$_am_tar -xf -"
+    ;;
+  plaintar)
+    # Must skip GNU tar: if it does not support --format= it doesn't create
+    # ustar tarball either.
+    (tar --version) >/dev/null 2>&1 && continue
+    am__tar='tar chf - "$$tardir"'
+    am__tar_='tar chf - "$tardir"'
+    am__untar='tar xf -'
+    ;;
+  pax)
+    am__tar='pax -L -x pax -w "$$tardir"'
+    am__tar_='pax -L -x pax -w "$tardir"'
+    am__untar='pax -r'
+    ;;
+  cpio)
+    am__tar='find "$$tardir" -print | cpio -o -H pax -L'
+    am__tar_='find "$tardir" -print | cpio -o -H pax -L'
+    am__untar='cpio -i -H pax -d'
+    ;;
+  none)
+    am__tar=false
+    am__tar_=false
+    am__untar=false
+    ;;
+  esac
+
+  # If the value was cached, stop now.  We just wanted to have am__tar
+  # and am__untar set.
+  test -n "${am_cv_prog_tar_pax}" && break
+
+  # tar/untar a dummy directory, and stop if the command works
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  echo GrepMe > conftest.dir/file
+  { echo "$as_me:$LINENO: tardir=conftest.dir && eval $am__tar_ >conftest.tar" >&5
+   (tardir=conftest.dir && eval $am__tar_ >conftest.tar) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); }
+  rm -rf conftest.dir
+  if test -s conftest.tar; then
+    { echo "$as_me:$LINENO: $am__untar <conftest.tar" >&5
+   ($am__untar <conftest.tar) >&5 2>&5
+   ac_status=$?
+   echo "$as_me:$LINENO: \$? = $ac_status" >&5
+   (exit $ac_status); }
+    grep GrepMe conftest.dir/file >/dev/null 2>&1 && break
+  fi
+done
+rm -rf conftest.dir
+
+if ${am_cv_prog_tar_pax+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  am_cv_prog_tar_pax=$_am_tool
+fi
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_prog_tar_pax" >&5
+$as_echo "$am_cv_prog_tar_pax" >&6; }
 
 
 
@@ -2932,284 +2958,69 @@ am__tar='$${TAR-tar} chof - "$$tardir"' am__untar='$${TAR-tar} xf -'
 
 ac_config_headers="$ac_config_headers config.h"
 
+DEPDIR="${am__leading_dot}deps"
+
+ac_config_commands="$ac_config_commands depfiles"
 
-# Check whether --enable-silent-rules was given.
-if test "${enable_silent_rules+set}" = set; then :
-  enableval=$enable_silent_rules;
-fi
 
-case $enable_silent_rules in
-yes) AM_DEFAULT_VERBOSITY=0;;
-no)  AM_DEFAULT_VERBOSITY=1;;
-*)   AM_DEFAULT_VERBOSITY=0;;
-esac
 am_make=${MAKE-make}
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
-$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
-if ${am_cv_make_support_nested_variables+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if $as_echo 'TRUE=$(BAR$(V))
-BAR0=false
-BAR1=true
-V=1
+cat > confinc << 'END'
 am__doit:
-       @$(TRUE)
-.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
-  am_cv_make_support_nested_variables=yes
-else
-  am_cv_make_support_nested_variables=no
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
-$as_echo "$am_cv_make_support_nested_variables" >&6; }
-if test $am_cv_make_support_nested_variables = yes; then
-    AM_V='$(V)'
-  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
-else
-  AM_V=$AM_DEFAULT_VERBOSITY
-  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
-fi
-AM_BACKSLASH='\'
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
-$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
-    # Check whether --enable-maintainer-mode was given.
-if test "${enable_maintainer_mode+set}" = set; then :
-  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
-else
-  USE_MAINTAINER_MODE=no
-fi
-
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
-$as_echo "$USE_MAINTAINER_MODE" >&6; }
-   if test $USE_MAINTAINER_MODE = yes; then
-  MAINTAINER_MODE_TRUE=
-  MAINTAINER_MODE_FALSE='#'
-else
-  MAINTAINER_MODE_TRUE='#'
-  MAINTAINER_MODE_FALSE=
-fi
-
-  MAINT=$MAINTAINER_MODE_TRUE
-
-
-
-
-
-
-
-
-
-
-if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
-       if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
-set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
+       @echo this is the am__doit target
+.PHONY: am__doit
+END
+# If we don't find an include directive, just comment out the code.
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
+$as_echo_n "checking for style of include used by $am_make... " >&6; }
+am__include="#"
+am__quote=
+_am_result=none
+# First try GNU make style include.
+echo "include confinc" > confmf
+# Ignore all kinds of additional output from `make'.
+case `$am_make -s -f confmf 2> /dev/null` in #(
+*the\ am__doit\ target*)
+  am__include=include
+  am__quote=
+  _am_result=GNU
   ;;
 esac
-fi
-PKG_CONFIG=$ac_cv_path_PKG_CONFIG
-if test -n "$PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
-$as_echo "$PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+# Now try BSD make style include.
+if test "$am__include" = "#"; then
+   echo '.include "confinc"' > confmf
+   case `$am_make -s -f confmf 2> /dev/null` in #(
+   *the\ am__doit\ target*)
+     am__include=.include
+     am__quote="\""
+     _am_result=BSD
+     ;;
+   esac
 fi
 
 
-fi
-if test -z "$ac_cv_path_PKG_CONFIG"; then
-  ac_pt_PKG_CONFIG=$PKG_CONFIG
-  # Extract the first word of "pkg-config", so it can be a program name with args.
-set dummy pkg-config; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  case $ac_pt_PKG_CONFIG in
-  [\\/]* | ?:[\\/]*)
-  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
-  ;;
-  *)
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-  ;;
-esac
-fi
-ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
-if test -n "$ac_pt_PKG_CONFIG"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
-$as_echo "$ac_pt_PKG_CONFIG" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
+$as_echo "$_am_result" >&6; }
+rm -f confinc confmf
 
-  if test "x$ac_pt_PKG_CONFIG" = x; then
-    PKG_CONFIG=""
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    PKG_CONFIG=$ac_pt_PKG_CONFIG
-  fi
-else
-  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
+# Check whether --enable-dependency-tracking was given.
+if test "${enable_dependency_tracking+set}" = set; then :
+  enableval=$enable_dependency_tracking;
 fi
 
+if test "x$enable_dependency_tracking" != xno; then
+  am_depcomp="$ac_aux_dir/depcomp"
+  AMDEPBACKSLASH='\'
+  am__nodep='_no'
 fi
-if test -n "$PKG_CONFIG"; then
-       _pkg_min_version=0.9.0
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
-$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
-       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       else
-               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-               PKG_CONFIG=""
-       fi
+ if test "x$enable_dependency_tracking" != xno; then
+  AMDEP_TRUE=
+  AMDEP_FALSE='#'
+else
+  AMDEP_TRUE='#'
+  AMDEP_FALSE=
 fi
 
 
-
-
-       if (test "${prefix}" = "NONE"); then
-                               if (test "$sysconfdir" = '${prefix}/etc'); then
-                       sysconfdir='/etc'
-
-               fi
-
-                               if (test "$localstatedir" = '${prefix}/var'); then
-                       localstatedir='/var'
-
-               fi
-
-                               if (test "$libexecdir" = '${exec_prefix}/libexec'); then
-                       libexecdir='/lib'
-
-               fi
-
-                               if (test "$mandir" = '${prefix}/man'); then
-                       mandir='${prefix}/share/man'
-
-               fi
-
-               prefix="${ac_default_prefix}"
-       fi
-
-       if (test "${libdir}" = '${exec_prefix}/lib'); then
-               libdir="${prefix}/lib"
-       fi
-
-       plugindir="${libdir}/bluetooth/plugins"
-
-       if (test "$sysconfdir" = '${prefix}/etc'); then
-               configdir="${prefix}/etc/bluetooth"
-       else
-               configdir="${sysconfdir}/bluetooth"
-       fi
-
-       if (test "$localstatedir" = '${prefix}/var'); then
-               storagedir="${prefix}/var/lib/bluetooth"
-       else
-               storagedir="${localstatedir}/lib/bluetooth"
-       fi
-
-
-cat >>confdefs.h <<_ACEOF
-#define CONFIGDIR "${configdir}"
-_ACEOF
-
-
-cat >>confdefs.h <<_ACEOF
-#define STORAGEDIR "${storagedir}"
-_ACEOF
-
-
-       CONFIGDIR="${configdir}"
-
-       STORAGEDIR="${storagedir}"
-
-
-       UDEV_DIR="`$PKG_CONFIG --variable=udevdir udev`"
-       if (test -z "${UDEV_DIR}"); then
-               UDEV_DIR="/lib/udev"
-       fi
-
-
-
-
-       with_cflags=""
-       if (test "$USE_MAINTAINER_MODE" = "yes"); then
-               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
-
-       WARNING_CFLAGS=$with_cflags
-
-
-
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-
 ac_ext=c
 ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
@@ -3998,69 +3809,6 @@ ac_cpp='$CPP $CPPFLAGS'
 ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
 ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
 ac_compiler_gnu=$ac_cv_c_compiler_gnu
-DEPDIR="${am__leading_dot}deps"
-
-ac_config_commands="$ac_config_commands depfiles"
-
-
-am_make=${MAKE-make}
-cat > confinc << 'END'
-am__doit:
-       @echo this is the am__doit target
-.PHONY: am__doit
-END
-# If we don't find an include directive, just comment out the code.
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for style of include used by $am_make" >&5
-$as_echo_n "checking for style of include used by $am_make... " >&6; }
-am__include="#"
-am__quote=
-_am_result=none
-# First try GNU make style include.
-echo "include confinc" > confmf
-# Ignore all kinds of additional output from `make'.
-case `$am_make -s -f confmf 2> /dev/null` in #(
-*the\ am__doit\ target*)
-  am__include=include
-  am__quote=
-  _am_result=GNU
-  ;;
-esac
-# Now try BSD make style include.
-if test "$am__include" = "#"; then
-   echo '.include "confinc"' > confmf
-   case `$am_make -s -f confmf 2> /dev/null` in #(
-   *the\ am__doit\ target*)
-     am__include=.include
-     am__quote="\""
-     _am_result=BSD
-     ;;
-   esac
-fi
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $_am_result" >&5
-$as_echo "$_am_result" >&6; }
-rm -f confinc confmf
-
-# Check whether --enable-dependency-tracking was given.
-if test "${enable_dependency_tracking+set}" = set; then :
-  enableval=$enable_dependency_tracking;
-fi
-
-if test "x$enable_dependency_tracking" != xno; then
-  am_depcomp="$ac_aux_dir/depcomp"
-  AMDEPBACKSLASH='\'
-  am__nodep='_no'
-fi
- if test "x$enable_dependency_tracking" != xno; then
-  AMDEP_TRUE=
-  AMDEP_FALSE='#'
-else
-  AMDEP_TRUE='#'
-  AMDEP_FALSE=
-fi
-
-
 
 depcc="$CC"   am_compiler_list=
 
@@ -4190,550 +3938,528 @@ else
 fi
 
 
-if test "x$CC" != xcc; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5
-$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5
-$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
+$as_echo_n "checking how to run the C preprocessor... " >&6; }
+# On Suns, sometimes $CPP names a directory.
+if test -n "$CPP" && test -d "$CPP"; then
+  CPP=
 fi
-set dummy $CC; ac_cc=`$as_echo "$2" |
-                     sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
-if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then :
+if test -z "$CPP"; then
+  if ${ac_cv_prog_CPP+:} false; then :
   $as_echo_n "(cached) " >&6
 else
+      # Double quotes because CPP needs to be expanded
+    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
+    do
+      ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
+do
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
 _ACEOF
-# Make sure it works both with $CC and with simple cc.
-# We do the test twice because some compilers refuse to overwrite an
-# existing .o file with -o, though they will create one.
-ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
-rm -f conftest2.*
-if { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } &&
-   test -f conftest2.$ac_objext && { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; };
-then
-  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
-  if test "x$CC" != xcc; then
-    # Test first that cc exists at all.
-    if { ac_try='cc -c conftest.$ac_ext >&5'
-  { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; }; then
-      ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
-      rm -f conftest2.*
-      if { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; } &&
-        test -f conftest2.$ac_objext && { { case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
-esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$ac_try") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; };
-      then
-       # cc works too.
-       :
-      else
-       # cc exists but doesn't like -o.
-       eval ac_cv_prog_cc_${ac_cc}_c_o=no
-      fi
-    fi
-  fi
+if ac_fn_c_try_cpp "$LINENO"; then :
+
 else
-  eval ac_cv_prog_cc_${ac_cc}_c_o=no
+  # Broken: fails on valid input.
+continue
 fi
-rm -f core conftest*
+rm -f conftest.err conftest.i conftest.$ac_ext
 
-fi
-if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h
-
+  # Passes both tests.
+ac_preproc_ok=:
+break
 fi
+rm -f conftest.err conftest.i conftest.$ac_ext
 
-# FIXME: we rely on the cache variable name because
-# there is no other way.
-set dummy $CC
-am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
-eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
-if test "$am_t" != yes; then
-   # Losing compiler, so override with the script.
-   # FIXME: It is wrong to rewrite CC.
-   # But if we don't then we get into trouble of one sort or another.
-   # A longer-term fix would be to have automake use am__CC in this case,
-   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
-   CC="$am_aux_dir/compile $CC"
+done
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
+  break
 fi
 
+    done
+    ac_cv_prog_CPP=$CPP
 
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fPIE" >&5
-$as_echo_n "checking whether ${CC-cc} accepts -fPIE... " >&6; }
-if ${ac_cv_prog_cc_pie+:} false; then :
-  $as_echo_n "(cached) " >&6
+fi
+  CPP=$ac_cv_prog_CPP
 else
-
-               echo 'void f(){}' > conftest.c
-               if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
-                       ac_cv_prog_cc_pie=yes
-               else
-                       ac_cv_prog_cc_pie=no
-               fi
-               rm -rf conftest*
-
+  ac_cv_prog_CPP=$CPP
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_pie" >&5
-$as_echo "$ac_cv_prog_cc_pie" >&6; }
-
-
-for ac_prog in 'bison -y' byacc
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
+$as_echo "$CPP" >&6; }
+ac_preproc_ok=false
+for ac_c_preproc_warn_flag in '' yes
 do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_YACC+:} false; then :
-  $as_echo_n "(cached) " >&6
+  # Use a header file that comes with gcc, so configuring glibc
+  # with a fresh cross-compiler works.
+  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
+  # <limits.h> exists even on freestanding compilers.
+  # On the NeXT, cc -E runs the code through the compiler's parser,
+  # not just through cpp. "Syntax error" is here to catch this case.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#ifdef __STDC__
+# include <limits.h>
+#else
+# include <assert.h>
+#endif
+                    Syntax error
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+
 else
-  if test -n "$YACC"; then
-  ac_cv_prog_YACC="$YACC" # Let the user override the test.
+  # Broken: fails on valid input.
+continue
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
+  # OK, works on sane cases.  Now check whether nonexistent headers
+  # can be detected and how.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ac_nonexistent.h>
+_ACEOF
+if ac_fn_c_try_cpp "$LINENO"; then :
+  # Broken: success on invalid input.
+continue
 else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_YACC="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
+  # Passes both tests.
+ac_preproc_ok=:
+break
+fi
+rm -f conftest.err conftest.i conftest.$ac_ext
+
 done
-  done
-IFS=$as_save_IFS
+# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
+rm -f conftest.i conftest.err conftest.$ac_ext
+if $ac_preproc_ok; then :
 
-fi
-fi
-YACC=$ac_cv_prog_YACC
-if test -n "$YACC"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $YACC" >&5
-$as_echo "$YACC" >&6; }
 else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
+  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
+See \`config.log' for more details" "$LINENO" 5; }
 fi
 
-
-  test -n "$YACC" && break
-done
-test -n "$YACC" || YACC="yacc"
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-for ac_prog in flex lex
-do
-  # Extract the first word of "$ac_prog", so it can be a program name with args.
-set dummy $ac_prog; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LEX+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
+$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
+if ${ac_cv_path_GREP+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$LEX"; then
-  ac_cv_prog_LEX="$LEX" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
+  if test -z "$GREP"; then
+  ac_path_GREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
+    for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_LEX="$ac_prog"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
+      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_GREP" || continue
+# Check for GNU ac_path_GREP and select it if it is found.
+  # Check for GNU $ac_path_GREP
+case `"$ac_path_GREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'GREP' >> "conftest.nl"
+    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_GREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_GREP="$ac_path_GREP"
+      ac_path_GREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
   done
-IFS=$as_save_IFS
-
-fi
-fi
-LEX=$ac_cv_prog_LEX
-if test -n "$LEX"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LEX" >&5
-$as_echo "$LEX" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-  test -n "$LEX" && break
-done
-test -n "$LEX" || LEX=":"
-
-if test "x$LEX" != "x:"; then
-  cat >conftest.l <<_ACEOF
-%%
-a { ECHO; }
-b { REJECT; }
-c { yymore (); }
-d { yyless (1); }
-e { /* IRIX 6.5 flex 2.5.4 underquotes its yyless argument.  */
-    yyless ((input () != 0)); }
-f { unput (yytext[0]); }
-. { BEGIN INITIAL; }
-%%
-#ifdef YYTEXT_POINTER
-extern char *yytext;
-#endif
-int
-main (void)
-{
-  return ! yylex () + ! yywrap ();
-}
-_ACEOF
-{ { ac_try="$LEX conftest.l"
-case "(($ac_try" in
-  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
-  *) ac_try_echo=$ac_try;;
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
 esac
-eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
-$as_echo "$ac_try_echo"; } >&5
-  (eval "$LEX conftest.l") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking lex output file root" >&5
-$as_echo_n "checking lex output file root... " >&6; }
-if ${ac_cv_prog_lex_root+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
 
-if test -f lex.yy.c; then
-  ac_cv_prog_lex_root=lex.yy
-elif test -f lexyy.c; then
-  ac_cv_prog_lex_root=lexyy
+      $ac_path_GREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_GREP"; then
+    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
 else
-  as_fn_error $? "cannot find output from $LEX; giving up" "$LINENO" 5
+  ac_cv_path_GREP=$GREP
 fi
+
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_root" >&5
-$as_echo "$ac_cv_prog_lex_root" >&6; }
-LEX_OUTPUT_ROOT=$ac_cv_prog_lex_root
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
+$as_echo "$ac_cv_path_GREP" >&6; }
+ GREP="$ac_cv_path_GREP"
 
-if test -z "${LEXLIB+set}"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking lex library" >&5
-$as_echo_n "checking lex library... " >&6; }
-if ${ac_cv_lib_lex+:} false; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
+$as_echo_n "checking for egrep... " >&6; }
+if ${ac_cv_path_EGREP+:} false; then :
   $as_echo_n "(cached) " >&6
 else
+  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
+   then ac_cv_path_EGREP="$GREP -E"
+   else
+     if test -z "$EGREP"; then
+  ac_path_EGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in egrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_EGREP" || continue
+# Check for GNU ac_path_EGREP and select it if it is found.
+  # Check for GNU $ac_path_EGREP
+case `"$ac_path_EGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'EGREP' >> "conftest.nl"
+    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_EGREP="$ac_path_EGREP"
+      ac_path_EGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
 
-    ac_save_LIBS=$LIBS
-    ac_cv_lib_lex='none needed'
-    for ac_lib in '' -lfl -ll; do
-      LIBS="$ac_lib $ac_save_LIBS"
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-`cat $LEX_OUTPUT_ROOT.c`
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_lex=$ac_lib
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-      test "$ac_cv_lib_lex" != 'none needed' && break
+      $ac_path_EGREP_found && break 3
     done
-    LIBS=$ac_save_LIBS
-
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_EGREP"; then
+    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_EGREP=$EGREP
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_lex" >&5
-$as_echo "$ac_cv_lib_lex" >&6; }
-  test "$ac_cv_lib_lex" != 'none needed' && LEXLIB=$ac_cv_lib_lex
+
+   fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
+$as_echo "$ac_cv_path_EGREP" >&6; }
+ EGREP="$ac_cv_path_EGREP"
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether yytext is a pointer" >&5
-$as_echo_n "checking whether yytext is a pointer... " >&6; }
-if ${ac_cv_prog_lex_yytext_pointer+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
+$as_echo_n "checking for ANSI C header files... " >&6; }
+if ${ac_cv_header_stdc+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  # POSIX says lex can declare yytext either as a pointer or an array; the
-# default is implementation-dependent.  Figure out which it is, since
-# not all implementations provide the %pointer and %array declarations.
-ac_cv_prog_lex_yytext_pointer=no
-ac_save_LIBS=$LIBS
-LIBS="$LEXLIB $ac_save_LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <float.h>
+
+int
+main ()
+{
 
-  #define YYTEXT_POINTER 1
-`cat $LEX_OUTPUT_ROOT.c`
+  ;
+  return 0;
+}
 _ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_prog_lex_yytext_pointer=yes
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_header_stdc=yes
+else
+  ac_cv_header_stdc=no
 fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_save_LIBS
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_lex_yytext_pointer" >&5
-$as_echo "$ac_cv_prog_lex_yytext_pointer" >&6; }
-if test $ac_cv_prog_lex_yytext_pointer = yes; then
+if test $ac_cv_header_stdc = yes; then
+  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <string.h>
 
-$as_echo "#define YYTEXT_POINTER 1" >>confdefs.h
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "memchr" >/dev/null 2>&1; then :
 
+else
+  ac_cv_header_stdc=no
 fi
-rm -f conftest.l $LEX_OUTPUT_ROOT.c
+rm -f conftest*
 
 fi
-if test "$LEX" = :; then
-  LEX=${am_missing_run}flex
-fi
-mkdir_p="$MKDIR_P"
-case $mkdir_p in
-  [\\/$]* | ?:[\\/]*) ;;
-  */*) mkdir_p="\$(top_builddir)/$mkdir_p" ;;
-esac
 
+if test $ac_cv_header_stdc = yes; then
+  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdlib.h>
 
+_ACEOF
+if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
+  $EGREP "free" >/dev/null 2>&1; then :
 
+else
+  ac_cv_header_stdc=no
+fi
+rm -f conftest*
 
+fi
 
-# Check whether --enable-static was given.
-if test "${enable_static+set}" = set; then :
-  enableval=$enable_static; p=${PACKAGE-default}
-    case $enableval in
-    yes) enable_static=yes ;;
-    no) enable_static=no ;;
-    *)
-     enable_static=no
-      # Look at the argument we got.  We use all the common list separators.
-      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
-      for pkg in $enableval; do
-       IFS="$lt_save_ifs"
-       if test "X$pkg" = "X$p"; then
-         enable_static=yes
-       fi
-      done
-      IFS="$lt_save_ifs"
-      ;;
-    esac
+if test $ac_cv_header_stdc = yes; then
+  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
+  if test "$cross_compiling" = yes; then :
+  :
 else
-  enable_static=no
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <ctype.h>
+#include <stdlib.h>
+#if ((' ' & 0x0FF) == 0x020)
+# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
+# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
+#else
+# define ISLOWER(c) \
+                  (('a' <= (c) && (c) <= 'i') \
+                    || ('j' <= (c) && (c) <= 'r') \
+                    || ('s' <= (c) && (c) <= 'z'))
+# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
+#endif
+
+#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
+int
+main ()
+{
+  int i;
+  for (i = 0; i < 256; i++)
+    if (XOR (islower (i), ISLOWER (i))
+       || toupper (i) != TOUPPER (i))
+      return 2;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_run "$LINENO"; then :
+
+else
+  ac_cv_header_stdc=no
+fi
+rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
+  conftest.$ac_objext conftest.beam conftest.$ac_ext
 fi
 
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
+$as_echo "$ac_cv_header_stdc" >&6; }
+if test $ac_cv_header_stdc = yes; then
 
+$as_echo "#define STDC_HEADERS 1" >>confdefs.h
 
+fi
 
+# On IRIX 5.3, sys/types and inttypes.h are conflicting.
+for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
+                 inttypes.h stdint.h unistd.h
+do :
+  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
+ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
+"
+if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
+  cat >>confdefs.h <<_ACEOF
+#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+_ACEOF
 
+fi
 
+done
 
 
 
-case `pwd` in
-  *\ * | *\    *)
-    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
-$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
-esac
+  ac_fn_c_check_header_mongrel "$LINENO" "minix/config.h" "ac_cv_header_minix_config_h" "$ac_includes_default"
+if test "x$ac_cv_header_minix_config_h" = xyes; then :
+  MINIX=yes
+else
+  MINIX=
+fi
 
 
+  if test "$MINIX" = yes; then
 
-macro_version='2.4.2'
-macro_revision='1.3337'
+$as_echo "#define _POSIX_SOURCE 1" >>confdefs.h
 
 
+$as_echo "#define _POSIX_1_SOURCE 2" >>confdefs.h
 
 
+$as_echo "#define _MINIX 1" >>confdefs.h
 
+  fi
 
 
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether it is safe to define __EXTENSIONS__" >&5
+$as_echo_n "checking whether it is safe to define __EXTENSIONS__... " >&6; }
+if ${ac_cv_safe_to_define___extensions__+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
+#         define __EXTENSIONS__ 1
+          $ac_includes_default
+int
+main ()
+{
 
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_safe_to_define___extensions__=yes
+else
+  ac_cv_safe_to_define___extensions__=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_safe_to_define___extensions__" >&5
+$as_echo "$ac_cv_safe_to_define___extensions__" >&6; }
+  test $ac_cv_safe_to_define___extensions__ = yes &&
+    $as_echo "#define __EXTENSIONS__ 1" >>confdefs.h
 
+  $as_echo "#define _ALL_SOURCE 1" >>confdefs.h
 
+  $as_echo "#define _GNU_SOURCE 1" >>confdefs.h
 
+  $as_echo "#define _POSIX_PTHREAD_SEMANTICS 1" >>confdefs.h
 
-ltmain="$ac_aux_dir/ltmain.sh"
+  $as_echo "#define _TANDEM_SOURCE 1" >>confdefs.h
 
-# Make sure we can run config.sub.
-$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
-  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
-$as_echo_n "checking build system type... " >&6; }
-if ${ac_cv_build+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_build_alias=$build_alias
-test "x$ac_build_alias" = x &&
-  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
-test "x$ac_build_alias" = x &&
-  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
-ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
-  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
 
+# Check whether --enable-silent-rules was given.
+if test "${enable_silent_rules+set}" = set; then :
+  enableval=$enable_silent_rules;
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
-$as_echo "$ac_cv_build" >&6; }
-case $ac_cv_build in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
-esac
-build=$ac_cv_build
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_build
-shift
-build_cpu=$1
-build_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-build_os=$*
-IFS=$ac_save_IFS
-case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
 
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
-$as_echo_n "checking host system type... " >&6; }
-if ${ac_cv_host+:} false; then :
+case $enable_silent_rules in
+yes) AM_DEFAULT_VERBOSITY=0;;
+no)  AM_DEFAULT_VERBOSITY=1;;
+*)   AM_DEFAULT_VERBOSITY=0;;
+esac
+am_make=${MAKE-make}
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $am_make supports nested variables" >&5
+$as_echo_n "checking whether $am_make supports nested variables... " >&6; }
+if ${am_cv_make_support_nested_variables+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test "x$host_alias" = x; then
-  ac_cv_host=$ac_cv_build
+  if $as_echo 'TRUE=$(BAR$(V))
+BAR0=false
+BAR1=true
+V=1
+am__doit:
+       @$(TRUE)
+.PHONY: am__doit' | $am_make -f - >/dev/null 2>&1; then
+  am_cv_make_support_nested_variables=yes
 else
-  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
-    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+  am_cv_make_support_nested_variables=no
 fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_make_support_nested_variables" >&5
+$as_echo "$am_cv_make_support_nested_variables" >&6; }
+if test $am_cv_make_support_nested_variables = yes; then
+    AM_V='$(V)'
+  AM_DEFAULT_V='$(AM_DEFAULT_VERBOSITY)'
+else
+  AM_V=$AM_DEFAULT_VERBOSITY
+  AM_DEFAULT_V=$AM_DEFAULT_VERBOSITY
+fi
+AM_BACKSLASH='\'
+
 
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether to enable maintainer-specific portions of Makefiles" >&5
+$as_echo_n "checking whether to enable maintainer-specific portions of Makefiles... " >&6; }
+    # Check whether --enable-maintainer-mode was given.
+if test "${enable_maintainer_mode+set}" = set; then :
+  enableval=$enable_maintainer_mode; USE_MAINTAINER_MODE=$enableval
+else
+  USE_MAINTAINER_MODE=no
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
-$as_echo "$ac_cv_host" >&6; }
-case $ac_cv_host in
-*-*-*) ;;
-*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
-esac
-host=$ac_cv_host
-ac_save_IFS=$IFS; IFS='-'
-set x $ac_cv_host
-shift
-host_cpu=$1
-host_vendor=$2
-shift; shift
-# Remember, the first character of IFS is used to create $*,
-# except with old shells:
-host_os=$*
-IFS=$ac_save_IFS
-case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
 
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $USE_MAINTAINER_MODE" >&5
+$as_echo "$USE_MAINTAINER_MODE" >&6; }
+   if test $USE_MAINTAINER_MODE = yes; then
+  MAINTAINER_MODE_TRUE=
+  MAINTAINER_MODE_FALSE='#'
+else
+  MAINTAINER_MODE_TRUE='#'
+  MAINTAINER_MODE_FALSE=
+fi
 
-# Backslashify metacharacters that are still active within
-# double-quoted strings.
-sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+  MAINT=$MAINTAINER_MODE_TRUE
 
-# Same as above, but do not quote variable references.
-double_quote_subst='s/\(["`\\]\)/\\\1/g'
-
-# Sed substitution to delay expansion of an escaped shell variable in a
-# double_quote_subst'ed string.
-delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
-
-# Sed substitution to delay expansion of an escaped single quote.
-delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
-
-# Sed substitution to avoid accidental globbing in evaled expressions
-no_glob_subst='s/\*/\\\*/g'
-
-ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
-ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
-$as_echo_n "checking how to print strings... " >&6; }
-# Test print first, because it will be a builtin if present.
-if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
-   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='print -r --'
-elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
-  ECHO='printf %s\n'
-else
-  # Use this function as a fallback that always works.
-  func_fallback_echo ()
-  {
-    eval 'cat <<_LTECHO_EOF
-$1
-_LTECHO_EOF'
-  }
-  ECHO='func_fallback_echo'
-fi
-
-# func_echo_all arg...
-# Invoke $ECHO with all args, space-separated.
-func_echo_all ()
-{
-    $ECHO ""
-}
-
-case "$ECHO" in
-  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
-$as_echo "printf" >&6; } ;;
-  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
-$as_echo "print -r" >&6; } ;;
-  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
-$as_echo "cat" >&6; } ;;
-esac
 
 
 
@@ -4745,489 +4471,397 @@ esac
 
 
 
+if test "x$ac_cv_env_PKG_CONFIG_set" != "xset"; then
+       if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}pkg-config", so it can be a program name with args.
+set dummy ${ac_tool_prefix}pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_PKG_CONFIG+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_PKG_CONFIG="$PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
+  ;;
+esac
+fi
+PKG_CONFIG=$ac_cv_path_PKG_CONFIG
+if test -n "$PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $PKG_CONFIG" >&5
+$as_echo "$PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
-$as_echo_n "checking for a sed that does not truncate output... " >&6; }
-if ${ac_cv_path_SED+:} false; then :
+fi
+if test -z "$ac_cv_path_PKG_CONFIG"; then
+  ac_pt_PKG_CONFIG=$PKG_CONFIG
+  # Extract the first word of "pkg-config", so it can be a program name with args.
+set dummy pkg-config; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_path_ac_pt_PKG_CONFIG+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
-     for ac_i in 1 2 3 4 5 6 7; do
-       ac_script="$ac_script$as_nl$ac_script"
-     done
-     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
-     { ac_script=; unset ac_script;}
-     if test -z "$SED"; then
-  ac_path_SED_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
+  case $ac_pt_PKG_CONFIG in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_ac_pt_PKG_CONFIG="$ac_pt_PKG_CONFIG" # Let the user override the test with a path.
+  ;;
+  *)
   as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-    for ac_prog in sed gsed; do
     for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_SED" || continue
-# Check for GNU ac_path_SED and select it if it is found.
-  # Check for GNU $ac_path_SED
-case `"$ac_path_SED" --version 2>&1` in
-*GNU*)
-  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo '' >> "conftest.nl"
-    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_SED_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_SED="$ac_path_SED"
-      ac_path_SED_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_path_ac_pt_PKG_CONFIG="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
   done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+IFS=$as_save_IFS
+
+  ;;
 esac
+fi
+ac_pt_PKG_CONFIG=$ac_cv_path_ac_pt_PKG_CONFIG
+if test -n "$ac_pt_PKG_CONFIG"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_pt_PKG_CONFIG" >&5
+$as_echo "$ac_pt_PKG_CONFIG" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
-      $ac_path_SED_found && break 3
-    done
-  done
-  done
-IFS=$as_save_IFS
-  if test -z "$ac_cv_path_SED"; then
-    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  if test "x$ac_pt_PKG_CONFIG" = x; then
+    PKG_CONFIG=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    PKG_CONFIG=$ac_pt_PKG_CONFIG
   fi
 else
-  ac_cv_path_SED=$SED
+  PKG_CONFIG="$ac_cv_path_PKG_CONFIG"
 fi
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
-$as_echo "$ac_cv_path_SED" >&6; }
- SED="$ac_cv_path_SED"
-  rm -f conftest.sed
-
-test -z "$SED" && SED=sed
-Xsed="$SED -e 1s/^X//"
+if test -n "$PKG_CONFIG"; then
+       _pkg_min_version=0.9.0
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking pkg-config is at least version $_pkg_min_version" >&5
+$as_echo_n "checking pkg-config is at least version $_pkg_min_version... " >&6; }
+       if $PKG_CONFIG --atleast-pkgconfig-version $_pkg_min_version; then
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       else
+               { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+               PKG_CONFIG=""
+       fi
+fi
 
 
+       with_cflags=""
+       if (test "$USE_MAINTAINER_MODE" = "yes"); then
+               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
+       WARNING_CFLAGS=$with_cflags
 
 
 
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for C/C++ restrict keyword" >&5
+$as_echo_n "checking for C/C++ restrict keyword... " >&6; }
+if ${ac_cv_c_restrict+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_c_restrict=no
+   # The order here caters to the fact that C++ does not require restrict.
+   for ac_kw in __restrict __restrict__ _Restrict restrict; do
+     cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+typedef int * int_ptr;
+       int foo (int_ptr $ac_kw ip) {
+       return ip[0];
+       }
+int
+main ()
+{
+int s[1];
+       int * $ac_kw t = s;
+       t[0] = 0;
+       return foo(t)
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_c_restrict=$ac_kw
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+     test "$ac_cv_c_restrict" != no && break
+   done
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_restrict" >&5
+$as_echo "$ac_cv_c_restrict" >&6; }
 
+ case $ac_cv_c_restrict in
+   restrict) ;;
+   no) $as_echo "#define restrict /**/" >>confdefs.h
+ ;;
+   *)  cat >>confdefs.h <<_ACEOF
+#define restrict $ac_cv_c_restrict
+_ACEOF
+ ;;
+ esac
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for grep that handles long lines and -e" >&5
-$as_echo_n "checking for grep that handles long lines and -e... " >&6; }
-if ${ac_cv_path_GREP+:} false; then :
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}gcc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -z "$GREP"; then
-  ac_path_GREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-    for ac_prog in grep ggrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_GREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_GREP" || continue
-# Check for GNU ac_path_GREP and select it if it is found.
-  # Check for GNU $ac_path_GREP
-case `"$ac_path_GREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_GREP="$ac_path_GREP" ac_path_GREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'GREP' >> "conftest.nl"
-    "$ac_path_GREP" -e 'GREP$' -e '-(cannot match)-' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_GREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_GREP="$ac_path_GREP"
-      ac_path_GREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_GREP_found && break 3
-    done
-  done
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
   done
 IFS=$as_save_IFS
-  if test -z "$ac_cv_path_GREP"; then
-    as_fn_error $? "no acceptable grep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_GREP=$GREP
-fi
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_GREP" >&5
-$as_echo "$ac_cv_path_GREP" >&6; }
- GREP="$ac_cv_path_GREP"
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for egrep" >&5
-$as_echo_n "checking for egrep... " >&6; }
-if ${ac_cv_path_EGREP+:} false; then :
+fi
+if test -z "$ac_cv_prog_CC"; then
+  ac_ct_CC=$CC
+  # Extract the first word of "gcc", so it can be a program name with args.
+set dummy gcc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if echo a | $GREP -E '(a|b)' >/dev/null 2>&1
-   then ac_cv_path_EGREP="$GREP -E"
-   else
-     if test -z "$EGREP"; then
-  ac_path_EGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-    for ac_prog in egrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_EGREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_EGREP" || continue
-# Check for GNU ac_path_EGREP and select it if it is found.
-  # Check for GNU $ac_path_EGREP
-case `"$ac_path_EGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_EGREP="$ac_path_EGREP" ac_path_EGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'EGREP' >> "conftest.nl"
-    "$ac_path_EGREP" 'EGREP$' < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_EGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_EGREP="$ac_path_EGREP"
-      ac_path_EGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_EGREP_found && break 3
-    done
-  done
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_CC="gcc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
   done
 IFS=$as_save_IFS
-  if test -z "$ac_cv_path_EGREP"; then
-    as_fn_error $? "no acceptable egrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
+
+fi
+fi
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
 else
-  ac_cv_path_EGREP=$EGREP
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-   fi
+  if test "x$ac_ct_CC" = x; then
+    CC=""
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    CC=$ac_ct_CC
+  fi
+else
+  CC="$ac_cv_prog_CC"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_EGREP" >&5
-$as_echo "$ac_cv_path_EGREP" >&6; }
- EGREP="$ac_cv_path_EGREP"
 
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
-$as_echo_n "checking for fgrep... " >&6; }
-if ${ac_cv_path_FGREP+:} false; then :
+if test -z "$CC"; then
+          if test -n "$ac_tool_prefix"; then
+    # Extract the first word of "${ac_tool_prefix}cc", so it can be a program name with args.
+set dummy ${ac_tool_prefix}cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
-   then ac_cv_path_FGREP="$GREP -F"
-   else
-     if test -z "$FGREP"; then
-  ac_path_FGREP_found=false
-  # Loop through the user's path and test for each of PROGNAME-LIST
-  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
 do
   IFS=$as_save_IFS
   test -z "$as_dir" && as_dir=.
-    for ac_prog in fgrep; do
     for ac_exec_ext in '' $ac_executable_extensions; do
-      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
-      as_fn_executable_p "$ac_path_FGREP" || continue
-# Check for GNU ac_path_FGREP and select it if it is found.
-  # Check for GNU $ac_path_FGREP
-case `"$ac_path_FGREP" --version 2>&1` in
-*GNU*)
-  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
-*)
-  ac_count=0
-  $as_echo_n 0123456789 >"conftest.in"
-  while :
-  do
-    cat "conftest.in" "conftest.in" >"conftest.tmp"
-    mv "conftest.tmp" "conftest.in"
-    cp "conftest.in" "conftest.nl"
-    $as_echo 'FGREP' >> "conftest.nl"
-    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
-    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
-    as_fn_arith $ac_count + 1 && ac_count=$as_val
-    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
-      # Best one so far, save it but keep looking for a better one
-      ac_cv_path_FGREP="$ac_path_FGREP"
-      ac_path_FGREP_max=$ac_count
-    fi
-    # 10*(2^10) chars as input seems more than enough
-    test $ac_count -gt 10 && break
-  done
-  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
-esac
-
-      $ac_path_FGREP_found && break 3
-    done
-  done
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_CC="${ac_tool_prefix}cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
   done
 IFS=$as_save_IFS
-  if test -z "$ac_cv_path_FGREP"; then
-    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
-  fi
-else
-  ac_cv_path_FGREP=$FGREP
-fi
 
-   fi
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
-$as_echo "$ac_cv_path_FGREP" >&6; }
- FGREP="$ac_cv_path_FGREP"
-
-
-test -z "$GREP" && GREP=grep
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-# Check whether --with-gnu-ld was given.
-if test "${with_gnu_ld+set}" = set; then :
-  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
-  with_gnu_ld=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-ac_prog=ld
-if test "$GCC" = yes; then
-  # Check if gcc -print-prog-name=ld gives a path.
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
-$as_echo_n "checking for ld used by $CC... " >&6; }
-  case $host in
-  *-*-mingw*)
-    # gcc leaves a trailing carriage return which upsets mingw
-    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
-  *)
-    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
-  esac
-  case $ac_prog in
-    # Accept absolute paths.
-    [\\/]* | ?:[\\/]*)
-      re_direlt='/[^/][^/]*/\.\./'
-      # Canonicalize the pathname of ld
-      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
-      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
-       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
-      done
-      test -z "$LD" && LD="$ac_prog"
-      ;;
-  "")
-    # If it fails, then pretend we aren't using GCC.
-    ac_prog=ld
-    ;;
-  *)
-    # If it is relative, then search for the first ld in PATH.
-    with_gnu_ld=unknown
-    ;;
-  esac
-elif test "$with_gnu_ld" = yes; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
-$as_echo_n "checking for GNU ld... " >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
-$as_echo_n "checking for non-GNU ld... " >&6; }
+
+  fi
 fi
-if ${lt_cv_path_LD+:} false; then :
+if test -z "$CC"; then
+  # Extract the first word of "cc", so it can be a program name with args.
+set dummy cc; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -z "$LD"; then
-  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-  for ac_dir in $PATH; do
-    IFS="$lt_save_ifs"
-    test -z "$ac_dir" && ac_dir=.
-    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
-      lt_cv_path_LD="$ac_dir/$ac_prog"
-      # Check to see if the program is GNU ld.  I'd rather use --version,
-      # but apparently some variants of GNU ld only accept -v.
-      # Break only if it was the GNU/non-GNU ld that we prefer.
-      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
-      *GNU* | *'with BFD'*)
-       test "$with_gnu_ld" != no && break
-       ;;
-      *)
-       test "$with_gnu_ld" != yes && break
-       ;;
-      esac
-    fi
-  done
-  IFS="$lt_save_ifs"
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
-  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+  ac_prog_rejected=no
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    if test "$as_dir/$ac_word$ac_exec_ext" = "/usr/ucb/cc"; then
+       ac_prog_rejected=yes
+       continue
+     fi
+    ac_cv_prog_CC="cc"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+if test $ac_prog_rejected = yes; then
+  # We found a bogon in the path, so make sure we never use it.
+  set dummy $ac_cv_prog_CC
+  shift
+  if test $# != 0; then
+    # We chose a different compiler from the bogus one.
+    # However, it has the same basename, so the bogon will be chosen
+    # first if we set CC to just the basename; use the full file name.
+    shift
+    ac_cv_prog_CC="$as_dir/$ac_word${1+' '}$@"
+  fi
 fi
 fi
-
-LD="$lt_cv_path_LD"
-if test -n "$LD"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
-$as_echo "$LD" >&6; }
+fi
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
-test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
-$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
-if ${lt_cv_prog_gnu_ld+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  # I'd rather use --version here, but apparently some GNU lds only accept -v.
-case `$LD -v 2>&1 </dev/null` in
-*GNU* | *'with BFD'*)
-  lt_cv_prog_gnu_ld=yes
-  ;;
-*)
-  lt_cv_prog_gnu_ld=no
-  ;;
-esac
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
-$as_echo "$lt_cv_prog_gnu_ld" >&6; }
-with_gnu_ld=$lt_cv_prog_gnu_ld
-
-
-
-
 
 
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
-$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
-if ${lt_cv_path_NM+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$NM"; then
-  # Let the user override the test.
-  lt_cv_path_NM="$NM"
-else
-  lt_nm_to_check="${ac_tool_prefix}nm"
-  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
-    lt_nm_to_check="$lt_nm_to_check nm"
-  fi
-  for lt_tmp_nm in $lt_nm_to_check; do
-    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
-    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
-      IFS="$lt_save_ifs"
-      test -z "$ac_dir" && ac_dir=.
-      tmp_nm="$ac_dir/$lt_tmp_nm"
-      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
-       # Check to see if the nm accepts a BSD-compat flag.
-       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
-       #   nm: unknown option "B" ignored
-       # Tru64's nm complains that /dev/null is an invalid object file
-       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
-       */dev/null* | *'Invalid file or object type'*)
-         lt_cv_path_NM="$tmp_nm -B"
-         break
-         ;;
-       *)
-         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
-         */dev/null*)
-           lt_cv_path_NM="$tmp_nm -p"
-           break
-           ;;
-         *)
-           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
-           continue # so that we can try to find one that supports BSD flags
-           ;;
-         esac
-         ;;
-       esac
-      fi
-    done
-    IFS="$lt_save_ifs"
-  done
-  : ${lt_cv_path_NM=no}
 fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
-$as_echo "$lt_cv_path_NM" >&6; }
-if test "$lt_cv_path_NM" != "no"; then
-  NM="$lt_cv_path_NM"
-else
-  # Didn't find any BSD compatible name lister, look for dumpbin.
-  if test -n "$DUMPBIN"; then :
-    # Let the user override the test.
-  else
-    if test -n "$ac_tool_prefix"; then
-  for ac_prog in dumpbin "link -dump"
+if test -z "$CC"; then
+  if test -n "$ac_tool_prefix"; then
+  for ac_prog in cl.exe
   do
     # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
 set dummy $ac_tool_prefix$ac_prog; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DUMPBIN+:} false; then :
+if ${ac_cv_prog_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$DUMPBIN"; then
-  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+  if test -n "$CC"; then
+  ac_cv_prog_CC="$CC" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -5236,7 +4870,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    ac_cv_prog_CC="$ac_tool_prefix$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -5246,32 +4880,32 @@ IFS=$as_save_IFS
 
 fi
 fi
-DUMPBIN=$ac_cv_prog_DUMPBIN
-if test -n "$DUMPBIN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
-$as_echo "$DUMPBIN" >&6; }
+CC=$ac_cv_prog_CC
+if test -n "$CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $CC" >&5
+$as_echo "$CC" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-    test -n "$DUMPBIN" && break
+    test -n "$CC" && break
   done
 fi
-if test -z "$DUMPBIN"; then
-  ac_ct_DUMPBIN=$DUMPBIN
-  for ac_prog in dumpbin "link -dump"
+if test -z "$CC"; then
+  ac_ct_CC=$CC
+  for ac_prog in cl.exe
 do
   # Extract the first word of "$ac_prog", so it can be a program name with args.
 set dummy $ac_prog; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+if ${ac_cv_prog_ac_ct_CC+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$ac_ct_DUMPBIN"; then
-  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+  if test -n "$ac_ct_CC"; then
+  ac_cv_prog_ac_ct_CC="$ac_ct_CC" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -5280,7 +4914,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    ac_cv_prog_ac_ct_CC="$ac_prog"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -5290,21 +4924,21 @@ IFS=$as_save_IFS
 
 fi
 fi
-ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
-if test -n "$ac_ct_DUMPBIN"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
-$as_echo "$ac_ct_DUMPBIN" >&6; }
+ac_ct_CC=$ac_cv_prog_ac_ct_CC
+if test -n "$ac_ct_CC"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_CC" >&5
+$as_echo "$ac_ct_CC" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
 
-  test -n "$ac_ct_DUMPBIN" && break
+  test -n "$ac_ct_CC" && break
 done
 
-  if test "x$ac_ct_DUMPBIN" = x; then
-    DUMPBIN=":"
+  if test "x$ac_ct_CC" = x; then
+    CC=""
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
@@ -5312,26 +4946,1183 @@ yes:)
 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
-    DUMPBIN=$ac_ct_DUMPBIN
+    CC=$ac_ct_CC
   fi
 fi
 
-    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
-    *COFF*)
-      DUMPBIN="$DUMPBIN -symbols"
-      ;;
-    *)
-      DUMPBIN=:
-      ;;
-    esac
-  fi
-
-  if test "$DUMPBIN" != ":"; then
-    NM="$DUMPBIN"
-  fi
 fi
-test -z "$NM" && NM=nm
-
+
+
+test -z "$CC" && { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
+$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
+as_fn_error $? "no acceptable C compiler found in \$PATH
+See \`config.log' for more details" "$LINENO" 5; }
+
+# Provide some information about the compiler.
+$as_echo "$as_me:${as_lineno-$LINENO}: checking for C compiler version" >&5
+set X $ac_compile
+ac_compiler=$2
+for ac_option in --version -v -V -qversion; do
+  { { ac_try="$ac_compiler $ac_option >&5"
+case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_compiler $ac_option >&5") 2>conftest.err
+  ac_status=$?
+  if test -s conftest.err; then
+    sed '10a\
+... rest of stderr output deleted ...
+         10q' conftest.err >conftest.er1
+    cat conftest.er1 >&5
+  fi
+  rm -f conftest.er1 conftest.err
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }
+done
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether we are using the GNU C compiler" >&5
+$as_echo_n "checking whether we are using the GNU C compiler... " >&6; }
+if ${ac_cv_c_compiler_gnu+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+#ifndef __GNUC__
+       choke me
+#endif
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_compiler_gnu=yes
+else
+  ac_compiler_gnu=no
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+ac_cv_c_compiler_gnu=$ac_compiler_gnu
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_c_compiler_gnu" >&5
+$as_echo "$ac_cv_c_compiler_gnu" >&6; }
+if test $ac_compiler_gnu = yes; then
+  GCC=yes
+else
+  GCC=
+fi
+ac_test_CFLAGS=${CFLAGS+set}
+ac_save_CFLAGS=$CFLAGS
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC accepts -g" >&5
+$as_echo_n "checking whether $CC accepts -g... " >&6; }
+if ${ac_cv_prog_cc_g+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_save_c_werror_flag=$ac_c_werror_flag
+   ac_c_werror_flag=yes
+   ac_cv_prog_cc_g=no
+   CFLAGS="-g"
+   cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+else
+  CFLAGS=""
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+
+else
+  ac_c_werror_flag=$ac_save_c_werror_flag
+        CFLAGS="-g"
+        cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_g=yes
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+fi
+rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
+   ac_c_werror_flag=$ac_save_c_werror_flag
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_g" >&5
+$as_echo "$ac_cv_prog_cc_g" >&6; }
+if test "$ac_test_CFLAGS" = set; then
+  CFLAGS=$ac_save_CFLAGS
+elif test $ac_cv_prog_cc_g = yes; then
+  if test "$GCC" = yes; then
+    CFLAGS="-g -O2"
+  else
+    CFLAGS="-g"
+  fi
+else
+  if test "$GCC" = yes; then
+    CFLAGS="-O2"
+  else
+    CFLAGS=
+  fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $CC option to accept ISO C89" >&5
+$as_echo_n "checking for $CC option to accept ISO C89... " >&6; }
+if ${ac_cv_prog_cc_c89+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_cv_prog_cc_c89=no
+ac_save_CC=$CC
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+#include <stdarg.h>
+#include <stdio.h>
+struct stat;
+/* Most of the following tests are stolen from RCS 5.7's src/conf.sh.  */
+struct buf { int x; };
+FILE * (*rcsopen) (struct buf *, struct stat *, int);
+static char *e (p, i)
+     char **p;
+     int i;
+{
+  return p[i];
+}
+static char *f (char * (*g) (char **, int), char **p, ...)
+{
+  char *s;
+  va_list v;
+  va_start (v,p);
+  s = g (p, va_arg (v,int));
+  va_end (v);
+  return s;
+}
+
+/* OSF 4.0 Compaq cc is some sort of almost-ANSI by default.  It has
+   function prototypes and stuff, but not '\xHH' hex character constants.
+   These don't provoke an error unfortunately, instead are silently treated
+   as 'x'.  The following induces an error, until -std is added to get
+   proper ANSI mode.  Curiously '\x00'!='x' always comes out true, for an
+   array size at least.  It's necessary to write '\x00'==0 to get something
+   that's true only with -std.  */
+int osf4_cc_array ['\x00' == 0 ? 1 : -1];
+
+/* IBM C 6 for AIX is almost-ANSI by default, but it replaces macro parameters
+   inside strings and character constants.  */
+#define FOO(x) 'x'
+int xlc6_cc_array[FOO(a) == 'x' ? 1 : -1];
+
+int test (int i, double x);
+struct s1 {int (*f) (int a);};
+struct s2 {int (*f) (double a);};
+int pairnames (int, char **, FILE *(*)(struct buf *, struct stat *, int), int, int);
+int argc;
+char **argv;
+int
+main ()
+{
+return f (e, argv, 0) != argv[0]  ||  f (e, argv, 1) != argv[1];
+  ;
+  return 0;
+}
+_ACEOF
+for ac_arg in '' -qlanglvl=extc89 -qlanglvl=ansi -std \
+       -Ae "-Aa -D_HPUX_SOURCE" "-Xc -D__EXTENSIONS__"
+do
+  CC="$ac_save_CC $ac_arg"
+  if ac_fn_c_try_compile "$LINENO"; then :
+  ac_cv_prog_cc_c89=$ac_arg
+fi
+rm -f core conftest.err conftest.$ac_objext
+  test "x$ac_cv_prog_cc_c89" != "xno" && break
+done
+rm -f conftest.$ac_ext
+CC=$ac_save_CC
+
+fi
+# AC_CACHE_VAL
+case "x$ac_cv_prog_cc_c89" in
+  x)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: none needed" >&5
+$as_echo "none needed" >&6; } ;;
+  xno)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: unsupported" >&5
+$as_echo "unsupported" >&6; } ;;
+  *)
+    CC="$CC $ac_cv_prog_cc_c89"
+    { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_c89" >&5
+$as_echo "$ac_cv_prog_cc_c89" >&6; } ;;
+esac
+if test "x$ac_cv_prog_cc_c89" != xno; then :
+
+fi
+
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
+
+depcc="$CC"   am_compiler_list=
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking dependency style of $depcc" >&5
+$as_echo_n "checking dependency style of $depcc... " >&6; }
+if ${am_cv_CC_dependencies_compiler_type+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$AMDEP_TRUE" && test -f "$am_depcomp"; then
+  # We make a subdir and do the tests there.  Otherwise we can end up
+  # making bogus files that we don't know about and never remove.  For
+  # instance it was reported that on HP-UX the gcc test will end up
+  # making a dummy file named `D' -- because `-MD' means `put the output
+  # in D'.
+  rm -rf conftest.dir
+  mkdir conftest.dir
+  # Copy depcomp to subdir because otherwise we won't find it if we're
+  # using a relative directory.
+  cp "$am_depcomp" conftest.dir
+  cd conftest.dir
+  # We will build objects and dependencies in a subdirectory because
+  # it helps to detect inapplicable dependency modes.  For instance
+  # both Tru64's cc and ICC support -MD to output dependencies as a
+  # side effect of compilation, but ICC will put the dependencies in
+  # the current directory while Tru64 will put them in the object
+  # directory.
+  mkdir sub
+
+  am_cv_CC_dependencies_compiler_type=none
+  if test "$am_compiler_list" = ""; then
+     am_compiler_list=`sed -n 's/^#*\([a-zA-Z0-9]*\))$/\1/p' < ./depcomp`
+  fi
+  am__universal=false
+  case " $depcc " in #(
+     *\ -arch\ *\ -arch\ *) am__universal=true ;;
+     esac
+
+  for depmode in $am_compiler_list; do
+    # Setup a source with many dependencies, because some compilers
+    # like to wrap large dependency lists on column 80 (with \), and
+    # we should not choose a depcomp mode which is confused by this.
+    #
+    # We need to recreate these files for each test, as the compiler may
+    # overwrite some of them when testing with obscure command lines.
+    # This happens at least with the AIX C compiler.
+    : > sub/conftest.c
+    for i in 1 2 3 4 5 6; do
+      echo '#include "conftst'$i'.h"' >> sub/conftest.c
+      # Using `: > sub/conftst$i.h' creates only sub/conftst1.h with
+      # Solaris 8's {/usr,}/bin/sh.
+      touch sub/conftst$i.h
+    done
+    echo "${am__include} ${am__quote}sub/conftest.Po${am__quote}" > confmf
+
+    # We check with `-c' and `-o' for the sake of the "dashmstdout"
+    # mode.  It turns out that the SunPro C++ compiler does not properly
+    # handle `-M -o', and we need to detect this.  Also, some Intel
+    # versions had trouble with output in subdirs
+    am__obj=sub/conftest.${OBJEXT-o}
+    am__minus_obj="-o $am__obj"
+    case $depmode in
+    gcc)
+      # This depmode causes a compiler race in universal mode.
+      test "$am__universal" = false || continue
+      ;;
+    nosideeffect)
+      # after this tag, mechanisms are not by side-effect, so they'll
+      # only be used when explicitly requested
+      if test "x$enable_dependency_tracking" = xyes; then
+       continue
+      else
+       break
+      fi
+      ;;
+    msvc7 | msvc7msys | msvisualcpp | msvcmsys)
+      # This compiler won't grok `-c -o', but also, the minuso test has
+      # not run yet.  These depmodes are late enough in the game, and
+      # so weak that their functioning should not be impacted.
+      am__obj=conftest.${OBJEXT-o}
+      am__minus_obj=
+      ;;
+    none) break ;;
+    esac
+    if depmode=$depmode \
+       source=sub/conftest.c object=$am__obj \
+       depfile=sub/conftest.Po tmpdepfile=sub/conftest.TPo \
+       $SHELL ./depcomp $depcc -c $am__minus_obj sub/conftest.c \
+         >/dev/null 2>conftest.err &&
+       grep sub/conftst1.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep sub/conftst6.h sub/conftest.Po > /dev/null 2>&1 &&
+       grep $am__obj sub/conftest.Po > /dev/null 2>&1 &&
+       ${MAKE-make} -s -f confmf > /dev/null 2>&1; then
+      # icc doesn't choke on unknown options, it will just issue warnings
+      # or remarks (even with -Werror).  So we grep stderr for any message
+      # that says an option was ignored or not supported.
+      # When given -MP, icc 7.0 and 7.1 complain thusly:
+      #   icc: Command line warning: ignoring option '-M'; no argument required
+      # The diagnosis changed in icc 8.0:
+      #   icc: Command line remark: option '-MP' not supported
+      if (grep 'ignoring option' conftest.err ||
+          grep 'not supported' conftest.err) >/dev/null 2>&1; then :; else
+        am_cv_CC_dependencies_compiler_type=$depmode
+        break
+      fi
+    fi
+  done
+
+  cd ..
+  rm -rf conftest.dir
+else
+  am_cv_CC_dependencies_compiler_type=none
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $am_cv_CC_dependencies_compiler_type" >&5
+$as_echo "$am_cv_CC_dependencies_compiler_type" >&6; }
+CCDEPMODE=depmode=$am_cv_CC_dependencies_compiler_type
+
+ if
+  test "x$enable_dependency_tracking" != xno \
+  && test "$am_cv_CC_dependencies_compiler_type" = gcc3; then
+  am__fastdepCC_TRUE=
+  am__fastdepCC_FALSE='#'
+else
+  am__fastdepCC_TRUE='#'
+  am__fastdepCC_FALSE=
+fi
+
+
+if test "x$CC" != xcc; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether $CC and cc understand -c and -o together" >&5
+$as_echo_n "checking whether $CC and cc understand -c and -o together... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether cc understands -c and -o together" >&5
+$as_echo_n "checking whether cc understands -c and -o together... " >&6; }
+fi
+set dummy $CC; ac_cc=`$as_echo "$2" |
+                     sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+if eval \${ac_cv_prog_cc_${ac_cc}_c_o+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
+_ACEOF
+# Make sure it works both with $CC and with simple cc.
+# We do the test twice because some compilers refuse to overwrite an
+# existing .o file with -o, though they will create one.
+ac_try='$CC -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+rm -f conftest2.*
+if { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } &&
+   test -f conftest2.$ac_objext && { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; };
+then
+  eval ac_cv_prog_cc_${ac_cc}_c_o=yes
+  if test "x$CC" != xcc; then
+    # Test first that cc exists at all.
+    if { ac_try='cc -c conftest.$ac_ext >&5'
+  { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; }; then
+      ac_try='cc -c conftest.$ac_ext -o conftest2.$ac_objext >&5'
+      rm -f conftest2.*
+      if { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; } &&
+        test -f conftest2.$ac_objext && { { case "(($ac_try" in
+  *\"* | *\`* | *\\*) ac_try_echo=\$ac_try;;
+  *) ac_try_echo=$ac_try;;
+esac
+eval ac_try_echo="\"\$as_me:${as_lineno-$LINENO}: $ac_try_echo\""
+$as_echo "$ac_try_echo"; } >&5
+  (eval "$ac_try") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; };
+      then
+       # cc works too.
+       :
+      else
+       # cc exists but doesn't like -o.
+       eval ac_cv_prog_cc_${ac_cc}_c_o=no
+      fi
+    fi
+  fi
+else
+  eval ac_cv_prog_cc_${ac_cc}_c_o=no
+fi
+rm -f core conftest*
+
+fi
+if eval test \$ac_cv_prog_cc_${ac_cc}_c_o = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+
+$as_echo "#define NO_MINUS_C_MINUS_O 1" >>confdefs.h
+
+fi
+
+# FIXME: we rely on the cache variable name because
+# there is no other way.
+set dummy $CC
+am_cc=`echo $2 | sed 's/[^a-zA-Z0-9_]/_/g;s/^[0-9]/_/'`
+eval am_t=\$ac_cv_prog_cc_${am_cc}_c_o
+if test "$am_t" != yes; then
+   # Losing compiler, so override with the script.
+   # FIXME: It is wrong to rewrite CC.
+   # But if we don't then we get into trouble of one sort or another.
+   # A longer-term fix would be to have automake use am__CC in this case,
+   # and then we could set am__CC="\$(top_srcdir)/compile \$(CC)"
+   CC="$am_aux_dir/compile $CC"
+fi
+
+
+
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking whether ${CC-cc} accepts -fPIE" >&5
+$as_echo_n "checking whether ${CC-cc} accepts -fPIE... " >&6; }
+if ${ac_cv_prog_cc_pie+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+
+               echo 'void f(){}' > conftest.c
+               if test -z "`${CC-cc} -fPIE -pie -c conftest.c 2>&1`"; then
+                       ac_cv_prog_cc_pie=yes
+               else
+                       ac_cv_prog_cc_pie=no
+               fi
+               rm -rf conftest*
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_prog_cc_pie" >&5
+$as_echo "$ac_cv_prog_cc_pie" >&6; }
+
+
+
+
+
+
+
+# Check whether --enable-static was given.
+if test "${enable_static+set}" = set; then :
+  enableval=$enable_static; p=${PACKAGE-default}
+    case $enableval in
+    yes) enable_static=yes ;;
+    no) enable_static=no ;;
+    *)
+     enable_static=no
+      # Look at the argument we got.  We use all the common list separators.
+      lt_save_ifs="$IFS"; IFS="${IFS}$PATH_SEPARATOR,"
+      for pkg in $enableval; do
+       IFS="$lt_save_ifs"
+       if test "X$pkg" = "X$p"; then
+         enable_static=yes
+       fi
+      done
+      IFS="$lt_save_ifs"
+      ;;
+    esac
+else
+  enable_static=no
+fi
+
+
+
+
+
+
+
+
+
+case `pwd` in
+  *\ * | *\    *)
+    { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&5
+$as_echo "$as_me: WARNING: Libtool does not cope well with whitespace in \`pwd\`" >&2;} ;;
+esac
+
+
+
+macro_version='2.4.2'
+macro_revision='1.3337'
+
+
+
+
+
+
+
+
+
+
+
+
+
+ltmain="$ac_aux_dir/ltmain.sh"
+
+# Make sure we can run config.sub.
+$SHELL "$ac_aux_dir/config.sub" sun4 >/dev/null 2>&1 ||
+  as_fn_error $? "cannot run $SHELL $ac_aux_dir/config.sub" "$LINENO" 5
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking build system type" >&5
+$as_echo_n "checking build system type... " >&6; }
+if ${ac_cv_build+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_build_alias=$build_alias
+test "x$ac_build_alias" = x &&
+  ac_build_alias=`$SHELL "$ac_aux_dir/config.guess"`
+test "x$ac_build_alias" = x &&
+  as_fn_error $? "cannot guess build type; you must specify one" "$LINENO" 5
+ac_cv_build=`$SHELL "$ac_aux_dir/config.sub" $ac_build_alias` ||
+  as_fn_error $? "$SHELL $ac_aux_dir/config.sub $ac_build_alias failed" "$LINENO" 5
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_build" >&5
+$as_echo "$ac_cv_build" >&6; }
+case $ac_cv_build in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical build" "$LINENO" 5;;
+esac
+build=$ac_cv_build
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_build
+shift
+build_cpu=$1
+build_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+build_os=$*
+IFS=$ac_save_IFS
+case $build_os in *\ *) build_os=`echo "$build_os" | sed 's/ /-/g'`;; esac
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking host system type" >&5
+$as_echo_n "checking host system type... " >&6; }
+if ${ac_cv_host+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test "x$host_alias" = x; then
+  ac_cv_host=$ac_cv_build
+else
+  ac_cv_host=`$SHELL "$ac_aux_dir/config.sub" $host_alias` ||
+    as_fn_error $? "$SHELL $ac_aux_dir/config.sub $host_alias failed" "$LINENO" 5
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_host" >&5
+$as_echo "$ac_cv_host" >&6; }
+case $ac_cv_host in
+*-*-*) ;;
+*) as_fn_error $? "invalid value of canonical host" "$LINENO" 5;;
+esac
+host=$ac_cv_host
+ac_save_IFS=$IFS; IFS='-'
+set x $ac_cv_host
+shift
+host_cpu=$1
+host_vendor=$2
+shift; shift
+# Remember, the first character of IFS is used to create $*,
+# except with old shells:
+host_os=$*
+IFS=$ac_save_IFS
+case $host_os in *\ *) host_os=`echo "$host_os" | sed 's/ /-/g'`;; esac
+
+
+# Backslashify metacharacters that are still active within
+# double-quoted strings.
+sed_quote_subst='s/\(["`$\\]\)/\\\1/g'
+
+# Same as above, but do not quote variable references.
+double_quote_subst='s/\(["`\\]\)/\\\1/g'
+
+# Sed substitution to delay expansion of an escaped shell variable in a
+# double_quote_subst'ed string.
+delay_variable_subst='s/\\\\\\\\\\\$/\\\\\\$/g'
+
+# Sed substitution to delay expansion of an escaped single quote.
+delay_single_quote_subst='s/'\''/'\'\\\\\\\'\''/g'
+
+# Sed substitution to avoid accidental globbing in evaled expressions
+no_glob_subst='s/\*/\\\*/g'
+
+ECHO='\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\\'
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO
+ECHO=$ECHO$ECHO$ECHO$ECHO$ECHO$ECHO
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to print strings" >&5
+$as_echo_n "checking how to print strings... " >&6; }
+# Test print first, because it will be a builtin if present.
+if test "X`( print -r -- -n ) 2>/dev/null`" = X-n && \
+   test "X`print -r -- $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='print -r --'
+elif test "X`printf %s $ECHO 2>/dev/null`" = "X$ECHO"; then
+  ECHO='printf %s\n'
+else
+  # Use this function as a fallback that always works.
+  func_fallback_echo ()
+  {
+    eval 'cat <<_LTECHO_EOF
+$1
+_LTECHO_EOF'
+  }
+  ECHO='func_fallback_echo'
+fi
+
+# func_echo_all arg...
+# Invoke $ECHO with all args, space-separated.
+func_echo_all ()
+{
+    $ECHO ""
+}
+
+case "$ECHO" in
+  printf*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: printf" >&5
+$as_echo "printf" >&6; } ;;
+  print*) { $as_echo "$as_me:${as_lineno-$LINENO}: result: print -r" >&5
+$as_echo "print -r" >&6; } ;;
+  *) { $as_echo "$as_me:${as_lineno-$LINENO}: result: cat" >&5
+$as_echo "cat" >&6; } ;;
+esac
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for a sed that does not truncate output" >&5
+$as_echo_n "checking for a sed that does not truncate output... " >&6; }
+if ${ac_cv_path_SED+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+            ac_script=s/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb/
+     for ac_i in 1 2 3 4 5 6 7; do
+       ac_script="$ac_script$as_nl$ac_script"
+     done
+     echo "$ac_script" 2>/dev/null | sed 99q >conftest.sed
+     { ac_script=; unset ac_script;}
+     if test -z "$SED"; then
+  ac_path_SED_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in sed gsed; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_SED="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_SED" || continue
+# Check for GNU ac_path_SED and select it if it is found.
+  # Check for GNU $ac_path_SED
+case `"$ac_path_SED" --version 2>&1` in
+*GNU*)
+  ac_cv_path_SED="$ac_path_SED" ac_path_SED_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo '' >> "conftest.nl"
+    "$ac_path_SED" -f conftest.sed < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_SED_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_SED="$ac_path_SED"
+      ac_path_SED_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_SED_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_SED"; then
+    as_fn_error $? "no acceptable sed could be found in \$PATH" "$LINENO" 5
+  fi
+else
+  ac_cv_path_SED=$SED
+fi
+
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_SED" >&5
+$as_echo "$ac_cv_path_SED" >&6; }
+ SED="$ac_cv_path_SED"
+  rm -f conftest.sed
+
+test -z "$SED" && SED=sed
+Xsed="$SED -e 1s/^X//"
+
+
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for fgrep" >&5
+$as_echo_n "checking for fgrep... " >&6; }
+if ${ac_cv_path_FGREP+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if echo 'ab*c' | $GREP -F 'ab*c' >/dev/null 2>&1
+   then ac_cv_path_FGREP="$GREP -F"
+   else
+     if test -z "$FGREP"; then
+  ac_path_FGREP_found=false
+  # Loop through the user's path and test for each of PROGNAME-LIST
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH$PATH_SEPARATOR/usr/xpg4/bin
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_prog in fgrep; do
+    for ac_exec_ext in '' $ac_executable_extensions; do
+      ac_path_FGREP="$as_dir/$ac_prog$ac_exec_ext"
+      as_fn_executable_p "$ac_path_FGREP" || continue
+# Check for GNU ac_path_FGREP and select it if it is found.
+  # Check for GNU $ac_path_FGREP
+case `"$ac_path_FGREP" --version 2>&1` in
+*GNU*)
+  ac_cv_path_FGREP="$ac_path_FGREP" ac_path_FGREP_found=:;;
+*)
+  ac_count=0
+  $as_echo_n 0123456789 >"conftest.in"
+  while :
+  do
+    cat "conftest.in" "conftest.in" >"conftest.tmp"
+    mv "conftest.tmp" "conftest.in"
+    cp "conftest.in" "conftest.nl"
+    $as_echo 'FGREP' >> "conftest.nl"
+    "$ac_path_FGREP" FGREP < "conftest.nl" >"conftest.out" 2>/dev/null || break
+    diff "conftest.out" "conftest.nl" >/dev/null 2>&1 || break
+    as_fn_arith $ac_count + 1 && ac_count=$as_val
+    if test $ac_count -gt ${ac_path_FGREP_max-0}; then
+      # Best one so far, save it but keep looking for a better one
+      ac_cv_path_FGREP="$ac_path_FGREP"
+      ac_path_FGREP_max=$ac_count
+    fi
+    # 10*(2^10) chars as input seems more than enough
+    test $ac_count -gt 10 && break
+  done
+  rm -f conftest.in conftest.tmp conftest.nl conftest.out;;
+esac
+
+      $ac_path_FGREP_found && break 3
+    done
+  done
+  done
+IFS=$as_save_IFS
+  if test -z "$ac_cv_path_FGREP"; then
+    as_fn_error $? "no acceptable fgrep could be found in $PATH$PATH_SEPARATOR/usr/xpg4/bin" "$LINENO" 5
+  fi
+else
+  ac_cv_path_FGREP=$FGREP
+fi
+
+   fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_path_FGREP" >&5
+$as_echo "$ac_cv_path_FGREP" >&6; }
+ FGREP="$ac_cv_path_FGREP"
+
+
+test -z "$GREP" && GREP=grep
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+# Check whether --with-gnu-ld was given.
+if test "${with_gnu_ld+set}" = set; then :
+  withval=$with_gnu_ld; test "$withval" = no || with_gnu_ld=yes
+else
+  with_gnu_ld=no
+fi
+
+ac_prog=ld
+if test "$GCC" = yes; then
+  # Check if gcc -print-prog-name=ld gives a path.
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for ld used by $CC" >&5
+$as_echo_n "checking for ld used by $CC... " >&6; }
+  case $host in
+  *-*-mingw*)
+    # gcc leaves a trailing carriage return which upsets mingw
+    ac_prog=`($CC -print-prog-name=ld) 2>&5 | tr -d '\015'` ;;
+  *)
+    ac_prog=`($CC -print-prog-name=ld) 2>&5` ;;
+  esac
+  case $ac_prog in
+    # Accept absolute paths.
+    [\\/]* | ?:[\\/]*)
+      re_direlt='/[^/][^/]*/\.\./'
+      # Canonicalize the pathname of ld
+      ac_prog=`$ECHO "$ac_prog"| $SED 's%\\\\%/%g'`
+      while $ECHO "$ac_prog" | $GREP "$re_direlt" > /dev/null 2>&1; do
+       ac_prog=`$ECHO $ac_prog| $SED "s%$re_direlt%/%"`
+      done
+      test -z "$LD" && LD="$ac_prog"
+      ;;
+  "")
+    # If it fails, then pretend we aren't using GCC.
+    ac_prog=ld
+    ;;
+  *)
+    # If it is relative, then search for the first ld in PATH.
+    with_gnu_ld=unknown
+    ;;
+  esac
+elif test "$with_gnu_ld" = yes; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for GNU ld" >&5
+$as_echo_n "checking for GNU ld... " >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for non-GNU ld" >&5
+$as_echo_n "checking for non-GNU ld... " >&6; }
+fi
+if ${lt_cv_path_LD+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -z "$LD"; then
+  lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+  for ac_dir in $PATH; do
+    IFS="$lt_save_ifs"
+    test -z "$ac_dir" && ac_dir=.
+    if test -f "$ac_dir/$ac_prog" || test -f "$ac_dir/$ac_prog$ac_exeext"; then
+      lt_cv_path_LD="$ac_dir/$ac_prog"
+      # Check to see if the program is GNU ld.  I'd rather use --version,
+      # but apparently some variants of GNU ld only accept -v.
+      # Break only if it was the GNU/non-GNU ld that we prefer.
+      case `"$lt_cv_path_LD" -v 2>&1 </dev/null` in
+      *GNU* | *'with BFD'*)
+       test "$with_gnu_ld" != no && break
+       ;;
+      *)
+       test "$with_gnu_ld" != yes && break
+       ;;
+      esac
+    fi
+  done
+  IFS="$lt_save_ifs"
+else
+  lt_cv_path_LD="$LD" # Let the user override the test with a path.
+fi
+fi
+
+LD="$lt_cv_path_LD"
+if test -n "$LD"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LD" >&5
+$as_echo "$LD" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+test -z "$LD" && as_fn_error $? "no acceptable ld found in \$PATH" "$LINENO" 5
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking if the linker ($LD) is GNU ld" >&5
+$as_echo_n "checking if the linker ($LD) is GNU ld... " >&6; }
+if ${lt_cv_prog_gnu_ld+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  # I'd rather use --version here, but apparently some GNU lds only accept -v.
+case `$LD -v 2>&1 </dev/null` in
+*GNU* | *'with BFD'*)
+  lt_cv_prog_gnu_ld=yes
+  ;;
+*)
+  lt_cv_prog_gnu_ld=no
+  ;;
+esac
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_prog_gnu_ld" >&5
+$as_echo "$lt_cv_prog_gnu_ld" >&6; }
+with_gnu_ld=$lt_cv_prog_gnu_ld
+
+
+
+
+
+
+
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for BSD- or MS-compatible name lister (nm)" >&5
+$as_echo_n "checking for BSD- or MS-compatible name lister (nm)... " >&6; }
+if ${lt_cv_path_NM+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$NM"; then
+  # Let the user override the test.
+  lt_cv_path_NM="$NM"
+else
+  lt_nm_to_check="${ac_tool_prefix}nm"
+  if test -n "$ac_tool_prefix" && test "$build" = "$host"; then
+    lt_nm_to_check="$lt_nm_to_check nm"
+  fi
+  for lt_tmp_nm in $lt_nm_to_check; do
+    lt_save_ifs="$IFS"; IFS=$PATH_SEPARATOR
+    for ac_dir in $PATH /usr/ccs/bin/elf /usr/ccs/bin /usr/ucb /bin; do
+      IFS="$lt_save_ifs"
+      test -z "$ac_dir" && ac_dir=.
+      tmp_nm="$ac_dir/$lt_tmp_nm"
+      if test -f "$tmp_nm" || test -f "$tmp_nm$ac_exeext" ; then
+       # Check to see if the nm accepts a BSD-compat flag.
+       # Adding the `sed 1q' prevents false positives on HP-UX, which says:
+       #   nm: unknown option "B" ignored
+       # Tru64's nm complains that /dev/null is an invalid object file
+       case `"$tmp_nm" -B /dev/null 2>&1 | sed '1q'` in
+       */dev/null* | *'Invalid file or object type'*)
+         lt_cv_path_NM="$tmp_nm -B"
+         break
+         ;;
+       *)
+         case `"$tmp_nm" -p /dev/null 2>&1 | sed '1q'` in
+         */dev/null*)
+           lt_cv_path_NM="$tmp_nm -p"
+           break
+           ;;
+         *)
+           lt_cv_path_NM=${lt_cv_path_NM="$tmp_nm"} # keep the first match, but
+           continue # so that we can try to find one that supports BSD flags
+           ;;
+         esac
+         ;;
+       esac
+      fi
+    done
+    IFS="$lt_save_ifs"
+  done
+  : ${lt_cv_path_NM=no}
+fi
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_path_NM" >&5
+$as_echo "$lt_cv_path_NM" >&6; }
+if test "$lt_cv_path_NM" != "no"; then
+  NM="$lt_cv_path_NM"
+else
+  # Didn't find any BSD compatible name lister, look for dumpbin.
+  if test -n "$DUMPBIN"; then :
+    # Let the user override the test.
+  else
+    if test -n "$ac_tool_prefix"; then
+  for ac_prog in dumpbin "link -dump"
+  do
+    # Extract the first word of "$ac_tool_prefix$ac_prog", so it can be a program name with args.
+set dummy $ac_tool_prefix$ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$DUMPBIN"; then
+  ac_cv_prog_DUMPBIN="$DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_DUMPBIN="$ac_tool_prefix$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+DUMPBIN=$ac_cv_prog_DUMPBIN
+if test -n "$DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DUMPBIN" >&5
+$as_echo "$DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+    test -n "$DUMPBIN" && break
+  done
+fi
+if test -z "$DUMPBIN"; then
+  ac_ct_DUMPBIN=$DUMPBIN
+  for ac_prog in dumpbin "link -dump"
+do
+  # Extract the first word of "$ac_prog", so it can be a program name with args.
+set dummy $ac_prog; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_DUMPBIN+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$ac_ct_DUMPBIN"; then
+  ac_cv_prog_ac_ct_DUMPBIN="$ac_ct_DUMPBIN" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_DUMPBIN="$ac_prog"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_DUMPBIN=$ac_cv_prog_ac_ct_DUMPBIN
+if test -n "$ac_ct_DUMPBIN"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DUMPBIN" >&5
+$as_echo "$ac_ct_DUMPBIN" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+  test -n "$ac_ct_DUMPBIN" && break
+done
+
+  if test "x$ac_ct_DUMPBIN" = x; then
+    DUMPBIN=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    DUMPBIN=$ac_ct_DUMPBIN
+  fi
+fi
+
+    case `$DUMPBIN -symbols /dev/null 2>&1 | sed '1q'` in
+    *COFF*)
+      DUMPBIN="$DUMPBIN -symbols"
+      ;;
+    *)
+      DUMPBIN=:
+      ;;
+    esac
+  fi
+
+  if test "$DUMPBIN" != ":"; then
+    NM="$DUMPBIN"
+  fi
+fi
+test -z "$NM" && NM=nm
+
 
 
 
@@ -5869,10 +6660,6 @@ freebsd* | dragonfly*)
   fi
   ;;
 
-gnu*)
-  lt_cv_deplibs_check_method=pass_all
-  ;;
-
 haiku*)
   lt_cv_deplibs_check_method=pass_all
   ;;
@@ -5911,7 +6698,7 @@ irix5* | irix6* | nonstopux*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   lt_cv_deplibs_check_method=pass_all
   ;;
 
 
 
 
-
-
-  case $host_os in
-    rhapsody* | darwin*)
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
-set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_DSYMUTIL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$DSYMUTIL"; then
-  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-DSYMUTIL=$ac_cv_prog_DSYMUTIL
-if test -n "$DSYMUTIL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
-$as_echo "$DSYMUTIL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_DSYMUTIL"; then
-  ac_ct_DSYMUTIL=$DSYMUTIL
-  # Extract the first word of "dsymutil", so it can be a program name with args.
-set dummy dsymutil; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_DSYMUTIL"; then
-  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
-if test -n "$ac_ct_DSYMUTIL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
-$as_echo "$ac_ct_DSYMUTIL" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_DSYMUTIL" = x; then
-    DSYMUTIL=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    DSYMUTIL=$ac_ct_DSYMUTIL
-  fi
-else
-  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
-fi
-
-    if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
-set dummy ${ac_tool_prefix}nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_NMEDIT+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$NMEDIT"; then
-  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-NMEDIT=$ac_cv_prog_NMEDIT
-if test -n "$NMEDIT"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
-$as_echo "$NMEDIT" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-
-fi
-if test -z "$ac_cv_prog_NMEDIT"; then
-  ac_ct_NMEDIT=$NMEDIT
-  # Extract the first word of "nmedit", so it can be a program name with args.
-set dummy nmedit; ac_word=$2
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
-$as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  if test -n "$ac_ct_NMEDIT"; then
-  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
-else
-as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
-for as_dir in $PATH
-do
-  IFS=$as_save_IFS
-  test -z "$as_dir" && as_dir=.
-    for ac_exec_ext in '' $ac_executable_extensions; do
-  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_NMEDIT="nmedit"
-    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
-    break 2
-  fi
-done
-  done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
-if test -n "$ac_ct_NMEDIT"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
-$as_echo "$ac_ct_NMEDIT" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_NMEDIT" = x; then
-    NMEDIT=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    NMEDIT=$ac_ct_NMEDIT
-  fi
-else
-  NMEDIT="$ac_cv_prog_NMEDIT"
-fi
-
+
+
+  case $host_os in
+    rhapsody* | darwin*)
     if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
-set dummy ${ac_tool_prefix}lipo; ac_word=$2
+  # Extract the first word of "${ac_tool_prefix}dsymutil", so it can be a program name with args.
+set dummy ${ac_tool_prefix}dsymutil; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_LIPO+:} false; then :
+if ${ac_cv_prog_DSYMUTIL+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$LIPO"; then
-  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
+  if test -n "$DSYMUTIL"; then
+  ac_cv_prog_DSYMUTIL="$DSYMUTIL" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -7454,7 +8057,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
+    ac_cv_prog_DSYMUTIL="${ac_tool_prefix}dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -7464,10 +8067,10 @@ IFS=$as_save_IFS
 
 fi
 fi
-LIPO=$ac_cv_prog_LIPO
-if test -n "$LIPO"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
-$as_echo "$LIPO" >&6; }
+DSYMUTIL=$ac_cv_prog_DSYMUTIL
+if test -n "$DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $DSYMUTIL" >&5
+$as_echo "$DSYMUTIL" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
@@ -7475,17 +8078,17 @@ fi
 
 
 fi
-if test -z "$ac_cv_prog_LIPO"; then
-  ac_ct_LIPO=$LIPO
-  # Extract the first word of "lipo", so it can be a program name with args.
-set dummy lipo; ac_word=$2
+if test -z "$ac_cv_prog_DSYMUTIL"; then
+  ac_ct_DSYMUTIL=$DSYMUTIL
+  # Extract the first word of "dsymutil", so it can be a program name with args.
+set dummy dsymutil; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
+if ${ac_cv_prog_ac_ct_DSYMUTIL+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$ac_ct_LIPO"; then
-  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
+  if test -n "$ac_ct_DSYMUTIL"; then
+  ac_cv_prog_ac_ct_DSYMUTIL="$ac_ct_DSYMUTIL" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -7494,7 +8097,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_LIPO="lipo"
+    ac_cv_prog_ac_ct_DSYMUTIL="dsymutil"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -7504,17 +8107,17 @@ IFS=$as_save_IFS
 
 fi
 fi
-ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
-if test -n "$ac_ct_LIPO"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
-$as_echo "$ac_ct_LIPO" >&6; }
+ac_ct_DSYMUTIL=$ac_cv_prog_ac_ct_DSYMUTIL
+if test -n "$ac_ct_DSYMUTIL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_DSYMUTIL" >&5
+$as_echo "$ac_ct_DSYMUTIL" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
-  if test "x$ac_ct_LIPO" = x; then
-    LIPO=":"
+  if test "x$ac_ct_DSYMUTIL" = x; then
+    DSYMUTIL=":"
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
@@ -7522,22 +8125,22 @@ yes:)
 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
-    LIPO=$ac_ct_LIPO
+    DSYMUTIL=$ac_ct_DSYMUTIL
   fi
 else
-  LIPO="$ac_cv_prog_LIPO"
+  DSYMUTIL="$ac_cv_prog_DSYMUTIL"
 fi
 
     if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool; ac_word=$2
+  # Extract the first word of "${ac_tool_prefix}nmedit", so it can be a program name with args.
+set dummy ${ac_tool_prefix}nmedit; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL+:} false; then :
+if ${ac_cv_prog_NMEDIT+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$OTOOL"; then
-  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+  if test -n "$NMEDIT"; then
+  ac_cv_prog_NMEDIT="$NMEDIT" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -7546,7 +8149,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    ac_cv_prog_NMEDIT="${ac_tool_prefix}nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -7556,10 +8159,10 @@ IFS=$as_save_IFS
 
 fi
 fi
-OTOOL=$ac_cv_prog_OTOOL
-if test -n "$OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
-$as_echo "$OTOOL" >&6; }
+NMEDIT=$ac_cv_prog_NMEDIT
+if test -n "$NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $NMEDIT" >&5
+$as_echo "$NMEDIT" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
@@ -7567,17 +8170,17 @@ fi
 
 
 fi
-if test -z "$ac_cv_prog_OTOOL"; then
-  ac_ct_OTOOL=$OTOOL
-  # Extract the first word of "otool", so it can be a program name with args.
-set dummy otool; ac_word=$2
+if test -z "$ac_cv_prog_NMEDIT"; then
+  ac_ct_NMEDIT=$NMEDIT
+  # Extract the first word of "nmedit", so it can be a program name with args.
+set dummy nmedit; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
+if ${ac_cv_prog_ac_ct_NMEDIT+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$ac_ct_OTOOL"; then
-  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+  if test -n "$ac_ct_NMEDIT"; then
+  ac_cv_prog_ac_ct_NMEDIT="$ac_ct_NMEDIT" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -7586,7 +8189,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_OTOOL="otool"
+    ac_cv_prog_ac_ct_NMEDIT="nmedit"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -7596,17 +8199,17 @@ IFS=$as_save_IFS
 
 fi
 fi
-ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
-if test -n "$ac_ct_OTOOL"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
-$as_echo "$ac_ct_OTOOL" >&6; }
+ac_ct_NMEDIT=$ac_cv_prog_ac_ct_NMEDIT
+if test -n "$ac_ct_NMEDIT"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_NMEDIT" >&5
+$as_echo "$ac_ct_NMEDIT" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
 fi
 
-  if test "x$ac_ct_OTOOL" = x; then
-    OTOOL=":"
+  if test "x$ac_ct_NMEDIT" = x; then
+    NMEDIT=":"
   else
     case $cross_compiling:$ac_tool_warned in
 yes:)
@@ -7614,22 +8217,22 @@ yes:)
 $as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
 ac_tool_warned=yes ;;
 esac
-    OTOOL=$ac_ct_OTOOL
+    NMEDIT=$ac_ct_NMEDIT
   fi
 else
-  OTOOL="$ac_cv_prog_OTOOL"
+  NMEDIT="$ac_cv_prog_NMEDIT"
 fi
 
     if test -n "$ac_tool_prefix"; then
-  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
-set dummy ${ac_tool_prefix}otool64; ac_word=$2
+  # Extract the first word of "${ac_tool_prefix}lipo", so it can be a program name with args.
+set dummy ${ac_tool_prefix}lipo; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_OTOOL64+:} false; then :
+if ${ac_cv_prog_LIPO+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$OTOOL64"; then
-  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+  if test -n "$LIPO"; then
+  ac_cv_prog_LIPO="$LIPO" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
@@ -7638,7 +8241,7 @@ do
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    ac_cv_prog_LIPO="${ac_tool_prefix}lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
@@ -7648,10 +8251,10 @@ IFS=$as_save_IFS
 
 fi
 fi
-OTOOL64=$ac_cv_prog_OTOOL64
-if test -n "$OTOOL64"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
-$as_echo "$OTOOL64" >&6; }
+LIPO=$ac_cv_prog_LIPO
+if test -n "$LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $LIPO" >&5
+$as_echo "$LIPO" >&6; }
 else
   { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
@@ -7659,17 +8262,17 @@ fi
 
 
 fi
-if test -z "$ac_cv_prog_OTOOL64"; then
-  ac_ct_OTOOL64=$OTOOL64
-  # Extract the first word of "otool64", so it can be a program name with args.
-set dummy otool64; ac_word=$2
+if test -z "$ac_cv_prog_LIPO"; then
+  ac_ct_LIPO=$LIPO
+  # Extract the first word of "lipo", so it can be a program name with args.
+set dummy lipo; ac_word=$2
 { $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
 $as_echo_n "checking for $ac_word... " >&6; }
-if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+if ${ac_cv_prog_ac_ct_LIPO+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  if test -n "$ac_ct_OTOOL64"; then
-  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+  if test -n "$ac_ct_LIPO"; then
+  ac_cv_prog_ac_ct_LIPO="$ac_ct_LIPO" # Let the user override the test.
 else
 as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
 for as_dir in $PATH
   test -z "$as_dir" && as_dir=.
     for ac_exec_ext in '' $ac_executable_extensions; do
   if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
-    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    ac_cv_prog_ac_ct_LIPO="lipo"
     $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
     break 2
   fi
 done
   done
-IFS=$as_save_IFS
-
-fi
-fi
-ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
-if test -n "$ac_ct_OTOOL64"; then
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
-$as_echo "$ac_ct_OTOOL64" >&6; }
-else
-  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-fi
-
-  if test "x$ac_ct_OTOOL64" = x; then
-    OTOOL64=":"
-  else
-    case $cross_compiling:$ac_tool_warned in
-yes:)
-{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
-$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
-ac_tool_warned=yes ;;
-esac
-    OTOOL64=$ac_ct_OTOOL64
-  fi
-else
-  OTOOL64="$ac_cv_prog_OTOOL64"
-fi
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
-$as_echo_n "checking for -single_module linker flag... " >&6; }
-if ${lt_cv_apple_cc_single_mod+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_apple_cc_single_mod=no
-      if test -z "${LT_MULTI_MODULE}"; then
-       # By default we will add the -single_module flag. You can override
-       # by either setting the environment variable LT_MULTI_MODULE
-       # non-empty at configure time, or by adding -multi_module to the
-       # link flags.
-       rm -rf libconftest.dylib*
-       echo "int foo(void){return 1;}" > conftest.c
-       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
--dynamiclib -Wl,-single_module conftest.c" >&5
-       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
-         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
-        _lt_result=$?
-       # If there is a non-empty error log, and "single_module"
-       # appears in it, assume the flag caused a linker warning
-        if test -s conftest.err && $GREP single_module conftest.err; then
-         cat conftest.err >&5
-       # Otherwise, if the output was created with a 0 exit code from
-       # the compiler, it worked.
-       elif test -f libconftest.dylib && test $_lt_result -eq 0; then
-         lt_cv_apple_cc_single_mod=yes
-       else
-         cat conftest.err >&5
-       fi
-       rm -rf libconftest.dylib*
-       rm -f conftest.*
-      fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
-$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
-
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
-$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
-if ${lt_cv_ld_exported_symbols_list+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  lt_cv_ld_exported_symbols_list=no
-      save_LDFLAGS=$LDFLAGS
-      echo "_main" > conftest.sym
-      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
-      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-int
-main ()
-{
-
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  lt_cv_ld_exported_symbols_list=yes
+IFS=$as_save_IFS
+
+fi
+fi
+ac_ct_LIPO=$ac_cv_prog_ac_ct_LIPO
+if test -n "$ac_ct_LIPO"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_LIPO" >&5
+$as_echo "$ac_ct_LIPO" >&6; }
 else
-  lt_cv_ld_exported_symbols_list=no
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-       LDFLAGS="$save_LDFLAGS"
 
+  if test "x$ac_ct_LIPO" = x; then
+    LIPO=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    LIPO=$ac_ct_LIPO
+  fi
+else
+  LIPO="$ac_cv_prog_LIPO"
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
-$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
 
-    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
-$as_echo_n "checking for -force_load linker flag... " >&6; }
-if ${lt_cv_ld_force_load+:} false; then :
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-  lt_cv_ld_force_load=no
-      cat > conftest.c << _LT_EOF
-int forced_loaded() { return 2;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
-      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
-      echo "$AR cru libconftest.a conftest.o" >&5
-      $AR cru libconftest.a conftest.o 2>&5
-      echo "$RANLIB libconftest.a" >&5
-      $RANLIB libconftest.a 2>&5
-      cat > conftest.c << _LT_EOF
-int main() { return 0;}
-_LT_EOF
-      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
-      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
-      _lt_result=$?
-      if test -s conftest.err && $GREP force_load conftest.err; then
-       cat conftest.err >&5
-      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
-       lt_cv_ld_force_load=yes
-      else
-       cat conftest.err >&5
-      fi
-        rm -f conftest.err libconftest.a conftest conftest.c
-        rm -rf conftest.dSYM
+  if test -n "$OTOOL"; then
+  ac_cv_prog_OTOOL="$OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL="${ac_tool_prefix}otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
-$as_echo "$lt_cv_ld_force_load" >&6; }
-    case $host_os in
-    rhapsody* | darwin1.[012])
-      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
-    darwin1.*)
-      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-    darwin*) # darwin 5.x on
-      # if running on 10.5 or later, the deployment target defaults
-      # to the OS version, if on x86, and 10.4, the deployment
-      # target defaults to 10.4. Don't you love it?
-      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
-       10.0,*86*-darwin8*|10.0,*-darwin[91]*)
-         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-       10.[012]*)
-         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
-       10.*)
-         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
-      esac
-    ;;
-  esac
-    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
-      _lt_dar_single_mod='$single_module'
-    fi
-    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
-      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
-    else
-      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
-    fi
-    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
-      _lt_dsymutil='~$DSYMUTIL $lib || :'
-    else
-      _lt_dsymutil=
-    fi
-    ;;
-  esac
+fi
+OTOOL=$ac_cv_prog_OTOOL
+if test -n "$OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL" >&5
+$as_echo "$OTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
 
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking how to run the C preprocessor" >&5
-$as_echo_n "checking how to run the C preprocessor... " >&6; }
-# On Suns, sometimes $CPP names a directory.
-if test -n "$CPP" && test -d "$CPP"; then
-  CPP=
 fi
-if test -z "$CPP"; then
-  if ${ac_cv_prog_CPP+:} false; then :
+if test -z "$ac_cv_prog_OTOOL"; then
+  ac_ct_OTOOL=$OTOOL
+  # Extract the first word of "otool", so it can be a program name with args.
+set dummy otool; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL+:} false; then :
   $as_echo_n "(cached) " >&6
 else
-      # Double quotes because CPP needs to be expanded
-    for CPP in "$CC -E" "$CC -E -traditional-cpp" "/lib/cpp"
-    do
-      ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
+  if test -n "$ac_ct_OTOOL"; then
+  ac_cv_prog_ac_ct_OTOOL="$ac_ct_OTOOL" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
 do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL="otool"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
+fi
+fi
+ac_ct_OTOOL=$ac_cv_prog_ac_ct_OTOOL
+if test -n "$ac_ct_OTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL" >&5
+$as_echo "$ac_ct_OTOOL" >&6; }
 else
-  # Broken: fails on valid input.
-continue
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
 
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
+  if test "x$ac_ct_OTOOL" = x; then
+    OTOOL=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL=$ac_ct_OTOOL
+  fi
 else
-  # Passes both tests.
-ac_preproc_ok=:
-break
+  OTOOL="$ac_cv_prog_OTOOL"
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
 
+    if test -n "$ac_tool_prefix"; then
+  # Extract the first word of "${ac_tool_prefix}otool64", so it can be a program name with args.
+set dummy ${ac_tool_prefix}otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  if test -n "$OTOOL64"; then
+  ac_cv_prog_OTOOL64="$OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_OTOOL64="${ac_tool_prefix}otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
 done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
-  break
+  done
+IFS=$as_save_IFS
+
+fi
+fi
+OTOOL64=$ac_cv_prog_OTOOL64
+if test -n "$OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $OTOOL64" >&5
+$as_echo "$OTOOL64" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
 
-    done
-    ac_cv_prog_CPP=$CPP
 
 fi
-  CPP=$ac_cv_prog_CPP
+if test -z "$ac_cv_prog_OTOOL64"; then
+  ac_ct_OTOOL64=$OTOOL64
+  # Extract the first word of "otool64", so it can be a program name with args.
+set dummy otool64; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if ${ac_cv_prog_ac_ct_OTOOL64+:} false; then :
+  $as_echo_n "(cached) " >&6
 else
-  ac_cv_prog_CPP=$CPP
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $CPP" >&5
-$as_echo "$CPP" >&6; }
-ac_preproc_ok=false
-for ac_c_preproc_warn_flag in '' yes
+  if test -n "$ac_ct_OTOOL64"; then
+  ac_cv_prog_ac_ct_OTOOL64="$ac_ct_OTOOL64" # Let the user override the test.
+else
+as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
 do
-  # Use a header file that comes with gcc, so configuring glibc
-  # with a fresh cross-compiler works.
-  # Prefer <limits.h> to <assert.h> if __STDC__ is defined, since
-  # <limits.h> exists even on freestanding compilers.
-  # On the NeXT, cc -E runs the code through the compiler's parser,
-  # not just through cpp. "Syntax error" is here to catch this case.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#ifdef __STDC__
-# include <limits.h>
-#else
-# include <assert.h>
-#endif
-                    Syntax error
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if as_fn_executable_p "$as_dir/$ac_word$ac_exec_ext"; then
+    ac_cv_prog_ac_ct_OTOOL64="otool64"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
 
+fi
+fi
+ac_ct_OTOOL64=$ac_cv_prog_ac_ct_OTOOL64
+if test -n "$ac_ct_OTOOL64"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_ct_OTOOL64" >&5
+$as_echo "$ac_ct_OTOOL64" >&6; }
 else
-  # Broken: fails on valid input.
-continue
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
 
-  # OK, works on sane cases.  Now check whether nonexistent headers
-  # can be detected and how.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ac_nonexistent.h>
-_ACEOF
-if ac_fn_c_try_cpp "$LINENO"; then :
-  # Broken: success on invalid input.
-continue
+  if test "x$ac_ct_OTOOL64" = x; then
+    OTOOL64=":"
+  else
+    case $cross_compiling:$ac_tool_warned in
+yes:)
+{ $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: using cross tools not prefixed with host triplet" >&5
+$as_echo "$as_me: WARNING: using cross tools not prefixed with host triplet" >&2;}
+ac_tool_warned=yes ;;
+esac
+    OTOOL64=$ac_ct_OTOOL64
+  fi
 else
-  # Passes both tests.
-ac_preproc_ok=:
-break
+  OTOOL64="$ac_cv_prog_OTOOL64"
 fi
-rm -f conftest.err conftest.i conftest.$ac_ext
 
-done
-# Because of `break', _AC_PREPROC_IFELSE's cleaning code was skipped.
-rm -f conftest.i conftest.err conftest.$ac_ext
-if $ac_preproc_ok; then :
 
-else
-  { { $as_echo "$as_me:${as_lineno-$LINENO}: error: in \`$ac_pwd':" >&5
-$as_echo "$as_me: error: in \`$ac_pwd':" >&2;}
-as_fn_error $? "C preprocessor \"$CPP\" fails sanity check
-See \`config.log' for more details" "$LINENO" 5; }
-fi
 
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
 
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ANSI C header files" >&5
-$as_echo_n "checking for ANSI C header files... " >&6; }
-if ${ac_cv_header_stdc+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
-#include <stdarg.h>
-#include <string.h>
-#include <float.h>
 
-int
-main ()
-{
 
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_compile "$LINENO"; then :
-  ac_cv_header_stdc=yes
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core conftest.err conftest.$ac_objext conftest.$ac_ext
 
-if test $ac_cv_header_stdc = yes; then
-  # SunOS 4.x string.h does not declare mem*, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <string.h>
 
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "memchr" >/dev/null 2>&1; then :
 
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
 
-fi
 
-if test $ac_cv_header_stdc = yes; then
-  # ISC 2.0.2 stdlib.h does not declare free, contrary to ANSI.
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <stdlib.h>
 
-_ACEOF
-if (eval "$ac_cpp conftest.$ac_ext") 2>&5 |
-  $EGREP "free" >/dev/null 2>&1; then :
 
-else
-  ac_cv_header_stdc=no
-fi
-rm -f conftest*
 
-fi
 
-if test $ac_cv_header_stdc = yes; then
-  # /bin/cc in Irix-4.0.5 gets non-ANSI ctype macros unless using -ansi.
-  if test "$cross_compiling" = yes; then :
-  :
-else
-  cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-#include <ctype.h>
-#include <stdlib.h>
-#if ((' ' & 0x0FF) == 0x020)
-# define ISLOWER(c) ('a' <= (c) && (c) <= 'z')
-# define TOUPPER(c) (ISLOWER(c) ? 'A' + ((c) - 'a') : (c))
-#else
-# define ISLOWER(c) \
-                  (('a' <= (c) && (c) <= 'i') \
-                    || ('j' <= (c) && (c) <= 'r') \
-                    || ('s' <= (c) && (c) <= 'z'))
-# define TOUPPER(c) (ISLOWER(c) ? ((c) | 0x40) : (c))
-#endif
 
-#define XOR(e, f) (((e) && !(f)) || (!(e) && (f)))
-int
-main ()
-{
-  int i;
-  for (i = 0; i < 256; i++)
-    if (XOR (islower (i), ISLOWER (i))
-       || toupper (i) != TOUPPER (i))
-      return 2;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_run "$LINENO"; then :
 
-else
-  ac_cv_header_stdc=no
-fi
-rm -f core *.core core.conftest.* gmon.out bb.out conftest$ac_exeext \
-  conftest.$ac_objext conftest.beam conftest.$ac_ext
-fi
 
-fi
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_header_stdc" >&5
-$as_echo "$ac_cv_header_stdc" >&6; }
-if test $ac_cv_header_stdc = yes; then
 
-$as_echo "#define STDC_HEADERS 1" >>confdefs.h
 
+
+
+
+
+
+
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -single_module linker flag" >&5
+$as_echo_n "checking for -single_module linker flag... " >&6; }
+if ${lt_cv_apple_cc_single_mod+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_apple_cc_single_mod=no
+      if test -z "${LT_MULTI_MODULE}"; then
+       # By default we will add the -single_module flag. You can override
+       # by either setting the environment variable LT_MULTI_MODULE
+       # non-empty at configure time, or by adding -multi_module to the
+       # link flags.
+       rm -rf libconftest.dylib*
+       echo "int foo(void){return 1;}" > conftest.c
+       echo "$LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+-dynamiclib -Wl,-single_module conftest.c" >&5
+       $LTCC $LTCFLAGS $LDFLAGS -o libconftest.dylib \
+         -dynamiclib -Wl,-single_module conftest.c 2>conftest.err
+        _lt_result=$?
+       # If there is a non-empty error log, and "single_module"
+       # appears in it, assume the flag caused a linker warning
+        if test -s conftest.err && $GREP single_module conftest.err; then
+         cat conftest.err >&5
+       # Otherwise, if the output was created with a 0 exit code from
+       # the compiler, it worked.
+       elif test -f libconftest.dylib && test $_lt_result -eq 0; then
+         lt_cv_apple_cc_single_mod=yes
+       else
+         cat conftest.err >&5
+       fi
+       rm -rf libconftest.dylib*
+       rm -f conftest.*
+      fi
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_apple_cc_single_mod" >&5
+$as_echo "$lt_cv_apple_cc_single_mod" >&6; }
 
-# On IRIX 5.3, sys/types and inttypes.h are conflicting.
-for ac_header in sys/types.h sys/stat.h stdlib.h string.h memory.h strings.h \
-                 inttypes.h stdint.h unistd.h
-do :
-  as_ac_Header=`$as_echo "ac_cv_header_$ac_header" | $as_tr_sh`
-ac_fn_c_check_header_compile "$LINENO" "$ac_header" "$as_ac_Header" "$ac_includes_default
-"
-if eval test \"x\$"$as_ac_Header"\" = x"yes"; then :
-  cat >>confdefs.h <<_ACEOF
-#define `$as_echo "HAVE_$ac_header" | $as_tr_cpp` 1
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -exported_symbols_list linker flag" >&5
+$as_echo_n "checking for -exported_symbols_list linker flag... " >&6; }
+if ${lt_cv_ld_exported_symbols_list+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_exported_symbols_list=no
+      save_LDFLAGS=$LDFLAGS
+      echo "_main" > conftest.sym
+      LDFLAGS="$LDFLAGS -Wl,-exported_symbols_list,conftest.sym"
+      cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
+
+int
+main ()
+{
+
+  ;
+  return 0;
+}
 _ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  lt_cv_ld_exported_symbols_list=yes
+else
+  lt_cv_ld_exported_symbols_list=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+       LDFLAGS="$save_LDFLAGS"
 
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_exported_symbols_list" >&5
+$as_echo "$lt_cv_ld_exported_symbols_list" >&6; }
 
-done
+    { $as_echo "$as_me:${as_lineno-$LINENO}: checking for -force_load linker flag" >&5
+$as_echo_n "checking for -force_load linker flag... " >&6; }
+if ${lt_cv_ld_force_load+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  lt_cv_ld_force_load=no
+      cat > conftest.c << _LT_EOF
+int forced_loaded() { return 2;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS -c -o conftest.o conftest.c" >&5
+      $LTCC $LTCFLAGS -c -o conftest.o conftest.c 2>&5
+      echo "$AR cru libconftest.a conftest.o" >&5
+      $AR cru libconftest.a conftest.o 2>&5
+      echo "$RANLIB libconftest.a" >&5
+      $RANLIB libconftest.a 2>&5
+      cat > conftest.c << _LT_EOF
+int main() { return 0;}
+_LT_EOF
+      echo "$LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a" >&5
+      $LTCC $LTCFLAGS $LDFLAGS -o conftest conftest.c -Wl,-force_load,./libconftest.a 2>conftest.err
+      _lt_result=$?
+      if test -s conftest.err && $GREP force_load conftest.err; then
+       cat conftest.err >&5
+      elif test -f conftest && test $_lt_result -eq 0 && $GREP forced_load conftest >/dev/null 2>&1 ; then
+       lt_cv_ld_force_load=yes
+      else
+       cat conftest.err >&5
+      fi
+        rm -f conftest.err libconftest.a conftest conftest.c
+        rm -rf conftest.dSYM
 
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $lt_cv_ld_force_load" >&5
+$as_echo "$lt_cv_ld_force_load" >&6; }
+    case $host_os in
+    rhapsody* | darwin1.[012])
+      _lt_dar_allow_undefined='${wl}-undefined ${wl}suppress' ;;
+    darwin1.*)
+      _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+    darwin*) # darwin 5.x on
+      # if running on 10.5 or later, the deployment target defaults
+      # to the OS version, if on x86, and 10.4, the deployment
+      # target defaults to 10.4. Don't you love it?
+      case ${MACOSX_DEPLOYMENT_TARGET-10.0},$host in
+       10.0,*86*-darwin8*|10.0,*-darwin[91]*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+       10.[012]*)
+         _lt_dar_allow_undefined='${wl}-flat_namespace ${wl}-undefined ${wl}suppress' ;;
+       10.*)
+         _lt_dar_allow_undefined='${wl}-undefined ${wl}dynamic_lookup' ;;
+      esac
+    ;;
+  esac
+    if test "$lt_cv_apple_cc_single_mod" = "yes"; then
+      _lt_dar_single_mod='$single_module'
+    fi
+    if test "$lt_cv_ld_exported_symbols_list" = "yes"; then
+      _lt_dar_export_syms=' ${wl}-exported_symbols_list,$output_objdir/${libname}-symbols.expsym'
+    else
+      _lt_dar_export_syms='~$NMEDIT -s $output_objdir/${libname}-symbols.expsym ${lib}'
+    fi
+    if test "$DSYMUTIL" != ":" && test "$lt_cv_ld_force_load" = "no"; then
+      _lt_dsymutil='~$DSYMUTIL $lib || :'
+    else
+      _lt_dsymutil=
+    fi
+    ;;
+  esac
 
 for ac_header in dlfcn.h
 do :
@@ -8803,7 +9323,7 @@ lt_prog_compiler_static=
       lt_prog_compiler_static='-non_shared'
       ;;
 
-    linux* | k*bsd*-gnu | kopensolaris*-gnu)
+    linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
       case $cc_basename in
       # old Intel for x86_64 which still supported -KPIC.
       ecc*)
@@ -10973,17 +11493,6 @@ freebsd* | dragonfly*)
   esac
   ;;
 
-gnu*)
-  version_type=linux # correct to gnu/linux during the next big refactor
-  need_lib_prefix=no
-  need_version=no
-  library_names_spec='${libname}${release}${shared_ext}$versuffix ${libname}${release}${shared_ext}${major} ${libname}${shared_ext}'
-  soname_spec='${libname}${release}${shared_ext}$major'
-  shlibpath_var=LD_LIBRARY_PATH
-  shlibpath_overrides_runpath=no
-  hardcode_into_libs=yes
-  ;;
-
 haiku*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
@@ -11100,7 +11609,7 @@ linux*oldld* | linux*aout* | linux*coff*)
   ;;
 
 # This must be glibc/ELF.
-linux* | k*bsd*-gnu | kopensolaris*-gnu)
+linux* | k*bsd*-gnu | kopensolaris*-gnu | gnu*)
   version_type=linux # correct to gnu/linux during the next big refactor
   need_lib_prefix=no
   need_version=no
@@ -12116,325 +12625,91 @@ $as_echo "$enable_static" >&6; }
 
 
 fi
-ac_ext=c
-ac_cpp='$CPP $CPPFLAGS'
-ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
-ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
-ac_compiler_gnu=$ac_cv_c_compiler_gnu
-
-CC="$lt_save_CC"
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-        ac_config_commands="$ac_config_commands libtool"
-
-
-
-
-# Only expand once:
-
-
-
-
-       ac_fn_c_check_func "$LINENO" "ppoll" "ac_cv_func_ppoll"
-if test "x$ac_cv_func_ppoll" = xyes; then :
-  dummy=yes
-else
-
-$as_echo "#define NEED_PPOLL 1" >>confdefs.h
-
-fi
-
-
-
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
-$as_echo_n "checking for dlopen in -ldl... " >&6; }
-if ${ac_cv_lib_dl_dlopen+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-ldl  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-/* Override any GCC internal prototype to avoid an error.
-   Use char because int might match the return type of a GCC
-   builtin and then its argument prototype would still apply.  */
-#ifdef __cplusplus
-extern "C"
-#endif
-char dlopen ();
-int
-main ()
-{
-return dlopen ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_dl_dlopen=yes
-else
-  ac_cv_lib_dl_dlopen=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
-$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
-if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
-  dummy=yes
-else
-  as_fn_error $? "dynamic linking loader is required" "$LINENO" 5
-fi
-
-
-ac_fn_c_check_header_mongrel "$LINENO" "sys/inotify.h" "ac_cv_header_sys_inotify_h" "$ac_includes_default"
-if test "x$ac_cv_header_sys_inotify_h" = xyes; then :
-
-$as_echo "#define HAVE_SYS_INOTIFY_H 1" >>confdefs.h
-
-else
-  as_fn_error $? "inotify headers are required and missing" "$LINENO" 5
-fi
-
-
-
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DBUS" >&5
-$as_echo_n "checking for DBUS... " >&6; }
-
-if test -n "$DBUS_CFLAGS"; then
-    pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1 >= 1.4" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$DBUS_LIBS"; then
-    pkg_cv_DBUS_LIBS="$DBUS_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1 >= 1.4" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1`
-        else
-               DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$DBUS_PKG_ERRORS" >&5
-
-       as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5
-else
-       DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS
-       DBUS_LIBS=$pkg_cv_DBUS_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       dummy=yes
-fi
+ac_ext=c
+ac_cpp='$CPP $CPPFLAGS'
+ac_compile='$CC -c $CFLAGS $CPPFLAGS conftest.$ac_ext >&5'
+ac_link='$CC -o conftest$ac_exeext $CFLAGS $CPPFLAGS $LDFLAGS conftest.$ac_ext $LIBS >&5'
+ac_compiler_gnu=$ac_cv_c_compiler_gnu
 
+CC="$lt_save_CC"
 
 
 
 
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5
-$as_echo_n "checking for GLIB... " >&6; }
 
-if test -n "$GLIB_CFLAGS"; then
-    pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.28" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$GLIB_LIBS"; then
-    pkg_cv_GLIB_LIBS="$GLIB_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.28" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
 
 
 
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1`
-        else
-               GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$GLIB_PKG_ERRORS" >&5
 
-       as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5
-else
-       GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS
-       GLIB_LIBS=$pkg_cv_GLIB_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       dummy=yes
-fi
 
 
 
 
 
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ALSA" >&5
-$as_echo_n "checking for ALSA... " >&6; }
+        ac_config_commands="$ac_config_commands libtool"
+
+
+
+
+# Only expand once:
+
+
+
+
+       misc_cflags=""
+       misc_ldflags=""
+       # Check whether --enable-optimization was given.
+if test "${enable_optimization+set}" = set; then :
+  enableval=$enable_optimization;
+               if (test "${enableval}" = "no"); then
+                       misc_cflags="$misc_cflags -O0"
+               fi
 
-if test -n "$ALSA_CFLAGS"; then
-    pkg_cv_ALSA_CFLAGS="$ALSA_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "alsa") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_ALSA_CFLAGS=`$PKG_CONFIG --cflags "alsa" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
 fi
-if test -n "$ALSA_LIBS"; then
-    pkg_cv_ALSA_LIBS="$ALSA_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"alsa\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "alsa") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_ALSA_LIBS=`$PKG_CONFIG --libs "alsa" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
+
+       # Check whether --enable-debug was given.
+if test "${enable_debug+set}" = set; then :
+  enableval=$enable_debug;
+               if (test "${enableval}" = "yes" &&
+                               test "${ac_cv_prog_cc_g}" = "yes"); then
+                       misc_cflags="$misc_cflags -g"
+               fi
+
 fi
- else
-    pkg_failed=untried
+
+       # Check whether --enable-pie was given.
+if test "${enable_pie+set}" = set; then :
+  enableval=$enable_pie;
+               if (test "${enableval}" = "yes" &&
+                               test "${ac_cv_prog_cc_pie}" = "yes"); then
+                       misc_cflags="$misc_cflags -fPIC"
+                       misc_ldflags="$misc_ldflags -pie"
+               fi
+
 fi
 
+       MISC_CFLAGS=$misc_cflags
 
+       MISC_LDFLAGS=$misc_ldflags
 
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
 
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
+
+# Check whether --enable-threads was given.
+if test "${enable_threads+set}" = set; then :
+  enableval=$enable_threads; enable_threads=${enableval}
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               ALSA_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "alsa" 2>&1`
-        else
-               ALSA_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "alsa" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$ALSA_PKG_ERRORS" >&5
 
-       alsa_found=no
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       alsa_found=no
+
+ac_fn_c_check_func "$LINENO" "signalfd" "ac_cv_func_signalfd"
+if test "x$ac_cv_func_signalfd" = xyes; then :
+  dummy=yes
 else
-       ALSA_CFLAGS=$pkg_cv_ALSA_CFLAGS
-       ALSA_LIBS=$pkg_cv_ALSA_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       alsa_found=yes
+  as_fn_error $? "signalfd support is required" "$LINENO" 5
 fi
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
+
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for clock_gettime in -lrt" >&5
 $as_echo_n "checking for clock_gettime in -lrt... " >&6; }
 if ${ac_cv_lib_rt_clock_gettime+:} false; then :
   $as_echo_n "(cached) " >&6
@@ -12457,188 +12732,33 @@ main ()
 return clock_gettime ();
   ;
   return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_rt_clock_gettime=yes
-else
-  ac_cv_lib_rt_clock_gettime=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
-$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
-if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
-  ALSA_LIBS="$ALSA_LIBS -lrt"
-else
-  alsa_found=no
-fi
-
-
-
-
-
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GSTREAMER" >&5
-$as_echo_n "checking for GSTREAMER... " >&6; }
-
-if test -n "$GSTREAMER_CFLAGS"; then
-    pkg_cv_GSTREAMER_CFLAGS="$GSTREAMER_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_GSTREAMER_CFLAGS=`$PKG_CONFIG --cflags "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$GSTREAMER_LIBS"; then
-    pkg_cv_GSTREAMER_LIBS="$GSTREAMER_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_GSTREAMER_LIBS=`$PKG_CONFIG --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
-else
-        _pkg_short_errors_supported=no
-fi
-        if test $_pkg_short_errors_supported = yes; then
-               GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>&1`
-        else
-               GSTREAMER_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gstreamer-0.10 >= 0.10.30 gstreamer-plugins-base-0.10" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$GSTREAMER_PKG_ERRORS" >&5
-
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GStreamer library version 0.10.30 or later is required" >&5
-$as_echo "$as_me: WARNING: GStreamer library version 0.10.30 or later is required" >&2;};gstreamer_found=no
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       { $as_echo "$as_me:${as_lineno-$LINENO}: WARNING: GStreamer library version 0.10.30 or later is required" >&5
-$as_echo "$as_me: WARNING: GStreamer library version 0.10.30 or later is required" >&2;};gstreamer_found=no
-else
-       GSTREAMER_CFLAGS=$pkg_cv_GSTREAMER_CFLAGS
-       GSTREAMER_LIBS=$pkg_cv_GSTREAMER_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       gstreamer_found=yes
-fi
-
-
-       GSTREAMER_PLUGINSDIR=`$PKG_CONFIG --variable=pluginsdir gstreamer-0.10`
-
-
-
-
-pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for USB" >&5
-$as_echo_n "checking for USB... " >&6; }
-
-if test -n "$USB_CFLAGS"; then
-    pkg_cv_USB_CFLAGS="$USB_CFLAGS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libusb") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_USB_CFLAGS=`$PKG_CONFIG --cflags "libusb" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-if test -n "$USB_LIBS"; then
-    pkg_cv_USB_LIBS="$USB_LIBS"
- elif test -n "$PKG_CONFIG"; then
-    if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libusb\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libusb") 2>&5
-  ac_status=$?
-  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
-  test $ac_status = 0; }; then
-  pkg_cv_USB_LIBS=`$PKG_CONFIG --libs "libusb" 2>/dev/null`
-                     test "x$?" != "x0" && pkg_failed=yes
-else
-  pkg_failed=yes
-fi
- else
-    pkg_failed=untried
-fi
-
-
-
-if test $pkg_failed = yes; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-
-if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
-        _pkg_short_errors_supported=yes
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_rt_clock_gettime=yes
 else
-        _pkg_short_errors_supported=no
+  ac_cv_lib_rt_clock_gettime=no
 fi
-        if test $_pkg_short_errors_supported = yes; then
-               USB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libusb" 2>&1`
-        else
-               USB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libusb" 2>&1`
-        fi
-       # Put the nasty error message in config.log where it belongs
-       echo "$USB_PKG_ERRORS" >&5
-
-       usb_found=no
-elif test $pkg_failed = untried; then
-       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
-$as_echo "no" >&6; }
-       usb_found=no
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
+fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_rt_clock_gettime" >&5
+$as_echo "$ac_cv_lib_rt_clock_gettime" >&6; }
+if test "x$ac_cv_lib_rt_clock_gettime" = xyes; then :
+  dummy=yes
 else
-       USB_CFLAGS=$pkg_cv_USB_CFLAGS
-       USB_LIBS=$pkg_cv_USB_LIBS
-        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
-$as_echo "yes" >&6; }
-       usb_found=yes
+  as_fn_error $? "realtime clock support is required" "$LINENO" 5
 fi
 
 
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_get_busses in -lusb" >&5
-$as_echo_n "checking for usb_get_busses in -lusb... " >&6; }
-if ${ac_cv_lib_usb_usb_get_busses+:} false; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for pthread_create in -lpthread" >&5
+$as_echo_n "checking for pthread_create in -lpthread... " >&6; }
+if ${ac_cv_lib_pthread_pthread_create+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lusb  $LIBS"
+LIBS="-lpthread  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -12648,41 +12768,40 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char usb_get_busses ();
+char pthread_create ();
 int
 main ()
 {
-return usb_get_busses ();
+return pthread_create ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_usb_usb_get_busses=yes
+  ac_cv_lib_pthread_pthread_create=yes
 else
-  ac_cv_lib_usb_usb_get_busses=no
+  ac_cv_lib_pthread_pthread_create=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_usb_get_busses" >&5
-$as_echo "$ac_cv_lib_usb_usb_get_busses" >&6; }
-if test "x$ac_cv_lib_usb_usb_get_busses" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_pthread_pthread_create" >&5
+$as_echo "$ac_cv_lib_pthread_pthread_create" >&6; }
+if test "x$ac_cv_lib_pthread_pthread_create" = xyes; then :
   dummy=yes
 else
-
-$as_echo "#define NEED_USB_GET_BUSSES 1" >>confdefs.h
-
+  as_fn_error $? "posix thread support is required" "$LINENO" 5
 fi
 
-       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for usb_interrupt_read in -lusb" >&5
-$as_echo_n "checking for usb_interrupt_read in -lusb... " >&6; }
-if ${ac_cv_lib_usb_usb_interrupt_read+:} false; then :
+
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for dlopen in -ldl" >&5
+$as_echo_n "checking for dlopen in -ldl... " >&6; }
+if ${ac_cv_lib_dl_dlopen+:} false; then :
   $as_echo_n "(cached) " >&6
 else
   ac_check_lib_save_LIBS=$LIBS
-LIBS="-lusb  $LIBS"
+LIBS="-ldl  $LIBS"
 cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 /* end confdefs.h.  */
 
@@ -12692,51 +12811,48 @@ cat confdefs.h - <<_ACEOF >conftest.$ac_ext
 #ifdef __cplusplus
 extern "C"
 #endif
-char usb_interrupt_read ();
+char dlopen ();
 int
 main ()
 {
-return usb_interrupt_read ();
+return dlopen ();
   ;
   return 0;
 }
 _ACEOF
 if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_usb_usb_interrupt_read=yes
+  ac_cv_lib_dl_dlopen=yes
 else
-  ac_cv_lib_usb_usb_interrupt_read=no
+  ac_cv_lib_dl_dlopen=no
 fi
 rm -f core conftest.err conftest.$ac_objext \
     conftest$ac_exeext conftest.$ac_ext
 LIBS=$ac_check_lib_save_LIBS
 fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_usb_usb_interrupt_read" >&5
-$as_echo "$ac_cv_lib_usb_usb_interrupt_read" >&6; }
-if test "x$ac_cv_lib_usb_usb_interrupt_read" = xyes; then :
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_dl_dlopen" >&5
+$as_echo "$ac_cv_lib_dl_dlopen" >&6; }
+if test "x$ac_cv_lib_dl_dlopen" = xyes; then :
   dummy=yes
 else
-
-$as_echo "#define NEED_USB_INTERRUPT_READ 1" >>confdefs.h
-
+  as_fn_error $? "dynamic linking loader is required" "$LINENO" 5
 fi
 
 
 
-
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UDEV" >&5
-$as_echo_n "checking for UDEV... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GLIB" >&5
+$as_echo_n "checking for GLIB... " >&6; }
 
-if test -n "$UDEV_CFLAGS"; then
-    pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS"
+if test -n "$GLIB_CFLAGS"; then
+    pkg_cv_GLIB_CFLAGS="$GLIB_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libudev") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev" 2>/dev/null`
+  pkg_cv_GLIB_CFLAGS=`$PKG_CONFIG --cflags "glib-2.0 >= 2.28" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
  else
     pkg_failed=untried
 fi
-if test -n "$UDEV_LIBS"; then
-    pkg_cv_UDEV_LIBS="$UDEV_LIBS"
+if test -n "$GLIB_LIBS"; then
+    pkg_cv_GLIB_LIBS="$GLIB_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "libudev") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"glib-2.0 >= 2.28\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "glib-2.0 >= 2.28") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev" 2>/dev/null`
+  pkg_cv_GLIB_LIBS=`$PKG_CONFIG --libs "glib-2.0 >= 2.28" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12774,44 +12890,47 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libudev" 2>&1`
+               GLIB_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1`
         else
-               UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libudev" 2>&1`
+               GLIB_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "glib-2.0 >= 2.28" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
-       echo "$UDEV_PKG_ERRORS" >&5
+       echo "$GLIB_PKG_ERRORS" >&5
 
-       udev_found=no
+       as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5
 elif test $pkg_failed = untried; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       udev_found=no
+       as_fn_error $? "GLib >= 2.28 is required" "$LINENO" 5
 else
-       UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS
-       UDEV_LIBS=$pkg_cv_UDEV_LIBS
+       GLIB_CFLAGS=$pkg_cv_GLIB_CFLAGS
+       GLIB_LIBS=$pkg_cv_GLIB_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-       udev_found=yes
+       dummy=yes
 fi
 
 
 
+if (test "${enable_threads}" = "yes"); then
+
+$as_echo "#define NEED_THREADS 1" >>confdefs.h
 
 
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for SNDFILE" >&5
-$as_echo_n "checking for SNDFILE... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for GTHREAD" >&5
+$as_echo_n "checking for GTHREAD... " >&6; }
 
-if test -n "$SNDFILE_CFLAGS"; then
-    pkg_cv_SNDFILE_CFLAGS="$SNDFILE_CFLAGS"
+if test -n "$GTHREAD_CFLAGS"; then
+    pkg_cv_GTHREAD_CFLAGS="$GTHREAD_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gthread-2.0 >= 2.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "gthread-2.0 >= 2.16") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_SNDFILE_CFLAGS=`$PKG_CONFIG --cflags "sndfile" 2>/dev/null`
+  pkg_cv_GTHREAD_CFLAGS=`$PKG_CONFIG --cflags "gthread-2.0 >= 2.16" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
  else
     pkg_failed=untried
 fi
-if test -n "$SNDFILE_LIBS"; then
-    pkg_cv_SNDFILE_LIBS="$SNDFILE_LIBS"
+if test -n "$GTHREAD_LIBS"; then
+    pkg_cv_GTHREAD_LIBS="$GTHREAD_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"sndfile\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "sndfile") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gthread-2.0 >= 2.16\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "gthread-2.0 >= 2.16") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_SNDFILE_LIBS=`$PKG_CONFIG --libs "sndfile" 2>/dev/null`
+  pkg_cv_GTHREAD_LIBS=`$PKG_CONFIG --libs "gthread-2.0 >= 2.16" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
@@ -12849,105 +12968,44 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               SNDFILE_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "sndfile" 2>&1`
+               GTHREAD_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "gthread-2.0 >= 2.16" 2>&1`
         else
-               SNDFILE_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "sndfile" 2>&1`
+               GTHREAD_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "gthread-2.0 >= 2.16" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
-       echo "$SNDFILE_PKG_ERRORS" >&5
+       echo "$GTHREAD_PKG_ERRORS" >&5
 
-       sndfile_found=no
+       as_fn_error $? "GThread >= 2.16 is required" "$LINENO" 5
 elif test $pkg_failed = untried; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       sndfile_found=no
+       as_fn_error $? "GThread >= 2.16 is required" "$LINENO" 5
 else
-       SNDFILE_CFLAGS=$pkg_cv_SNDFILE_CFLAGS
-       SNDFILE_LIBS=$pkg_cv_SNDFILE_LIBS
+       GTHREAD_CFLAGS=$pkg_cv_GTHREAD_CFLAGS
+       GTHREAD_LIBS=$pkg_cv_GTHREAD_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-       sndfile_found=yes
-fi
-
-
-
-
-
-# Check whether --with-ouifile was given.
-if test "${with_ouifile+set}" = set; then :
-  withval=$with_ouifile; ac_with_ouifile=$withval
-else
-  ac_with_ouifile="/var/lib/misc/oui.txt"
-fi
-
-
-cat >>confdefs.h <<_ACEOF
-#define OUIFILE "$ac_with_ouifile"
-_ACEOF
-
-
-
-       ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default"
-if test "x$ac_cv_header_readline_readline_h" = xyes; then :
-  { $as_echo "$as_me:${as_lineno-$LINENO}: checking for main in -lreadline" >&5
-$as_echo_n "checking for main in -lreadline... " >&6; }
-if ${ac_cv_lib_readline_main+:} false; then :
-  $as_echo_n "(cached) " >&6
-else
-  ac_check_lib_save_LIBS=$LIBS
-LIBS="-lreadline  $LIBS"
-cat confdefs.h - <<_ACEOF >conftest.$ac_ext
-/* end confdefs.h.  */
-
-
-int
-main ()
-{
-return main ();
-  ;
-  return 0;
-}
-_ACEOF
-if ac_fn_c_try_link "$LINENO"; then :
-  ac_cv_lib_readline_main=yes
-else
-  ac_cv_lib_readline_main=no
-fi
-rm -f core conftest.err conftest.$ac_objext \
-    conftest$ac_exeext conftest.$ac_ext
-LIBS=$ac_check_lib_save_LIBS
-fi
-{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_readline_main" >&5
-$as_echo "$ac_cv_lib_readline_main" >&6; }
-if test "x$ac_cv_lib_readline_main" = xyes; then :
-   readline_found=yes
-                       READLINE_LIBS="-lreadline"
-
-
-else
-  readline_found=no
+       dummy=yes
 fi
-
+       GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+       GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
 fi
 
 
-
-
-
 pkg_failed=no
-{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for CHECK" >&5
-$as_echo_n "checking for CHECK... " >&6; }
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for DBUS" >&5
+$as_echo_n "checking for DBUS... " >&6; }
 
-if test -n "$CHECK_CFLAGS"; then
-    pkg_cv_CHECK_CFLAGS="$CHECK_CFLAGS"
+if test -n "$DBUS_CFLAGS"; then
+    pkg_cv_DBUS_CFLAGS="$DBUS_CFLAGS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.6\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "check >= 0.9.6") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_CHECK_CFLAGS=`$PKG_CONFIG --cflags "check >= 0.9.6" 2>/dev/null`
+  pkg_cv_DBUS_CFLAGS=`$PKG_CONFIG --cflags "dbus-1 >= 1.4" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
  else
     pkg_failed=untried
 fi
-if test -n "$CHECK_LIBS"; then
-    pkg_cv_CHECK_LIBS="$CHECK_LIBS"
+if test -n "$DBUS_LIBS"; then
+    pkg_cv_DBUS_LIBS="$DBUS_LIBS"
  elif test -n "$PKG_CONFIG"; then
     if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"check >= 0.9.6\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "check >= 0.9.6") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"dbus-1 >= 1.4\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "dbus-1 >= 1.4") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_CHECK_LIBS=`$PKG_CONFIG --libs "check >= 0.9.6" 2>/dev/null`
+  pkg_cv_DBUS_LIBS=`$PKG_CONFIG --libs "dbus-1 >= 1.4" 2>/dev/null`
                      test "x$?" != "x0" && pkg_failed=yes
 else
   pkg_failed=yes
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-               CHECK_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "check >= 0.9.6" 2>&1`
+               DBUS_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1`
         else
-               CHECK_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "check >= 0.9.6" 2>&1`
+               DBUS_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "dbus-1 >= 1.4" 2>&1`
         fi
        # Put the nasty error message in config.log where it belongs
-       echo "$CHECK_PKG_ERRORS" >&5
+       echo "$DBUS_PKG_ERRORS" >&5
 
-       check_found=no
+       as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5
 elif test $pkg_failed = untried; then
        { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
 $as_echo "no" >&6; }
-       check_found=no
+       as_fn_error $? "D-Bus >= 1.4 is required" "$LINENO" 5
 else
-       CHECK_CFLAGS=$pkg_cv_CHECK_CFLAGS
-       CHECK_LIBS=$pkg_cv_CHECK_LIBS
+       DBUS_CFLAGS=$pkg_cv_DBUS_CFLAGS
+       DBUS_LIBS=$pkg_cv_DBUS_LIBS
         { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
 $as_echo "yes" >&6; }
-       check_found=yes
-fi
-
-
-
-
-
-       debug_enable=no
-       optimization_enable=yes
-       fortify_enable=yes
-       pie_enable=yes
-       sndfile_enable=${sndfile_found}
-       hal_enable=no
-       usb_enable=${usb_found}
-       alsa_enable=${alsa_found}
-       gstreamer_enable=${gstreamer_found}
-       audio_enable=yes
-       input_enable=yes
-       serial_enable=yes
-       network_enable=yes
-       sap_enable=no
-       service_enable=yes
-       health_enable=no
-       pnat_enable=no
-       tools_enable=yes
-       hidd_enable=no
-       pand_enable=no
-       dund_enable=no
-       cups_enable=no
-       test_enable=no
-       bccmd_enable=no
-       pcmcia_enable=no
-       hid2hci_enable=no
-       dfutool_enable=no
-       datafiles_enable=yes
-       telephony_driver=dummy
-       maemo6_enable=no
-       sap_driver=dummy
-       dbusoob_enable=no
-       wiimote_enable=no
-       gatt_enable=no
-
-       # Check whether --enable-optimization was given.
-if test "${enable_optimization+set}" = set; then :
-  enableval=$enable_optimization;
-               optimization_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-fortify was given.
-if test "${enable_fortify+set}" = set; then :
-  enableval=$enable_fortify;
-               fortify_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-pie was given.
-if test "${enable_pie+set}" = set; then :
-  enableval=$enable_pie;
-               pie_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-network was given.
-if test "${enable_network+set}" = set; then :
-  enableval=$enable_network;
-               network_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-sap was given.
-if test "${enable_sap+set}" = set; then :
-  enableval=$enable_sap;
-               sap_enable=${enableval}
-
+       dummy=yes
 fi
 
 
 
-# Check whether --with-sap was given.
-if test "${with_sap+set}" = set; then :
-  withval=$with_sap;
-               sap_driver=${withval}
 
+# Check whether --with-dbusconfdir was given.
+if test "${with_dbusconfdir+set}" = set; then :
+  withval=$with_dbusconfdir; path_dbusconfdir=${withval}
 fi
 
-       SAP_DRIVER=sap-${sap_driver}.c
-
-
-       # Check whether --enable-serial was given.
-if test "${enable_serial+set}" = set; then :
-  enableval=$enable_serial;
-               serial_enable=${enableval}
-
+if (test -z "${path_dbusconfdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking D-Bus configuration directory" >&5
+$as_echo_n "checking D-Bus configuration directory... " >&6; }
+       path_dbusconfdir="`$PKG_CONFIG --variable=sysconfdir dbus-1`"
+       if (test -z "${path_dbusconfdir}"); then
+               as_fn_error $? "D-Bus configuration directory is required" "$LINENO" 5
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_dbusconfdir}" >&5
+$as_echo "${path_dbusconfdir}" >&6; }
 fi
+DBUS_CONFDIR=${path_dbusconfdir}
 
 
-       # Check whether --enable-input was given.
-if test "${enable_input+set}" = set; then :
-  enableval=$enable_input;
-               input_enable=${enableval}
 
+# Check whether --with-dbussystembusdir was given.
+if test "${with_dbussystembusdir+set}" = set; then :
+  withval=$with_dbussystembusdir; path_dbussystembusdir=${withval}
 fi
 
-
-       # Check whether --enable-audio was given.
-if test "${enable_audio+set}" = set; then :
-  enableval=$enable_audio;
-               audio_enable=${enableval}
-
+if (test -z "${path_dbussystembusdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking D-Bus system bus services dir" >&5
+$as_echo_n "checking D-Bus system bus services dir... " >&6; }
+       path_dbussystembusdir="`$PKG_CONFIG --variable=system_bus_services_dir dbus-1`"
+       if (test -z "${path_dbussystembusdir}"); then
+               as_fn_error $? "D-Bus system bus services directory is required" "$LINENO" 5
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_dbussystembusdir}" >&5
+$as_echo "${path_dbussystembusdir}" >&6; }
 fi
+DBUS_SYSTEMBUSDIR=${path_dbussystembusdir}
 
 
-       # Check whether --enable-service was given.
-if test "${enable_service+set}" = set; then :
-  enableval=$enable_service;
-               service_enable=${enableval}
 
+# Check whether --with-dbussessionbusdir was given.
+if test "${with_dbussessionbusdir+set}" = set; then :
+  withval=$with_dbussessionbusdir; path_dbussessionbusdir=${withval}
 fi
 
-
-       # Check whether --enable-health was given.
-if test "${enable_health+set}" = set; then :
-  enableval=$enable_health;
-               health_enable=${enableval}
-
+if (test -z "${path_dbussessionbusdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking D-Bus session bus services dir" >&5
+$as_echo_n "checking D-Bus session bus services dir... " >&6; }
+       path_dbussessionbusdir="`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`"
+       if (test -z "${path_dbussessionbusdir}"); then
+               as_fn_error $? "D-Bus session bus services directory is required" "$LINENO" 5
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_dbussessionbusdir}" >&5
+$as_echo "${path_dbussessionbusdir}" >&6; }
 fi
+DBUS_SESSIONBUSDIR=${path_dbussessionbusdir}
 
 
-       # Check whether --enable-pnat was given.
-if test "${enable_pnat+set}" = set; then :
-  enableval=$enable_pnat;
-               pnat_enable=${enableval}
-
+# Check whether --enable-library was given.
+if test "${enable_library+set}" = set; then :
+  enableval=$enable_library; enable_library=${enableval}
 fi
 
-
-       # Check whether --enable-gstreamer was given.
-if test "${enable_gstreamer+set}" = set; then :
-  enableval=$enable_gstreamer;
-               gstreamer_enable=${enableval}
-
+ if test "${enable_library}" = "yes"; then
+  LIBRARY_TRUE=
+  LIBRARY_FALSE='#'
+else
+  LIBRARY_TRUE='#'
+  LIBRARY_FALSE=
 fi
 
 
-       # Check whether --enable-alsa was given.
-if test "${enable_alsa+set}" = set; then :
-  enableval=$enable_alsa;
-               alsa_enable=${enableval}
-
+# Check whether --enable-test was given.
+if test "${enable_test+set}" = set; then :
+  enableval=$enable_test; enable_test=${enableval}
 fi
 
-
-       # Check whether --enable-usb was given.
-if test "${enable_usb+set}" = set; then :
-  enableval=$enable_usb;
-               usb_enable=${enableval}
-
+ if test "${enable_test}" = "yes"; then
+  TEST_TRUE=
+  TEST_FALSE='#'
+else
+  TEST_TRUE='#'
+  TEST_FALSE=
 fi
 
 
-       # Check whether --enable-tools was given.
+# Check whether --enable-tools was given.
 if test "${enable_tools+set}" = set; then :
-  enableval=$enable_tools;
-               tools_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-bccmd was given.
-if test "${enable_bccmd+set}" = set; then :
-  enableval=$enable_bccmd;
-               bccmd_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-pcmcia was given.
-if test "${enable_pcmcia+set}" = set; then :
-  enableval=$enable_pcmcia;
-               pcmcia_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-hid2hci was given.
-if test "${enable_hid2hci+set}" = set; then :
-  enableval=$enable_hid2hci;
-               hid2hci_enable=${enableval}
-
-fi
-
-
-       # Check whether --enable-dfutool was given.
-if test "${enable_dfutool+set}" = set; then :
-  enableval=$enable_dfutool;
-               dfutool_enable=${enableval}
-
+  enableval=$enable_tools; enable_tools=${enableval}
 fi
 
-
-       # Check whether --enable-hidd was given.
-if test "${enable_hidd+set}" = set; then :
-  enableval=$enable_hidd;
-               hidd_enable=${enableval}
-
+ if test "${enable_tools}" != "no"; then
+  TOOLS_TRUE=
+  TOOLS_FALSE='#'
+else
+  TOOLS_TRUE='#'
+  TOOLS_FALSE=
 fi
 
 
-       # Check whether --enable-pand was given.
-if test "${enable_pand+set}" = set; then :
-  enableval=$enable_pand;
-               pand_enable=${enableval}
-
+# Check whether --enable-monitor was given.
+if test "${enable_monitor+set}" = set; then :
+  enableval=$enable_monitor; enable_monitor=${enableval}
 fi
 
-
-       # Check whether --enable-dund was given.
-if test "${enable_dund+set}" = set; then :
-  enableval=$enable_dund;
-               dund_enable=${enableval}
-
+ if test "${enable_monitor}" != "no"; then
+  MONITOR_TRUE=
+  MONITOR_FALSE='#'
+else
+  MONITOR_TRUE='#'
+  MONITOR_FALSE=
 fi
 
 
-       # Check whether --enable-cups was given.
-if test "${enable_cups+set}" = set; then :
-  enableval=$enable_cups;
-               cups_enable=${enableval}
-
+# Check whether --enable-udev was given.
+if test "${enable_udev+set}" = set; then :
+  enableval=$enable_udev; enable_udev=${enableval}
 fi
 
+if (test "${enable_tools}" != "no" && test "${enable_udev}" != "no"); then
 
-       # Check whether --enable-test was given.
-if test "${enable_test+set}" = set; then :
-  enableval=$enable_test;
-               test_enable=${enableval}
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for UDEV" >&5
+$as_echo_n "checking for UDEV... " >&6; }
 
+if test -n "$UDEV_CFLAGS"; then
+    pkg_cv_UDEV_CFLAGS="$UDEV_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UDEV_CFLAGS=`$PKG_CONFIG --cflags "libudev >= 143" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
 fi
-
-
-       # Check whether --enable-datafiles was given.
-if test "${enable_datafiles+set}" = set; then :
-  enableval=$enable_datafiles;
-               datafiles_enable=${enableval}
-
+ else
+    pkg_failed=untried
 fi
-
-
-       # Check whether --enable-debug was given.
-if test "${enable_debug+set}" = set; then :
-  enableval=$enable_debug;
-               debug_enable=${enableval}
-
+if test -n "$UDEV_LIBS"; then
+    pkg_cv_UDEV_LIBS="$UDEV_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libudev >= 143\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libudev >= 143") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_UDEV_LIBS=`$PKG_CONFIG --libs "libudev >= 143" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
+else
+  pkg_failed=yes
 fi
-
-
-
-# Check whether --with-telephony was given.
-if test "${with_telephony+set}" = set; then :
-  withval=$with_telephony;
-               telephony_driver=${withval}
-
+ else
+    pkg_failed=untried
 fi
 
 
-       TELEPHONY_DRIVER=telephony-${telephony_driver}.c
 
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-       # Check whether --enable-maemo6 was given.
-if test "${enable_maemo6+set}" = set; then :
-  enableval=$enable_maemo6;
-               maemo6_enable=${enableval}
-
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
+else
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               UDEV_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libudev >= 143" 2>&1`
+        else
+               UDEV_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libudev >= 143" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$UDEV_PKG_ERRORS" >&5
 
-
-       # Check whether --enable-dbusoob was given.
-if test "${enable_dbusoob+set}" = set; then :
-  enableval=$enable_dbusoob;
-               dbusoob_enable=${enableval}
-
+       as_fn_error $? "libudev >= 143 is required" "$LINENO" 5
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       as_fn_error $? "libudev >= 143 is required" "$LINENO" 5
+else
+       UDEV_CFLAGS=$pkg_cv_UDEV_CFLAGS
+       UDEV_LIBS=$pkg_cv_UDEV_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       dummy=yes
 fi
 
 
-       # Check whether --enable-wiimote was given.
-if test "${enable_wiimote+set}" = set; then :
-  enableval=$enable_wiimote;
-               wiimote_enable=${enableval}
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking for udev_hwdb_new in -ludev" >&5
+$as_echo_n "checking for udev_hwdb_new in -ludev... " >&6; }
+if ${ac_cv_lib_udev_udev_hwdb_new+:} false; then :
+  $as_echo_n "(cached) " >&6
+else
+  ac_check_lib_save_LIBS=$LIBS
+LIBS="-ludev  $LIBS"
+cat confdefs.h - <<_ACEOF >conftest.$ac_ext
+/* end confdefs.h.  */
 
+/* Override any GCC internal prototype to avoid an error.
+   Use char because int might match the return type of a GCC
+   builtin and then its argument prototype would still apply.  */
+#ifdef __cplusplus
+extern "C"
+#endif
+char udev_hwdb_new ();
+int
+main ()
+{
+return udev_hwdb_new ();
+  ;
+  return 0;
+}
+_ACEOF
+if ac_fn_c_try_link "$LINENO"; then :
+  ac_cv_lib_udev_udev_hwdb_new=yes
+else
+  ac_cv_lib_udev_udev_hwdb_new=no
+fi
+rm -f core conftest.err conftest.$ac_objext \
+    conftest$ac_exeext conftest.$ac_ext
+LIBS=$ac_check_lib_save_LIBS
 fi
+{ $as_echo "$as_me:${as_lineno-$LINENO}: result: $ac_cv_lib_udev_udev_hwdb_new" >&5
+$as_echo "$ac_cv_lib_udev_udev_hwdb_new" >&6; }
+if test "x$ac_cv_lib_udev_udev_hwdb_new" = xyes; then :
 
+$as_echo "#define HAVE_UDEV_HWDB_NEW 1" >>confdefs.h
 
-       # Check whether --enable-hal was given.
-if test "${enable_hal+set}" = set; then :
-  enableval=$enable_hal;
-               hal_enable=${enableval}
+fi
 
 fi
+ if test "${enable_udev}" != "no"; then
+  UDEV_TRUE=
+  UDEV_FALSE='#'
+else
+  UDEV_TRUE='#'
+  UDEV_FALSE=
+fi
 
 
-       # Check whether --enable-gatt was given.
-if test "${enable_gatt+set}" = set; then :
-  enableval=$enable_gatt;
-               gatt_enable=${enableval}
 
+# Check whether --with-udevdir was given.
+if test "${with_udevdir+set}" = set; then :
+  withval=$with_udevdir; path_udevdir=${withval}
 fi
 
-
-       misc_cflags=""
-       misc_ldflags=""
-
-       if (test "${fortify_enable}" = "yes"); then
-               misc_cflags="$misc_cflags -D_FORTIFY_SOURCE=2"
+if (test "${enable_udev}" != "no" && test -z "${path_udevdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking udev directory" >&5
+$as_echo_n "checking udev directory... " >&6; }
+       path_udevdir="`$PKG_CONFIG --variable=udevdir udev`"
+       if (test -z "${path_udevdir}"); then
+               as_fn_error $? "udev directory is required" "$LINENO" 5
        fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_udevdir}" >&5
+$as_echo "${path_udevdir}" >&6; }
+fi
+UDEV_DIR=${path_udevdir}
 
-       if (test "${pie_enable}" = "yes" && test "${ac_cv_prog_cc_pie}" = "yes"); then
-               misc_cflags="$misc_cflags -fPIC"
-               misc_ldflags="$misc_ldflags -pie"
-       fi
 
-       if (test "${debug_enable}" = "yes" && test "${ac_cv_prog_cc_g}" = "yes"); then
-               misc_cflags="$misc_cflags -g"
-       fi
+ if test "${enable_tools}" != "no" &&
+                                               test "${enable_udev}" != "no"; then
+  HID2HCI_TRUE=
+  HID2HCI_FALSE='#'
+else
+  HID2HCI_TRUE='#'
+  HID2HCI_FALSE=
+fi
 
-       if (test "${optimization_enable}" = "no"); then
-               misc_cflags="$misc_cflags -O0"
-       fi
 
-       MISC_CFLAGS=$misc_cflags
+# Check whether --enable-cups was given.
+if test "${enable_cups+set}" = set; then :
+  enableval=$enable_cups; enable_cups=${enableval}
+fi
 
-       MISC_LDFLAGS=$misc_ldflags
+ if test "${enable_cups}" != "no"; then
+  CUPS_TRUE=
+  CUPS_FALSE='#'
+else
+  CUPS_TRUE='#'
+  CUPS_FALSE=
+fi
 
 
-       if (test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"); then
+# Check whether --enable-obex was given.
+if test "${enable_obex+set}" = set; then :
+  enableval=$enable_obex; enable_obex=${enableval}
+fi
 
-$as_echo "#define HAVE_LIBUSB 1" >>confdefs.h
+if (test "${enable_obex}" != "no"); then
 
-       fi
+pkg_failed=no
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for ICAL" >&5
+$as_echo_n "checking for ICAL... " >&6; }
 
-        if test "${sndfile_enable}" = "yes" && test "${sndfile_found}" = "yes"; then
-  SNDFILE_TRUE=
-  SNDFILE_FALSE='#'
+if test -n "$ICAL_CFLAGS"; then
+    pkg_cv_ICAL_CFLAGS="$ICAL_CFLAGS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libical\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libical") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ICAL_CFLAGS=`$PKG_CONFIG --cflags "libical" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
 else
-  SNDFILE_TRUE='#'
-  SNDFILE_FALSE=
+  pkg_failed=yes
 fi
-
-        if test "${usb_enable}" = "yes" && test "${usb_found}" = "yes"; then
-  USB_TRUE=
-  USB_FALSE='#'
-else
-  USB_TRUE='#'
-  USB_FALSE=
+ else
+    pkg_failed=untried
 fi
-
-        if test "${alsa_enable}" = "yes" || test "${gstreamer_enable}" = "yes" ||
-                                                                       test "${test_enable}" = "yes"; then
-  SBC_TRUE=
-  SBC_FALSE='#'
+if test -n "$ICAL_LIBS"; then
+    pkg_cv_ICAL_LIBS="$ICAL_LIBS"
+ elif test -n "$PKG_CONFIG"; then
+    if test -n "$PKG_CONFIG" && \
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"libical\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "libical") 2>&5
+  ac_status=$?
+  $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
+  test $ac_status = 0; }; then
+  pkg_cv_ICAL_LIBS=`$PKG_CONFIG --libs "libical" 2>/dev/null`
+                     test "x$?" != "x0" && pkg_failed=yes
 else
-  SBC_TRUE='#'
-  SBC_FALSE=
+  pkg_failed=yes
 fi
-
-        if test "${alsa_enable}" = "yes" && test "${alsa_found}" = "yes"; then
-  ALSA_TRUE=
-  ALSA_FALSE='#'
-else
-  ALSA_TRUE='#'
-  ALSA_FALSE=
+ else
+    pkg_failed=untried
 fi
 
-        if test "${gstreamer_enable}" = "yes" && test "${gstreamer_found}" = "yes"; then
-  GSTREAMER_TRUE=
-  GSTREAMER_FALSE='#'
-else
-  GSTREAMER_TRUE='#'
-  GSTREAMER_FALSE=
-fi
 
-        if test "${audio_enable}" = "yes"; then
-  AUDIOPLUGIN_TRUE=
-  AUDIOPLUGIN_FALSE='#'
-else
-  AUDIOPLUGIN_TRUE='#'
-  AUDIOPLUGIN_FALSE=
-fi
 
-        if test "${input_enable}" = "yes"; then
-  INPUTPLUGIN_TRUE=
-  INPUTPLUGIN_FALSE='#'
-else
-  INPUTPLUGIN_TRUE='#'
-  INPUTPLUGIN_FALSE=
-fi
+if test $pkg_failed = yes; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
 
-        if test "${serial_enable}" = "yes"; then
-  SERIALPLUGIN_TRUE=
-  SERIALPLUGIN_FALSE='#'
+if $PKG_CONFIG --atleast-pkgconfig-version 0.20; then
+        _pkg_short_errors_supported=yes
 else
-  SERIALPLUGIN_TRUE='#'
-  SERIALPLUGIN_FALSE=
+        _pkg_short_errors_supported=no
 fi
+        if test $_pkg_short_errors_supported = yes; then
+               ICAL_PKG_ERRORS=`$PKG_CONFIG --short-errors --print-errors --cflags --libs "libical" 2>&1`
+        else
+               ICAL_PKG_ERRORS=`$PKG_CONFIG --print-errors --cflags --libs "libical" 2>&1`
+        fi
+       # Put the nasty error message in config.log where it belongs
+       echo "$ICAL_PKG_ERRORS" >&5
 
-        if test "${network_enable}" = "yes"; then
-  NETWORKPLUGIN_TRUE=
-  NETWORKPLUGIN_FALSE='#'
+       as_fn_error $? "libical is required" "$LINENO" 5
+elif test $pkg_failed = untried; then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+       as_fn_error $? "libical is required" "$LINENO" 5
 else
-  NETWORKPLUGIN_TRUE='#'
-  NETWORKPLUGIN_FALSE=
+       ICAL_CFLAGS=$pkg_cv_ICAL_CFLAGS
+       ICAL_LIBS=$pkg_cv_ICAL_LIBS
+        { $as_echo "$as_me:${as_lineno-$LINENO}: result: yes" >&5
+$as_echo "yes" >&6; }
+       dummy=yes
 fi
 
-        if test "${sap_enable}" = "yes"; then
-  SAPPLUGIN_TRUE=
-  SAPPLUGIN_FALSE='#'
-else
-  SAPPLUGIN_TRUE='#'
-  SAPPLUGIN_FALSE=
-fi
 
-        if test "${service_enable}" = "yes"; then
-  SERVICEPLUGIN_TRUE=
-  SERVICEPLUGIN_FALSE='#'
+fi
+ if test "${enable_obex}" != "no"; then
+  OBEX_TRUE=
+  OBEX_FALSE='#'
 else
-  SERVICEPLUGIN_TRUE='#'
-  SERVICEPLUGIN_FALSE=
+  OBEX_TRUE='#'
+  OBEX_FALSE=
 fi
 
-        if test "${health_enable}" = "yes"; then
-  HEALTHPLUGIN_TRUE=
-  HEALTHPLUGIN_FALSE='#'
-else
-  HEALTHPLUGIN_TRUE='#'
-  HEALTHPLUGIN_FALSE=
+
+# Check whether --enable-client was given.
+if test "${enable_client+set}" = set; then :
+  enableval=$enable_client; enable_client=${enableval}
 fi
 
       if test "${health_enable}" = "yes"; then
-  MCAP_TRUE=
-  MCAP_FALSE='#'
if test "${enable_client}" != "no"; then
+  CLIENT_TRUE=
+  CLIENT_FALSE='#'
 else
-  MCAP_TRUE='#'
-  MCAP_FALSE=
+  CLIENT_TRUE='#'
+  CLIENT_FALSE=
 fi
 
-        if test "${hal_enable}" = "yes"; then
-  HAL_TRUE=
-  HAL_FALSE='#'
+
+if (test "${enable_client}" != "no"); then
+        for ac_header in readline/readline.h
+do :
+  ac_fn_c_check_header_mongrel "$LINENO" "readline/readline.h" "ac_cv_header_readline_readline_h" "$ac_includes_default"
+if test "x$ac_cv_header_readline_readline_h" = xyes; then :
+  cat >>confdefs.h <<_ACEOF
+#define HAVE_READLINE_READLINE_H 1
+_ACEOF
+ enable_readline=yes
 else
-  HAL_TRUE='#'
-  HAL_FALSE=
+  as_fn_error $? "readline header files are required" "$LINENO" 5
 fi
 
-        if test "${readline_found}" = "yes"; then
+done
+
+fi
+ if test "${enable_readline}" = "yes"; then
   READLINE_TRUE=
   READLINE_FALSE='#'
 else
@@ -13467,95 +13479,65 @@ else
   READLINE_FALSE=
 fi
 
-        if test "${pnat_enable}" = "yes"; then
-  PNATPLUGIN_TRUE=
-  PNATPLUGIN_FALSE='#'
-else
-  PNATPLUGIN_TRUE='#'
-  PNATPLUGIN_FALSE=
-fi
 
-        if test "${hidd_enable}" = "yes"; then
-  HIDD_TRUE=
-  HIDD_FALSE='#'
-else
-  HIDD_TRUE='#'
-  HIDD_FALSE=
+# Check whether --enable-systemd was given.
+if test "${enable_systemd+set}" = set; then :
+  enableval=$enable_systemd; enable_systemd=${enableval}
 fi
 
       if test "${pand_enable}" = "yes"; then
-  PAND_TRUE=
-  PAND_FALSE='#'
if test "${enable_systemd}" != "no"; then
+  SYSTEMD_TRUE=
+  SYSTEMD_FALSE='#'
 else
-  PAND_TRUE='#'
-  PAND_FALSE=
+  SYSTEMD_TRUE='#'
+  SYSTEMD_FALSE=
 fi
 
-        if test "${dund_enable}" = "yes"; then
-  DUND_TRUE=
-  DUND_FALSE='#'
-else
-  DUND_TRUE='#'
-  DUND_FALSE=
-fi
 
-        if test "${cups_enable}" = "yes"; then
-  CUPS_TRUE=
-  CUPS_FALSE='#'
-else
-  CUPS_TRUE='#'
-  CUPS_FALSE=
-fi
 
-        if test "${test_enable}" = "yes" && test "${check_found}" = "yes"; then
-  TEST_TRUE=
-  TEST_FALSE='#'
-else
-  TEST_TRUE='#'
-  TEST_FALSE=
+# Check whether --with-systemdsystemunitdir was given.
+if test "${with_systemdsystemunitdir+set}" = set; then :
+  withval=$with_systemdsystemunitdir; path_systemunitdir=${withval}
 fi
 
-        if test "${tools_enable}" = "yes"; then
-  TOOLS_TRUE=
-  TOOLS_FALSE='#'
-else
-  TOOLS_TRUE='#'
-  TOOLS_FALSE=
+if (test "${enable_systemd}" != "no" && test -z "${path_systemunitdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking systemd system unit dir" >&5
+$as_echo_n "checking systemd system unit dir... " >&6; }
+       path_systemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"
+       if (test -z "${path_systemunitdir}"); then
+               as_fn_error $? "systemd system unit directory is required" "$LINENO" 5
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_systemunitdir}" >&5
+$as_echo "${path_systemunitdir}" >&6; }
 fi
+SYSTEMD_SYSTEMUNITDIR=${path_systemunitdir}
 
-        if test "${bccmd_enable}" = "yes"; then
-  BCCMD_TRUE=
-  BCCMD_FALSE='#'
-else
-  BCCMD_TRUE='#'
-  BCCMD_FALSE=
-fi
 
-        if test "${pcmcia_enable}" = "yes"; then
-  PCMCIA_TRUE=
-  PCMCIA_FALSE='#'
-else
-  PCMCIA_TRUE='#'
-  PCMCIA_FALSE=
+
+# Check whether --with-systemduserunitdir was given.
+if test "${with_systemduserunitdir+set}" = set; then :
+  withval=$with_systemduserunitdir; path_userunitdir=${withval}
 fi
 
-        if test "${hid2hci_enable}" = "yes" && test "${usb_found}" = "yes" && test "${udev_found}" = "yes"; then
-  HID2HCI_TRUE=
-  HID2HCI_FALSE='#'
-else
-  HID2HCI_TRUE='#'
-  HID2HCI_FALSE=
+if (test "${enable_systemd}" != "no" && test -z "${path_userunitdir}"); then
+       { $as_echo "$as_me:${as_lineno-$LINENO}: checking systemd user unit dir" >&5
+$as_echo_n "checking systemd user unit dir... " >&6; }
+       path_userunitdir="`$PKG_CONFIG --variable=systemduserunitdir systemd`"
+       if (test -z "${path_userunitdir}"); then
+               as_fn_error $? "systemd user unit directory is required" "$LINENO" 5
+       fi
+       { $as_echo "$as_me:${as_lineno-$LINENO}: result: ${path_userunitdir}" >&5
+$as_echo "${path_userunitdir}" >&6; }
 fi
+SYSTEMD_USERUNITDIR=${path_userunitdir}
 
-        if test "${dfutool_enable}" = "yes" && test "${usb_found}" = "yes"; then
-  DFUTOOL_TRUE=
-  DFUTOOL_FALSE='#'
-else
-  DFUTOOL_TRUE='#'
-  DFUTOOL_FALSE=
+
+# Check whether --enable-datafiles was given.
+if test "${enable_datafiles+set}" = set; then :
+  enableval=$enable_datafiles; enable_datafiles=${enableval}
 fi
 
       if test "${datafiles_enable}" = "yes"; then
if test "${enable_datafiles}" != "no"; then
   DATAFILES_TRUE=
   DATAFILES_FALSE='#'
 else
@@ -13563,62 +13545,69 @@ else
   DATAFILES_FALSE=
 fi
 
-        if test "${maemo6_enable}" = "yes"; then
-  MAEMO6PLUGIN_TRUE=
-  MAEMO6PLUGIN_FALSE='#'
-else
-  MAEMO6PLUGIN_TRUE='#'
-  MAEMO6PLUGIN_FALSE=
+
+# Check whether --enable-experimental was given.
+if test "${enable_experimental+set}" = set; then :
+  enableval=$enable_experimental; enable_experimental=${enableval}
 fi
 
       if test "${dbusoob_enable}" = "yes"; then
-  DBUSOOBPLUGIN_TRUE=
-  DBUSOOBPLUGIN_FALSE='#'
if test "${enable_experimental}" = "yes"; then
+  EXPERIMENTAL_TRUE=
+  EXPERIMENTAL_FALSE='#'
 else
-  DBUSOOBPLUGIN_TRUE='#'
-  DBUSOOBPLUGIN_FALSE=
+  EXPERIMENTAL_TRUE='#'
+  EXPERIMENTAL_FALSE=
 fi
 
-        if test "${wiimote_enable}" = "yes"; then
-  WIIMOTEPLUGIN_TRUE=
-  WIIMOTEPLUGIN_FALSE='#'
-else
-  WIIMOTEPLUGIN_TRUE='#'
-  WIIMOTEPLUGIN_FALSE=
+
+if (test "${prefix}" = "NONE"); then
+               if (test "$localstatedir" = '${prefix}/var'); then
+               localstatedir='/var'
+
+       fi
+
+       prefix="${ac_default_prefix}"
 fi
 
-        if test "${gatt_enable}" = "yes"; then
-  GATTMODULES_TRUE=
-  GATTMODULES_FALSE='#'
+if (test "$localstatedir" = '${prefix}/var'); then
+       storagedir="${prefix}/var/lib/bluetooth"
 else
-  GATTMODULES_TRUE='#'
-  GATTMODULES_FALSE=
+       storagedir="${localstatedir}/lib/bluetooth"
 fi
 
+cat >>confdefs.h <<_ACEOF
+#define STORAGEDIR "${storagedir}"
+_ACEOF
 
 
-
-# Check whether --with-systemdunitdir was given.
-if test "${with_systemdunitdir+set}" = set; then :
-  withval=$with_systemdunitdir; path_systemdunit=${withval}
+if (test "$sysconfdir" = '${prefix}/etc'); then
+       configdir="${prefix}/etc/bluetooth"
 else
-  path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"
+       configdir="${sysconfdir}/bluetooth"
 fi
 
-if (test -n "${path_systemdunit}"); then
-       SYSTEMD_UNITDIR="${path_systemdunit}"
+cat >>confdefs.h <<_ACEOF
+#define CONFIGDIR "${configdir}"
+_ACEOF
+
+CONFIGDIR="${configdir}"
 
+
+# Check whether --enable-android was given.
+if test "${enable_android+set}" = set; then :
+  enableval=$enable_android; enable_android=${enableval}
 fi
- if test -n "${path_systemdunit}"; then
-  SYSTEMD_TRUE=
-  SYSTEMD_FALSE='#'
+
+ if test "${enable_android}" = "yes"; then
+  ANDROID_TRUE=
+  ANDROID_FALSE='#'
 else
-  SYSTEMD_TRUE='#'
-  SYSTEMD_FALSE=
+  ANDROID_TRUE='#'
+  ANDROID_FALSE=
 fi
 
 
-ac_config_files="$ac_config_files Makefile doc/version.xml src/bluetoothd.8 src/bluetooth.service bluez.pc"
+ac_config_files="$ac_config_files Makefile src/bluetoothd.8 lib/bluez.pc"
 
 cat >confcache <<\_ACEOF
 # This file is a shell script that caches the results of configure
@@ -13737,10 +13726,6 @@ else
   am__EXEEXT_FALSE=
 fi
 
-if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
-  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
 if test -z "${AMDEP_TRUE}" && test -z "${AMDEP_FALSE}"; then
   as_fn_error $? "conditional \"AMDEP\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
@@ -13749,84 +13734,16 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
   as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${SNDFILE_TRUE}" && test -z "${SNDFILE_FALSE}"; then
-  as_fn_error $? "conditional \"SNDFILE\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${USB_TRUE}" && test -z "${USB_FALSE}"; then
-  as_fn_error $? "conditional \"USB\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${SBC_TRUE}" && test -z "${SBC_FALSE}"; then
-  as_fn_error $? "conditional \"SBC\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${ALSA_TRUE}" && test -z "${ALSA_FALSE}"; then
-  as_fn_error $? "conditional \"ALSA\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${GSTREAMER_TRUE}" && test -z "${GSTREAMER_FALSE}"; then
-  as_fn_error $? "conditional \"GSTREAMER\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${AUDIOPLUGIN_TRUE}" && test -z "${AUDIOPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"AUDIOPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${INPUTPLUGIN_TRUE}" && test -z "${INPUTPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"INPUTPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${SERIALPLUGIN_TRUE}" && test -z "${SERIALPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"SERIALPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${NETWORKPLUGIN_TRUE}" && test -z "${NETWORKPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"NETWORKPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${SAPPLUGIN_TRUE}" && test -z "${SAPPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"SAPPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${SERVICEPLUGIN_TRUE}" && test -z "${SERVICEPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"SERVICEPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${HEALTHPLUGIN_TRUE}" && test -z "${HEALTHPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"HEALTHPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${MCAP_TRUE}" && test -z "${MCAP_FALSE}"; then
-  as_fn_error $? "conditional \"MCAP\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${HAL_TRUE}" && test -z "${HAL_FALSE}"; then
-  as_fn_error $? "conditional \"HAL\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${READLINE_TRUE}" && test -z "${READLINE_FALSE}"; then
-  as_fn_error $? "conditional \"READLINE\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${PNATPLUGIN_TRUE}" && test -z "${PNATPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"PNATPLUGIN\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${HIDD_TRUE}" && test -z "${HIDD_FALSE}"; then
-  as_fn_error $? "conditional \"HIDD\" was never defined.
-Usually this means the macro was only invoked conditionally." "$LINENO" 5
-fi
-if test -z "${PAND_TRUE}" && test -z "${PAND_FALSE}"; then
-  as_fn_error $? "conditional \"PAND\" was never defined.
+if test -z "${MAINTAINER_MODE_TRUE}" && test -z "${MAINTAINER_MODE_FALSE}"; then
+  as_fn_error $? "conditional \"MAINTAINER_MODE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${DUND_TRUE}" && test -z "${DUND_FALSE}"; then
-  as_fn_error $? "conditional \"DUND\" was never defined.
+if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
+  as_fn_error $? "conditional \"am__fastdepCC\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${CUPS_TRUE}" && test -z "${CUPS_FALSE}"; then
-  as_fn_error $? "conditional \"CUPS\" was never defined.
+if test -z "${LIBRARY_TRUE}" && test -z "${LIBRARY_FALSE}"; then
+  as_fn_error $? "conditional \"LIBRARY\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 if test -z "${TEST_TRUE}" && test -z "${TEST_FALSE}"; then
@@ -13837,44 +13754,48 @@ if test -z "${TOOLS_TRUE}" && test -z "${TOOLS_FALSE}"; then
   as_fn_error $? "conditional \"TOOLS\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${BCCMD_TRUE}" && test -z "${BCCMD_FALSE}"; then
-  as_fn_error $? "conditional \"BCCMD\" was never defined.
+if test -z "${MONITOR_TRUE}" && test -z "${MONITOR_FALSE}"; then
+  as_fn_error $? "conditional \"MONITOR\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${PCMCIA_TRUE}" && test -z "${PCMCIA_FALSE}"; then
-  as_fn_error $? "conditional \"PCMCIA\" was never defined.
+if test -z "${UDEV_TRUE}" && test -z "${UDEV_FALSE}"; then
+  as_fn_error $? "conditional \"UDEV\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 if test -z "${HID2HCI_TRUE}" && test -z "${HID2HCI_FALSE}"; then
   as_fn_error $? "conditional \"HID2HCI\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${DFUTOOL_TRUE}" && test -z "${DFUTOOL_FALSE}"; then
-  as_fn_error $? "conditional \"DFUTOOL\" was never defined.
+if test -z "${CUPS_TRUE}" && test -z "${CUPS_FALSE}"; then
+  as_fn_error $? "conditional \"CUPS\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
+if test -z "${OBEX_TRUE}" && test -z "${OBEX_FALSE}"; then
+  as_fn_error $? "conditional \"OBEX\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${DATAFILES_TRUE}" && test -z "${DATAFILES_FALSE}"; then
-  as_fn_error $? "conditional \"DATAFILES\" was never defined.
+if test -z "${CLIENT_TRUE}" && test -z "${CLIENT_FALSE}"; then
+  as_fn_error $? "conditional \"CLIENT\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${MAEMO6PLUGIN_TRUE}" && test -z "${MAEMO6PLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"MAEMO6PLUGIN\" was never defined.
+if test -z "${READLINE_TRUE}" && test -z "${READLINE_FALSE}"; then
+  as_fn_error $? "conditional \"READLINE\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${DBUSOOBPLUGIN_TRUE}" && test -z "${DBUSOOBPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"DBUSOOBPLUGIN\" was never defined.
+if test -z "${SYSTEMD_TRUE}" && test -z "${SYSTEMD_FALSE}"; then
+  as_fn_error $? "conditional \"SYSTEMD\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${WIIMOTEPLUGIN_TRUE}" && test -z "${WIIMOTEPLUGIN_FALSE}"; then
-  as_fn_error $? "conditional \"WIIMOTEPLUGIN\" was never defined.
+if test -z "${DATAFILES_TRUE}" && test -z "${DATAFILES_FALSE}"; then
+  as_fn_error $? "conditional \"DATAFILES\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${GATTMODULES_TRUE}" && test -z "${GATTMODULES_FALSE}"; then
-  as_fn_error $? "conditional \"GATTMODULES\" was never defined.
+if test -z "${EXPERIMENTAL_TRUE}" && test -z "${EXPERIMENTAL_FALSE}"; then
+  as_fn_error $? "conditional \"EXPERIMENTAL\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
-if test -z "${SYSTEMD_TRUE}" && test -z "${SYSTEMD_FALSE}"; then
-  as_fn_error $? "conditional \"SYSTEMD\" was never defined.
+if test -z "${ANDROID_TRUE}" && test -z "${ANDROID_FALSE}"; then
+  as_fn_error $? "conditional \"ANDROID\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
 
@@ -14274,7 +14195,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by bluez $as_me 4.101, which was
+This file was extended by bluez $as_me 5.10, which was
 generated by GNU Autoconf 2.69.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -14340,7 +14261,7 @@ _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_config="`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`"
 ac_cs_version="\\
-bluez config.status 4.101
+bluez config.status 5.10
 configured by $0, generated by GNU Autoconf 2.69,
   with options \\"\$ac_cs_config\\"
 
     "depfiles") CONFIG_COMMANDS="$CONFIG_COMMANDS depfiles" ;;
     "libtool") CONFIG_COMMANDS="$CONFIG_COMMANDS libtool" ;;
     "Makefile") CONFIG_FILES="$CONFIG_FILES Makefile" ;;
-    "doc/version.xml") CONFIG_FILES="$CONFIG_FILES doc/version.xml" ;;
     "src/bluetoothd.8") CONFIG_FILES="$CONFIG_FILES src/bluetoothd.8" ;;
-    "src/bluetooth.service") CONFIG_FILES="$CONFIG_FILES src/bluetooth.service" ;;
-    "bluez.pc") CONFIG_FILES="$CONFIG_FILES bluez.pc" ;;
+    "lib/bluez.pc") CONFIG_FILES="$CONFIG_FILES lib/bluez.pc" ;;
 
   *) as_fn_error $? "invalid argument: \`$ac_config_target'" "$LINENO" 5;;
   esac
index f2db920..b4d3998 100644 (file)
@@ -1,28 +1,30 @@
 AC_PREREQ(2.60)
-AC_INIT(bluez, 4.101)
+AC_INIT(bluez, 5.10)
 
-AM_INIT_AUTOMAKE([foreign subdir-objects color-tests])
-AM_CONFIG_HEADER(config.h)
+AM_INIT_AUTOMAKE([foreign subdir-objects color-tests silent-rules
+                                       tar-pax no-dist-gzip dist-xz])
+AC_CONFIG_HEADERS(config.h)
+AC_USE_SYSTEM_EXTENSIONS
 
 m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
 
 AM_MAINTAINER_MODE
 
-PKG_PROG_PKG_CONFIG
+AC_PREFIX_DEFAULT(/usr/local)
 
-AC_INIT_BLUEZ
+PKG_PROG_PKG_CONFIG
 
 COMPILER_FLAGS
 
 AC_LANG_C
 
+AC_C_RESTRICT
+
 AC_PROG_CC
 AM_PROG_CC_C_O
 AC_PROG_CC_PIE
 AC_PROG_INSTALL
-AC_PROG_YACC
-AM_PROG_LEX
-AM_PROG_MKDIR_P
+AC_PROG_MKDIR_P
 
 m4_define([_LT_AC_TAGCONFIG], [])
 m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
@@ -30,35 +32,219 @@ m4_ifdef([AC_LIBTOOL_TAGS], [AC_LIBTOOL_TAGS([])])
 AC_DISABLE_STATIC
 AC_PROG_LIBTOOL
 
-AC_FUNC_PPOLL
+MISC_FLAGS
+
+AC_ARG_ENABLE(threads, AC_HELP_STRING([--enable-threads],
+               [enable threading support]), [enable_threads=${enableval}])
+
+AC_CHECK_FUNC(signalfd, dummy=yes,
+                       AC_MSG_ERROR(signalfd support is required))
+
+AC_CHECK_LIB(rt, clock_gettime, dummy=yes,
+                       AC_MSG_ERROR(realtime clock support is required))
+
+AC_CHECK_LIB(pthread, pthread_create, dummy=yes,
+                       AC_MSG_ERROR(posix thread support is required))
 
 AC_CHECK_LIB(dl, dlopen, dummy=yes,
                        AC_MSG_ERROR(dynamic linking loader is required))
 
-AC_CHECK_HEADER([sys/inotify.h],
-               [AC_DEFINE([HAVE_SYS_INOTIFY_H], 1,
-                       [Define to 1 if you have <sys/inotify.h>.])],
-                       [AC_MSG_ERROR(inotify headers are required and missing)])
-AC_PATH_DBUS
-AC_PATH_GLIB
-AC_PATH_ALSA
-AC_PATH_GSTREAMER
-AC_PATH_USB
-AC_PATH_UDEV
-AC_PATH_SNDFILE
-AC_PATH_OUI
-AC_PATH_READLINE
-AC_PATH_CHECK
-
-AC_ARG_BLUEZ
-
-AC_ARG_WITH([systemdunitdir], AC_HELP_STRING([--with-systemdunitdir=DIR],
-       [path to systemd system service directory]), [path_systemdunit=${withval}],
-               [path_systemdunit="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"])
-if (test -n "${path_systemdunit}"); then
-       SYSTEMD_UNITDIR="${path_systemdunit}"
-       AC_SUBST(SYSTEMD_UNITDIR)
+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)
+
+if (test "${enable_threads}" = "yes"); then
+       AC_DEFINE(NEED_THREADS, 1, [Define if threading support is required])
+       PKG_CHECK_MODULES(GTHREAD, gthread-2.0 >= 2.16, dummy=yes,
+                               AC_MSG_ERROR(GThread >= 2.16 is required))
+       GLIB_CFLAGS="$GLIB_CFLAGS $GTHREAD_CFLAGS"
+       GLIB_LIBS="$GLIB_LIBS $GTHREAD_LIBS"
 fi
-AM_CONDITIONAL(SYSTEMD, test -n "${path_systemdunit}")
 
-AC_OUTPUT(Makefile doc/version.xml src/bluetoothd.8 src/bluetooth.service bluez.pc)
+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_ARG_WITH([dbusconfdir], AC_HELP_STRING([--with-dbusconfdir=DIR],
+                               [path to D-Bus configuration directory]),
+                                       [path_dbusconfdir=${withval}])
+if (test -z "${path_dbusconfdir}"); then
+       AC_MSG_CHECKING([D-Bus configuration directory])
+       path_dbusconfdir="`$PKG_CONFIG --variable=sysconfdir dbus-1`"
+       if (test -z "${path_dbusconfdir}"); then
+               AC_MSG_ERROR([D-Bus configuration directory is required])
+       fi
+       AC_MSG_RESULT([${path_dbusconfdir}])
+fi
+AC_SUBST(DBUS_CONFDIR, [${path_dbusconfdir}])
+
+AC_ARG_WITH([dbussystembusdir], AC_HELP_STRING([--with-dbussystembusdir=DIR],
+                               [path to D-Bus system bus services directory]),
+                                       [path_dbussystembusdir=${withval}])
+if (test -z "${path_dbussystembusdir}"); then
+       AC_MSG_CHECKING([D-Bus system bus services dir])
+       path_dbussystembusdir="`$PKG_CONFIG --variable=system_bus_services_dir dbus-1`"
+       if (test -z "${path_dbussystembusdir}"); then
+               AC_MSG_ERROR([D-Bus system bus services directory is required])
+       fi
+       AC_MSG_RESULT([${path_dbussystembusdir}])
+fi
+AC_SUBST(DBUS_SYSTEMBUSDIR, [${path_dbussystembusdir}])
+
+AC_ARG_WITH([dbussessionbusdir], AC_HELP_STRING([--with-dbussessionbusdir=DIR],
+                               [path to D-Bus session bus services directory]),
+                                       [path_dbussessionbusdir=${withval}])
+if (test -z "${path_dbussessionbusdir}"); then
+       AC_MSG_CHECKING([D-Bus session bus services dir])
+       path_dbussessionbusdir="`$PKG_CONFIG --variable=session_bus_services_dir dbus-1`"
+       if (test -z "${path_dbussessionbusdir}"); then
+               AC_MSG_ERROR([D-Bus session bus services directory is required])
+       fi
+       AC_MSG_RESULT([${path_dbussessionbusdir}])
+fi
+AC_SUBST(DBUS_SESSIONBUSDIR, [${path_dbussessionbusdir}])
+
+AC_ARG_ENABLE(library, AC_HELP_STRING([--enable-library],
+               [install Bluetooth library]), [enable_library=${enableval}])
+AM_CONDITIONAL(LIBRARY, test "${enable_library}" = "yes")
+
+AC_ARG_ENABLE(test, AC_HELP_STRING([--enable-test],
+               [enable test/example scripts]), [enable_test=${enableval}])
+AM_CONDITIONAL(TEST, test "${enable_test}" = "yes")
+
+AC_ARG_ENABLE(tools, AC_HELP_STRING([--disable-tools],
+               [disable Bluetooth tools]), [enable_tools=${enableval}])
+AM_CONDITIONAL(TOOLS, test "${enable_tools}" != "no")
+
+AC_ARG_ENABLE(monitor, AC_HELP_STRING([--disable-monitor],
+               [disable Bluetooth monitor]), [enable_monitor=${enableval}])
+AM_CONDITIONAL(MONITOR, test "${enable_monitor}" != "no")
+
+AC_ARG_ENABLE(udev, AC_HELP_STRING([--disable-udev],
+               [disable udev device support]), [enable_udev=${enableval}])
+if (test "${enable_tools}" != "no" && test "${enable_udev}" != "no"); then
+       PKG_CHECK_MODULES(UDEV, libudev >= 143, dummy=yes,
+                               AC_MSG_ERROR(libudev >= 143 is required))
+       AC_SUBST(UDEV_CFLAGS)
+       AC_SUBST(UDEV_LIBS)
+       AC_CHECK_LIB(udev, udev_hwdb_new,
+               AC_DEFINE(HAVE_UDEV_HWDB_NEW, 1,
+                       [Define to 1 if you have the udev_hwdb_new() function.]))
+fi
+AM_CONDITIONAL(UDEV, test "${enable_udev}" != "no")
+
+AC_ARG_WITH([udevdir], AC_HELP_STRING([--with-udevdir=DIR],
+                       [path to udev directory]), [path_udevdir=${withval}])
+if (test "${enable_udev}" != "no" && test -z "${path_udevdir}"); then
+       AC_MSG_CHECKING([udev directory])
+       path_udevdir="`$PKG_CONFIG --variable=udevdir udev`"
+       if (test -z "${path_udevdir}"); then
+               AC_MSG_ERROR([udev directory is required])
+       fi
+       AC_MSG_RESULT([${path_udevdir}])
+fi
+AC_SUBST(UDEV_DIR, [${path_udevdir}])
+
+AM_CONDITIONAL(HID2HCI, test "${enable_tools}" != "no" &&
+                                               test "${enable_udev}" != "no")
+
+AC_ARG_ENABLE(cups, AC_HELP_STRING([--disable-cups],
+                [disable CUPS printer support]), [enable_cups=${enableval}])
+AM_CONDITIONAL(CUPS, test "${enable_cups}" != "no")
+
+AC_ARG_ENABLE(obex, AC_HELP_STRING([--disable-obex],
+               [disable OBEX profile support]), [enable_obex=${enableval}])
+if (test "${enable_obex}" != "no"); then
+       PKG_CHECK_MODULES(ICAL, libical, dummy=yes,
+                                       AC_MSG_ERROR(libical is required))
+       AC_SUBST(ICAL_CFLAGS)
+       AC_SUBST(ICAL_LIBS)
+fi
+AM_CONDITIONAL(OBEX, test "${enable_obex}" != "no")
+
+AC_ARG_ENABLE(client, AC_HELP_STRING([--disable-client],
+               [disable command line client]), [enable_client=${enableval}])
+AM_CONDITIONAL(CLIENT, test "${enable_client}" != "no")
+
+if (test "${enable_client}" != "no"); then
+        AC_CHECK_HEADERS(readline/readline.h, enable_readline=yes,
+                AC_MSG_ERROR(readline header files are required))
+fi
+AM_CONDITIONAL(READLINE, test "${enable_readline}" = "yes")
+
+AC_ARG_ENABLE(systemd, AC_HELP_STRING([--disable-systemd],
+               [disable systemd integration]), [enable_systemd=${enableval}])
+AM_CONDITIONAL(SYSTEMD, test "${enable_systemd}" != "no")
+
+AC_ARG_WITH([systemdsystemunitdir],
+                       AC_HELP_STRING([--with-systemdsystemunitdir=DIR],
+                       [path to systemd system unit directory]),
+                                       [path_systemunitdir=${withval}])
+if (test "${enable_systemd}" != "no" && test -z "${path_systemunitdir}"); then
+       AC_MSG_CHECKING([systemd system unit dir])
+       path_systemunitdir="`$PKG_CONFIG --variable=systemdsystemunitdir systemd`"
+       if (test -z "${path_systemunitdir}"); then
+               AC_MSG_ERROR([systemd system unit directory is required])
+       fi
+       AC_MSG_RESULT([${path_systemunitdir}])
+fi
+AC_SUBST(SYSTEMD_SYSTEMUNITDIR, [${path_systemunitdir}])
+
+AC_ARG_WITH([systemduserunitdir],
+                       AC_HELP_STRING([--with-systemduserunitdir=DIR],
+                       [path to systemd user unit directory]),
+                                       [path_userunitdir=${withval}])
+if (test "${enable_systemd}" != "no" && test -z "${path_userunitdir}"); then
+       AC_MSG_CHECKING([systemd user unit dir])
+       path_userunitdir="`$PKG_CONFIG --variable=systemduserunitdir systemd`"
+       if (test -z "${path_userunitdir}"); then
+               AC_MSG_ERROR([systemd user unit directory is required])
+       fi
+       AC_MSG_RESULT([${path_userunitdir}])
+fi
+AC_SUBST(SYSTEMD_USERUNITDIR, [${path_userunitdir}])
+
+AC_ARG_ENABLE(datafiles, AC_HELP_STRING([--disable-datafiles],
+                       [do not install configuration and data files]),
+                                       [enable_datafiles=${enableval}])
+AM_CONDITIONAL(DATAFILES, test "${enable_datafiles}" != "no")
+
+AC_ARG_ENABLE(experimental, AC_HELP_STRING([--enable-experimental],
+                       [enable experimental plugins (SAP, NFC, ...)]),
+                                       [enable_experimental=${enableval}])
+AM_CONDITIONAL(EXPERIMENTAL, test "${enable_experimental}" = "yes")
+
+if (test "${prefix}" = "NONE"); then
+       dnl no prefix and no localstatedir, so default to /var
+       if (test "$localstatedir" = '${prefix}/var'); then
+               AC_SUBST([localstatedir], ['/var'])
+       fi
+
+       prefix="${ac_default_prefix}"
+fi
+
+if (test "$localstatedir" = '${prefix}/var'); then
+       storagedir="${prefix}/var/lib/bluetooth"
+else
+       storagedir="${localstatedir}/lib/bluetooth"
+fi
+AC_DEFINE_UNQUOTED(STORAGEDIR, "${storagedir}",
+                       [Directory for the storage files])
+
+if (test "$sysconfdir" = '${prefix}/etc'); then
+       configdir="${prefix}/etc/bluetooth"
+else
+       configdir="${sysconfdir}/bluetooth"
+fi
+AC_DEFINE_UNQUOTED(CONFIGDIR, "${configdir}",
+                       [Directory for the configuration files])
+AC_SUBST(CONFIGDIR, "${configdir}")
+
+AC_ARG_ENABLE(android, AC_HELP_STRING([--enable-android],
+                       [enable BlueZ for Android]),
+                                       [enable_android=${enableval}])
+AM_CONDITIONAL(ANDROID, test "${enable_android}" = "yes")
+
+AC_OUTPUT(Makefile src/bluetoothd.8 lib/bluez.pc)
diff --git a/depcomp b/depcomp
index bd0ac08..25a39e6 100755 (executable)
--- a/depcomp
+++ b/depcomp
@@ -1,10 +1,10 @@
 #! /bin/sh
 # depcomp - compile a program generating dependencies as side-effects
 
-scriptversion=2011-12-04.11; # UTC
+scriptversion=2012-03-27.16; # UTC
 
 # Copyright (C) 1999, 2000, 2003, 2004, 2005, 2006, 2007, 2009, 2010,
-# 2011 Free Software Foundation, Inc.
+# 2011, 2012 Free Software Foundation, Inc.
 
 # This program is free software; you can redistribute it and/or modify
 # it under the terms of the GNU General Public License as published by
@@ -28,7 +28,7 @@ scriptversion=2011-12-04.11; # UTC
 
 case $1 in
   '')
-     echo "$0: No command.  Try \`$0 --help' for more information." 1>&2
+     echo "$0: No command.  Try '$0 --help' for more information." 1>&2
      exit 1;
      ;;
   -h | --h*)
@@ -40,8 +40,8 @@ as side-effects.
 
 Environment variables:
   depmode     Dependency tracking mode.
-  source      Source file read by `PROGRAMS ARGS'.
-  object      Object file output by `PROGRAMS ARGS'.
+  source      Source file read by 'PROGRAMS ARGS'.
+  object      Object file output by 'PROGRAMS ARGS'.
   DEPDIR      directory where to store dependencies.
   depfile     Dependency file to output.
   tmpdepfile  Temporary file to use when outputting dependencies.
@@ -57,6 +57,12 @@ EOF
     ;;
 esac
 
+# A tabulation character.
+tab='  '
+# A newline character.
+nl='
+'
+
 if test -z "$depmode" || test -z "$source" || test -z "$object"; then
   echo "depcomp: Variables source, object and depmode must be set" 1>&2
   exit 1
@@ -102,6 +108,12 @@ if test "$depmode" = msvc7msys; then
    depmode=msvc7
 fi
 
+if test "$depmode" = xlc; then
+   # IBM C/C++ Compilers xlc/xlC can output gcc-like dependency informations.
+   gccflag=-qmakedep=gcc,-MF
+   depmode=gcc
+fi
+
 case "$depmode" in
 gcc3)
 ## gcc 3 implements dependency tracking that does exactly what
@@ -156,15 +168,14 @@ gcc)
 ## The second -e expression handles DOS-style file names with drive letters.
   sed -e 's/^[^:]*: / /' \
       -e 's/^['$alpha']:\/[^:]*: / /' < "$tmpdepfile" >> "$depfile"
-## This next piece of magic avoids the `deleted header file' problem.
+## This next piece of magic avoids the "deleted header file" problem.
 ## The problem is that when a header file which appears in a .P file
 ## is deleted, the dependency causes make to die (because there is
 ## typically no way to rebuild the header).  We avoid this by adding
 ## dummy dependencies for each header file.  Too bad gcc doesn't do
 ## this for us directly.
-  tr ' ' '
-' < "$tmpdepfile" |
-## Some versions of gcc put a space before the `:'.  On the theory
+  tr ' ' "$nl" < "$tmpdepfile" |
+## Some versions of gcc put a space before the ':'.  On the theory
 ## that the space means something, we add a space to the output as
 ## well.  hp depmode also adds that space, but also prefixes the VPATH
 ## to the object.  Take care to not repeat it in the output.
@@ -203,18 +214,15 @@ sgi)
     # clever and replace this with sed code, as IRIX sed won't handle
     # lines with more than a fixed number of characters (4096 in
     # IRIX 6.2 sed, 8192 in IRIX 6.5).  We also remove comment lines;
-    # the IRIX cc adds comments like `#:fec' to the end of the
+    # the IRIX cc adds comments like '#:fec' to the end of the
     # dependency line.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
     | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' | \
-    tr '
-' ' ' >> "$depfile"
+    tr "$nl" ' ' >> "$depfile"
     echo >> "$depfile"
 
     # The second pass generates a dummy entry for each header file.
-    tr ' ' '
-' < "$tmpdepfile" \
+    tr ' ' "$nl" < "$tmpdepfile" \
    | sed -e 's/^.*\.o://' -e 's/#.*$//' -e '/^$/ d' -e 's/$/:/' \
    >> "$depfile"
   else
@@ -226,10 +234,17 @@ sgi)
   rm -f "$tmpdepfile"
   ;;
 
+xlc)
+  # This case exists only to let depend.m4 do its work.  It works by
+  # looking at the text of this script.  This case will never be run,
+  # since it is checked for above.
+  exit 1
+  ;;
+
 aix)
   # The C for AIX Compiler uses -M and outputs the dependencies
   # in a .u file.  In older versions, this file always lives in the
-  # current directory.  Also, the AIX compiler puts `$object:' at the
+  # current directory.  Also, the AIX compiler puts '$object:' at the
   # start of each line; $object doesn't have directory information.
   # Version 6 uses the directory in both cases.
   dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
@@ -259,12 +274,11 @@ aix)
     test -f "$tmpdepfile" && break
   done
   if test -f "$tmpdepfile"; then
-    # Each line is of the form `foo.o: dependent.h'.
+    # Each line is of the form 'foo.o: dependent.h'.
     # Do two passes, one to just change these to
-    # `$object: dependent.h' and one to simply `dependent.h:'.
+    # '$object: dependent.h' and one to simply 'dependent.h:'.
     sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-    # That's a tab and a space in the [].
-    sed -e 's,^.*\.[a-z]*:[     ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+    sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
   else
     # The sourcefile does not contain any dependencies, so just
     # store a dummy comment line, to avoid errors with the Makefile
@@ -275,23 +289,26 @@ aix)
   ;;
 
 icc)
-  # Intel's C compiler understands `-MD -MF file'.  However on
-  #    icc -MD -MF foo.d -c -o sub/foo.o sub/foo.c
+  # Intel's C compiler anf tcc (Tiny C Compiler) understand '-MD -MF file'.
+  # However on
+  #    $CC -MD -MF foo.d -c -o sub/foo.o sub/foo.c
   # ICC 7.0 will fill foo.d with something like
   #    foo.o: sub/foo.c
   #    foo.o: sub/foo.h
-  # which is wrong.  We want:
+  # which is wrong.  We want
   #    sub/foo.o: sub/foo.c
   #    sub/foo.o: sub/foo.h
   #    sub/foo.c:
   #    sub/foo.h:
   # ICC 7.1 will output
   #    foo.o: sub/foo.c sub/foo.h
-  # and will wrap long lines using :
+  # and will wrap long lines using '\':
   #    foo.o: sub/foo.c ... \
   #     sub/foo.h ... \
   #     ...
-
+  # tcc 0.9.26 (FIXME still under development at the moment of writing)
+  # will emit a similar output, but also prepend the continuation lines
+  # with horizontal tabulation characters.
   "$@" -MD -MF "$tmpdepfile"
   stat=$?
   if test $stat -eq 0; then :
@@ -300,15 +317,21 @@ icc)
     exit $stat
   fi
   rm -f "$depfile"
-  # Each line is of the form `foo.o: dependent.h',
-  # or `foo.o: dep1.h dep2.h \', or ` dep3.h dep4.h \'.
+  # Each line is of the form 'foo.o: dependent.h',
+  # or 'foo.o: dep1.h dep2.h \', or ' dep3.h dep4.h \'.
   # Do two passes, one to just change these to
-  # `$object: dependent.h' and one to simply `dependent.h:'.
-  sed "s,^[^:]*:,$object :," < "$tmpdepfile" > "$depfile"
-  # Some versions of the HPUX 10.20 sed can't process this invocation
-  # correctly.  Breaking it into two sed invocations is a workaround.
-  sed 's,^[^:]*: \(.*\)$,\1,;s/^\\$//;/^$/d;/:$/d' < "$tmpdepfile" |
-    sed -e 's/$/ :/' >> "$depfile"
+  # '$object: dependent.h' and one to simply 'dependent.h:'.
+  sed -e "s/^[ $tab][ $tab]*/  /" -e "s,^[^:]*:,$object :," \
+    < "$tmpdepfile" > "$depfile"
+  sed '
+    s/[ '"$tab"'][ '"$tab"']*/ /g
+    s/^ *//
+    s/ *\\*$//
+    s/^[^:]*: *//
+    /^$/d
+    /:$/d
+    s/$/ :/
+  ' < "$tmpdepfile" >> "$depfile"
   rm -f "$tmpdepfile"
   ;;
 
@@ -344,7 +367,7 @@ hp2)
   done
   if test -f "$tmpdepfile"; then
     sed -e "s,^.*\.[a-z]*:,$object:," "$tmpdepfile" > "$depfile"
-    # Add `dependent.h:' lines.
+    # Add 'dependent.h:' lines.
     sed -ne '2,${
               s/^ *//
               s/ \\*$//
@@ -359,9 +382,9 @@ hp2)
 
 tru64)
    # The Tru64 compiler uses -MD to generate dependencies as a side
-   # effect.  `cc -MD -o foo.o ...' puts the dependencies into `foo.o.d'.
+   # effect.  'cc -MD -o foo.o ...' puts the dependencies into 'foo.o.d'.
    # At least on Alpha/Redhat 6.1, Compaq CCC V6.2-504 seems to put
-   # dependencies in `foo.d' instead, so we check for that too.
+   # dependencies in 'foo.d' instead, so we check for that too.
    # Subdirectories are respected.
    dir=`echo "$object" | sed -e 's|/[^/]*$|/|'`
    test "x$dir" = "x$object" && dir=
@@ -407,8 +430,7 @@ tru64)
    done
    if test -f "$tmpdepfile"; then
       sed -e "s,^.*\.[a-z]*:,$object:," < "$tmpdepfile" > "$depfile"
-      # That's a tab and a space in the [].
-      sed -e 's,^.*\.[a-z]*:[   ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
+      sed -e 's,^.*\.[a-z]*:['"$tab"' ]*,,' -e 's,$,:,' < "$tmpdepfile" >> "$depfile"
    else
       echo "#dummy" > "$depfile"
    fi
@@ -443,11 +465,11 @@ msvc7)
   p
 }' | $cygpath_u | sort -u | sed -n '
 s/ /\\ /g
-s/\(.*\)/      \1 \\/p
+s/\(.*\)/'"$tab"'\1 \\/p
 s/.\(.*\) \\/\1:/
 H
 $ {
-  s/.*/        /
+  s/.*/'"$tab"'/
   G
   p
 }' >> "$depfile"
@@ -478,7 +500,7 @@ dashmstdout)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -498,15 +520,14 @@ dashmstdout)
   done
 
   test -z "$dashmflag" && dashmflag=-M
-  # Require at least two characters before searching for `:'
+  # Require at least two characters before searching for ':'
   # in the target name.  This is to cope with DOS-style filenames:
-  # a dependency such as `c:/foo/bar' could be seen as target `c' otherwise.
+  # a dependency such as 'c:/foo/bar' could be seen as target 'c' otherwise.
   "$@" $dashmflag |
-    sed 's:^[  ]*[^: ][^:][^:]*\:[    ]*:'"$object"'\: :' > "$tmpdepfile"
+    sed 's:^['"$tab"' ]*[^:'"$tab"' ][^:][^:]*\:['"$tab"' ]*:'"$object"'\: :' > "$tmpdepfile"
   rm -f "$depfile"
   cat < "$tmpdepfile" > "$depfile"
-  tr ' ' '
-' < "$tmpdepfile" | \
+  tr ' ' "$nl" < "$tmpdepfile" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -562,8 +583,7 @@ makedepend)
   # makedepend may prepend the VPATH from the source file name to the object.
   # No need to regex-escape $object, excess matching of '.' is harmless.
   sed "s|^.*\($object *:\)|\1|" "$tmpdepfile" > "$depfile"
-  sed '1,2d' "$tmpdepfile" | tr ' ' '
-' | \
+  sed '1,2d' "$tmpdepfile" | tr ' ' "$nl" | \
 ## Some versions of the HPUX 10.20 sed can't process this invocation
 ## correctly.  Breaking it into two sed invocations is a workaround.
     sed -e 's/^\\$//' -e '/^$/d' -e '/:$/d' | sed -e 's/$/ :/' >> "$depfile"
@@ -583,7 +603,7 @@ cpp)
     shift
   fi
 
-  # Remove `-o $object'.
+  # Remove '-o $object'.
   IFS=" "
   for arg
   do
@@ -652,8 +672,8 @@ msvisualcpp)
   sed -n '/^#line [0-9][0-9]* "\([^"]*\)"/ s::\1:p' | $cygpath_u | sort -u > "$tmpdepfile"
   rm -f "$depfile"
   echo "$object : \\" > "$depfile"
-  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::     \1 \\:p' >> "$depfile"
-  echo "       " >> "$depfile"
+  sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::'"$tab"'\1 \\:p' >> "$depfile"
+  echo "$tab" >> "$depfile"
   sed < "$tmpdepfile" -n -e 's% %\\ %g' -e '/^\(.*\)$/ s::\1\::p' >> "$depfile"
   rm -f "$tmpdepfile"
   ;;
diff --git a/deviceinfo/deviceinfo.h b/deviceinfo/deviceinfo.h
deleted file mode 100644 (file)
index 7a804a5..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- *  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/manager.c b/deviceinfo/manager.c
deleted file mode 100644 (file)
index 1d59918..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- *  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);
-}
index dccb6bf..74d235a 100644 (file)
@@ -1,67 +1,23 @@
 BlueZ D-Bus Adapter API description
 ***********************************
 
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
-Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
-Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
-
 
 Adapter hierarchy
 =================
 
 Service                org.bluez
-Interface      org.bluez.Adapter
+Interface      org.bluez.Adapter1
 Object path    [variable prefix]/{hci0,hci1,...}
 
-Methods                dict GetProperties()
-
-                       Returns all properties for the adapter. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.NotReady
-
-               void SetProperty(string name, variant value)
-
-                       Changes the value of the specified property. Only
-                       properties that are listed a read-write are changeable.
-                       On success this will emit a PropertyChanged signal.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-               void RequestSession()
-
-                       This method requests a client session that provides
-                       operational Bluetooth. A possible mode change must be
-                       confirmed by the user via the agent.
-
-                       Clients may request multiple sessions. All sessions
-                       are released when adapter's mode is changed to off
-                       state.
-
-                       Possible Errors: org.bluez.Error.Rejected
-
-               void ReleaseSession()
-
-                       Release a previously requested session. It sets
-                       adapter to the mode in use on the moment of session
-                       request.
-
-                       SetProperty method call changes adapter's mode
-                       persistently, such that session release will not
-                       modify it.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-
-               void StartDiscovery()
+Methods                void StartDiscovery()
 
                        This method starts the device discovery session. This
                        includes an inquiry procedure and remote device name
                        resolving. Use StopDiscovery to release the sessions
                        acquired.
 
-                       This process will start emitting DeviceFound and
-                       PropertyChanged "Discovering" signals.
+                       This process will start creating Device objects as
+                       new devices are discovered.
 
                        Possible errors: org.bluez.Error.NotReady
                                         org.bluez.Error.Failed
@@ -79,73 +35,6 @@ Methods              dict GetProperties()
                                         org.bluez.Error.Failed
                                         org.bluez.Error.NotAuthorized
 
-               object FindDevice(string address)
-
-                       Returns the object path of device for given address.
-                       The device object needs to be first created via
-                       CreateDevice or CreatePairedDevice.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
-
-               array{object} ListDevices() {deprecated}
-
-                       Returns list of device object paths.
-                       This method is deprecated, instead use the Devices
-                       Property to get the list of devices object paths.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-                                        org.bluez.Error.OutOfMemory
-
-               object CreateDevice(string address)
-
-                       Creates a new object path for a remote device. This
-                       method will connect to the remote device and retrieve
-                       all SDP records.
-
-                       If the object for the remote device already exists
-                       this method will fail.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-
-               object CreatePairedDevice(string address, object agent,
-                                                       string capability)
-
-                       Creates a new object path for a remote device. This
-                       method will connect to the remote device and retrieve
-                       all SDP records and then initiate the pairing.
-
-                       If previously CreateDevice was used successfully,
-                       this method will only initiate the pairing.
-
-                       Compared to CreateDevice this method will fail if
-                       the pairing already exists, but not if the object
-                       path already has been created. This allows applications
-                       to use CreateDevice first and the if needed use
-                       CreatePairedDevice to initiate pairing.
-
-                       The agent object path is assumed to reside within the
-                       process (D-Bus connection instance) that calls this
-                       method. No separate registration procedure is needed
-                       for it and it gets automatically released once the
-                       pairing operation is complete.
-
-                       The capability parameter is the same as for the
-                       RegisterAgent method.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-
-               void CancelDeviceCreation(string address)
-
-                       Aborts either a CreateDevice call or a
-                       CreatePairedDevice call.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotInProgress
-
                void RemoveDevice(object device)
 
                        This removes the remote device object at the given
@@ -154,82 +43,53 @@ Methods            dict GetProperties()
                        Possible errors: org.bluez.Error.InvalidArguments
                                         org.bluez.Error.Failed
 
-               void RegisterAgent(object agent, string capability)
-
-                       This registers the adapter wide agent.
-
-                       The object path defines the path of the agent
-                       that will be called when user input is needed.
-
-                       If an application disconnects from the bus all
-                       of its registered agents will be removed.
-
-                       The capability parameter can have the values
-                       "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
-
-               void UnregisterAgent(object agent)
-
-                       This unregisters the agent that has been previously
-                       registered. The object path parameter must match the
-                       same value that has been used on registration.
-
-                       Possible errors: org.bluez.Error.DoesNotExist
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-               DeviceFound(string address, dict values)
-
-                       This signal will be sent every time an inquiry result
-                       has been found by the service daemon. In general they
-                       only appear during a device discovery.
-
-                       The dictionary can contain basically the same values
-                       that are returned by the GetProperties method
-                       from the org.bluez.Device interface. In addition there
-                       can be values for the RSSI, the TX power level and
-                       Broadcaster role.
-
-               DeviceDisappeared(string address)
+Properties     string Address [readonly]
 
-                       This signal will be sent when an inquiry session for
-                       a periodic discovery finishes and previously found
-                       devices are no longer in range or visible.
+                       The Bluetooth device address.
 
-               DeviceCreated(object device)
+               string Name [readonly]
 
-                       Parameter is object path of created device.
+                       The Bluetooth system name (pretty hostname).
 
-               DeviceRemoved(object device)
+                       This property is either a static system default
+                       or controlled by an external daemon providing
+                       access to the pretty hostname configuration.
 
-                       Parameter is object path of removed device.
+               string Alias [readwrite]
 
-Properties     string Address [readonly]
+                       The Bluetooth friendly name. This value can be
+                       changed.
 
-                       The Bluetooth device address.
+                       In case no alias is set, it will return the system
+                       provided name. Setting an empty string as alias will
+                       convert it back to the system provided name.
 
-               string Name [readwrite]
+                       When resetting the alias with an empty string, the
+                       property will default back to system name.
 
-                       The Bluetooth friendly name. This value can be
-                       changed and a PropertyChanged signal will be emitted.
+                       On a well configured system, this property never
+                       needs to be changed since it defaults to the system
+                       name and provides the pretty hostname. Only if the
+                       local name needs to be different from the pretty
+                       hostname, this property should be used as last
+                       resort.
 
                uint32 Class [readonly]
 
                        The Bluetooth class of device.
 
+                       This property represents the value that is either
+                       automatically configured by DMI/ACPI information
+                       or provided as static configuration.
+
                boolean Powered [readwrite]
 
                        Switch an adapter on or off. This will also set the
-                       appropriate connectable state.
+                       appropriate connectable state of the controller.
+
+                       The value of this property is not persistent. After
+                       restart or unplugging of the adapter it will reset
+                       back to false.
 
                boolean Discoverable [readwrite]
 
@@ -249,6 +109,8 @@ Properties  string Address [readonly]
                        this property will be updated via a PropertyChanged
                        signal.
 
+                       For any new adapter this settings defaults to false.
+
                boolean Pairable [readwrite]
 
                        Switch an adapter to pairable or non-pairable. This is
@@ -258,12 +120,17 @@ Properties        string Address [readonly]
                        Note that this property only affects incoming pairing
                        requests.
 
+                       For any new adapter this settings defaults to true.
+
                uint32 PairableTimeout [readwrite]
 
                        The pairable timeout in seconds. A value of zero
                        means that the timeout is disabled and it will stay in
                        pairable mode forever.
 
+                       The default value for pairable timeout should be
+                       disabled (value 0).
+
                uint32 DiscoverableTimeout [readwrite]
 
                        The discoverable timeout in seconds. A value of zero
@@ -277,11 +144,12 @@ Properties        string Address [readonly]
 
                        Indicates that a device discovery procedure is active.
 
-               array{object} Devices [readonly]
-
-                       List of device object paths.
-
                array{string} UUIDs [readonly]
 
                        List of 128-bit UUIDs that represents the available
                        local services.
+
+               string Modalias [readonly, optional]
+
+                       Local Device ID information in modalias format
+                       used by the kernel and udev.
index 5c8d4d2..2e70931 100644 (file)
@@ -1,15 +1,72 @@
 BlueZ D-Bus Agent API description
 **********************************
 
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
+
+Agent Manager hierarchy
+=======================
+
+Service                org.bluez
+Interface      org.bluez.AgentManager1
+Object path    /org/bluez
+
+               void RegisterAgent(object agent, string capability)
+
+                       This registers an agent handler.
+
+                       The object path defines the path of the agent
+                       that will be called when user input is needed.
+
+                       Every application can register its own agent and
+                       for all actions triggered by that application its
+                       agent is used.
+
+                       It is not required by an application to register
+                       an agent. If an application does chooses to not
+                       register an agent, the default agent is used. This
+                       is on most cases a good idea. Only application
+                       like a pairing wizard should register their own
+                       agent.
+
+                       An application can only register one agent. Multiple
+                       agents per application is not supported.
+
+                       The capability parameter can have the values
+                       "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
+
+               void UnregisterAgent(object agent)
+
+                       This unregisters the agent that has been previously
+                       registered. The object path parameter must match the
+                       same value that has been used on registration.
+
+                       Possible errors: org.bluez.Error.DoesNotExist
+
+               void RequestDefaultAgent(object agent)
+
+                       This requests is to make the application agent
+                       the default agent. The application is required
+                       to register an agent.
+
+                       Special permission might be required to become
+                       the default agent.
+
+                       Possible errors: org.bluez.Error.DoesNotExist
 
 
 Agent hierarchy
 ===============
 
 Service                unique name
-Interface      org.bluez.Agent
+Interface      org.bluez.Agent1
 Object path    freely definable
 
 Methods                void Release()
@@ -31,6 +88,30 @@ Methods              void Release()
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
 
+               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.
+
+                       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.
+
+                       Possible errors: org.bluez.Error.Rejected
+                                        org.bluez.Error.Canceled
+
                uint32 RequestPasskey(object device)
 
                        This method gets called when the service daemon
@@ -42,7 +123,8 @@ Methods              void Release()
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
 
-               void DisplayPasskey(object device, uint32 passkey, uint8 entered)
+               void DisplayPasskey(object device, uint32 passkey,
+                                                               uint16 entered)
 
                        This method gets called when the service daemon
                        needs to display a passkey for an authentication.
@@ -61,30 +143,6 @@ 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
@@ -100,19 +158,20 @@ Methods           void Release()
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
 
-               void Authorize(object device, string uuid)
+               void RequestAuthorization(object device)
 
-                       This method gets called when the service daemon
-                       needs to authorize a connection/service request.
+                       This method gets called to request the user to
+                       authorize an incoming pairing attempt which
+                       would in other circumstances trigger the just-works
+                       model.
 
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
 
-               void ConfirmModeChange(string mode)
+               void AuthorizeService(object device, string uuid)
 
-                       This method gets called if a mode change is requested
-                       that needs to be confirmed by the user. An example
-                       would be leaving flight mode.
+                       This method gets called when the service daemon
+                       needs to authorize a connection/service request.
 
                        Possible errors: org.bluez.Error.Rejected
                                         org.bluez.Error.Canceled
diff --git a/doc/alert-api.txt b/doc/alert-api.txt
new file mode 100644 (file)
index 0000000..fc427c8
--- /dev/null
@@ -0,0 +1,108 @@
+BlueZ D-Bus Alert API description
+*********************************
+
+
+Introduction
+------------
+
+Currently, there are two different GATT server profiles that depend on
+receiving alerts or notifications from the platform: Phone Alert Status (PASP)
+and Alert Notification (ANP). PASP is very specific to mobile phones, and also
+allows limited control to alerts (i.e. mute once or switch to a silent mode).
+
+This document presents a unified API that allows to register and notify alerts,
+and to control some alerts (using the provided agent object).
+
+
+Alert hierarchy
+===============
+
+Service                org.bluez
+Interface      org.bluez.Alert1
+Object path    /org/bluez
+
+Methods                void RegisterAlert(string category, object agent)
+
+                       Register a new alert category and an agent for it. This
+                       means the application will be responsible for notifying
+                       BlueZ of any alerts of that category, using the
+                       NewAlert() method.
+
+                       Supported ANP categories: simple, email, news, call,
+                               missed-call, sms-mms, voice-mail, schedule,
+                               high-priority, instant-message
+                       Supported PASP categories: ringer, vibrate, display
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               void NewAlert(string category, uint16 count, string description)
+
+                       Notify BlueZ of new alert(s) for the given category. The
+                       description is relative to the last received alert and
+                       can be sender name, caller ID, title, or other
+                       information specific to the category.
+
+                       For ringer, vibrate and display categories, valid
+                       descriptions are "active" and "not active". Alerts from
+                       ringer category also accept "enabled" and "disabled",
+                       depending on whether ringer is in silent mode or not.
+
+                       Description must not exceed 18 bytes when encoded in
+                       UTF-8 format, otherwise an error is returned. If there
+                       is no description, an empty string should be used.
+
+                       The count argument contains the number of alerts not
+                       yet acknowledged by the user on the UI. To save D-Bus
+                       traffic, events that may generate multiple alerts at
+                       the same time (like email, sms, news) should trigger a
+                       single NewAlert().
+
+                       If there are more than 254 new alerts, count must be
+                       set to 255. PASP alerts should always set count to 1.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               void UnreadAlert(string category, uint16 count)
+
+                       Some services (like SMS and e-mail) keep track of
+                       number of unread items. This method allows to update
+                       this counter, so peer devices can be notified using
+                       Alert Notification Profile.
+
+                       If there are more than 254 unread alerts, count must be
+                       set to 255.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+Alert Agent hierarchy
+=====================
+
+Service                org.bluez
+Interface      org.bluez.AlertAgent1
+Object path    freely definable
+
+Methods                void MuteOnce()
+
+                       This method is only called if "ringer" alert category
+                       is specified when registering the agent.
+
+                       Mute the ringer once (e.g. during a incoming call). If
+                       ringer is not active, does nothing.
+
+               void SetRinger(string mode)
+
+                       This method is only called if "ringer" alert category
+                       is specified when registering the agent.
+
+                       Set ringer to the specified mode. If mode is "enabled",
+                       ringer is set to the default mode, as defined by the
+                       current active profile. If mode is "disabled", ringer
+                       will not activate on incoming calls, until it is set
+                       back to "enabled" mode.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               void Release()
+
+                       Release this agent. At this point, it will not be used
+                       by BlueZ anymore and can be destroyed by the owner.
index cda934c..ca171c4 100644 (file)
@@ -16,7 +16,8 @@ HSP AG                12
 HFP AG         13
 SYNCH (IrMC)   14
 PBAP           15
-MAP            16
+MAP MAS                16
+MAP MNS                17
 SyncEvolution  19
 PC/Ovi Suite   24
 SyncML Client  25
diff --git a/doc/attribute-api.txt b/doc/attribute-api.txt
deleted file mode 100644 (file)
index 98d7f30..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-BlueZ D-Bus Attribute API description
-*************************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-
-Service details
----------------
-
-One service object path for every remote SDP record or service in the
-attribute database. One service object path for every local SDP record
-or service from attribute database.
-
-Local services are children of the adapter object path. Remote services
-are children of the remote device object path. This doesn't solve the
-problem where local attributes can have different instances based on
-the remote device.
-
-In general the idea is to also represent SDP records as services so that
-new style application can just use the service interfaces to retrieve the
-needed information. That way the usage of SDP and GATT would be mostly
-fully transparent and a differentiation becomes unimportant in the future.
-
-A service consists of some generic service information and a set of
-characteristics. All characteristic are presented as object path as well.
-
-
-Local Service hierarchy
-=======================
-
-Service                org.bluez
-Interface      org.bluez.Service
-               org.bluez.Characteristic
-Object path    [prefix]/{hci0}/{service0, service1, ...}
-
-Methods
-
-Properties
-
-
-Device Service hierarchy
-========================
-
-Service                org.bluez
-Interface      org.bluez.Characteristic
-Object path    [prefix]/{hci0}/{device0}/{service0, service1, ...}
-               [prefix]/{hci0}/{device1}/{service0, service1, ...}
-
-Methods        dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       Properties section for the available properties.
-
-               array{object} DiscoverCharacteristics()
-
-                       Discover all characteristics that belongs in this service.
-                       When it returns all the characteristics paths will be
-                       already registered. It will return the characteristics paths
-                       as soon as they are discovered. After that it will try to
-                       read all values.
-
-               RegisterCharacteristicsWatcher(object agent)
-
-                       Register a watcher to monitor characteristic changes.
-
-                       A watcher will be registered for this service and will
-                       notify about any changed characteristics in the service.
-                       This also notifies about any included characteristics.
-
-               UnregisterCharacteristicsWatcher(object agent)
-
-                       Unregister a watcher.
-
-Properties     string Name (mandatory) [readonly]
-
-                       General name of service
-
-               string Description (optional) [readonly]
-
-                       Description of service
-
-               string UUID (mandatory) [readonly]
-
-                       UUID of service. Service class value for SDP and GATT
-                       UUID for attribute based services.
-
-               array{object} Characteristics [readonly]
-
-                       This list contains the characteristics owned by this
-                       specific service and other characteristics from service
-                       includes. That way no complicated service includes array
-                       is needed.
-
-
-Device Characteristic hierarchy
-===============================
-
-Service                org.bluez
-Interface      org.bluez.Characteristic
-Object path    [prefix]/{hci0}/{device0}/{service0}/{characteristic0,...}
-               [prefix]/{hci0}/{device0}/{service1}/{characteristic0,...}
-
-Methods                dict GetProperties()
-
-                       Returns all properties for the characteristic. See the
-                       properties section for available properties.
-
-               void SetProperty(string name, variant value)
-
-                       Changes the value of the specified property. Only
-                       read-write properties can be changed. On success
-                       this will emit a PropertyChanged signal.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-Properties     string UUID [readonly]
-
-                       UUID128 of this characteristic.
-
-               string Name [readonly]
-
-                       Optional field containing a friendly name for the
-                       Characteristic UUID.
-
-               string Description [readonly]
-
-                       Textual optional characteristic descriptor describing
-                       the Characteristic Value.
-
-               struct Format [readonly]
-
-                       Optional Characteristic descriptor which defines the
-                       format of the Characteristic Value. For numeric
-                       values, the actual value can be value * 10^Exponent.
-                       NameSpace and Description are defined on the Assigned
-                       Number Specification.
-
-                         uint8  | Format: format of the value
-                         uint8  | Exponent: Field to determine how the value is
-                                | further formatted.
-                         uint16 | Unit: unit of the characteristic
-                         uint8  | NameSpace: Name space of description.
-                         uint16 | Description: Description of the characteristic defined
-                                | in a high layer profile.
-
-               array{byte} Value [readwrite]
-
-                       Raw value of the Characteristic Value attribute.
-
-               string Representation (of the binary Value) [readonly]
-
-                       Friendly representation of the Characteristic Value
-                       based on the format attribute.
-
-
-Characteristic Watcher hierarchy
-===============================
-
-Service                unique name
-Interface      org.bluez.Watcher
-Object path    freely definable
-
-Methods                void ValueChanged(object characteristic, array{byte})
-
-                       New raw value of the Characteristic Value attribute.
diff --git a/doc/audio-api.txt b/doc/audio-api.txt
deleted file mode 100644 (file)
index 02291fd..0000000
+++ /dev/null
@@ -1,458 +0,0 @@
-BlueZ D-Bus Audio API description
-*********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2007  Johan Hedberg <johan.hedberg@nokia.com>
-Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
-
-Audio hierarchy
-===============
-
-Service                org.bluez
-Interface      org.bluez.Audio
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-This is a generic audio interface that abstracts the different audio profiles.
-
-Methods                void Connect()
-
-                       Connect all supported audio profiles on the device.
-
-               void Disconnect()
-
-                       Disconnect all audio profiles on the device
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-Signals                void PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-Properties     string State
-
-                       Possible values: "disconnected", "connecting",
-                       "connected"
-
-                       "disconnected" -> "connecting"
-                               Either an incoming or outgoing connection
-                               attempt ongoing.
-
-                       "connecting" -> "disconnected"
-                               Connection attempt failed
-
-                       "connecting" -> "connected"
-                               Successfully connected
-
-                       "connected" -> "disconnected"
-                               Disconnected from the remote device
-
-Headset hierarchy
-=================
-
-Service                org.bluez
-Interface      org.bluez.Headset
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                void Connect()
-
-                       Connect to the HSP/HFP service on the remote device.
-
-               void Disconnect()
-
-                       Disconnect from the HSP/HFP service on the remote
-                       device.
-
-               boolean IsConnected() {deprecated}
-
-                       Returns TRUE if there is a active connection to the
-                       HSP/HFP connection on the remote device.
-
-               void IndicateCall()
-
-                       Indicate an incoming call on the headset
-                       connected to the stream. Will continue to
-                       ring the headset about every 3 seconds.
-
-               void CancelCall()
-
-                       Cancel the incoming call indication.
-
-               void Play() {deprecated}
-
-                       Open the audio connection to the headset.
-
-               void Stop()
-
-                       Close the audio connection.
-
-               boolean IsPlaying() {deprecated}
-
-                       Returns true if an audio connection to the headset
-                       is active.
-
-               uint16 GetSpeakerGain() {deprecated}
-
-                       Returns the current speaker gain if available,
-                       otherwise returns the error NotAvailable.
-
-               uint16 GetMicrophoneGain() {deprecated}
-
-                       Returns the current microphone gain if available,
-                       otherwise returns the error NotAvailable.
-
-               void SetSpeakerGain(uint16 gain) {deprecated}
-
-                       Changes the current speaker gain if possible.
-
-               void SetMicrophoneGain(uint16 gain) {deprecated}
-
-                       Changes the current speaker gain if possible.
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-               void SetProperty(string name, variant value)
-
-                       Changes the value of the specified property. Only
-                       properties that are listed a read-write are changeable.
-                       On success this will emit a PropertyChanged signal.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
-
-Signals                void AnswerRequested()
-
-                       Sent when the answer button is pressed on the headset
-
-               void Connected() {deprecated}
-
-                       Sent when the device has been connected to.
-
-               void Disconnected() {deprecated}
-
-                       Sent when the device has been disconnected from.
-
-               void Stopped() {deprecated}
-
-                       Sent when the audio connection is closed
-
-               void Playing() {deprecated}
-
-                       Sent when the audio connection is opened
-
-               void SpeakerGainChanged(uint16 gain) {deprecated}
-
-                       The speaker gain changed.
-
-               void MicrophoneGainChanged(uint16 gain) {deprecated}
-
-                       The microphone gain changed.
-
-               PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-properties     string State [readonly]
-
-                       Possible values: "disconnected", "connecting",
-                       "connected", "playing"
-
-                       "disconnected" -> "connecting"
-                               Either an incoming or outgoing connection
-                               attempt ongoing.
-
-                       "connecting" -> "disconnected"
-                               Connection attempt failed
-
-                       "connecting" -> "connected"
-                               Successfully connected
-
-                       "connected" -> "playing"
-                               SCO audio connection successfully opened
-
-                       "playing" -> "connected"
-                               SCO audio connection closed
-
-                       "connected" -> "disconnected"
-                       "playing" -> "disconnected"
-                               Disconnected from the remote device
-
-               boolean Connected [readonly]
-
-                       Indicates if there is a active connection to the
-                       HSP/HFP connection on the remote device.
-
-               boolean Playing  [readonly]
-
-                       Indicates if an audio connection to the headset
-                       is active.
-
-               uint16 SpeakerGain  [readwrite]
-
-                       The speaker gain when available.
-
-               uint16 MicrophoneGain  [readwrite]
-
-                       The speaker gain when available.
-
-
-AudioSink hierarchy
-===================
-
-Service                org.bluez
-Interface      org.bluez.AudioSink
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                void Connect()
-
-                       Connect and setup a stream to a A2DP sink on the
-                       remote device.
-
-               void Disconnect()
-
-                       Disconnect from the remote device.
-
-               boolean IsConnected() {deprecated}
-
-                       Returns TRUE if a stream is setup to a A2DP sink on
-                       the remote device.
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-Signals                void Connected() {deprecated}
-
-                       Sent when a successful connection has been made to the
-                       remote A2DP Sink
-
-               void Disconnected() {deprecated}
-
-                       Sent when the device has been disconnected from.
-
-               void Playing() {deprecated}
-
-                       Sent when a stream with remote device is started.
-
-               void Stopped() {deprecated}
-
-                       Sent when a stream with remote device is suspended.
-
-               PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-properties     string State [readonly]
-
-                       Possible values: "disconnected", "connecting",
-                       "connected", "playing"
-
-                       "disconnected" -> "connecting"
-                               Either an incoming or outgoing connection
-                               attempt ongoing.
-
-                       "connecting" -> "disconnected"
-                               Connection attempt failed
-
-                       "connecting" -> "connected"
-                               Successfully connected
-
-                       "connected" -> "playing"
-                               Audio stream active
-
-                       "playing" -> "connected"
-                               Audio stream suspended
-
-                       "connected" -> "disconnected"
-                       "playing" -> "disconnected"
-                               Disconnected from the remote device
-
-               boolean Connected [readonly]
-
-                       Indicates if a stream is setup to a A2DP sink on
-                       the remote device.
-
-               boolean Playing  [readonly]
-
-                       Indicates if a stream is active to a A2DP sink on
-                       the remote device.
-
-AudioSource hierarchy
-=====================
-
-Service                org.bluez
-Interface      org.bluez.AudioSource
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                void Connect()
-
-                       Connect and setup a stream to a A2DP source on the
-                       remote device.
-
-               void Disconnect()
-
-                       Disconnect from the remote device.
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-properties     string State [readonly]
-
-                       Possible values: "disconnected", "connecting",
-                       "connected", "playing"
-
-                       "disconnected" -> "connecting"
-                               Either an incoming or outgoing connection
-                               attempt ongoing.
-
-                       "connecting" -> "disconnected"
-                               Connection attempt failed
-
-                       "connecting" -> "connected"
-                               Successfully connected
-
-                       "connected" -> "playing"
-                               Audio stream active
-
-                       "playing" -> "connected"
-                               Audio stream suspended
-
-                       "connected" -> "disconnected"
-                       "playing" -> "disconnected"
-                               Disconnected from the remote device
-
-
-HeadsetGateway hierarchy
-========================
-
-Service                org.bluez
-Interface      org.bluez.HeadsetGateway
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-This interface is available for remote devices which can function in the Audio
-Gateway role of the HFP profiles.
-
-Methods                void Connect()
-
-                       Connect to the AG service on the remote device.
-
-               void Disconnect()
-
-                       Disconnect from the AG service on the remote device
-
-               void AnswerCall()
-
-                       It has to called only after Ring signal received.
-
-               void TerminateCall()
-
-                       Terminate call which is running or reject an incoming
-                       call. This has nothing with any 3-way situation incl.
-                       RaH. Just plain old PDH.
-
-               void Call(string number)
-
-                       Dial a number 'number'. No number processing is done
-                       thus if AG would reject to dial it don't blame me :)
-
-               string GetOperatorName()
-
-                       Find out the name of the currently selected network
-                       operator by AG.
-
-               void SendDTMF(string digits)
-
-                       Will send each digit in the 'digits' sequentially. Would
-                       send nothing if there is non-dtmf digit.
-
-               string GetSubscriberNumber()
-
-                       Get the voicecall subscriber number of AG
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-Signals                void Ring(string number)
-
-                       Someone's calling from 'number'.
-                       Caller number is provided as received from AG.
-
-               void CallTerminated()
-
-                       Call failed to set up. It means that we tried to call
-                       someone or someone tried to call us but call was not
-                       accepted.
-
-               void CallStarted()
-
-                       Call set up successfully.
-
-               void CallEnded()
-
-                       Call was started and now ended. In contrast with
-                       CallTerminated where call didn't started
-
-               PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-properties     boolean Connected [readonly]
-
-                       Indicates if there is an active connection to the
-                       AG service on the remote device.
-
-               uint16 RegistrationStatus [readonly]
-
-                       Service availability indicator of AG, where:
-                       0 implies no service. No Home/Roam network available.
-                       1 implies presence of service. Home/Roam network
-                       available.
-
-               uint16 SignalStrength [readonly]
-
-                       Signal strength indicator of AG, the value ranges from
-                       0 to 5.
-
-               uint16 RoamingStatus [readonly]
-
-                       Roaming status indicator of AG, where:
-                       0 means roaming is not active
-                       1 means a roaming is active
-
-               uint16 BatteryCharge [readonly]
-
-                       Battery Charge indicator of AG, the value ranges from
-                       0 to 5.
-
-               uint16 SpeakerGain  [readonly]
-
-                       The speaker gain when available.
-
-               uint16 MicrophoneGain  [readonly]
-
-                       The speaker gain when available.
diff --git a/doc/control-api.txt b/doc/control-api.txt
deleted file mode 100644 (file)
index eacfbcd..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-BlueZ D-Bus Control API description
-***********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2007-2008  David Stockwell <dstockwell@frequency-one.com>
-
-
-Control hierarchy
-=================
-
-Service                org.bluez
-Interface      org.bluez.Control
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                boolean IsConnected() {deprecated}
-
-                       Returns True if connected, otherwise FALSE.
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-               void VolumeUp()
-
-                       Adjust remote volume one step up
-
-               void VolumeDown()
-
-                       Adjust remote volume one step down
-
-Signals                Connected() {deprecated}
-
-                       Sent when a successful AVRCP connection has been made
-                       to the remote device.
-
-               Disconnected() {deprecated}
-
-                       Sent when the AVRCP connection to the remote device
-                       has been disconnected.
-
-Properties
-
-               boolean Connected [readonly]
diff --git a/doc/cyclingspeed-api.txt b/doc/cyclingspeed-api.txt
new file mode 100644 (file)
index 0000000..a1f1a93
--- /dev/null
@@ -0,0 +1,99 @@
+Cycling Speed and Cadence API description
+*****************************************
+
+
+Cycling Speed and Cadence Manager hierarchy
+===========================================
+
+Service                org.bluez
+Interface      org.bluez.CyclingSpeedManager1
+Object path    [variable prefix]/{hci0,hci1,...}
+
+Methods                RegisterWatcher(object agent)
+
+                       Registers a watcher to monitor cycling speed and
+                       cadence measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               UnregisterWatcher(object agent)
+
+                       Unregisters a watcher.
+
+Cycling Speed and Cadence Profile hierarchy
+===========================================
+
+Service                org.bluez
+Interface      org.bluez.CyclingSpeed1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods                SetCumulativeWheelRevolutions(uint32 value)
+
+                       Sets cumulative wheel revolutions value if
+                       Cumulative Wheel Revolutions feature is supported.
+
+                       Possible Errors: org.bluez.Error.NotSupported
+
+Properties     string Location (optional) [readwrite]
+
+                       Current sensor location, if supported.
+                       If Multiple Sensor Locations feature is supported,
+                       this property can be set to one of values read from
+                       SupportedLocations property.
+
+                       Possible values: "other", "top-of-shoe", "in-shoe",
+                                       "hip", "front-wheel", "left-crank",
+                                       "right-crank", "left-pedal",
+                                       "right-pedal", "front-hub",
+                                       "rear-dropout", "chainstay",
+                                       "rear-wheel", "rear-hub"
+
+               array{string} SupportedLocations (optional) [readonly]
+
+                       List of locations supported by sensor, only present
+                       if Multiple Sensor Locations feature is supported.
+
+               boolean WheelRevolutionDataSupported [readonly]
+
+                       true if sensor can read and set Cumulative Wheel
+                       Revolutions value, false otherwise.
+
+               boolean MultipleLocationsSupported [readonly]
+
+                       true if sensor supports Multiple Sensor Locations
+                       feature and can set Location, false otherwise.
+
+Cycling Speed and Cadence Watcher hierarchy
+===========================================
+
+Service                unique name
+Interface      org.bluez.CyclingSpeedWatcher1
+Object path    freely definable
+
+Methods                void MeasurementReceived(object device, dict measurement)
+
+                       This callback is called whenever wheel and/or crank
+                       revolutions measurement is received from sensor.
+
+                       Measurement:
+
+                               uint32 WheelRevolutions (optional):
+
+                                       Cumulative number of wheel revolutions.
+
+                               uint16 LastWheelEventTime (optional):
+
+                                       Time of last event from wheel sensor.
+                                       Value is expressed in 1/1024 second
+                                       units and can roll over during a ride.
+
+                               uint16 CrankRevolutions (optional):
+
+                                       Cumulative number of crank revolutions.
+                                       This value can occasionally roll over.
+
+                               uint16 LastCrankEventTime (optional):
+
+                                       Time of last event from crank sensor.
+                                       Value is expressed in 1/1024 second
+                                       units and can roll over during a ride.
index 4a170e4..6201780 100644 (file)
 BlueZ D-Bus Device API description
 **********************************
 
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
-Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
-Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
-
 
 Device hierarchy
 ================
 
 Service                org.bluez
-Interface      org.bluez.Device
+Interface      org.bluez.Device1
 Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
-Methods                dict GetProperties()
-
-                       Returns all properties for the device. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
-
-               void SetProperty(string name, variant value)
-
-                       Changes the value of the specified property. Only
-                       properties that are listed a read-write are changeable.
-                       On success this will emit a PropertyChanged signal.
+Methods                void Connect()
 
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
+                       This is a generic method to connect any profiles
+                       the remote device supports that can be connected
+                       to and have been flagged as auto-connectable on
+                       our side. If only subset of profiles is already
+                       connected it will try to connect currently disconnected
+                       ones.
 
-               dict DiscoverServices(string pattern)
-
-                       This method starts the service discovery to retrieve
-                       remote service records. The pattern parameter can
-                       be used to specify specific UUIDs. And empty string
-                       will look for the public browse group.
-
-                       The return value is a dictionary with the record
-                       handles as keys and the service record in XML format
-                       as values. The key is uint32 and the value a string
-                       for this dictionary.
+                       If at least one profile was connected successfully this
+                       method will indicate success.
 
                        Possible errors: org.bluez.Error.NotReady
                                         org.bluez.Error.Failed
                                         org.bluez.Error.InProgress
-
-               void CancelDiscovery()
-
-                       This method will cancel any previous DiscoverServices
-                       transaction.
-
-                       Possible errors: org.bluez.Error.NotReady
-                                        org.bluez.Error.Failed
-                                        org.bluez.Error.NotAuthorized
+                                        org.bluez.Error.AlreadyConnected
 
                void Disconnect()
 
-                       This method disconnects a specific remote device by
-                       terminating the low-level ACL connection. The use of
-                       this method should be restricted to administrator
-                       use.
+                       This method gracefully disconnects all connected
+                       profiles and then terminates low-level ACL connection.
 
-                       A DisconnectRequested signal will be sent and the
-                       actual disconnection will only happen 2 seconds later.
-                       This enables upper-level applications to terminate
-                       their connections gracefully before the ACL connection
-                       is terminated.
+                       ACL connection will be terminated even if some profiles
+                       were not disconnected properly e.g. due to misbehaving
+                       device.
 
-                       Possible errors: org.bluez.Error.NotConnected
+                       This method can be also used to cancel a preceding
+                       Connect call before a reply to it has been received.
 
-               array{object} ListNodes()
+                       Possible errors: org.bluez.Error.NotConnected
 
-                       Returns list of device node object paths.
+               void ConnectProfile(string uuid)
 
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-                                        org.bluez.Error.OutOfMemory
+                       This method connects a specific profile of this
+                       device. The UUID provided is the remote service
+                       UUID for the profile.
 
-               object CreateNode(string uuid)
+                       Possible errors: org.bluez.Error.DoesNotExist
+                                        org.bluez.Error.AlreadyConnected
+                                        org.bluez.Error.ConnectFailed
 
-                       Creates a persistent device node binding with a
-                       remote device. The actual support for the specified
-                       UUID depends if the device driver has support for
-                       persistent binding. At the moment only RFCOMM TTY
-                       nodes are supported.
+               void DisconnectProfile(string uuid)
 
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotSupported
+                       This method disconnects a specific profile of
+                       this device. The profile needs to be registered
+                       client profile.
 
-               void RemoveNode(object node)
+                       There is no connection tracking for a profile, so
+                       as long as the profile is registered this will always
+                       succeed.
 
-                       Removes a persistent device node binding.
+                       Possible errors: org.bluez.Error.DoesNotExist
+                                        org.bluez.Error.Failed
+                                        org.bluez.Error.NotConnected
+                                        org.bluez.Error.NotSupported
 
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.DoesNotExist
+               void Pair()
 
-Signals                PropertyChanged(string name, variant value)
+                       This method will connect to the remote device,
+                       initiate pairing and then retrieve all SDP records
+                       (or GATT primary services).
 
-                       This signal indicates a changed value of the given
-                       property.
+                       If the application has registered its own agent,
+                       then that specific agent will be used. Otherwise
+                       it will use the default agent.
 
-               DisconnectRequested()
+                       Only for applications like a pairing wizard it
+                       would make sense to have its own agent. In almost
+                       all other cases the default agent will handle
+                       this just fine.
 
-                       This signal will be sent when a low level
-                       disconnection to a remote device has been requested.
-                       The actual disconnection will happen 2 seconds later.
+                       In case there is no application agent and also
+                       no default agent present, this method will fail.
 
-               NodeCreated(object node)
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.Failed
+                                        org.bluez.Error.AuthenticationCanceled
+                                        org.bluez.Error.AuthenticationFailed
+                                        org.bluez.Error.AuthenticationRejected
+                                        org.bluez.Error.AuthenticationTimeout
+                                        org.bluez.Error.ConnectionAttemptFailed
 
-                       Parameter is object path of created device node.
+               void CancelPairing()
 
-               NodeRemoved(object node)
+                       This method can be used to cancel a pairing
+                       operation initiated by the Pair method.
 
-                       Parameter is object path of removed device node.
+                       Possible errors: org.bluez.Error.DoesNotExist
+                                        org.bluez.Error.Failed
 
 Properties     string Address [readonly]
 
                        The Bluetooth device address of the remote device.
 
-               string Name [readonly]
+               string Name [readonly, optional]
 
                        The Bluetooth remote name. This value can not be
                        changed. Use the Alias property instead.
 
-               uint16 Vendor [readonly]
-
-                       Vendor unique numeric identifier.
-
-               uint16 VendorSource [readonly]
-
-                       Vendor source numeric identifier.
-
-               uint16 Product [readonly]
-
-                       Product unique numeric identifier.
-
-               uint16 Version [readonly]
+                       This value is only present for completeness. It is
+                       better to always use the Alias property when
+                       displaying the devices name.
 
-                       Version unique numeric identifier.
+                       If the Alias property is unset, it will reflect
+                       this value which makes it more convenient.
 
-               string Icon [readonly]
+               string Icon [readonly, optional]
 
                        Proposed icon name according to the freedesktop.org
                        icon naming specification.
 
-               uint32 Class [readonly]
+               uint32 Class [readonly, optional]
 
                        The Bluetooth class of device of the remote device.
 
-               array{string} UUIDs [readonly]
+               uint16 Appearance [readonly, optional]
 
-                       List of 128-bit UUIDs that represents the available
-                       remote services.
+                       External appearance of device, as found on GAP service.
 
-               array{object} Services [readonly]
+               array{string} UUIDs [readonly, optional]
 
-                       List of characteristics based services.
+                       List of 128-bit UUIDs that represents the available
+                       remote services.
 
                boolean Paired [readonly]
 
@@ -166,7 +140,7 @@ Properties  string Address [readonly]
                boolean Connected [readonly]
 
                        Indicates if the remote device is currently connected.
-                       A PropertyChanged signal indicate changes to this
+                       A PropertiesChanged signal indicate changes to this
                        status.
 
                boolean Trusted [readwrite]
@@ -192,12 +166,7 @@ Properties string Address [readonly]
                        convert it back to the remote device name.
 
                        When resetting the alias with an empty string, the
-                       emitted PropertyChanged signal will show the remote
-                       name again.
-
-               array{object} Nodes [readonly]
-
-                       List of device node object paths.
+                       property will default back to the remote name.
 
                object Adapter [readonly]
 
@@ -213,3 +182,13 @@ Properties string Address [readonly]
                        Note that this property can exhibit false-positives
                        in the case of Bluetooth 2.1 (or newer) devices that
                        have disabled Extended Inquiry Response support.
+
+               string Modalias [readonly, optional]
+
+                       Remote Device ID information in modalias format
+                       used by the kernel and udev.
+
+               int16 RSSI [readonly, optional]
+
+                       Received Signal Strength Indicator of the remote
+                       device.
index 7a000cb..2c48ff2 100644 (file)
 BlueZ D-Bus Health API description
 **********************************
 
-       Santiago Carot-Nemesio <sancane@gmail.com>
-       José Antonio Santos-Cadenas <santoscadenas@gmail.com>
-       Elvis Pfützenreuter <epx@signove.com>
 
-Health Device Profile hierarchy
-===============================
+HealthManager hierarchy
+=======================
 
 Service                org.bluez
-Interface      org.bluez.HealthManager
+Interface      org.bluez.HealthManager1
 Object path    /org/bluez/
 
-Methods:
+Methods                object CreateApplication(dict config)
 
-       object  CreateApplication(dict config)
+                       Returns the path of the new registered application.
+                       Application will be closed by the call or implicitly
+                       when the programs leaves the bus.
 
-               Returns the path of the new registered application.
+                       config:
+                               uint16 DataType:
 
-               Dict is defined as below:
-               {
-                       "DataType": uint16, (mandatory)
-                       "Role" : ("Source" or "Sink"), (mandatory)
-                       "Description" : string, (optional)
-                       "ChannelType" : ("Reliable" or "Streaming")
-                                               (just for Sources, optional)
-               }
+                                       Mandatory
 
-               Application will be closed by the call or implicitly when the
-               programs leaves the bus.
+                               string Role:
 
-               Possible errors: org.bluez.Error.InvalidArguments
+                                       Mandatory. Possible values: "source",
+                                                                       "sink"
 
-       void    DestroyApplication(object application)
+                               string Description:
 
-               Closes the HDP application identified by the object path. Also
-               application will be closed if the process that started it leaves
-               the bus. Only the creator of the application will be able to
-               destroy it.
+                                       Optional
 
-               Possible errors: org.bluez.Error.InvalidArguments
-                               org.bluez.Error.NotFound
-                               org.bluez.Error.NotAllowed
+                               ChannelType:
 
---------------------------------------------------------------------------------
+                                       Optional, just for sources. Possible
+                                       values: "reliable", "streaming"
 
-Service                org.bluez
-Interface      org.bluez.HealthDevice
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods:
+                       Possible Errors: org.bluez.Error.InvalidArguments
 
-       dict GetProperties()
+               void DestroyApplication(object application)
 
-               Returns all properties for the interface. See the properties
-               section for available properties.
+                       Closes the HDP application identified by the object
+                       path. Also application will be closed if the process
+                       that started it leaves the bus. Only the creator of the
+                       application will be able to destroy it.
 
-               Posible errors: org.bluez.Error.NotAllowed
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.NotFound
+                                        org.bluez.Error.NotAllowed
 
-       Boolean Echo()
 
-               Sends an echo petition to the remote service. Returns True if
-               response matches with the buffer sent. If some error is detected
-               False value is returned.
+HealthDevice hierarchy
+======================
 
-               Possible errors: org.bluez.Error.InvalidArguments
-                               org.bluez.Error.OutOfRange
+Service                org.bluez
+Interface      org.bluez.HealthDevice1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
-       object CreateChannel(object application, string configuration)
+Methods                boolean Echo()
 
-               Creates a new data channel.
-               The configuration should indicate the channel quality of
-               service using one of this values "Reliable", "Streaming", "Any".
+                       Sends an echo petition to the remote service. Returns
+                       True if response matches with the buffer sent. If some
+                       error is detected False value is returned.
 
-               Returns the object path that identifies the data channel that
-               is already connected.
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.OutOfRange
 
-               Possible errors: org.bluez.Error.InvalidArguments
-                               org.bluez.Error.HealthError
+               object CreateChannel(object application, string configuration)
 
-       void DestroyChannel(object channel)
+                       Creates a new data channel.  The configuration should
+                       indicate the channel quality of service using one of
+                       this values "reliable", "streaming", "any".
 
-               Destroys the data channel object. Only the creator of the
-               channel or the creator of the HealthApplication that received
-               the data channel will be able to destroy it.
+                       Returns the object path that identifies the data
+                       channel that is already connected.
 
-               Possible errors: org.bluez.Error.InvalidArguments
-                               org.bluez.Error.NotFound
-                               org.bluez.Error.NotAllowed
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.HealthError
 
-Signals:
+               void DestroyChannel(object channel)
 
-       void ChannelConnected(object channel)
+                       Destroys the data channel object. Only the creator of
+                       the channel or the creator of the HealthApplication
+                       that received the data channel will be able to destroy
+                       it.
 
-               This signal is launched when a new data channel is created or
-               when a known data channel is reconnected.
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.NotFound
+                                        org.bluez.Error.NotAllowed
 
-       void ChannelDeleted(object channel)
+Signals                void ChannelConnected(object channel)
 
-               This signal is launched when a data channel is deleted.
+                       This signal is launched when a new data channel is
+                       created or when a known data channel is reconnected.
 
-               After this signal the data channel path will not be valid and
-               its path can be reused for future data channels.
+               void ChannelDeleted(object channel)
 
-       void PropertyChanged(string name, variant value)
+                       This signal is launched when a data channel is deleted.
 
-               This signal indicates a changed value of the given property.
+                       After this signal the data channel path will not be
+                       valid and its path can be reused for future data
+                       channels.
 
-Properties:
+Properties     object MainChannel [readonly]
 
-       object MainChannel [readonly]
+                       The first reliable channel opened. It is needed by
+                       upper applications in order to send specific protocol
+                       data units. The first reliable can change after a
+                       reconnection.
 
-               The first reliable channel opened. It is needed by upper
-               applications in order to send specific protocol data units. The
-               first reliable can change after a reconnection.
 
---------------------------------------------------------------------------------
+HealthChannel hierarchy
+=======================
 
 Service                org.bluez
-Interface      org.bluez.HealthChannel
+Interface      org.bluez.HealthChannel1
 Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/chanZZZ
 
 Only the process that created the data channel or the creator of the
-HealthApplication that received it will be able to call this methods.
-
-Methods:
-
-       dict GetProperties()
-
-               Returns all properties for the interface. See the properties
-               section for available properties.
-
-               Possible errors: org.bluez.Error.NotAllowed
-
-       fd Acquire()
+HealthApplication that received it will be able to call these methods.
 
-               Returns the file descriptor for this data channel. If the data
-               channel is not connected it will also reconnect.
+Methods                fd Acquire()
 
-               Possible errors: org.bluez.Error.NotConnected
-                               org.bluez.Error.NotAllowed
+                       Returns the file descriptor for this data channel. If
+                       the data channel is not connected it will also
+                       reconnect.
 
-       void Release()
+                       Possible Errors: org.bluez.Error.NotConnected
+                                        org.bluez.Error.NotAllowed
 
-               Releases the fd. Application should also need to close() it.
+               void Release()
 
-               Possible errors: org.bluez.Error.NotAcquired
-                               org.bluez.Error.NotAllowed
+                       Releases the fd. Application should also need to
+                       close() it.
 
-Properties:
+                       Possible Errors: org.bluez.Error.NotAcquired
+                                        org.bluez.Error.NotAllowed
 
-       string Type [readonly]
+Properties     string Type [readonly]
 
-               The quality of service of the data channel. ("Reliable" or
-               "Streaming")
+                       The quality of service of the data channel. ("reliable"
+                       or "streaming")
 
-       object Device [readonly]
+               object Device [readonly]
 
-               Identifies the Remote Device that is connected with. Maps with
-               a HealthDevice object.
+                       Identifies the Remote Device that is connected with.
+                       Maps with a HealthDevice object.
 
-       object Application [readonly]
+               object Application [readonly]
 
-               Identifies the HealthApplication to which this channel is
-               related to (which indirectly defines its role and data type).
+                       Identifies the HealthApplication to which this channel
+                       is related to (which indirectly defines its role and
+                       data type).
diff --git a/doc/heartrate-api.txt b/doc/heartrate-api.txt
new file mode 100644 (file)
index 0000000..665db12
--- /dev/null
@@ -0,0 +1,77 @@
+Heart Rate API description
+**************************
+
+
+Heart Rate Manager hierarchy
+============================
+
+Service                org.bluez
+Interface      org.bluez.HeartRateManager1
+Object path    [variable prefix]/{hci0,hci1,...}
+
+Methods                RegisterWatcher(object agent)
+
+                       Registers a watcher to monitor heart rate measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               UnregisterWatcher(object agent)
+
+                       Unregisters a watcher.
+
+Heart Rate Profile hierarchy
+============================
+
+Service                org.bluez
+Interface      org.bluez.HeartRate1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Methods                Reset()
+
+                       Restart the accumulation of energy expended from zero.
+
+                       Possible Errors: org.bluez.Error.NotSupported
+
+Properties     string Location (optional) [readonly]
+
+                       Possible values: "other", "chest", "wrist","winger",
+                                       "hand", "earlobe", "foot"
+
+               boolean ResetSupported [readonly]
+
+                       True if energy expended is supported.
+
+Heart Rate Watcher hierarchy
+============================
+
+Service                unique name
+Interface      org.bluez.HeartRateWatcher1
+Object path    freely definable
+
+Methods                void MeasurementReceived(object device, dict measurement)
+
+                       This callback is called whenever a heart rate
+                       measurement is received from the heart rate device.
+
+                       Measurement:
+
+                               uint16 Value:
+
+                                       Measurement value expressed in beats per
+                                       minute (bpm)
+
+                               uint16 Energy (optional):
+
+                                       Accumulated energy expended in kilo Joules
+
+                               boolean Contact (optional):
+
+                                       true if skin contact is detected by sensor,
+                                       false otherwise
+
+                               array{uint16} Interval (optional):
+
+                                       RR-Interval values which represent the time
+                                       between two consecutive R waves in an ECG.
+                                       Values are ordered starting from oldest to
+                                       most recent.
diff --git a/doc/hfp-api.txt b/doc/hfp-api.txt
deleted file mode 100644 (file)
index fad89ae..0000000
+++ /dev/null
@@ -1,84 +0,0 @@
-Gateway hierarchy
-========================
-
-Service                org.bluez
-Interface      org.bluez.HandsfreeGateway
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-This interface is available for remote devices which can function in the Audio
-Gateway role of the HFP profiles.  It is intended to be used with external
-telephony stacks / handlers of the HFP protocol.
-
-Methods                void Connect()
-
-                       Connect to the AG service on the remote device.
-
-               void Disconnect()
-
-                       Disconnect from the AG service on the remote device
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-               void RegisterAgent(object path)
-
-                       The object path defines the path the of the agent
-                       that will be called when a new Handsfree connection
-                       is established.
-
-                       If an application disconnects from the bus all of its
-                       registered agents will be removed.
-
-               void UnregisterAgent(object path)
-
-                       This unregisters the agent that has been previously
-                       registered. The object path parameter must match the
-                       same value that has been used on registration.
-
-                       Possible Errors: org.bluez.Error.Failed
-                                        org.bluez.Error.InvalidArguments
-
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-Properties     string State [readonly]
-
-                       Indicates the state of the connection.  Possible
-                       values are:
-                               "disconnected"
-                               "connecting"
-                               "connected"
-                               "playing"
-
-HandsfreeAgent hierarchy
-===============
-
-Service         unique name
-Interface       org.bluez.HandsfreeAgent
-Object path     freely definable
-
-Methods                void NewConnection(filedescriptor fd, uint16 version)
-
-                       This method gets called whenever a new handsfree
-                       connection has been established.  The objectpath
-                       contains the object path of the remote device.
-
-                       The agent should only return successfully once the
-                       establishment of the service level connection (SLC)
-                       has been completed.  In the case of Handsfree this
-                       means that BRSF exchange has been performed and
-                       necessary initialization has been done.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-
-               void Release()
-
-                       This method gets called whenever the service daemon
-                       unregisters the agent or whenever the Adapter where
-                       the HandsfreeAgent registers itself is removed.
diff --git a/doc/input-api.txt b/doc/input-api.txt
deleted file mode 100644 (file)
index 7c3a4b2..0000000
+++ /dev/null
@@ -1,44 +0,0 @@
-BlueZ D-Bus Input API description
-*********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-
-
-Input hierarchy
-===============
-
-Service                org.bluez
-Interface      org.bluez.Input
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                void Connect()
-
-                       Connect to the input device.
-
-                       Possible errors: org.bluez.Error.AlreadyConnected
-                                        org.bluez.Error.ConnectionAttemptFailed
-
-               void Disconnect()
-
-                       Disconnect from the input device.
-
-                       To abort a connection attempt in case of errors or
-                       timeouts in the client it is fine to call this method.
-
-                       Possible errors: org.bluez.Error.Failed
-
-               dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-Properties     boolean Connected [readonly]
-
-                       Indicates if the device is connected.
diff --git a/doc/manager-api.txt b/doc/manager-api.txt
deleted file mode 100644 (file)
index d2c1caf..0000000
+++ /dev/null
@@ -1,74 +0,0 @@
-BlueZ D-Bus Manager API description
-***********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
-Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
-Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
-
-
-Manager hierarchy
-=================
-
-Service                org.bluez
-Interface      org.bluez.Manager
-Object path    /
-
-Methods                dict GetProperties()
-
-                       Returns all global properties. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.InvalidArguments
-
-               object DefaultAdapter()
-
-                       Returns object path for the default adapter.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NoSuchAdapter
-
-               object FindAdapter(string pattern)
-
-                       Returns object path for the specified adapter. Valid
-                       patterns are "hci0" or "00:11:22:33:44:55".
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NoSuchAdapter
-
-               array{object} ListAdapters() {deprecated}
-
-                       Returns list of adapter object paths under /org/bluez.
-                       This method is deprecated, instead use the Adapters
-                       Property to get the list of adapter object paths.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-                                        org.bluez.Error.OutOfMemory
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
-               AdapterAdded(object adapter)
-
-                       Parameter is object path of added adapter.
-
-               AdapterRemoved(object adapter)
-
-                       Parameter is object path of removed adapter.
-
-               DefaultAdapterChanged(object adapter)
-
-                       Parameter is object path of the new default adapter.
-
-                       In case all adapters are removed this signal will not
-                       be emitted. The AdapterRemoved signal has to be used
-                       to detect that no default adapter is selected or
-                       available anymore.
-
-Properties     array{object} Adapters [readonly]
-
-                       List of adapter object paths.
index 4446439..05f90e3 100644 (file)
@@ -1,11 +1,12 @@
 BlueZ D-Bus Media API description
 *********************************
 
+
 Media hierarchy
 ===============
 
 Service                org.bluez
-Interface      org.bluez.Media
+Interface      org.bluez.Media1
 Object path    [variable prefix]/{hci0,hci1,...}
 
 Methods                void RegisterEndpoint(object endpoint, dict properties)
@@ -44,119 +45,152 @@ Methods           void RegisterEndpoint(object endpoint, dict properties)
 
                        Unregister sender end point.
 
-               void RegisterPlayer(object player, dict properties,
-                                                               dict metadata)
+               void RegisterPlayer(object player, dict properties)
 
                        Register a media player object to sender, the sender
-                       can register as many objets as it likes.
+                       can register as many objects as it likes.
+
+                       Object must implement at least
+                       org.mpris.MediaPlayer2.Player as defined in MPRIS 2.2
+                       spec:
+
+                       http://specifications.freedesktop.org/mpris-spec/latest/
 
                        Note: If the sender disconnects its objects are
                        automatically unregistered.
 
-                       Properties:
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.NotSupported
 
-                               string Equalizer:
+               void UnregisterPlayer(object player)
 
-                                       Possible values: "off" or "on"
+                       Unregister sender media player.
 
-                               string Repeat:
 
-                                       Possible values: "off", "singletrack",
-                                                       "alltracks" or "group"
+Media Control hierarchy
+=======================
 
-                               string Shuffle:
+Service                org.bluez
+Interface      org.bluez.MediaControl1 [Deprecated]
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
-                                       Possible values: "off", "alltracks" or
-                                                       "group"
+Methods                void Play()
 
-                               string Scan:
+                       Resume playback.
 
-                                       Possible values: "off", "alltracks" or
-                                                       "group"
+               void Pause()
 
-                               string Status:
+                       Pause playback.
 
-                                       Possible values: "playing", "stopped",
-                                                       "paused",
-                                                       "forward-seek",
-                                                       "reverse-seek" or
-                                                       "error"
+               void Stop()
 
-                               uint32 Position
+                       Stop playback.
 
-                                       Playback position in milliseconds
+               void Next()
 
-                       Metadata:
+                       Next item.
 
-                               string Title:
+               void Previous()
 
-                                       Track title name
+                       Previous item.
 
-                               string Artist:
+               void VolumeUp()
 
-                                       Track artist name
+                       Adjust remote volume one step up
 
-                               string Album:
+               void VolumeDown()
 
-                                       Track album name
+                       Adjust remote volume one step down
 
-                               string Genre:
+               void FastForward()
 
-                                       Track genre name
+                       Fast forward playback, this action is only stopped
+                       when another method in this interface is called.
 
-                               uint32 NumberOfTracks:
+               void Rewind()
 
-                                       Number of tracks in total
+                       Rewind playback, this action is only stopped
+                       when another method in this interface is called.
 
-                               uint32 Number:
+Properties
 
-                                       Track number
+               boolean Connected [readonly]
 
-                               uint32 Duration:
 
-                                       Track duration in milliseconds
+MediaPlayer1 hierarchy
+======================
 
-                       Possible Errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotSupported
+Service                org.bluez (Controller role)
+Interface      org.bluez.MediaPlayer1 [Experimental]
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX
 
-               void UnregisterPlayer(object player)
+Methods                void Play()
 
-                       Unregister sender media player.
+                       Resume playback.
 
-MediaPlayer hierarchy
-=====================
+               void Pause()
 
-Service                unique name
-Interface      org.bluez.MediaPlayer
-Object path    freely definable
+                       Pause playback.
 
-Methods                void SetProperty(string property, variant value)
+               void Stop()
 
-                       Changes the value of the specified property. Only
-                       properties that are listed as read-write can be changed.
+                       Stop playback.
 
-                       On success this will emit a PropertyChanged signal.
+               void Next()
 
-               void Release()
+                       Next item.
 
-                       This method gets called when the service daemon
-                       unregisters the player which can then perform
-                       cleanup tasks. There is no need to unregister the
-                       player, because when this method gets called it has
-                       already been unregistered.
+               void Previous()
+
+                       Previous item.
+
+               void FastForward()
+
+                       Fast forward playback, this action is only stopped
+                       when another method in this interface is called.
+
+               void Rewind()
+
+                       Rewind playback, this action is only stopped
+                       when another method in this interface is called.
+
+Properties     string Equalizer [readwrite]
+
+                       Possible values: "off" or "on"
+
+               string Repeat [readwrite]
+
+                       Possible values: "off", "singletrack", "alltracks" or
+                                       "group"
+
+               string Shuffle [readwrite]
+
+                       Possible values: "off", "alltracks" or "group"
+
+               string Scan [readwrite]
+
+                       Possible values: "off", "alltracks" or "group"
 
-Signals                PropertyChanged(string setting, variant value)
+               string Status [readonly]
 
-                       This signal indicates a changed value of the given
-                       property.
+                       Possible status: "playing", "stopped", "paused",
+                                       "forward-seek", "reverse-seek"
+                                       or "error"
+
+               uint32 Position [readonly]
+
+                       Playback position in milliseconds. Changing the
+                       position may generate additional events that will be
+                       sent to the remote device. When position is 0 it means
+                       the track is starting and when it's greater than or
+                       equal to track's duration the track has ended. Note
+                       that even if duration is not available in metadata it's
+                       possible to signal its end by setting position to the
+                       maximum uint32 value.
 
-               TrackChanged(dict metadata)
+               dict Track [readonly]
 
-                       This signal indicates that current track has changed.
-                       All available metadata for the new track shall be set
-                       at once in the metadata argument. Metadata cannot be
-                       updated in parts, otherwise it will be interpreted as
-                       multiple track changes.
+                       Track metadata.
 
                        Possible values:
 
@@ -180,7 +214,7 @@ Signals             PropertyChanged(string setting, variant value)
 
                                        Number of tracks in total
 
-                               uint32 Number:
+                               uint32 TrackNumber:
 
                                        Track number
 
@@ -188,45 +222,244 @@ Signals          PropertyChanged(string setting, variant value)
 
                                        Track duration in milliseconds
 
-Properties     string Equalizer [readwrite]
+               object Device [readonly]
 
-                       Possible values: "off" or "on"
+                       Device object path.
 
-               string Repeat [readwrite]
+               string Name [readonly]
 
-                       Possible values: "off", "singletrack", "alltracks" or
-                                       "group"
+                       Player name
 
-               string Shuffle [readwrite]
+               string Type [readonly]
 
-                       Possible values: "off", "alltracks" or "group"
+                       Player type
 
-               string Scan [readwrite]
+                       Possible values:
 
-                       Possible values: "off", "alltracks" or "group"
+                               "Audio"
+                               "Video"
+                               "Audio Broadcasting"
+                               "Video Broadcasting"
 
-               string Status [readonly]
+               string Subtype [readonly]
 
-                       Possible status: "playing", "stopped", "paused",
-                                       "forward-seek", "reverse-seek" or
-                                       "error"
+                       Player subtype
 
-               uint32 Position [readonly]
+                       Possible values:
 
-                       Playback position in milliseconds. Changing the
-                       position may generate additional events that will be
-                       sent to the remote device. When position is 0 it means
-                       the track is starting and when it's greater than or
-                       equal to track's duration the track has ended. Note
-                       that even if duration is not available in metadata it's
-                       possible to signal its end by setting position to the
-                       maximum uint32 value.
+                               "Audio Book"
+                               "Podcast"
 
-MediaEndpoint hierarchy
-=======================
+               boolean Browsable [readonly]
+
+                       If present indicates the player can be browsed using
+                       MediaFolder interface.
+
+                       Possible values:
+
+                               True: Supported and active
+                               False: Supported but inactive
+
+                       Note: If supported but inactive clients can enable it
+                       by using MediaFolder interface but it might interfere
+                       in the playback of other players.
+
+
+               boolean Searchable [readonly]
+
+                       If present indicates the player can be searched using
+                       MediaFolder interface.
+
+                       Possible values:
+
+                               True: Supported and active
+                               False: Supported but inactive
+
+                       Note: If supported but inactive clients can enable it
+                       by using MediaFolder interface but it might interfere
+                       in the playback of other players.
+
+               object Playlist
+
+                       Playlist object path.
+
+MediaFolder1 hierarchy
+======================
+
+Service                unique name (Target role)
+               org.bluez (Controller role)
+Interface      org.bluez.MediaFolder1 [Experimental]
+Object path    freely definable (Target role)
+               [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX
+               (Controller role)
+
+Methods                object Search(string value, dict filter)
+
+                       Return a folder object containing the search result.
+
+                       To list the items found use the folder object returned
+                       and pass to ChangeFolder.
+
+               array{objects, properties} ListItems(dict filter)
+
+                       Return a list of items found
+
+               void ChangeFolder(object folder)
+
+                       Change current folder.
+
+                       Note: By changing folder the items of previous folder
+                       might be destroyed and have to be listed again, the
+                       exception is NowPlaying folder which should be always
+                       present while the player is active.
+
+Properties     uint32 NumberOfItems [readonly]
+
+                       Number of items in the folder
+
+               string Name [readonly]
+
+                       Folder name:
+
+                       Possible values:
+                               "/Filesystem/...": Filesystem scope
+                               "/NowPlaying/...": NowPlaying scope
+
+                       Note: /NowPlaying folder might not be listed if player
+                       is stopped, folders created by Search are virtual so
+                       once another Search is perform or the folder is
+                       changed using ChangeFolder it will no longer be listed.
+
+Filters                uint32 Start:
+
+                       Offset of the first item.
+
+                       Default value: 0
+
+               uint32 End:
+
+                       Offset of the last item.
+
+                       Default value: NumbeOfItems
+
+               array{string} Attributes
+
+                       Item properties that should be included in the list.
+
+                       Possible Values:
+
+                               "title", "artist", "album", "genre",
+                               "number-of-tracks", "number", "duration"
+
+                       Default Value: All
+
+MediaItem1 hierarchy
+====================
+
+Service                unique name (Target role)
+               org.bluez (Controller role)
+Interface      org.bluez.MediaItem1 [Experimental]
+Object path    freely definable (Target role)
+               [variable
+               prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/playerX/itemX
+               (Controller role)
+
+Methods                void Play()
+
+                       Play item
+
+               void AddtoNowPlaying()
+
+                       Add item to now playing list
+
+Properties     object Player [readonly]
+
+                       Player object path the item belongs to
+
+               string Name [readonly]
+
+                       Item displayable name
+
+               string Type [readonly]
+
+                       Item type
+
+                       Possible values: "video", "audio", "folder"
+
+               string FolderType [readonly, optional]
+
+                       Folder type.
+
+                       Possible values: "mixed", "titles", "albums", "artists"
+
+                       Available if property Type is "Folder"
+
+               boolean Playable [readonly, optional]
+
+                       Indicates if the item can be played
+
+                       Available if property Type is "folder"
+
+               dict Metadata [readonly]
+
+                       Item metadata.
+
+                       Possible values:
+
+                               string Title
+
+                                       Item title name
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               string Artist
+
+                                       Item artist name
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               string Album
+
+                                       Item album name
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               string Genre
+
+                                       Item genre name
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               uint32 NumberOfTracks
+
+                                       Item album number of tracks in total
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               uint32 Number
+
+                                       Item album number
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+                               uint32 Duration
+
+                                       Item duration in milliseconds
+
+                                       Available if property Type is "audio"
+                                       or "video"
+
+MediaEndpoint1 hierarchy
+========================
 
 Service                unique name
-Interface      org.bluez.MediaEndpoint
+Interface      org.bluez.MediaEndpoint1
 Object path    freely definable
 
 Methods                void SetConfiguration(object transport, dict properties)
@@ -257,47 +490,38 @@ Methods           void SetConfiguration(object transport, dict properties)
                        endpoint, because when this method gets called it has
                        already been unregistered.
 
-MediaTransport hierarchy
-========================
+
+MediaTransport1 hierarchy
+=========================
 
 Service                org.bluez
-Interface      org.bluez.MediaTransport
+Interface      org.bluez.MediaTransport1
 Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX/fdX
 
-Methods                dict GetProperties()
-
-                       Returns all properties for the interface. See the
-                       properties section for available properties.
-
-               fd, uint16, uint16 Acquire(string accesstype)
+Methods                fd, uint16, uint16 Acquire()
 
                        Acquire transport file descriptor and the MTU for read
                        and write respectively.
 
-                       possible accesstype:
+                       Possible Errors: org.bluez.Error.NotAuthorized
+                                        org.bluez.Error.Failed
 
-                               "r" : Read only access
+               fd, uint16, uint16 TryAcquire()
 
-                               "w" : Write only access
+                       Acquire transport file descriptor only if the transport
+                       is in "pending" state at the time the message is
+                       received by BlueZ. Otherwise no request will be sent
+                       to the remote device and the function will just fail
+                       with org.bluez.Error.NotAvailable.
 
-                               "rw": Read and write access
+                       Possible Errors: org.bluez.Error.NotAuthorized
+                                        org.bluez.Error.Failed
+                                        org.bluez.Error.NotAvailable
 
-               void Release(string accesstype)
+               void Release()
 
                        Releases file descriptor.
 
-               void SetProperty(string name, variant value)
-
-                       Changes the value of the specified property. Only
-                       properties that are listed a read-write can be changed.
-
-                       On success this will emit a PropertyChanged signal.
-
-Signals                void PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
 Properties     object Device [readonly]
 
                        Device object which the transport is connected to.
@@ -317,6 +541,14 @@ Properties object Device [readonly]
                        Configuration blob, it is used as it is so the size and
                        byte order must match.
 
+               string State [readonly]
+
+                       Indicates the state of the transport. Possible
+                       values are:
+                               "idle": not streaming
+                               "pending": streaming but not acquired
+                               "active": streaming and acquired
+
                uint16 Delay [readwrite]
 
                        Optional. Transport delay in 1/10 of millisecond, this
@@ -325,20 +557,23 @@ Properties        object Device [readonly]
 
                boolean NREC [readwrite]
 
-                       Optional. Indicates if echo cancelling and noise
-                       reduction functions are active in the transport, this
-                       property is only writeable when the transport was
-                       acquired by the sender.
+                       Optional and HFP specific (external to BlueZ).
+                       Indicates if echo cancelling and noise reduction
+                       functions are active in the transport, this
+                       property is only writeable when the transport
+                       was acquired by the sender.
 
                boolean InbandRingtone [readwrite]
 
-                       Optional. Indicates if the transport support sending
-                       ringtones, this property is only writeable when the
-                       transport was acquired by the sender.
+                       Optional and HFP specific (external to BlueZ).
+                       Indicates if the transport support sending
+                       ringtones, this property is only writeable when
+                       the transport was acquired by the sender.
 
                string Routing [readonly]
 
-                       Optional. Indicates where is the transport being routed
+                       Optional and HFP specific (external to BlueZ).
+                       Indicates where is the transport being routed.
 
                        Possible Values: "HCI" or "PCM"
 
@@ -348,4 +583,26 @@ Properties object Device [readonly]
                        this property is only writeable when the transport was
                        acquired by the sender.
 
+                       Note: the property will not be present for HSP/HFP
+                       transports and MicrophoneGain/SpeakerGain should be
+                       used instead.
+
                        Possible Values: 0-127
+
+               byte MicrophoneGain [readwrite]
+
+                       Optional. Indicates volume level of the transport's
+                       incoming audio stream for HSP/HFP transports. This
+                       property is only writeable when the transport was
+                       acquired by the sender.
+
+                       Possible Values: 0-15
+
+               byte SpeakerGain [readwrite]
+
+                       Optional. Indicates volume level of the transport's
+                       outgoing audio stream for HSP/HFP transports. This
+                       property is only writeable when the transport was
+                       acquired by the sender.
+
+                       Possible Values: 0-15
diff --git a/doc/mgmt-api.txt b/doc/mgmt-api.txt
new file mode 100644 (file)
index 0000000..371f252
--- /dev/null
@@ -0,0 +1,1747 @@
+Bluetooth Management API
+*************************
+
+Copyright (C) 2008-2009  Marcel Holtmann <marcel@holtmann.org>
+
+
+This document describes the format of data used for communicating with
+the kernel using a so-called Bluetooth Management sockets. These sockets
+are available starting with Linux kernel version 3.4, and can be created
+by setting the hci_channel member of struct sockaddr_hci to
+HCI_CHANNEL_CONTROL (3) when creating a raw HCI socket. In C the needed
+code would look something like the following:
+
+int mgmt_create(void)
+{
+       struct sockaddr_hci addr;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                                                BTPROTO_HCI);
+       if (fd < 0)
+               return -errno;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = HCI_DEV_NONE;
+       addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               int err = -errno;
+               close(fd);
+               return err;
+       }
+
+       return fd;
+}
+
+The process creating the mgmt socket is required to have the
+CAP_NET_ADMIN capability (e.g. root would have this).
+
+
+Packet Structures
+=================
+
+       Commands:
+
+       0    4    8   12   16   22   24   28   31   35   39   43   47
+       +-------------------+-------------------+-------------------+
+       |  Command Code     |  Controller Index |  Parameter Length |
+       +-------------------+-------------------+-------------------+
+       |                                                           |
+
+       Events:
+
+       0    4    8   12   16   22   24   28   31   35   39   43   47
+       +-------------------+-------------------+-------------------+
+       |  Event Code       |  Controller Index |  Parameter Length |
+       +-------------------+-------------------+-------------------+
+       |                                                           |
+
+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:
+
+       <controller id>         0x0000 to 0xFFFE
+       <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
+0x10   Cancelled
+0x11   Invalid Index
+
+
+Read Management Version Information Command
+===========================================
+
+       Command Code:           0x0001
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Version (1 Octets)
+                               Revision (2 Octets)
+
+       This command returns the Management version and revision.
+       Besides, being informational the information can be used to
+       determine whether certain behavior has changed or bugs fixed
+       when interacting with the kernel.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+
+Read Management Supported Commands Command
+==========================================
+
+       Command Code:           0x0002
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Num_Of_Commands (2 Octets)
+                               Num_Of_Events (2 Octets)
+                               Command1 (2 Octets)
+                               Command2 (2 Octets)
+                               ...
+                               Event1 (2 Octets)
+                               Event2 (2 Octets)
+                               ...
+
+       This command returns the list of supported Management commands
+       and events.
+
+       The commands Read Management Version Information and Read
+       management Supported Commands are not included in this list.
+       Both commands are always supported and mandatory.
+
+       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
+==================================
+
+       Command Code:           0x0003
+       Controller Index:       <non-controller>
+       Command Parameters:
+       Return Parameters:      Num_Controllers (2 Octets)
+                               Controller_Index[i] (2 Octets)
+
+       This command returns the list of currently known controllers.
+       Controllers added or removed after calling this command can be
+       monitored using the Index Added and Index Removed events.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+
+Read Controller Information Command
+===================================
+
+       Command Code:           0x0004
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Address (6 Octets)
+                               Bluetooth_Version (1 Octet)
+                               Manufacturer (2 Octets)
+                               Supported_Settings (4 Octets)
+                               Current_Settings (4 Octets)
+                               Class_Of_Device (3 Octets)
+                               Name (249 Octets)
+                               Short_Name (11 Octets)
+
+       This command is used to retreive the current state and basic
+       information of a controller. It is typically used right after
+       getting the response to the Read Controller Index List command
+       or an Index Added event.
+
+       If not short name is set the Short_Name parameter will be empty
+       (begin with a nul byte).
+
+       Current_Settings & Supported_Settings is a bitmask with
+       currently the following available bits:
+
+               1       Powered
+               2       Connectable
+               3       Fast Connectable
+               4       Discoverable
+               5       Pairable
+               6       Link Level Security (Sec. mode 3)
+               7       Secure Simple Pairing
+               8       Basic Rate/Enhanced Data Rate
+               9       High Speed
+               10      Low Energy
+               11      Advertising
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Set Powered Command
+===================
+
+       Command Code:           0x0005
+       Controller Index:       <controller id>
+       Command Parameters:     Powered (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to power on or off a controller. The
+       allowed Powered command parameter values are 0x00 and 0x01. All
+       other values will return Invalid Parameters.
+
+       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.
+
+       Possible errors:        Busy
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Discoverable Command
+========================
+
+       Command Code:           0x0006
+       Controller Index:       <controller id>
+       Command Parameters:     Discoverable (1 Octet)
+                               Timeout (2 Octets)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to set the discoverable property of a
+       controller. The allowed Discoverable command parameter values
+       are 0x00, 0x01 and 0x02. All other values will return Invalid
+       Parameters.
+
+       Timeout is the time in seconds and is only meaningful when
+       Discoverable is set to 0x01 or 0x02. Providing a timeout
+       with 0x00 return Invalid Parameters. For 0x02, the timeout
+       value is required.
+
+       The value 0x00 disables discoverable, the value 0x01 enables
+       general discoverable and the value 0x02 enables limited
+       discoverable.
+
+       This command is only available for BR/EDR capable controllers
+       (e.g. not for single-mode LE ones). It will return Not Supported
+       otherwise.
+
+       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 Not Powered error.
+
+       When switching discoverable on and the connectable setting is
+       off it will return Rejected error.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Busy
+                               Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Set Connectable Command
+=======================
+
+       Command Code:           0x0007
+       Controller Index:       <controller id>
+       Command Parameters:     Connectable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to set the connectable property of a
+       controller. The allowed Connectable command parameter values are
+       0x00 and 0x01. All other values will return Invalid Parameters.
+
+       This command is available for BR/EDR, LE-only and also dual
+       mode controllers. For BR/EDR is changes the page scan setting
+       and for LE controllers it changes the advertising type. For
+       dual mode controllers it affects both settings.
+
+       For LE capable controllers the connectable setting only takes
+       affect when advertising is enabled.
+
+       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.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Fast Connectable Command
+============================
+
+       Command Code:           0x0008
+       Controller Index:       <controller id>
+       Command Parameters:     Enable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to set the controller into a connectable
+       state where the page scan parameters have been set in a way to
+       favor faster connect times with the expense of higher power
+       consumption.
+
+       The allowed values of the Enable command parameter are 0x00 and
+       0x01. All other values will return Invalid Parameters.
+
+       This command is only available for BR/EDR capable controllers
+       (e.g. not for single-mode LE ones). It will return Not Supported
+       otherwise.
+
+       This command can only be used when the controller is powered on
+       and will return Not Powerd otherwise.
+
+       If connectable is not set, then this command will fail with
+       Rejected error.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Failed
+                               Busy
+                               Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Set Pairable Command
+====================
+
+       Command Code:           0x0009
+       Controller Index:       <controller id>
+       Command Parameters:     Pairable (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to set the pairable property of an
+       controller. The allowed values for the Pairable command
+       parameter are 0x00 and 0x01. All other values will return
+       Invalid Parameters.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Set Link Security Command
+=========================
+
+       Command Code:           0x000A
+       Controller Index:       <controller id>
+       Command Parameters:     Link_Security (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to either enable or disable link level
+       security for an controller (also known as Security Mode 3). The
+       allowed values for the Link_Security command parameter are 0x00
+       and 0x01. All other values will return Invalid Parameters.
+
+       This command is only available for BR/EDR capable controllers
+       (e.g. not for single-mode LE ones). It will return Not Supported
+       otherwise.
+
+       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.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Secure Simple Pairing Command
+=================================
+
+       Command Code:           0x000B
+       Controller Index:       <controller id>
+       Command Parameters:     Secure_Simple_Pairing (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to enable/disable Secure Simple Pairing
+       support for a controller. The allowed values for the
+       Secure_Simple_Pairing command parameter are 0x00 and 0x01. All
+       other values will return Invalid Parameters.
+
+       This command is only available for BR/EDR capable controllers
+       supporting the core specification version 2.1 or greater
+       (e.g. not for single-mode LE controllers or pre-2.1 ones).
+
+       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 with Not Supported error.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+Set High Speed Command
+======================
+
+       Command Code:           0x000C
+       Controller Index:       <controller id>
+       Command Parameters:     High_Speed (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to enable/disable Bluetooth High Speed
+       support for a controller. The allowed values for the High_Speed
+       command parameter are 0x00 and 0x01. All other values will
+       return Invalid Parameters.
+
+       This command is only available for BR/EDR capable controllers
+       (e.g. not for single-mode LE ones).
+
+       This command can be used when the controller is not powered and
+       all settings will be programmed once powered.
+
+       To enable High Speed support, it is required that Secure Simple
+       Pairing support is enabled first. High Speed support is not
+       possible for connections without Secure Simple Pairing.
+
+       When switching Secure Simple Pairing off, the support for High
+       Speed will be switched off as well. Switching Secure Simple
+       Pairing back on, will not re-enable High Speed support. That
+       needs to be done manually.
+
+       This command generates a Command Complete event on success or
+       a Command Status event on failure.
+
+       Possible errors:        Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Low Energy Command
+======================
+
+       Command Code:           0x000D
+       Controller Index:       <controller id>
+       Command Parameters:     Low_Energy (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to enable/disable Low Energy support for a
+       controller. The allowed values of the Low_Energy command
+       parameter are 0x00 and 0x01. All other values will return
+       Invalid Parameters.
+
+       This command is only available for LE capable controllers and
+       will yield in a Not Supported error otherwise.
+
+       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.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Device Class
+================
+
+       Command Code:           0x000E
+       Controller Index:       <controller id>
+       Command Parameters:     Major_Class (1 Octet)
+                               Minor_Class (1 Octet)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+       This command is used to set the major and minor device class for
+       BR/EDR capable controllers.
+
+       This command will also implicitly disable caching of pending CoD
+       and EIR updates.
+
+       This command is only available for BR/EDR capable controllers
+       (e.g. not for single-mode LE ones).
+
+       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.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Local Name Command
+======================
+
+       Command Code:           0x000F
+       Controller Index:       <controller id>
+       Command Parameters:     Name (249 Octets)
+                               Short_Name (11 Octets)
+       Return Parameters:      Name (249 Octets)
+                               Short_Name (11 Octets)
+
+       This command is used to set the local name of a controller. The
+       command parameters also include a short name which will be used
+       in case the full name doesn't fit within EIR/AD data.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Add UUID Command
+================
+
+       Command Code:           0x0010
+       Controller Index:       <controller id>
+       Command Parameters:     UUID (16 Octets)
+                               SVC_Hint (1 Octet)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+       This command is used to add a UUID to be published in EIR
+       and/or AD data. The accompanied SVC_Hint parameter is used to
+       tell the kernel whether the service class bits of the Class of
+       Device value need modifying due to this UUID.
+
+       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.
+
+       Possible errors:        Busy
+                               Invalid Parameters
+                               Invalid Index
+
+
+Remove UUID Command
+===================
+
+       Command Code:           0x0011
+       Controller Index:       <controller id>
+       Command Parameters:     UUID (16 Octets)
+       Return Parameters:      Class_Of_Device (3 Octets)
+
+       This command is used to remove a UUID previously added using the
+       Add UUID command.
+
+       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.
+
+       Possible errors:        Busy
+                               Invalid Parameters
+                               Invalid Index
+
+
+Load Link Keys Command
+======================
+
+       Command Code:           0x0012
+       Controller Index:       <controller id>
+       Command Parameters:     Debug_Keys (1 Octet)
+                               Key_Count (2 Octets)
+                               Key1 {
+                                       Address (6 Octets)
+                                       Address_Type (1 Octet)
+                                       Key_Type (1 Octet)
+                                       Value (16 Octets)
+                                       PIN_Length (1 Octet)
+                               }
+                               Key2 { }
+                               ...
+       Return Parameters:
+
+       This command is used to feed the kernel with currently known
+       link keys. The command does not need to be called again upon the
+       receiption of new link key events since the kernel updates its
+       list automatically.
+
+       The Debug_Keys parameter is used to tell the kernel whether to
+       accept the usage of debug keys or not. The allowed values for
+       this parameter are 0x00 and 0x01. All other values will return
+       an Invalid Parameters response.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Load Long Term Keys Command
+===========================
+
+       Command Code:           0x0013
+       Controller Index:       <controller id>
+       Command Parameters:     Key_Count (2 Octets)
+                               Key1 {
+                                       Address (6 Octets)
+                                       Address_Type (1 Octet)
+                                       Authenticated (1 Octet)
+                                       Master (1 Octet)
+                                       Encryption_Size (1 Octet)
+                                       Encryption_Diversifier (2 Octets)
+                                       Random_Number (8 Octets)
+                                       Value (16 Octets)
+                               }
+                               Key2 {  }
+                               ...
+       Return Parameters:
+
+       This command is used to feed the kernel with currently known
+       (SMP) Long Term Keys. The command does not need to be called
+       again upon the receiption of new Long Term Key events since the
+       kernel updates its list automatically.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Disconnect Command
+==================
+
+       Command Code:           0x0014
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to force the disconnection of a currently
+       connected device.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Busy
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Get Connections Command
+=======================
+
+       Command Code:           0x0015
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Connection_Count (2 Octets)
+                               Address1 {
+                                       Address (6 Octets)
+                                       Address_Type (1 Octet)
+                               }
+                               Address2 { }
+                               ...
+
+       This command is used to retreive a list of currently connected
+       devices.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+PIN Code Reply Command
+=======================
+
+       Command Code:           0x0016
+       Controller Index:       <controller id>
+       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 is used to respond to a PIN Code request event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+PIN Code Negative Reply Command
+===============================
+
+       Command Code:           0x0017
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to return a negative response to a PIN Code
+       Request event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Set IO Capability Command
+=========================
+
+       Command Code:           0x0018
+       Controller Index:       <controller id>
+       Command Parameters:     IO_Capability (1 Octet)
+       Return Parameters:
+
+       This command is used to set the IO Capability used for pairing.
+       The command accepts both SSP and SMP values. The KeyboardDisplay
+       SMP value (which doesn't exist for SSP will) automatically be
+       downgraded to DisplayYesNo by the kernel for SSP pairing events.
+
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Pair Device Command
+===================
+
+       Command Code:           0x0019
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+                               IO_Capability (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to trigger pairing with a remote device.
+       The IO_Capability command parameter is used to temporarily (for
+       this pairing event only) override the global IO Capaility (set
+       using the Set IO Capability command).
+
+       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.
+
+       Possible errors:        Connect Failed
+                               Busy
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+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.
+
+       Possible errors:        Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+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.
+
+       Possible errors:        Not Paired
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+User Confirmation Reply Command
+===============================
+
+       Command Code:           0x001C
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to respond to a User Confirmation Request
+       event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+User Confirmation Negative Reply Command
+========================================
+
+       Command Code:           0x001D
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to return a negative response to a User
+       Confirmation Request event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+User Passkey Reply Command
+==========================
+
+       Command Code:           0x001E
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Passkey (4 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to respond to a User Confirmation Passkey
+       Request event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+User Passkey Negative Reply Command
+===================================
+
+       Command Code:           0x001F
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to return a negative response to a User
+       Passkey Request event.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Not Connected
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Read Local Out Of Band Data Command
+===================================
+
+       Command Code:           0x0020
+       Controller Index:       <controller id>
+       Command Parameters:
+       Return Parameters:      Hash (16 Octets)
+                               Randomizer (16 Octets)
+
+       This command is used to read the local Out of Band data.
+
+       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.
+
+       Possible errors:        Not Supported
+                               Busy
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Add Remote Out Of Band Data Command
+===================================
+
+       Command Code:           0x0021
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Hash (16 Octets)
+                               Randomizer (16 Octets)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to provide Out of Band data for a remote
+       device.
+
+       Provided Out Of Band data is persistent over power down/up toggles.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Failed
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Remove Remote Out Of Band Data Command
+======================================
+
+       Command Code:           0x0022
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to remove data added using the Add Remote
+       Out Of Band Data command.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Start Discovery Command
+=======================
+
+       Command Code:           0x0023
+       Controller Index:       <controller id>
+       Command Parameters:     Address_Type (1 Octet)
+       Return Parameters:      Address_Type (1 Octet)
+
+       This command is used to start the process of discovering remote
+       devices. A Device Found event will be sent for each discovered
+       device.
+
+       Possible values for the Address_Type parameter are a bit-wise or
+       of the following bits:
+
+               1       BR/EDR
+               2       LE Public
+               3       LE Random
+
+       By combining these e.g. the following values are possible:
+
+               1       BR/EDR
+               6       LE (public & random)
+               7       BR/EDR/LE (interleaved discovery)
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Busy
+                               Not Supported
+                               Invalid Parameters
+                               Not Powered
+                               Invalid Index
+
+
+Stop Discovery Command
+======================
+
+       Command Code:           0x0024
+       Controller Index:       <controller id>
+       Command Parameters:     Address_Type (1 Octet)
+       Return Parameters:      Address_Type (1 Octet)
+
+       This command is used to stop the discovery process started using
+       the Start Discovery command.
+
+       This command can only be used when the controller is powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Rejected
+                               Invalid Parameters
+                               Invalid Index
+
+
+Confirm Name Command
+====================
+
+       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)
+                               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.
+
+       Possible errors:        Failed
+                               Invalid Parameters
+                               Invalid Index
+
+
+Block Device Command
+====================
+
+       Command Code:           0x0026
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to add a device to the list of devices
+       which should be blocked from being connect to the local
+       controller.
+
+       This command can be used when the controller is not powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Failed
+                               Invalid Parameters
+                               Invalid Index
+
+
+Unblock Device Command
+======================
+
+       Command Code:           0x0027
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+                               Address_Type (1 Octet)
+       Return Parameters:      Address (6 Octets)
+                               Address_Type (1 Octet)
+
+       This command is used to remove a device from the list of blocked
+       devices (where it was added to using the Block Device command).
+
+       This command can be used when the controller is not powered.
+
+       This command generates a Command Complete event on success
+       or failure.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Set Device ID Command
+=====================
+
+       Command Code:           0x0028
+       Controller Index:       <controller id>
+       Command Parameters:     Source (2 Octets)
+                               Vendor (2 Octets)
+                               Product (2 Octets)
+                               Version (2 Octets)
+       Return Parameters:
+
+       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:
+
+               0x0000  Disable Device ID
+               0x0001  Bluetooth SIG
+               0x0002  USB Implementer’s Forum
+
+       The information are put into the EIR data. If the controller does
+       not support EIR or if SSP is disabled, this command will still
+       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.
+
+       Possible errors:        Invalid Parameters
+                               Invalid Index
+
+
+Set Advertising Command
+=======================
+
+       Command Code:           0x0029
+       Controller Index:       <controller id>
+       Command Parameters:     Advertising (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to enable LE advertising on a controller
+       that supports it. The allowed values for the Advertising
+       command parameter are 0x00 and 0x01. All other values will
+       return Invalid Parameters.
+
+       A pre-requisite is that LE is already enabled, otherwise
+       this command will return a "rejected" response.
+
+       This command generates a Command Complete event on success or a
+       Command Status event on failure.
+
+       Possible errors:        Busy
+                               Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set BR/EDR Command
+==================
+
+       Command Code:           0x002A
+       Controller Index:       <controller id>
+       Command Parameters:     BR/EDR (1 Octet)
+       Return Parameters:      Current_Settings (4 Octets)
+
+       This command is used to enable or disable BR/EDR support
+       on a dual-mode controller. The allowed values for the Advertising
+       command parameter are 0x00 and 0x01. All other values will
+       return Invalid Parameters.
+
+       A pre-requisite is that LE is already enabled, otherwise
+       this command will return a "rejected" response. Enabling BR/EDR
+       can be done both when powered on and powered off, however
+       disabling it can only be done when powered off (otherwise the
+       command will again return "rejected"). Disabling BR/EDR will
+       automatically disable all other BR/EDR related settings.
+
+       This command generates a Command Complete event on success or a
+       Command Status event on failure.
+
+       Possible errors:        Busy
+                               Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Static Address Command
+==========================
+
+       Command Code:           0x002B
+       Controller Index:       <controller id>
+       Command Parameters:     Address (6 Octets)
+       Return Parameters:
+
+       This command allows for setting the static random address. It is
+       only supported on controllers with LE support. The static random
+       address is suppose to be valid for the lifetime of the
+       controller or at least until the next power cycle. To ensure
+       such behavior, setting of the address is limited to when the
+       controller is powered off.
+
+       The special BDADDR_ANY address (00:00:00:00:00:00) can be used
+       to disable the static address.
+
+       This command generates a Command Complete event on success or a
+       Command Status event on failure.
+
+       Possible errors:        Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Set Scan Parameters Command
+===========================
+
+       Command Code:           0x002C
+       Controller Index:       <controller id>
+       Command Parameters:     Interval (2 Octets)
+                               Window (2 Octets)
+       Return Parameters:
+
+       This command allows for setting the Low Energy scan parameters
+       used for connection establishment and passive scanning. It is
+       only supported on controllers with LE support.
+
+       This command generates a Command Complete event on success or a
+       Command Status event on failure.
+
+       Possible errors:        Rejected
+                               Not Supported
+                               Invalid Parameters
+                               Invalid Index
+
+
+Command Complete Event
+======================
+
+Event Code             0x0001
+Controller Index:      <controller id> or <non-controller>
+Event Parameters       Command_Opcode (2 Octets)
+                       Status (1 Octet)
+                       Return_Parameters
+
+       This event is an indication that a command has completed. The
+       fixed set of parameters includes the opcode to identify the
+       command that completed as well as a status value to indicate
+       success or failure. The rest of the parameters are command
+       specific and documented in the section for each command
+       separately.
+
+
+Command Status Event
+====================
+
+Event Code             0x0002
+Controller Index:      <controller id> or <non-controller>
+Event Parameters       Command_Opcode (2 Octets)
+                       Status (1 Octet)
+
+       The command status event is used to indicate an early status for
+       a pending command. In the case that the status indicates failure
+       (anything else except success status) this also means that the
+       command has finished executing.
+
+
+Controller Error Event
+======================
+
+Event Code             0x0003
+Controller Index:      <controller id>
+Event Parameters       Error_Code (1 Octet)
+
+       This event maps straight to the HCI Hardware Error event and is
+       used to indicate something wrong with the controller hardware.
+
+
+Index Added Event
+=================
+
+Event Code             0x0004
+Controller Index:      <controller id>
+Event Parameters
+
+       This event indicates that a new controller has been added to the
+       system. It is usually followed by a Read Controller Information
+       command.
+
+
+Index Removed Event
+===================
+
+Event Code             0x0005
+Controller Index:      <controller id>
+Event Parameters
+
+       This event indicates that a controller has been removed from the
+       system.
+
+
+New Settings Event
+==================
+
+Event Code             0x0006
+Controller Index:      <controller id>
+Event Parameters:      Current_Settings (4 Octets)
+
+       This event indicates that one or more of the settings for a
+       controller has changed.
+
+
+Class Of Device Changed Event
+=============================
+
+Event Code             0x0007
+Controller Index:      <controller id>
+Event Parameters:      Class_Of_Device (3 Octets)
+
+       This event indicates that the Class of Device value for the
+       controller has changed. When the controller is powered off the
+       Class of Device value will always be reported as zero.
+
+
+Local Name Changed Event
+========================
+
+Event Code             0x0008
+Controller Index       <controller id>
+Event Parameters       Name (249 Octets)
+                       Short_Name (11 Octets)
+
+       This event indicates that the local name of the controller has
+       changed.
+
+
+New Link Key Event
+==================
+
+Event Code             0x0009
+Controller Index:      <controller id>
+Event Parametersa      Store_Hint (1 Octet)
+                       Key {
+                               Address (6 Octets)
+                               Address_Type (1 Octet)
+                               Key_Type (1 Octet)
+                               Value (16 Octets)
+                               PIN_Length (1 Octet)
+                       }
+
+       This event indicates that a new link key has bee generated for a
+       remote device. The Store_Hint parameter indicates whether the
+       host is expected to store the key persistently or not (e.g. this
+       would not be set if the authentication requirement was "No
+       Bonding").
+
+
+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)
+                       }
+
+       This event indicates that a new long term key has bee generated
+       for a remote device. The Store_Hint parameter indicates whether
+       the host is expected to store the key persistently or not (e.g.
+       this would not be set if the authentication requirement was "No
+       Bonding").
+
+
+Device Connected Event
+======================
+
+Event Code             0x000B
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Flags (4 Octets)
+                       EIR_Data_Length (2 Octets)
+                       EIR_Data (0-65535 Octets)
+
+       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
+
+       This event indicates that a successful baseband connection has
+       been created to the remote device.
+
+
+Device Disconnected Event
+=========================
+
+Event Code             0x000C
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Reason (1 Octet)
+
+       This event indicates that the baseband connection was lost to a
+       remote device.
+
+       Possible values for the Address_Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+       Possible values for the Reason parameter:
+               0       Unspecified
+               1       Connection timeout
+               2       Connection terminated by local host
+               3       Connection terminated by remote host
+
+       Note that the local/remote distinction just determines which side
+       terminated the low-level connection, regardless of the
+       disconnection of the higher-level profiles.
+
+       This can sometimes be misleading and thus must be used with care.
+       For example, some hardware combinations would report a locally
+       initiated disconnection even if the user turned Bluetooth off in
+       the remote side.
+
+
+Connect Failed Event
+====================
+
+Event Code             0x000D
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Status (1 Octet)
+
+       This event indicates that a connection attempt failed to a
+       remote device.
+
+       Possible values for the Address_Type parameter:
+               0       BR/EDR
+               1       LE Public
+               2       LE Random
+
+
+PIN Code Request Event
+======================
+
+Event Code             0x000E
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Secure (1 Octet)
+
+       This event is used to request a PIN Code reply from user space.
+       The reply should either be returned using the PIN Code Reply or
+       the PIN Code Negative Reply command.
+
+       Secure: 0x01  secure PIN code required
+               0x00  secure PIN code not required
+
+
+User Confirmation Request Event
+===============================
+
+Event Code             0x000F
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Confirm_Hint (1 Octet)
+                       Value (4 Octets)
+
+       This event is used to request a user confirmation request from
+       user space. If the Confirm_Hint parameter value is 0x01 this
+       means that a simple "Yes/No" confirmation should be presented to
+       the user instead of a full numerical confirmation (in which case
+       the parameter value will be 0x00).
+
+       User space should respond to this command either using the User
+       Confirmation Reply or the User Confirmation Negative Reply
+       command.
+
+
+User Passkey Request Event
+==========================
+
+Event Code             0x0010
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+
+       This event is used to request a passkey from user space. The
+       response to this event should either be the User Passkey Reply
+       command or the User Passkey Negative Reply command.
+
+
+Authentication Failed Event
+===========================
+
+Event Code             0x0011
+Controller Index:      <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Status (1 Octet)
+
+       This event indicates that there was an authentication failure
+       with a remote device.
+
+
+Device Found Event
+==================
+
+Event Code             0x0012
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       RSSI (1 Octet)
+                       Flags (4 Octets)
+                       EIR_Data_Length (2 Octets)
+                       EIR_Data (0-65535 Octets)
+
+       This event indicates that a device was found during device
+       discovery.
+
+       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       Confirm name
+               1       Legacy Pairing
+
+       The Confirm name flag indicates that the kernel wants to know
+       whether user space knows the name for this device or not. If
+       this flag is set user space should respond to it using the
+       Confirm Name command.
+
+       The Legacy Pairing flag indicates that Legacy Pairing is likely
+       to occur when pairing with this device. An application could use
+       this information to optimize the pairing process by locally
+       pre-generating a PIN code and thereby eliminate the risk of
+       local input timeout when pairing. Note that there is a risk of
+       false-positives for this flag so user space should be able to
+       handle getting something else as a PIN Request when pairing.
+
+
+Discovering Event
+=================
+
+Event Code             0x0013
+Controller Index       <controller id>
+Event Parameters       Address_Type (1 Octet)
+                       Discovering (1 Octet)
+
+       This event indicates that the controller has started discovering
+       devices. This discovering state can come and go multiple times
+       between a StartDiscover and a StopDiscovery command.
+
+       The valid values for the Discovering parameter are 0x01
+       (enabled) and 0x00 (disabled).
+
+
+Device Blocked Event
+====================
+
+Event Code             0x0014
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+
+       This event indicates that a device has been blocked using the
+       Block Device command. The event will only be sent to Management
+       sockets other than the one through which the command was sent.
+
+
+Device Unblocked Event
+======================
+
+Event Code             0x0015
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+
+       This event indicates that a device has been unblocked using the
+       Unblock Device command. The event will only be sent to
+       Management sockets other than the one through which the command
+       was sent.
+
+
+Device Unpaired Event
+=====================
+
+Event Code             0x0016
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+
+       This event indicates that a device has been unpaired (i.e. all
+       its keys have been removed from the kernel) using the Unpair
+       Device command. The event will only be sent to Management
+       sockets other than the one through which the Unpair Device
+       command was sent.
+
+
+Passkey Notify Event
+====================
+
+Event Code             0x0017
+Controller Index       <controller id>
+Event Parameters       Address (6 Octets)
+                       Address_Type (1 Octet)
+                       Passkey (4 Octets)
+                       Entered (1 Octet)
+
+       This event is used to request passkey notification to the user.
+       Unlike the other authentication events it does not need
+       responding to using any Management command.
+
+       The Passkey parameter indicates the passkey to be shown to the
+       user whereas the Entered parameter indicates how many characters
+       the user has entered on the remote side.
index 4dd3e58..109da28 100644 (file)
@@ -1,14 +1,12 @@
 BlueZ D-Bus Network API description
 ***********************************
 
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-
 
 Network hierarchy
 =================
 
 Service                org.bluez
-Interface      org.bluez.Network
+Interface      org.bluez.Network1
 Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
 
 Methods                string Connect(string uuid)
@@ -37,16 +35,6 @@ Methods              string Connect(string uuid)
 
                        Possible errors: org.bluez.Error.Failed
 
-               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 the given
-                       property.
-
 Properties     boolean Connected [readonly]
 
                        Indicates if the device is connected.
@@ -64,7 +52,7 @@ Network server hierarchy
 ========================
 
 Service                org.bluez
-Interface      org.bluez.NetworkServer
+Interface      org.bluez.NetworkServer1
 Object path    /org/bluez/{hci0,hci1,...}
 
 Methods                void Register(string uuid, string bridge)
diff --git a/doc/obex-agent-api.txt b/doc/obex-agent-api.txt
new file mode 100644 (file)
index 0000000..3923da6
--- /dev/null
@@ -0,0 +1,61 @@
+OBEX D-Bus Agent API description
+********************************
+
+
+Agent Manager hierarchy
+=======================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.AgentManager1
+Object path    /org/bluez/obex
+
+Methods                void RegisterAgent(object agent)
+
+                       Register an agent to request authorization of
+                       the user to accept/reject objects. Object push
+                       service needs to authorize each received object.
+
+                       Possible errors: org.bluez.obex.Error.AlreadyExists
+
+               void UnregisterAgent(object agent)
+
+                       This unregisters the agent that has been previously
+                       registered. The object path parameter must match the
+                       same value that has been used on registration.
+
+                       Possible errors: org.bluez.obex.Error.DoesNotExist
+
+
+Agent hierarchy
+===============
+
+Service                unique name
+Interface      org.bluez.obex.Agent1
+Object path    freely definable
+
+Methods                void Release()
+
+                       This method gets called when the service daemon
+                       unregisters the agent. An agent can use it to do
+                       cleanup tasks. There is no need to unregister the
+                       agent, because when this method gets called it has
+                       already been unregistered.
+
+               string AuthorizePush(object transfer)
+
+                       This method gets called when the service daemon
+                       needs to accept/reject a Bluetooth object push request.
+
+                       Returns the full path (including the filename) where
+                       the object shall be stored. The tranfer object will
+                       contain a Filename property that contains the default
+                       location and name that can be returned.
+
+                       Possible errors: org.bluez.obex.Error.Rejected
+                                        org.bluez.obex.Error.Canceled
+
+               void Cancel()
+
+                       This method gets called to indicate that the agent
+                       request failed before a reply was returned. It cancels
+                       the previous request.
diff --git a/doc/obex-api.txt b/doc/obex-api.txt
new file mode 100644 (file)
index 0000000..c3f5243
--- /dev/null
@@ -0,0 +1,812 @@
+OBEX D-Bus API description
+**************************
+
+
+Client hierarchy
+================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.Client1
+Object path    /org/bluez/obex
+
+Methods                object CreateSession(string destination, dict args)
+
+                       Create a new OBEX session for the given remote address.
+
+                       The last parameter is a dictionary to hold optional or
+                       type-specific parameters. Typical parameters that can
+                       be set in this dictionary include the following:
+
+                               string "Target" : type of session to be created
+                               string "Source" : local address to be used
+                               byte "Channel"
+
+                       The currently supported targets are the following:
+
+                               "ftp"
+                               "map"
+                               "opp"
+                               "pbap"
+                               "sync"
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void RemoveSession(object session)
+
+                       Unregister session and abort pending transfers.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.NotAuthorized
+
+Session hierarchy
+=================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.Session1
+Object path    /org/bluez/obex/server/session{0, 1, 2, ...} or
+               /org/bluez/obex/client/session{0, 1, 2, ...}
+
+Methods                string GetCapabilities()
+
+                       Get remote device capabilities.
+
+                       Possible errors: org.bluez.obex.Error.NotSupported
+                                        org.bluez.obex.Error.Failed
+
+Properties     string Source [readonly]
+
+                       Bluetooth adapter address
+
+               string Destination [readonly]
+
+                       Bluetooth device address
+
+               byte Channel [readonly]
+
+                       Bluetooth channel
+
+               string Target [readonly]
+
+                       Target UUID
+
+               string Root [readonly]
+
+                       Root path
+
+
+Transfer hierarchy
+==================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.Transfer1
+Object path    [Session object path]/transfer{0, 1, 2, ...}
+
+Methods                void Cancel()
+
+                       Stops the current transference.
+
+                       Possible errors: org.bluez.obex.Error.NotAuthorized
+                                        org.bluez.obex.Error.InProgress
+                                        org.bluez.obex.Error.Failed
+
+Properties     string Status [readonly]
+
+                       Inform the current status of the transfer.
+
+                       Possible values: "queued", "active", "complete" or
+                                       "error"
+
+               object Session [readonly]
+
+                       The object path of the session the transfer belongs
+                       to.
+
+               string Name [readonly]
+
+                       Name of the transferred object. Either Name or Type
+                       or both will be present.
+
+               string Type [readonly]
+
+                       Type of the transferred object. Either Name or Type
+                       or both will be present.
+
+               uint64 Time [readonly, optional]
+
+                       Time of the transferred object if this is
+                       provided by the remote party.
+
+               uint64 Size [readonly, optional]
+
+                       Size of the transferred object. If the size is
+                       unknown, then this property will not be present.
+
+               uint64 Transferred [readonly, optional]
+
+                       Number of bytes transferred. For queued transfers, this
+                       value will not be present.
+
+               string Filename [readonly, optional]
+
+                       Complete name of the file being received or sent.
+
+                       For incoming object push transaction, this will be
+                       the proposed default location and name. It can be
+                       overwritten by the AuthorizePush agent callback
+                       and will be then updated accordingly.
+
+
+Object Push hierarchy
+=====================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.ObjectPush1
+Object path    [Session object path]
+
+Methods                object, dict SendFile(string sourcefile)
+
+                       Send one local file to the remote device.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               object, dict PullBusinessCard(string targetfile)
+
+                       Request the business card from a remote device and
+                       store it in the local file.
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               object, dict ExchangeBusinessCards(string clientfile,
+                                                       string targetfile)
+
+                       Push the client's business card to the remote device
+                       and then retrieve the remote business card and store
+                       it in a local file.
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+
+File Transfer hierarchy
+=======================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.FileTransfer
+Object path    [Session object path]
+
+Methods                void ChangeFolder(string folder)
+
+                       Change the current folder of the remote device.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void CreateFolder(string folder)
+
+                       Create a new folder in the remote device.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               array{dict} ListFolder()
+
+                       Returns a dictionary containing information about
+                       the current folder content.
+
+                       The following keys are defined:
+
+                               string Name : Object name in UTF-8 format
+                               string Type : Either "folder" or "file"
+                               uint64 Size : Object size or number of items in
+                                               folder
+                               string Permission : Group, owner and other
+                                                       permission
+                               uint64 Modified : Last change
+                               uint64 Accessed : Last access
+                               uint64 Created : Creation date
+
+                       Possible errors: org.bluez.obex.Error.Failed
+
+               object, dict GetFile(string targetfile, string sourcefile)
+
+                       Copy the source file (from remote device) to the
+                       target file (on local filesystem).
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               object, dict PutFile(string sourcefile, string targetfile)
+
+                       Copy the source file (from local filesystem) to the
+                       target file (on remote device).
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void CopyFile(string sourcefile, string targetfile)
+
+                       Copy a file within the remote device from source file
+                       to target file.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void MoveFile(string sourcefile, string targetfile)
+
+                       Move a file within the remote device from source file
+                       to the target file.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void Delete(string file)
+
+                       Deletes the specified file/folder.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+
+Phonebook Access hierarchy
+==========================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.PhonebookAccess1
+Object path    [Session object path]
+
+Methods                void Select(string location, string phonebook)
+
+                       Select the phonebook object for other operations. Should
+                       be call before all the other operations.
+
+                       location : Where the phonebook is stored, possible
+                       inputs :
+                               "int" ( "internal" which is default )
+                               "sim" ( "sim1" )
+                               "sim2"
+                               ...
+
+                       phonebook : Possible inputs :
+                               "pb" :  phonebook for the saved contacts
+                               "ich":  incoming call history
+                               "och":  outgoing call history
+                               "mch":  missing call history
+                               "cch":  combination of ich och mch
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               object, dict PullAll(string targetfile, dict filters)
+
+                       Return the entire phonebook object from the PSE server
+                       in plain string with vcard format, and store it in
+                       a local file.
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible filters: Format, Order, Offset, MaxCount and
+                       Fields
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                       org.bluez.obex.Forbidden
+
+               array{string vcard, string name} List(dict filters)
+
+                       Return an array of vcard-listing data where every entry
+                       consists of a pair of strings containing the vcard
+                       handle and the contact name. For example:
+                               "1.vcf" : "John"
+
+                       Possible filters: Order, Offset and MaxCount
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Forbidden
+
+               object, dict
+               Pull(string vcard, string targetfile, dict filters)
+
+                       Given a vcard handle, retrieve the vcard in the current
+                       phonebook object and store it in a local file.
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possbile filters: Format and Fields
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Forbidden
+                                        org.bluez.obex.Error.Failed
+
+               array{string vcard, string name}
+               Search(string field, string value, dict filters)
+
+                       Search for entries matching the given condition and
+                       return an array of vcard-listing data where every entry
+                       consists of a pair of strings containing the vcard
+                       handle and the contact name.
+
+                       vcard : name paired string match the search condition.
+
+                       field : the field in the vcard to search with
+                               { "name" (default) | "number" | "sound" }
+                       value : the string value to search for
+
+
+                       Possible filters: Order, Offset and MaxCount
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Forbidden
+                                        org.bluez.obex.Error.Failed
+
+               uint16 GetSize()
+
+                       Return the number of entries in the selected phonebook
+                       object that are actually used (i.e. indexes that
+                       correspond to non-NULL entries).
+
+                       Possible errors: org.bluez.obex.Error.Forbidden
+                                        org.bluez.obex.Error.Failed
+
+               array{string} ListFilterFields()
+
+                       Return All Available fields that can be used in Fields
+                       filter.
+
+                       Possible errors: None
+
+Filter:                string Format:
+
+                       Items vcard format
+
+                       Possible values: "vcard21" (default) or "vcard30"
+
+               string Order:
+
+                       Items order
+
+                       Possible values: "indexed" (default), "alphanumeric" or
+                       "phonetic"
+
+               uint16 Offset:
+
+                       Offset of the first item, default is 0
+
+               uint16 MaxCount:
+
+                       Maximum number of items, default is unlimited (65535)
+
+               array{string} Fields:
+
+                       Item vcard fields, default is all values.
+
+                       Possible values can be query with ListFilterFields.
+
+
+Synchronization hierarchy
+=========================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.Synchronization1
+Object path    [Session object path]
+
+Methods                void SetLocation(string location)
+
+                       Set the phonebook object store location for other
+                       operations. Should be called before all the other
+                       operations.
+
+                       location: Where the phonebook is stored, possible
+                       values:
+                               "int" ( "internal" which is default )
+                               "sim1"
+                               "sim2"
+                               ......
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+
+               object, dict GetPhonebook(string targetfile)
+
+                       Retrieve an entire Phonebook Object store from remote
+                       device, and stores it in a local file.
+
+                       If an empty target file is given, a name will be
+                       automatically calculated for the temporary file.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               object, dict PutPhonebook(string sourcefile)
+
+                       Send an entire Phonebook Object store to remote device.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+
+Message Access hierarchy
+=========================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.MessageAccess1
+Object path    [Session object path]
+
+Methods                void SetFolder(string name)
+
+                       Set working directory for current session, *name* may
+                       be the directory name or '..[/dir]'.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               array{dict} ListFolders(dict filter)
+
+                       Returns a dictionary containing information about
+                       the current folder content.
+
+                       The following keys are defined:
+
+                               string Name : Folder name
+
+                       Possible filters: Offset and MaxCount
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               array{string} ListFilterFields()
+
+                       Return all available fields that can be used in Fields
+                       filter.
+
+                       Possible errors: None
+
+               array{object, dict} ListMessages(string folder, dict filter)
+
+                       Returns an array containing the messages found in the
+                       given subfolder of the current folder, or in the
+                       current folder if folder is empty.
+
+                       Possible Filters: Offset, MaxCount, SubjectLength, Fields,
+                       Type, PeriodStart, PeriodEnd, Status, Recipient, Sender,
+                       Priority
+
+                       Each message is represented by an object path followed
+                       by a dictionary of the properties.
+
+                       Properties:
+
+                               string Subject:
+
+                                       Message subject
+
+                               string Timestamp:
+
+                                       Message timestamp
+
+                               string Sender:
+
+                                       Message sender name
+
+                               string SenderAddress:
+
+                                       Message sender address
+
+                               string ReplyTo:
+
+                                       Message Reply-To address
+
+                               string Recipient:
+
+                                       Message recipient name
+
+                               string RecipientAddress:
+
+                                       Message recipient address
+
+                               string Type:
+
+                                       Message type
+
+                                       Possible values: "email", "sms-gsm",
+                                       "sms-cdma" and "mms"
+
+                               uint64 Size:
+
+                                       Message size in bytes
+
+                               boolean Text:
+
+                                       Message text flag
+
+                                       Specifies whether message has textual
+                                       content or is binary only
+
+                               string Status:
+
+                                       Message status
+
+                                       Possible values for received messages:
+                                       "complete", "fractioned", "notification"
+
+                                       Possible values for sent messages:
+                                       "delivery-success", "sending-success",
+                                       "delivery-failure", "sending-failure"
+
+                               uint64 AttachmentSize:
+
+                                       Message overall attachment size in bytes
+
+                               boolean Priority:
+
+                                       Message priority flag
+
+                               boolean Read:
+
+                                       Message read flag
+
+                               boolean Sent:
+
+                                       Message sent flag
+
+                               boolean Protected:
+
+                                       Message protected flag
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+               void UpdateInbox(void)
+
+                       Request remote to update its inbox.
+
+                       Possible errors: org.bluez.obex.Error.Failed
+
+               object, dict
+               PushMessage(string sourcefile, string folder, dict args)
+
+                       Transfer a message (in bMessage format) to the
+                       remote device.
+
+                       The message is transferred either to the given
+                       subfolder of the current folder, or to the current
+                       folder if folder is empty.
+
+                       Possible args: Transparent, Retry, Charset
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetAll.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+
+Filter:                uint16 Offset:
+
+                       Offset of the first item, default is 0
+
+               uint16 MaxCount:
+
+                       Maximum number of items, default is 1024
+
+               byte SubjectLength:
+
+                       Maximum length of the Subject property in the
+                       message, default is 256
+
+               array{string} Fields:
+
+                       Message fields, default is all values.
+
+                       Possible values can be query with ListFilterFields.
+
+               array{string} Types:
+
+                       Filter messages by type.
+
+                       Possible values: "sms", "email", "mms".
+
+               string PeriodBegin:
+
+                       Filter messages by starting period.
+
+                       Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+               string PeriodEnd:
+
+                       Filter messages by ending period.
+
+                       Possible values: Date in "YYYYMMDDTHHMMSS" format.
+
+               boolean Read:
+
+                       Filter messages by read flag.
+
+                       Possible values: True for read or False for unread
+
+               string Recipient:
+
+                       Filter messages by recipient address.
+
+               string Sender:
+
+                       Filter messages by sender address.
+
+               boolean Priority:
+
+                       Filter messages by priority flag.
+
+                       Possible values: True for high priority or False for
+                       non-high priority
+
+Message hierarchy
+=================
+
+Service                org.bluez.obex
+Interface      org.bluez.obex.Message1
+Object path    [Session object path]/{message0,...}
+
+Methods                object, dict Get(string targetfile, boolean attachment)
+
+                       Download message and store it in the target file.
+
+                       If an empty target file is given, a temporary file
+                       will be automatically generated.
+
+                       The returned path represents the newly created transfer,
+                       which should be used to find out if the content has been
+                       successfully transferred or if the operation fails.
+
+                       The properties of this transfer are also returned along
+                       with the object path, to avoid a call to GetProperties.
+
+                       Possible errors: org.bluez.obex.Error.InvalidArguments
+                                        org.bluez.obex.Error.Failed
+
+Properties     string Folder [readonly]
+
+                       Folder which the message belongs to
+
+               string Subject [readonly]
+
+                       Message subject
+
+               string Timestamp [readonly]
+
+                       Message timestamp
+
+               string Sender [readonly]
+
+                       Message sender name
+
+               string SenderAddress [readonly]
+
+                       Message sender address
+
+               string ReplyTo [readonly]
+
+                       Message Reply-To address
+
+               string Recipient [readonly]
+
+                       Message recipient name
+
+               string RecipientAddress [readonly]
+
+                       Message recipient address
+
+               string Type [readonly]
+
+                       Message type
+
+                       Possible values: "email", "sms-gsm",
+                       "sms-cdma" and "mms"
+
+               uint64 Size [readonly]
+
+                       Message size in bytes
+
+               string Status [readonly]
+
+                       Message reception status
+
+                       Possible values: "complete",
+                       "fractioned" and "notification"
+
+               boolean Priority [readonly]
+
+                       Message priority flag
+
+               boolean Read [read/write]
+
+                       Message read flag
+
+               boolean Deleted [writeonly]
+
+                       Message read flag
+
+               boolean Sent [readonly]
+
+                       Message sent flag
+
+               boolean Protected [readonly]
+
+                       Message protected flag
diff --git a/doc/profile-api.txt b/doc/profile-api.txt
new file mode 100644 (file)
index 0000000..ec18034
--- /dev/null
@@ -0,0 +1,147 @@
+BlueZ D-Bus Profile API description
+***********************************
+
+
+Profile Manager hierarchy
+=========================
+
+Service                org.bluez
+Interface      org.bluez.ProfileManager1
+Object path    /org/bluez
+
+               void RegisterProfile(object profile, string uuid, dict options)
+
+                       This registers a profile implementation.
+
+                       If an application disconnects from the bus all
+                       its registered profiles will be removed.
+
+                       HFP HS UUID: 0000111e-0000-1000-8000-00805f9b34fb
+
+                               Default RFCOMM channel is 6. And this requires
+                               authentication.
+
+                       Available options:
+
+                               string Name
+
+                                       Human readable name for the profile
+
+                               string Service
+
+                                       The primary service class UUID
+                                       (if different from the actual
+                                        profile UUID)
+
+                               string Role
+
+                                       For asymmetric profiles that do not
+                                       have UUIDs available to uniquely
+                                       identify each side this
+                                       parameter allows specifying the
+                                       precise local role.
+
+                                       Possible values: "client", "server"
+
+                               uint16 Channel
+
+                                       RFCOMM channel number that is used
+                                       for client and server UUIDs.
+
+                                       If applicable it will be used in the
+                                       SDP record as well.
+
+                               uint16 PSM
+
+                                       PSM number that is used for client
+                                       and server UUIDs.
+
+                                       If applicable it will be used in the
+                                       SDP record as well.
+
+                               boolean RequireAuthentication
+
+                                       Pairing is required before connections
+                                       will be established. No devices will
+                                       be connected if not paired.
+
+                               boolean RequireAuthorization
+
+                                       Request authorization before any
+                                       connection will be established.
+
+                               boolean AutoConnect
+
+                                       In case of a client UUID this will
+                                       force connection of the RFCOMM or
+                                       L2CAP channels when a remote device
+                                       is connected.
+
+                               string ServiceRecord
+
+                                       Provide a manual SDP record.
+
+                               uint16 Version
+
+                                       Profile version (for SDP record)
+
+                               uint16 Features
+
+                                       Profile features (for SDP record)
+
+                       Possible errors: org.bluez.Error.InvalidArguments
+                                        org.bluez.Error.AlreadyExists
+
+               void UnregisterProfile(object profile)
+
+                       This unregisters the profile that has been previously
+                       registered. The object path parameter must match the
+                       same value that has been used on registration.
+
+                       Possible errors: org.bluez.Error.DoesNotExist
+
+
+Profile hierarchy
+=================
+
+Service                unique name
+Interface      org.bluez.Profile1
+Object path    freely definable
+
+Methods                void Release() [noreply]
+
+                       This method gets called when the service daemon
+                       unregisters the profile. A profile can use it to do
+                       cleanup tasks. There is no need to unregister the
+                       profile, because when this method gets called it has
+                       already been unregistered.
+
+               void NewConnection(object device, fd, dict fd_properties)
+
+                       This method gets called when a new service level
+                       connection has been made and authorized.
+
+                       Common fd_properties:
+
+                       uint16 Version          Profile version (optional)
+                       uint16 Features         Profile features (optional)
+
+                       Possible errors: org.bluez.Error.Rejected
+                                        org.bluez.Error.Canceled
+
+               void RequestDisconnection(object device)
+
+                       This method gets called when a profile gets
+                       disconnected.
+
+                       The file descriptor is no longer owned by the service
+                       daemon and the profile implementation needs to take
+                       care of cleaning up all connections.
+
+                       If multiple file descriptors are indicated via
+                       NewConnection, it is expected that all of them
+                       are disconnected before returning from this
+                       method call.
+
+                       Possible errors: org.bluez.Error.Rejected
+                                        org.bluez.Error.Canceled
diff --git a/doc/proximity-api.txt b/doc/proximity-api.txt
new file mode 100644 (file)
index 0000000..5322544
--- /dev/null
@@ -0,0 +1,56 @@
+BlueZ D-Bus Proximity API description
+***********************************
+
+
+Proximity Monitor hierarchy
+===========================
+
+Service                org.bluez
+Interface      org.bluez.ProximityMonitor1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+Properties     string SignalLevel [readonly]
+
+                       Alert indicating that a threshold has been reached.
+                       Possible values: "unknown", "good", "regular", "weak"
+
+               string LinkLossAlertLevel [readwrite]
+
+                       Persistent property. Sets the alert level in the
+                       proximity reporter for link loss scenario. Values:
+                       "none", "mild", "high".
+
+               string ImmediateAlertLevel [readwrite]
+
+                       Alert level to be written in the Immediate Alert Level.
+                       Property shared between Path Loss and Find Me.
+                       Values: "none", "mild", "high". Default value is
+                       "none". Applications can disable the alert setting
+                       the value to "none". If the "Target" is not found,
+                       "none" will be emitted after the configured timeout.
+                       When changing the level, signal is the confirmation
+                       that the value was written in the remote.
+
+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.ProximityReporter1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+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 b8b7253..b28c4e3 100644 (file)
@@ -1,14 +1,12 @@
-BlueZ D-Bus Sim Access Profile API description
-***********************************
-
-Copyright (C) 2010 ST-Ericsson SA
+BlueZ D-Bus Sim Access API description
+**************************************
 
 
 Sim Access Profile hierarchy
 ============================
 
 Service                org.bluez
-Interface      org.bluez.SimAccess
+Interface      org.bluez.SimAccess1
 Object path    [variable prefix]/{hci0,hci1,...}
 
 Methods                void Disconnect()
@@ -17,18 +15,6 @@ Methods              void Disconnect()
 
                        Possible errors: org.bluez.Error.Failed
 
-               dict GetProperties()
-
-                       Return all properties for the interface. See the
-                       properties section for available properties.
-
-                       Possible Errors: org.bluez.Error.Failed
-
-Signals                PropertyChanged(string name, variant value)
-
-                       This signal indicates a changed value of the given
-                       property.
-
 Properties     boolean Connected [readonly]
 
                        Indicates if SAP client is connected to the server.
diff --git a/doc/serial-api.txt b/doc/serial-api.txt
deleted file mode 100644 (file)
index 0bdbdcd..0000000
+++ /dev/null
@@ -1,163 +0,0 @@
-BlueZ D-Bus Serial API description
-**********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-
-
-Serial hierarchy
-================
-
-Service                org.bluez
-Interface      org.bluez.Serial
-Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
-
-Methods                string Connect(string pattern)
-
-                       Connects to a specific RFCOMM based service on a
-                       remote device and then creates a RFCOMM TTY
-                       device for it. The RFCOMM TTY device is returned.
-
-                       Possible patterns: UUID 128 bit as string
-                                          Profile short names, e.g: spp, dun
-                                          RFCOMM channel as string, 1-30
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.InProgress
-                                        org.bluez.Error.ConnectionAttemptFailed
-                                        org.bluez.Error.NotSupported
-
-Methods                fd ConnectFD(string pattern) [experimental]
-
-                       Connects to a specific RFCOMM based service on a
-                       remote device and returns a file descriptor to talk
-                        with this device.
-
-                       Possible patterns: UUID 128 bit as string
-                                          Profile short names, e.g: spp, dun
-                                          RFCOMM channel as string, 1-30
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.InProgress
-                                        org.bluez.Error.ConnectionAttemptFailed
-                                        org.bluez.Error.NotSupported
-
-
-               void Disconnect(string device)
-
-                       Disconnect a RFCOMM TTY device that has been
-                       created by Connect method.
-
-                       To abort a connection attempt in case of errors or
-                       timeouts in the client it is fine to call this method.
-
-                       In that case one of patterns of the Connect method should
-                       be supplied instead of the TTY device.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.DoesNotExist
-
-Serial Proxy Manager hierarchy [experimental]
-=============================================
-
-Service                org.bluez
-Interface      org.bluez.SerialProxyManager
-Object path    [variable prefix]/{hci0,hci1,...}
-
-Methods                array{string} ListProxies()
-
-                       Returns an array of the object path strings of
-                       all the proxies created for the adapter.
-
-               string CreateProxy(string pattern, string address)
-
-                       Possible patterns: UUID 128 bit as string
-                                          Profile short names, e.g: spp, dun
-                                          RFCOMM channel as string, 1-30
-
-                       Address is the path to the TTY or Unix socket to be used.
-                       Only one proxy per address (TTY or Unix socket)
-                       is allowed.
-
-                       The object path of created proxy is returned.
-                       On success this will emit a ProxyCreated signal.
-
-                       Possible Errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.AlreadyExists
-                                        org.bluez.Error.Failed
-
-               void RemoveProxy(string path)
-
-                       This removes the proxy object at the given path.
-                       On success this will emit a ProxyRemoved signal.
-
-                       Possible Errors: org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.NotAuthorized
-
-Signals                ProxyCreated(string path)
-
-                       This signal indicates a proxy was created.
-                       Parameter is object path of created proxy.
-
-               ProxyRemoved(string path)
-
-                       This signal indicates a proxy was removed.
-                       Parameter is object path of removed proxy.
-
-Serial Proxy hierarchy [experimental]
-=====================================
-
-Service                org.bluez
-Interface      org.bluez.SerialProxy
-Object path    [variable prefix]/{hci0,hci1,...}/{proxy0,proxy1,...}
-
-Methods                void Enable()
-
-                       Starts to listen to the TTY or Unix socket, allocates
-                       a RFCOMM channel and add record to the server.
-
-                       Possible errors: org.bluez.Error.Failed
-
-               void Disable()
-
-                       Stops to listen to the TTY or Unix socket, shutdown
-                       the RFCOMM channel allocated for the proxy, and remove
-                       record from the server.
-
-                       Possible errors: org.bluez.Error.Failed
-
-               dict GetInfo()
-
-                       Returns all properties for the proxy. See the
-                       properties section for available properties.
-
-               void SetSerialParameters(string rate, uint8 data, uint8 stop,
-                       string parity)
-
-                       Configures serial communication setting baud rate,
-                       data bits, stop bits and parity.
-
-                       Doesn't allow change TTY settings if it is open.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotAuthorized
-
-Properties     string uuid [readonly]
-
-                       128-bit UUID that represents the available remote service.
-
-               string address [readonly]
-
-                       Address is the path to the TTY or Unix socket name used,
-                       set when the proxy was created.
-
-               uint8 channel [readonly]
-
-                       RFCOMM channel.
-
-               boolean enabled [readonly]
-
-                       Indicates if the proxy is currently enabled.
-
-               boolean connected [readonly]
-
-                       Indicates if the proxy is currently connected.
diff --git a/doc/service-api.txt b/doc/service-api.txt
deleted file mode 100644 (file)
index 5c8c7f3..0000000
+++ /dev/null
@@ -1,62 +0,0 @@
-BlueZ D-Bus Adapter API description
-***********************************
-
-Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
-Copyright (C) 2005-2006  Johan Hedberg <johan.hedberg@nokia.com>
-Copyright (C) 2005-2006  Claudio Takahasi <claudio.takahasi@indt.org.br>
-Copyright (C) 2006-2007  Luiz von Dentz <luiz.dentz@indt.org.br>
-
-
-Service hierarchy
-=================
-
-Service                org.bluez
-Interface      org.bluez.Service
-Object path    [variable prefix]/{hci0,hci1,...}
-
-Methods                uint32 AddRecord(string record)
-
-                       Adds a new service record from the XML description
-                       and returns the assigned record handle.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.Failed
-
-               void UpdateRecord(uint32 handle, string record)
-
-                       Updates a given service record provided in the
-                       XML format.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotAvailable
-                                        org.bluez.Error.Failed
-
-               void RemoveRecord(uint32 handle)
-
-                       Remove a service record identified by its handle.
-
-                       It is only possible to remove service records that
-                       where added by the current connection.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.Failed
-
-               void RequestAuthorization(string address, uint32 handle)
-
-                       Request an authorization for an incoming connection
-                       for a specific service record. The service record
-                       needs to be registered via AddRecord first.
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.Failed
-
-               void CancelAuthorization()
-
-                       Possible errors: org.bluez.Error.InvalidArguments
-                                        org.bluez.Error.NotAuthorized
-                                        org.bluez.Error.DoesNotExist
-                                        org.bluez.Error.Failed
diff --git a/doc/supported-features.txt b/doc/supported-features.txt
new file mode 100644 (file)
index 0000000..b337f78
--- /dev/null
@@ -0,0 +1,52 @@
+Supported features in BlueZ
+===========================
+
+Note that some profiles/roles will depend on external components such as
+oFono or ConnMan.
+
+Profile/protocol       Version         Role(s)
+---------------------------------------------------------------------------
+
+GAP                    4.0             (LE) Central, Observer, Broadcaster
+L2CAP                  4.0             Server, Client
+SDP                    4.0             Server, Client
+GATT                   4.0             Server, Client
+SDAP                   1.1             Server, Client
+RFCOMM                 1.1             Server, Client
+SPP                    1.1             Server, Client
+
+PXP                    1.0             Reporter, Monitor
+HOGP                   1.0             Host
+HTP                    1.0
+TIP                    1.0
+CSCP                   1.0             Collector
+
+SAP                    1.1             Server
+DUN                    1.1             Server, Client
+
+DID                    1.3             Server, Client
+
+HFP                    1.5             AG, HF
+HSP                    1.2             AG, HS
+GAVDTP                 1.2             Source, Sink
+AVDTP                  1.3             Source, Sink
+A2DP                   1.3             Source, Sink
+AVCTP                  1.3             CT, TG
+AVRCP                  1.5             CT, TG
+
+GOEP                   2.0             Client, Server
+FTP                    1.2             Client, Server
+OPP                    1.2             Client, Server
+SYNCH                  1.1             Client
+PBAP                   1.1             Client, Server
+MAP                    1.0             Client, Server
+
+HID                    1.1             Host
+
+BNEP                   1.0
+PAN                    1.0             PANU, NAP, GN
+
+HCRP                   1.2
+
+MCAP                   1.0
+HDP                    1.0
diff --git a/doc/thermometer-api.txt b/doc/thermometer-api.txt
new file mode 100644 (file)
index 0000000..c7c8a5d
--- /dev/null
@@ -0,0 +1,134 @@
+BlueZ D-Bus Thermometer API description
+***************************************
+
+       Santiago Carot-Nemesio <sancane@gmail.com>
+
+Health Thermometer Manager hierarchy
+====================================
+
+Service                org.bluez
+Interface      org.bluez.ThermometerManager1
+Object path    [variable prefix]/{hci0,hci1,...}
+
+Methods                RegisterWatcher(object agent)
+
+                       Registers a watcher to monitor scanned measurements.
+                       This agent will be notified about final temperature
+                       measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               UnregisterWatcher(object agent)
+
+                       Unregisters a watcher.
+
+               EnableIntermediateMeasurement(object agent)
+
+                       Enables intermediate measurement notifications
+                       for this agent. Intermediate measurements will
+                       be enabled only for thermometers which support it.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+
+               DisableIntermediateMeasurement(object agent)
+
+                       Disables intermediate measurement notifications
+                       for this agent. It will disable notifications in
+                       thermometers when the last agent removes the
+                       watcher for intermediate measurements.
+
+                       Possible Errors: org.bluez.Error.InvalidArguments
+                                       org.bluez.Error.NotFound
+
+Health Thermometer Profile hierarchy
+====================================
+
+Service                org.bluez
+Interface      org.bluez.Thermometer1
+Object path    [variable prefix]/{hci0,hci1,...}/dev_XX_XX_XX_XX_XX_XX
+
+
+Properties     boolean Intermediate [readonly]
+
+                       True if the thermometer supports intermediate
+                       measurement notifications.
+
+               uint16 Interval (optional) [readwrite]
+
+                       The Measurement Interval defines the time (in
+                       seconds) between measurements. This interval is
+                       not related to the intermediate measurements and
+                       must be defined into a valid range. Setting it
+                       to zero means that no periodic measurements will
+                       be taken.
+
+               uint16 Maximum (optional) [readonly]
+
+                       Defines the maximum value allowed for the interval
+                       between periodic measurements.
+
+               uint16 Minimum (optional) [readonly]
+
+                       Defines the minimum value allowed for the interval
+                       between periodic measurements.
+
+
+Health Thermometer Watcher hierarchy
+====================================
+
+Service                unique name
+Interface      org.bluez.ThermometerWatcher1
+Object path    freely definable
+
+Methods                void MeasurementReceived(dict measurement)
+
+                       This callback gets called when a measurement has been
+                       scanned in the thermometer.
+
+                       Measurement:
+
+                               int16 Exponent:
+                               int32 Mantissa:
+
+                                       Exponent and Mantissa values as
+                                       extracted from float value defined by
+                                       IEEE-11073-20601.
+
+                                       Measurement value is calculated as
+                                       (Mantissa) * (10^Exponent)
+
+                                       For special cases Exponent is
+                                       set to 0 and Mantissa is set to
+                                       one of following values:
+
+                                       +(2^23 - 1)     NaN (invalid or
+                                                       missing data)
+                                       -(2^23)         NRes
+                                       +(2^23 - 2)     +Infinity
+                                       -(2^23 - 2)     -Infinity
+
+                               string Unit:
+
+                                       Possible values: "celsius" or
+                                                       "fahrenheit"
+
+                               uint64 Time (optional):
+
+                                       Time of measurement, if
+                                       supported by device.
+                                       Expressed in seconds since epoch.
+
+                               string Type (optional):
+
+                                       Only present if measurement type
+                                       is known.
+
+                                       Possible values: "armpit", "body",
+                                               "ear", "finger", "intestines",
+                                               "mouth", "rectum", "toe",
+                                               "tympanum"
+
+                               string Measurement:
+
+                                       Possible values: "final" or
+                                                       "intermediate"
diff --git a/doc/version.xml.in b/doc/version.xml.in
deleted file mode 100644 (file)
index d78bda9..0000000
+++ /dev/null
@@ -1 +0,0 @@
-@VERSION@
diff --git a/emulator/amp.c b/emulator/amp.c
new file mode 100644 (file)
index 0000000..714854b
--- /dev/null
@@ -0,0 +1,1056 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/mainloop.h"
+#include "monitor/bt.h"
+
+#include "amp.h"
+
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+
+#define PHY_MODE_IDLE          0x00
+#define PHY_MODE_INITIATOR     0x01
+#define PHY_MODE_ACCEPTOR      0x02
+
+#define MAX_ASSOC_LEN  672
+
+struct bt_amp {
+       volatile int ref_count;
+       int vhci_fd;
+
+       char phylink_path[32];
+       int phylink_fd;
+
+       uint8_t  event_mask[16];
+       uint16_t manufacturer;
+       uint8_t  commands[64];
+       uint8_t  features[8];
+
+       uint8_t  amp_status;
+       uint8_t  amp_type;
+       uint8_t  local_assoc[MAX_ASSOC_LEN];
+       uint16_t local_assoc_len;
+       uint8_t  remote_assoc[MAX_ASSOC_LEN];
+       uint16_t remote_assoc_len;
+
+       uint8_t  phy_mode;
+       uint8_t  phy_handle;
+       uint16_t logic_handle;
+};
+
+static void reset_defaults(struct bt_amp *amp)
+{
+       memset(amp->event_mask, 0, sizeof(amp->event_mask));
+       amp->event_mask[1] |= 0x20;     /* Command Complete */
+       amp->event_mask[1] |= 0x40;     /* Command Status */
+       amp->event_mask[1] |= 0x80;     /* Hardware Error */
+       amp->event_mask[2] |= 0x01;     /* Flush Occurred */
+       amp->event_mask[2] |= 0x04;     /* Number of Completed Packets */
+       amp->event_mask[3] |= 0x02;     /* Data Buffer Overflow */
+       amp->event_mask[3] |= 0x20;     /* QoS Violation */
+       amp->event_mask[7] |= 0x01;     /* Enhanced Flush Complete */
+
+       amp->event_mask[8] |= 0x01;     /* Physical Link Complete */
+       amp->event_mask[8] |= 0x02;     /* Channel Selected */
+       amp->event_mask[8] |= 0x04;     /* Disconnection Physical Link Complete */
+       amp->event_mask[8] |= 0x08;     /* Physical Link Loss Early Warning */
+       amp->event_mask[8] |= 0x10;     /* Physical Link Recovery */
+       amp->event_mask[8] |= 0x20;     /* Logical Link Complete */
+       amp->event_mask[8] |= 0x40;     /* Disconection Logical Link Complete */
+       amp->event_mask[8] |= 0x80;     /* Flow Specification Modify Complete */
+       amp->event_mask[9] |= 0x01;     /* Number of Completed Data Blocks */
+       amp->event_mask[9] |= 0x02;     /* AMP Start Test */
+       amp->event_mask[9] |= 0x04;     /* AMP Test End */
+       amp->event_mask[9] |= 0x08;     /* AMP Receiver Report */
+       amp->event_mask[9] |= 0x10;     /* Short Range Mode Change Complete */
+       amp->event_mask[9] |= 0x20;     /* AMP Status Change */
+
+       amp->manufacturer = 0x003f;     /* Bluetooth SIG (63) */
+
+       memset(amp->commands, 0, sizeof(amp->commands));
+       amp->commands[5]  |= 0x40;      /* Set Event Mask */
+       amp->commands[5]  |= 0x80;      /* Reset */
+       //amp->commands[6]  |= 0x01;    /* Set Event Filter */
+       //amp->commands[7]  |= 0x04;    /* Read Connection Accept Timeout */
+       //amp->commands[7]  |= 0x08;    /* Write Connection Accept Timeout */
+       //amp->commands[10] |= 0x80;    /* Host Number of Completed Packets */
+       //amp->commands[11] |= 0x01;    /* Read Link Supervision Timeout */
+       //amp->commands[11] |= 0x02;    /* Write Link Supervision Timeout */
+       amp->commands[14] |= 0x08;      /* Read Local Version Information */
+       amp->commands[14] |= 0x10;      /* Read Local Supported Commands */
+       amp->commands[14] |= 0x20;      /* Read Local Supported Features */
+       amp->commands[14] |= 0x80;      /* Read Buffer Size */
+       //amp->commands[15] |= 0x04;    /* Read Failed Contact Counter */
+       //amp->commands[15] |= 0x08;    /* Reset Failed Contact Counter */
+       //amp->commands[15] |= 0x10;    /* Read Link Quality */
+       //amp->commands[15] |= 0x20;    /* Read RSSI */
+       //amp->commands[16] |= 0x04;    /* Enable Device Under Test Mode */
+       //amp->commands[19] |= 0x40;    /* Enhanced Flush */
+
+       amp->commands[21] |= 0x01;      /* Create Physical Link */
+       amp->commands[21] |= 0x02;      /* Accept Physical Link */
+       amp->commands[21] |= 0x04;      /* Disconnect Phyiscal Link */
+       amp->commands[21] |= 0x08;      /* Create Logical Link */
+       amp->commands[21] |= 0x10;      /* Accept Logical Link */
+       amp->commands[21] |= 0x20;      /* Disconnect Logical Link */
+       amp->commands[21] |= 0x40;      /* Logical Link Cancel */
+       //amp->commands[21] |= 0x80;    /* Flow Specification Modify */
+       //amp->commands[22] |= 0x01;    /* Read Logical Link Accept Timeout */
+       //amp->commands[22] |= 0x02;    /* Write Logical Link Accept Timeout */
+       amp->commands[22] |= 0x04;      /* Set Event Mask Page 2 */
+       amp->commands[22] |= 0x08;      /* Read Location Data */
+       amp->commands[22] |= 0x10;      /* Write Location Data */
+       amp->commands[22] |= 0x20;      /* Read Local AMP Info */
+       amp->commands[22] |= 0x40;      /* Read Local AMP ASSOC */
+       amp->commands[22] |= 0x80;      /* Write Remote AMP ASSOC */
+       amp->commands[23] |= 0x01;      /* Read Flow Control Mode */
+       amp->commands[23] |= 0x02;      /* Write Flow Control Mode */
+       amp->commands[23] |= 0x04;      /* Read Data Block Size */
+       //amp->commands[23] |= 0x20;    /* Enable AMP Receiver Reports */
+       //amp->commands[23] |= 0x40;    /* AMP Test End */
+       //amp->commands[23] |= 0x80;    /* AMP Test */
+       //amp->commands[24] |= 0x04;    /* Read Best Effort Flush Timeout */
+       //amp->commands[24] |= 0x08;    /* Write Best Effort Flush Timeout */
+       //amp->commands[24] |= 0x10;    /* Short Range Mode */
+
+       memset(amp->features, 0, sizeof(amp->features));
+
+       amp->amp_status = 0x01;         /* Used for Bluetooth only */
+       amp->amp_type = 0x42;           /* Fake virtual AMP type */
+
+       memset(amp->local_assoc, 0, sizeof(amp->local_assoc));
+       amp->local_assoc_len = 0;
+
+       memset(amp->remote_assoc, 0, sizeof(amp->remote_assoc));
+       amp->remote_assoc_len = 0;
+
+       amp->phy_mode = PHY_MODE_IDLE;
+       amp->phy_handle = 0x00;         /* Invalid physical link handle */
+       amp->logic_handle = 0x0000;
+}
+
+static void send_packet(struct bt_amp *amp, const void *data, uint16_t len)
+{
+       if (write(amp->vhci_fd, data, len) < 0)
+               fprintf(stderr, "Write to /dev/vhci failed\n");
+}
+
+static void send_event(struct bt_amp *amp, 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 = alloca(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(amp, pkt_data, pkt_len);
+}
+
+static void cmd_complete(struct bt_amp *amp, 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 = alloca(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(amp, pkt_data, pkt_len);
+}
+
+static void cmd_status(struct bt_amp *amp, uint8_t status, uint16_t opcode)
+{
+       struct bt_hci_evt_hdr *hdr;
+       struct bt_hci_evt_cmd_status *cs;
+       uint16_t pkt_len;
+       void *pkt_data;
+
+       pkt_len = 1 + sizeof(*hdr) + sizeof(*cs);
+
+       pkt_data = alloca(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_STATUS;
+       hdr->plen = sizeof(*cs);
+
+       cs = pkt_data + 1 + sizeof(*hdr);
+       cs->status = status;
+       cs->ncmd = 0x01;
+       cs->opcode = cpu_to_le16(opcode);
+
+       send_packet(amp, pkt_data, pkt_len);
+}
+
+static void cmd_set_event_mask(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_event_mask *cmd = data;
+       uint8_t status;
+
+       memcpy(amp->event_mask, cmd->mask, 8);
+
+       status = BT_HCI_ERR_SUCCESS;
+       cmd_complete(amp, BT_HCI_CMD_SET_EVENT_MASK, &status, sizeof(status));
+}
+
+static void cmd_reset(struct bt_amp *amp, const void *data, uint8_t size)
+{
+       uint8_t status;
+
+       reset_defaults(amp);
+
+       amp->local_assoc[0] = 0x00;
+       amp->local_assoc_len = 1;
+
+       status = BT_HCI_ERR_SUCCESS;
+       cmd_complete(amp, BT_HCI_CMD_RESET, &status, sizeof(status));
+}
+
+static void cmd_read_local_version(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_local_version rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.hci_ver = 0x05;
+       rsp.hci_rev = cpu_to_le16(0x0000);
+       rsp.lmp_ver = 0x01;
+       rsp.manufacturer = cpu_to_le16(amp->manufacturer);
+       rsp.lmp_subver = cpu_to_le16(0x0000);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCAL_VERSION, &rsp, sizeof(rsp));
+}
+
+static void cmd_read_local_commands(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_local_commands rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       memcpy(rsp.commands, amp->commands, 64);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCAL_COMMANDS, &rsp, sizeof(rsp));
+}
+
+static void cmd_read_local_features(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_local_features rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       memcpy(rsp.features, amp->features, 8);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCAL_FEATURES, &rsp, sizeof(rsp));
+}
+
+static void cmd_read_buffer_size(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_buffer_size rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.acl_mtu = cpu_to_le16(0x0000);
+       rsp.sco_mtu = 0x00;
+       rsp.acl_max_pkt = cpu_to_le16(0x0000);
+       rsp.sco_max_pkt = cpu_to_le16(0x0000);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_BUFFER_SIZE, &rsp, sizeof(rsp));
+}
+
+static void evt_phy_link_complete(struct bt_amp *amp)
+{
+       struct bt_hci_evt_phy_link_complete evt;
+
+       evt.status = BT_HCI_ERR_SUCCESS;
+       evt.phy_handle = amp->phy_handle;
+
+       send_event(amp, BT_HCI_EVT_PHY_LINK_COMPLETE, &evt, sizeof(evt));
+}
+
+static void evt_disconn_phy_link_complete(struct bt_amp *amp, uint8_t reason)
+{
+       struct bt_hci_evt_disconn_phy_link_complete evt;
+
+       evt.status = BT_HCI_ERR_SUCCESS;
+       evt.phy_handle = amp->phy_handle;
+       evt.reason = reason;
+
+       send_event(amp, BT_HCI_EVT_DISCONN_PHY_LINK_COMPLETE,
+                                               &evt, sizeof(evt));
+}
+
+static void link_callback(int fd, uint32_t events, void *user_data)
+{
+       struct bt_amp *amp = user_data;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               close(fd);
+               mainloop_remove_fd(fd);
+
+               evt_disconn_phy_link_complete(amp, 0x13);
+
+               amp->phy_mode = PHY_MODE_IDLE;
+               amp->phy_handle = 0x00;
+               return;
+       }
+}
+
+static void cmd_create_phy_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_phy_link *cmd = data;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_CREATE_PHY_LINK);
+               return;
+       }
+
+       if (amp->phy_mode != PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_CREATE_PHY_LINK);
+               return;
+       }
+
+       amp->phy_mode = PHY_MODE_INITIATOR;
+       amp->phy_handle = cmd->phy_handle;
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_CREATE_PHY_LINK);
+}
+
+static void cmd_accept_phy_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_accept_phy_link *cmd = data;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_ACCEPT_PHY_LINK);
+               return;
+       }
+
+       if (amp->phy_mode != PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_ACCEPT_PHY_LINK);
+               return;
+       }
+
+       amp->phy_mode = PHY_MODE_ACCEPTOR;
+       amp->phy_handle = cmd->phy_handle;
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_ACCEPT_PHY_LINK);
+}
+
+static void cmd_disconn_phy_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_disconn_phy_link *cmd = data;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_DISCONN_PHY_LINK);
+               return;
+       }
+
+       if (amp->phy_mode == PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_DISCONN_PHY_LINK);
+               return;
+       }
+
+       if (cmd->phy_handle != amp->phy_handle) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_DISCONN_PHY_LINK);
+               return;
+       }
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_DISCONN_PHY_LINK);
+
+       mainloop_remove_fd(amp->phylink_fd);
+       close(amp->phylink_fd);
+
+       evt_disconn_phy_link_complete(amp, cmd->reason);
+
+       amp->phy_mode = PHY_MODE_IDLE;
+       amp->phy_handle = 0x00;
+}
+
+static void evt_logic_link_complete(struct bt_amp *amp)
+{
+       struct bt_hci_evt_logic_link_complete evt;
+
+       evt.status = BT_HCI_ERR_SUCCESS;
+       evt.handle = htobs(amp->logic_handle);
+       evt.phy_handle = amp->phy_handle;
+       evt.flow_spec = 0x00;
+
+       send_event(amp, BT_HCI_EVT_LOGIC_LINK_COMPLETE, &evt, sizeof(evt));
+}
+
+static void evt_disconn_logic_link_complete(struct bt_amp *amp, uint8_t reason)
+{
+       struct bt_hci_evt_disconn_logic_link_complete evt;
+
+       evt.status = BT_HCI_ERR_SUCCESS;
+       evt.handle = htobs(amp->logic_handle);
+       evt.reason = reason;
+
+       send_event(amp, BT_HCI_EVT_DISCONN_LOGIC_LINK_COMPLETE,
+                                               &evt, sizeof(evt));
+}
+
+static void cmd_create_logic_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_logic_link *cmd = data;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_CREATE_LOGIC_LINK);
+               return;
+       }
+
+       if (amp->phy_mode != PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_CREATE_LOGIC_LINK);
+               return;
+       }
+
+       if (amp->logic_handle != 0x00) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_CREATE_LOGIC_LINK);
+               return;
+       }
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_CREATE_LOGIC_LINK);
+
+       amp->logic_handle = 0x0042;
+
+       evt_logic_link_complete(amp);
+}
+
+static void cmd_accept_logic_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_accept_logic_link *cmd = data;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_ACCEPT_LOGIC_LINK);
+               return;
+       }
+
+       if (amp->phy_mode != PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_ACCEPT_LOGIC_LINK);
+               return;
+       }
+
+       if (amp->logic_handle != 0x00) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_ACCEPT_LOGIC_LINK);
+               return;
+       }
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_ACCEPT_LOGIC_LINK);
+
+       amp->logic_handle = 0x0023;
+
+       evt_logic_link_complete(amp);
+}
+
+static void cmd_disconn_logic_link(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_disconn_logic_link *cmd = data;
+
+       if (cmd->handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_DISCONN_LOGIC_LINK);
+               return;
+       }
+
+       if (cmd->handle != amp->logic_handle) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_DISCONN_LOGIC_LINK);
+               return;
+       }
+
+       cmd_status(amp, BT_HCI_ERR_SUCCESS, BT_HCI_CMD_DISCONN_LOGIC_LINK);
+
+       evt_disconn_logic_link_complete(amp, 0x13);
+
+       amp->logic_handle = 0x0000;
+}
+
+static void cmd_logic_link_cancel(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_logic_link_cancel *cmd = data;
+       struct bt_hci_rsp_logic_link_cancel rsp;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_LOGIC_LINK_CANCEL);
+               return;
+       }
+
+       if (amp->phy_mode != PHY_MODE_IDLE) {
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_LOGIC_LINK_CANCEL);
+               return;
+       }
+
+       amp->logic_handle = 0x0000;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.phy_handle = amp->phy_handle;
+       rsp.flow_spec = 0x00;
+
+       cmd_complete(amp, BT_HCI_CMD_LOGIC_LINK_CANCEL, &rsp, sizeof(rsp));
+}
+
+static void cmd_set_event_mask_page2(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_event_mask_page2 *cmd = data;
+       uint8_t status;
+
+       memcpy(amp->event_mask + 8, cmd->mask, 8);
+
+       status = BT_HCI_ERR_SUCCESS;
+       cmd_complete(amp, BT_HCI_CMD_SET_EVENT_MASK_PAGE2,
+                                               &status, sizeof(status));
+}
+
+static void cmd_read_location_data(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_location_data rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.domain_aware = 0x00;
+       rsp.domain[0] = 0x58;
+       rsp.domain[1] = 0x58;
+       rsp.domain_options = 0x58;
+       rsp.options = 0x00;
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCATION_DATA, &rsp, sizeof(rsp));
+}
+
+static void cmd_write_location_data(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_location_data *cmd = data;
+       uint8_t status;
+
+       if (cmd->domain_aware > 0x01) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_WRITE_LOCATION_DATA);
+               return;
+       }
+
+       status = BT_HCI_ERR_SUCCESS;
+       cmd_complete(amp, BT_HCI_CMD_WRITE_LOCATION_DATA,
+                                               &status, sizeof(status));
+}
+
+static void cmd_read_flow_control_mode(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_flow_control_mode rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.mode = 0x01;
+
+       cmd_complete(amp, BT_HCI_CMD_READ_FLOW_CONTROL_MODE,
+                                               &rsp, sizeof(rsp));
+}
+
+static void cmd_write_flow_control_mode(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_flow_control_mode *cmd = data;
+       uint8_t status;
+
+       if (cmd->mode != 0x01) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_WRITE_FLOW_CONTROL_MODE);
+               return;
+       }
+
+       status = BT_HCI_ERR_SUCCESS;
+       cmd_complete(amp, BT_HCI_CMD_WRITE_FLOW_CONTROL_MODE,
+                                               &status, sizeof(status));
+}
+
+static void cmd_read_data_block_size(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_data_block_size rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.max_acl_len = cpu_to_le16(1492);
+       rsp.block_len = cpu_to_le16(1492);
+       rsp.num_blocks = cpu_to_le16(1);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_DATA_BLOCK_SIZE, &rsp, sizeof(rsp));
+}
+
+static void cmd_read_local_amp_info(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       struct bt_hci_rsp_read_local_amp_info rsp;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.amp_status = amp->amp_status;
+       rsp.total_bw = cpu_to_le32(24000);
+       rsp.max_bw = cpu_to_le32(24000);
+       rsp.min_latency = cpu_to_le32(100);
+       rsp.max_pdu = cpu_to_le32(1492);
+       rsp.amp_type = amp->amp_type;
+       rsp.pal_cap = cpu_to_le16(0x0001);
+       rsp.max_assoc_len = cpu_to_le16(MAX_ASSOC_LEN);
+       rsp.max_flush_to = cpu_to_le32(20000);
+       rsp.be_flush_to = cpu_to_le32(20000);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCAL_AMP_INFO, &rsp, sizeof(rsp));
+}
+
+static void cmd_read_local_amp_assoc(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_local_amp_assoc *cmd = data;
+       struct bt_hci_rsp_read_local_amp_assoc rsp;
+       uint16_t len_so_far, remain_assoc_len, fragment_len;
+
+       if (cmd->phy_handle != amp->phy_handle) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_READ_LOCAL_AMP_ASSOC);
+               return;
+       }
+
+       len_so_far = le16_to_cpu(cmd->len_so_far);
+       remain_assoc_len = amp->local_assoc_len - len_so_far;
+       fragment_len = remain_assoc_len > 248 ? 248 : remain_assoc_len;
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.phy_handle = cmd->phy_handle;
+       rsp.remain_assoc_len = cpu_to_le16(remain_assoc_len);
+       memcpy(rsp.assoc_fragment, amp->local_assoc + len_so_far,
+                                                       fragment_len);
+
+       cmd_complete(amp, BT_HCI_CMD_READ_LOCAL_AMP_ASSOC,
+                                               &rsp, 4 + fragment_len);
+}
+
+static int create_unix_server(const char *path)
+{
+       struct sockaddr_un addr;
+       int fd;
+
+       fd = socket(PF_UNIX, SOCK_SEQPACKET, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       addr.sun_path[0] = '\0';
+       strcpy(addr.sun_path + 1, path);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       if (listen(fd, 1) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int connect_unix_client(const char *path)
+{
+       struct sockaddr_un addr;
+       int fd;
+
+       fd = socket(PF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC | SOCK_NONBLOCK, 0);
+       if (fd < 0)
+               return -1;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       addr.sun_path[0] = '\0';
+       strcpy(addr.sun_path + 1, path);
+
+       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static void accept_callback(int fd, uint32_t events, void *user_data)
+{
+       struct bt_amp *amp = user_data;
+       struct sockaddr_un addr;
+       socklen_t len;
+       int new_fd;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       len = sizeof(addr);
+
+       new_fd = accept4(fd, (struct sockaddr *) &addr, &len,
+                                               SOCK_CLOEXEC | SOCK_NONBLOCK);
+       if (new_fd < 0)
+               return;
+
+       mainloop_remove_fd(fd);
+       close(fd);
+
+       amp->phylink_fd = new_fd;
+
+       evt_phy_link_complete(amp);
+
+       mainloop_add_fd(new_fd, EPOLLIN, link_callback, amp, NULL);
+}
+
+static void connect_callback(int fd, uint32_t events, void *user_data)
+{
+       struct bt_amp *amp = user_data;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       mainloop_remove_fd(fd);
+
+       evt_phy_link_complete(amp);
+
+       mainloop_add_fd(fd, EPOLLIN, link_callback, amp, NULL);
+}
+
+static void cmd_write_remote_amp_assoc(struct bt_amp *amp,
+                                               const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_remote_amp_assoc *cmd = data;
+       struct bt_hci_rsp_write_remote_amp_assoc rsp;
+       int fd;
+
+       if (cmd->phy_handle == 0x00) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+               return;
+       }
+
+       if (cmd->phy_handle != amp->phy_handle) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+               return;
+       }
+
+       switch (amp->phy_mode) {
+       case PHY_MODE_INITIATOR:
+               strcpy(amp->phylink_path, "amp");
+
+               fd = create_unix_server(amp->phylink_path);
+               if (fd < 0) {
+                       cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+                       return;
+               }
+
+               amp->local_assoc[0] = 0x01;
+               memcpy(amp->local_assoc + 1, amp->phylink_path,
+                                       strlen(amp->phylink_path) + 1);
+               amp->local_assoc_len = strlen(amp->phylink_path) + 2;
+
+               mainloop_add_fd(fd, EPOLLIN, accept_callback, amp, NULL);
+
+               amp->phylink_fd = fd;
+               break;
+
+       case PHY_MODE_ACCEPTOR:
+               if (cmd->assoc_fragment[0] != 0x01) {
+                       cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+                       return;
+               }
+
+               memcpy(amp->phylink_path, cmd->assoc_fragment + 1,
+                                               cmd->remain_assoc_len - 1);
+
+               fd = connect_unix_client(amp->phylink_path);
+               if (fd < 0) {
+                       cmd_status(amp, BT_HCI_ERR_UNSPECIFIED_ERROR,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+                       return;
+               }
+
+               mainloop_add_fd(fd, EPOLLOUT, connect_callback, amp, NULL);
+
+               amp->phylink_fd = fd;
+               break;
+
+       default:
+               cmd_status(amp, BT_HCI_ERR_COMMAND_DISALLOWED,
+                                       BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC);
+               return;
+       }
+
+       rsp.status = BT_HCI_ERR_SUCCESS;
+       rsp.phy_handle = amp->phy_handle;
+
+       cmd_complete(amp, BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC, &rsp, sizeof(rsp));
+
+       if (amp->phy_mode == PHY_MODE_INITIATOR) {
+               struct bt_hci_evt_channel_selected evt;
+
+               evt.phy_handle = amp->phy_handle;
+
+               send_event(amp, BT_HCI_EVT_CHANNEL_SELECTED, &evt, sizeof(evt));
+       }
+}
+
+static const struct {
+       uint16_t opcode;
+       void (*func) (struct bt_amp *amp, const void *data, uint8_t size);
+       uint8_t size;
+       bool fixed;
+} cmd_table[] = {
+       { BT_HCI_CMD_SET_EVENT_MASK,       cmd_set_event_mask,      8, true },
+       { BT_HCI_CMD_RESET,                cmd_reset,               0, true },
+       { BT_HCI_CMD_READ_LOCAL_VERSION,   cmd_read_local_version,  0, true },
+       { BT_HCI_CMD_READ_LOCAL_COMMANDS,  cmd_read_local_commands, 0, true },
+       { BT_HCI_CMD_READ_LOCAL_FEATURES,  cmd_read_local_features, 0, true },
+       { BT_HCI_CMD_READ_BUFFER_SIZE,     cmd_read_buffer_size,    0, true },
+
+       { BT_HCI_CMD_CREATE_PHY_LINK,
+                               cmd_create_phy_link, 3, false },
+       { BT_HCI_CMD_ACCEPT_PHY_LINK,
+                               cmd_accept_phy_link, 3, false },
+       { BT_HCI_CMD_DISCONN_PHY_LINK,
+                               cmd_disconn_phy_link, 2, true },
+       { BT_HCI_CMD_CREATE_LOGIC_LINK,
+                               cmd_create_logic_link, 33, true },
+       { BT_HCI_CMD_ACCEPT_LOGIC_LINK,
+                               cmd_accept_logic_link, 33, true },
+       { BT_HCI_CMD_DISCONN_LOGIC_LINK,
+                               cmd_disconn_logic_link, 2, true },
+       { BT_HCI_CMD_LOGIC_LINK_CANCEL,
+                               cmd_logic_link_cancel, 2, true },
+       { BT_HCI_CMD_SET_EVENT_MASK_PAGE2,
+                               cmd_set_event_mask_page2, 8, true },
+       { BT_HCI_CMD_READ_LOCATION_DATA,
+                               cmd_read_location_data, 0, true },
+       { BT_HCI_CMD_WRITE_LOCATION_DATA,
+                               cmd_write_location_data, 5, true },
+       { BT_HCI_CMD_READ_FLOW_CONTROL_MODE,
+                               cmd_read_flow_control_mode, 0, true },
+       { BT_HCI_CMD_WRITE_FLOW_CONTROL_MODE,
+                               cmd_write_flow_control_mode, 1, true },
+       { BT_HCI_CMD_READ_DATA_BLOCK_SIZE,
+                               cmd_read_data_block_size, 0, true },
+       { BT_HCI_CMD_READ_LOCAL_AMP_INFO,
+                               cmd_read_local_amp_info, 0, true },
+       { BT_HCI_CMD_READ_LOCAL_AMP_ASSOC,
+                               cmd_read_local_amp_assoc, 5, true },
+       { BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC,
+                               cmd_write_remote_amp_assoc, 6, false },
+       { }
+};
+
+static void process_command(struct bt_amp *amp, const void *data, size_t size)
+{
+       const struct bt_hci_cmd_hdr *hdr = data;
+       uint16_t opcode;
+       unsigned int i;
+
+       if (size < sizeof(*hdr))
+               return;
+
+       data += sizeof(*hdr);
+       size -= sizeof(*hdr);
+
+       opcode = le16_to_cpu(hdr->opcode);
+
+       if (hdr->plen != size) {
+               cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS, opcode);
+               return;
+       }
+
+       for (i = 0; cmd_table[i].func; i++) {
+               if (cmd_table[i].opcode != opcode)
+                       continue;
+
+               if ((cmd_table[i].fixed && size != cmd_table[i].size) ||
+                                               size < cmd_table[i].size) {
+                       cmd_status(amp, BT_HCI_ERR_INVALID_PARAMETERS, opcode);
+                       return;
+               }
+
+               cmd_table[i].func(amp, data, size);
+               return;
+       }
+
+       cmd_status(amp, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+}
+
+static void vhci_read_callback(int fd, uint32_t events, void *user_data)
+{
+       struct bt_amp *amp = user_data;
+       unsigned char buf[4096];
+       ssize_t len;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+       len = read(amp->vhci_fd, buf, sizeof(buf));
+       if (len < 1)
+               return;
+
+       switch (buf[0]) {
+       case BT_H4_CMD_PKT:
+               process_command(amp, buf + 1, len - 1);
+               break;
+       }
+}
+
+struct bt_amp *bt_amp_new(void)
+{
+       unsigned char setup_cmd[2];
+       struct bt_amp *amp;
+
+       amp = calloc(1, sizeof(*amp));
+       if (!amp)
+               return NULL;
+
+       reset_defaults(amp);
+
+       amp->vhci_fd = open("/dev/vhci", O_RDWR);
+       if (amp->vhci_fd < 0) {
+               free(amp);
+               return NULL;
+       }
+
+       setup_cmd[0] = HCI_VENDOR_PKT;
+       setup_cmd[1] = HCI_AMP;
+
+       if (write(amp->vhci_fd, setup_cmd, sizeof(setup_cmd)) < 0) {
+               close(amp->vhci_fd);
+               free(amp);
+               return NULL;
+       }
+
+       mainloop_add_fd(amp->vhci_fd, EPOLLIN, vhci_read_callback, amp, NULL);
+
+       return bt_amp_ref(amp);
+}
+
+struct bt_amp *bt_amp_ref(struct bt_amp *amp)
+{
+       if (!amp)
+               return NULL;
+
+       __sync_fetch_and_add(&amp->ref_count, 1);
+
+       return amp;
+}
+
+void bt_amp_unref(struct bt_amp *amp)
+{
+       if (!amp)
+               return;
+
+       if (__sync_sub_and_fetch(&amp->ref_count, 1))
+               return;
+
+       mainloop_remove_fd(amp->vhci_fd);
+
+       close(amp->vhci_fd);
+
+       free(amp);
+}
similarity index 81%
rename from audio/gstpragma.h
rename to emulator/amp.h
index 0cb08d2..189dfb7 100644 (file)
@@ -2,6 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *
  */
 
-/* #pragma GCC diagnostic warning "-Wmissing-declarations" */
+#include <stdbool.h>
+
+struct bt_amp;
+
+struct bt_amp *bt_amp_new(void);
+
+struct bt_amp *bt_amp_ref(struct bt_amp *amp);
+void bt_amp_unref(struct bt_amp *amp);
diff --git a/emulator/b1ee.c b/emulator/b1ee.c
new file mode 100644 (file)
index 0000000..17a60fc
--- /dev/null
@@ -0,0 +1,256 @@
+/*
+ *
+ *  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 <netdb.h>
+#include <arpa/inet.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/mainloop.h"
+
+#define DEFAULT_SERVER         "b1ee.com"
+#define DEFAULT_HOST_PORT      "45550"         /* 0xb1ee */
+#define DEFAULT_SNIFFER_PORT   "45551"         /* 0xb1ef */
+
+static int sniffer_fd;
+static int server_fd;
+static int vhci_fd;
+
+static void sniffer_read_callback(int fd, uint32_t events, void *user_data)
+{
+       static uint8_t buf[4096];
+       ssize_t len;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+again:
+       len = recv(fd, buf, sizeof(buf), MSG_DONTWAIT);
+       if (len < 0) {
+               if (errno == EAGAIN)
+                       goto again;
+               return;
+       }
+
+       printf("Sniffer received: %zi bytes\n", len);
+}
+
+static uint8_t *server_pkt_data;
+static uint8_t server_pkt_type;
+static uint16_t server_pkt_expect;
+static uint16_t server_pkt_len;
+static uint16_t server_pkt_offset;
+
+static void server_read_callback(int fd, uint32_t events, void *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 + server_pkt_offset,
+                       sizeof(buf) - server_pkt_offset, MSG_DONTWAIT);
+       if (len < 0) {
+               if (errno == EAGAIN)
+                       goto again;
+               return;
+       }
+
+       count = server_pkt_offset + len;
+
+       while (count > 0) {
+               hci_event_hdr *evt_hdr;
+
+               if (!server_pkt_data) {
+                       server_pkt_type = ptr[0];
+
+                       switch (server_pkt_type) {
+                       case HCI_EVENT_PKT:
+                               if (count < HCI_EVENT_HDR_SIZE + 1) {
+                                       server_pkt_offset += len;
+                                       return;
+                               }
+                               evt_hdr = (hci_event_hdr *) (ptr + 1);
+                               server_pkt_expect = HCI_EVENT_HDR_SIZE +
+                                                       evt_hdr->plen + 1;
+                               server_pkt_data = malloc(server_pkt_expect);
+                               server_pkt_len = 0;
+                               break;
+                       default:
+                               fprintf(stderr, "Unknown packet from server\n");
+                               return;
+                       }
+
+                       server_pkt_offset = 0;
+               }
+
+               if (count >= server_pkt_expect) {
+                       ssize_t written;
+
+                       memcpy(server_pkt_data + server_pkt_len,
+                                               ptr, server_pkt_expect);
+                       ptr += server_pkt_expect;
+                       count -= server_pkt_expect;
+
+                       written = write(vhci_fd, server_pkt_data,
+                                       server_pkt_len + server_pkt_expect);
+                       if (written != server_pkt_len + server_pkt_expect)
+                               fprintf(stderr, "Write to /dev/vhci failed\n");
+
+                       free(server_pkt_data);
+                       server_pkt_data = NULL;
+               } else {
+                       memcpy(server_pkt_data + server_pkt_len, ptr, count);
+                       server_pkt_len += count;
+                       server_pkt_expect -= count;
+                       count = 0;
+               }
+       }
+}
+
+static void vhci_read_callback(int fd, uint32_t events, void *user_data)
+{
+       unsigned char buf[4096];
+       ssize_t len, written;
+
+       if (events & (EPOLLERR | EPOLLHUP))
+               return;
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0)
+               return;
+
+       written = write(server_fd, buf, len);
+       if (written != len)
+               fprintf(stderr, "Write to server failed\n");
+}
+
+static void signal_callback(int signum, void *user_data)
+{
+       switch (signum) {
+       case SIGINT:
+       case SIGTERM:
+               mainloop_quit();
+               break;
+       }
+}
+
+static int do_connect(const char *node, const char *service)
+{
+       struct addrinfo hints;
+       struct addrinfo *info, *res;
+       int err, fd = -1;
+
+       memset(&hints, 0, sizeof(hints));
+       hints.ai_family = PF_UNSPEC;
+       hints.ai_socktype = SOCK_STREAM;
+
+       err = getaddrinfo(DEFAULT_SERVER, DEFAULT_HOST_PORT, &hints, &res);
+       if (err) {
+               perror(gai_strerror(err));
+               exit(1);
+       }
+
+       for (info = res; info; info = info->ai_next) {
+               char str[INET6_ADDRSTRLEN];
+
+               inet_ntop(info->ai_family, info->ai_addr->sa_data,
+                                                       str, sizeof(str));
+
+               fd = socket(info->ai_family, info->ai_socktype,
+                                               info->ai_protocol);
+               if (fd < 0)
+                       continue;
+
+               printf("Trying to connect to %s on port %s\n", str, service);
+
+               if (connect(fd, res->ai_addr, res->ai_addrlen) < 0) {
+                       perror("Failed to connect");
+                       continue;
+               }
+
+               printf("Successfully connected to %s on port %s\n",
+                                                       str, service);
+               break;
+       }
+
+       freeaddrinfo(res);
+
+       if (res == NULL)
+               exit(1);
+
+       return fd;
+}
+
+int main(int argc, char *argv[])
+{
+       const char sniff_cmd[] = { 0x01, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+       ssize_t written;
+       sigset_t mask;
+
+       server_fd = do_connect(DEFAULT_SERVER, DEFAULT_HOST_PORT);
+       sniffer_fd = do_connect(DEFAULT_SERVER, DEFAULT_SNIFFER_PORT);
+
+       written = write(sniffer_fd, sniff_cmd, sizeof(sniff_cmd));
+       if (written < 0)
+               perror("Failed to enable sniffer");
+
+       vhci_fd = open("/dev/vhci", O_RDWR | O_NONBLOCK);
+       if (vhci_fd < 0) {
+               perror("Failed to /dev/vhci");
+               close(server_fd);
+               exit(1);
+       }
+
+       mainloop_init();
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       mainloop_set_signal(&mask, signal_callback, NULL, NULL);
+
+       mainloop_add_fd(sniffer_fd, EPOLLIN, sniffer_read_callback, NULL, NULL);
+       mainloop_add_fd(server_fd, EPOLLIN, server_read_callback, NULL, NULL);
+       mainloop_add_fd(vhci_fd, EPOLLIN, vhci_read_callback, NULL, NULL);
+
+       return mainloop_run();
+}
index 7d4517a..5f04bd1 100644 (file)
@@ -6,18 +6,18 @@
  *  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 library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  This library is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 #include <ctype.h>
 #include <stdlib.h>
 #include <string.h>
+#include <alloca.h>
 
-#include "bt.h"
+#include "monitor/bt.h"
 #include "btdev.h"
 
 #define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
 #define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+
+#define has_bredr(btdev)       (!((btdev)->features[4] & 0x20))
+#define has_le(btdev)          (!!((btdev)->features[4] & 0x40))
+
+struct hook {
+       btdev_hook_func handler;
+       void *user_data;
+       enum btdev_hook_type type;
+       uint16_t opcode;
+};
+
+#define MAX_HOOK_ENTRIES 16
 
 struct btdev {
+       enum btdev_type type;
+
        struct btdev *conn;
 
+       btdev_command_func command_handler;
+       void *command_data;
+
        btdev_send_func send_handler;
        void *send_data;
 
+       struct hook *hook_list[MAX_HOOK_ENTRIES];
+
         uint16_t manufacturer;
         uint8_t  version;
        uint16_t revision;
        uint8_t  commands[64];
+       uint8_t  max_page;
        uint8_t  features[8];
+       uint8_t  feat_page_2[8];
        uint16_t acl_mtu;
        uint16_t acl_max_pkt;
        uint8_t  country_code;
@@ -57,6 +81,7 @@ struct btdev {
 
        uint16_t default_link_policy;
        uint8_t  event_mask[8];
+       uint8_t  event_mask_page2[8];
        uint8_t  event_filter;
        uint8_t  name[248];
        uint8_t  dev_class[3];
@@ -64,21 +89,63 @@ struct btdev {
        uint16_t conn_accept_timeout;
        uint16_t page_timeout;
        uint8_t  scan_enable;
+       uint16_t page_scan_interval;
+       uint16_t page_scan_window;
+       uint16_t page_scan_type;
        uint8_t  auth_enable;
+       uint16_t inquiry_scan_interval;
+       uint16_t inquiry_scan_window;
        uint8_t  inquiry_mode;
-       uint8_t  afh_assess_mode;
+       uint8_t  afh_assessment_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];
+       uint8_t  le_adv_data[31];
+       uint8_t  le_adv_data_len;
+       uint8_t  le_scan_enable;
+       uint8_t  le_filter_dup;
+       uint8_t  le_adv_enable;
+
+       uint16_t sync_train_interval;
+       uint32_t sync_train_timeout;
+       uint8_t  sync_train_service_data;
 };
 
 #define MAX_BTDEV_ENTRIES 16
 
 static struct btdev *btdev_list[MAX_BTDEV_ENTRIES] = { };
 
+static int get_hook_index(struct btdev *btdev, enum btdev_hook_type type,
+                                                               uint16_t opcode)
+{
+       int i;
+
+       for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+               if (btdev->hook_list[i] == NULL)
+                       continue;
+
+               if (btdev->hook_list[i]->type == type &&
+                                       btdev->hook_list[i]->opcode == opcode)
+                       return i;
+       }
+
+       return -1;
+}
+
+static bool run_hooks(struct btdev *btdev, enum btdev_hook_type type,
+                               uint16_t opcode, const void *data, uint16_t len)
+{
+       int index = get_hook_index(btdev, type, opcode);
+       if (index < 0)
+               return true;
+
+       return btdev->hook_list[index]->handler(data, len,
+                                       btdev->hook_list[index]->user_data);
+}
+
 static inline int add_btdev(struct btdev *btdev)
 {
        int i, index = -1;
@@ -160,30 +227,140 @@ static void hexdump(const unsigned char *buf, uint16_t len)
        }
 }
 
-static void get_bdaddr(uint16_t id, uint8_t *bdaddr)
+static void get_bdaddr(uint16_t id, uint8_t index, uint8_t *bdaddr)
 {
        bdaddr[0] = id & 0xff;
        bdaddr[1] = id >> 8;
-       bdaddr[2] = 0x00;
+       bdaddr[2] = index;
        bdaddr[3] = 0x01;
        bdaddr[4] = 0xaa;
        bdaddr[5] = 0x00;
 }
 
-struct btdev *btdev_create(uint16_t id)
+static void set_common_commands_all(struct btdev *btdev)
 {
-       struct btdev *btdev;
+       btdev->commands[5]  |= 0x40;    /* Set Event Mask */
+       btdev->commands[5]  |= 0x80;    /* Reset */
+       btdev->commands[14] |= 0x08;    /* Read Local Version */
+       btdev->commands[14] |= 0x10;    /* Read Local Supported Commands */
+       btdev->commands[14] |= 0x20;    /* Read Local Supported Features */
+       btdev->commands[14] |= 0x80;    /* Read Buffer Size */
+}
 
-       btdev = malloc(sizeof(*btdev));
-       if (!btdev)
-               return NULL;
+static void set_common_commands_bredrle(struct btdev *btdev)
+{
+       btdev->commands[0]  |= 0x20;    /* Disconnect */
+       btdev->commands[2]  |= 0x80;    /* Read Remote Version Information */
+       btdev->commands[10] |= 0x40;    /* Host Buffer Size */
+       btdev->commands[15] |= 0x02;    /* Read BD ADDR */
+}
 
-       memset(btdev, 0, sizeof(*btdev));
+static void set_bredr_commands(struct btdev *btdev)
+{
+       set_common_commands_all(btdev);
+       set_common_commands_bredrle(btdev);
+
+       btdev->commands[0]  |= 0x01;    /* Inquiry */
+       btdev->commands[0]  |= 0x02;    /* Inquiry Cancel */
+       btdev->commands[0]  |= 0x10;    /* Create Connection */
+       btdev->commands[0]  |= 0x40;    /* Add SCO Connection */
+       btdev->commands[0]  |= 0x80;    /* Cancel Create Connection */
+       btdev->commands[1]  |= 0x01;    /* Accept Connection Request */
+       btdev->commands[1]  |= 0x02;    /* Reject Connection Request */
+       btdev->commands[2]  |= 0x08;    /* Remote Name Request */
+       btdev->commands[2]  |= 0x10;    /* Cancel Remote Name Request */
+       btdev->commands[2]  |= 0x20;    /* Read Remote Supported Features */
+       btdev->commands[2]  |= 0x40;    /* Read Remote Extended Features */
+       btdev->commands[5]  |= 0x08;    /* Read Default Link Policy */
+       btdev->commands[5]  |= 0x10;    /* Write Default Link Policy */
+       btdev->commands[6]  |= 0x01;    /* Set Event Filter */
+       btdev->commands[6]  |= 0x20;    /* Read Stored Link Key */
+       btdev->commands[6]  |= 0x40;    /* Write Stored Link Key */
+       btdev->commands[6]  |= 0x80;    /* Delete Stored Link Key */
+       btdev->commands[7]  |= 0x01;    /* Write Local Name */
+       btdev->commands[7]  |= 0x02;    /* Read Local Name */
+       btdev->commands[7]  |= 0x04;    /* Read Connection Accept Timeout */
+       btdev->commands[7]  |= 0x08;    /* Write Connection Accept Timeout */
+       btdev->commands[7]  |= 0x10;    /* Read Page Timeout */
+       btdev->commands[7]  |= 0x20;    /* Write Page Timeout */
+       btdev->commands[7]  |= 0x40;    /* Read Scan Enable */
+       btdev->commands[7]  |= 0x80;    /* Write Scan Enable */
+       btdev->commands[8]  |= 0x01;    /* Read Page Scan Activity */
+       btdev->commands[8]  |= 0x02;    /* Write Page Scan Activity */
+       btdev->commands[8]  |= 0x04;    /* Read Inquiry Scan Activity */
+       btdev->commands[8]  |= 0x08;    /* Write Inquiry Scan Activity */
+       btdev->commands[8]  |= 0x10;    /* Read Authentication Enable */
+       btdev->commands[8]  |= 0x20;    /* Write Authentication Enable */
+       btdev->commands[9]  |= 0x01;    /* Read Class Of Device */
+       btdev->commands[9]  |= 0x02;    /* Write Class Of Device */
+       btdev->commands[9]  |= 0x04;    /* Read Voice Setting */
+       btdev->commands[9]  |= 0x08;    /* Write Voice Setting */
+       btdev->commands[11] |= 0x10;    /* Write Current IAC LAP */
+       btdev->commands[12] |= 0x40;    /* Read Inquiry Mode */
+       btdev->commands[12] |= 0x80;    /* Write Inquiry Mode */
+       btdev->commands[13] |= 0x01;    /* Read Page Scan Type */
+       btdev->commands[13] |= 0x02;    /* Write Page Scan Type */
+       btdev->commands[13] |= 0x04;    /* Read AFH Assess Mode */
+       btdev->commands[13] |= 0x08;    /* Write AFH Assess Mode */
+       btdev->commands[14] |= 0x40;    /* Read Local Extended Features */
+       btdev->commands[15] |= 0x01;    /* Read Country Code */
+       btdev->commands[16] |= 0x04;    /* Enable Device Under Test Mode */
+       btdev->commands[16] |= 0x08;    /* Setup Synchronous Connection */
+       btdev->commands[17] |= 0x01;    /* Read Extended Inquiry Response */
+       btdev->commands[17] |= 0x02;    /* Write Extended Inquiry Response */
+       btdev->commands[17] |= 0x20;    /* Read Simple Pairing Mode */
+       btdev->commands[17] |= 0x40;    /* Write Simple Pairing Mode */
+       btdev->commands[17] |= 0x80;    /* Read Local OOB Data */
+       btdev->commands[18] |= 0x01;    /* Read Inquiry Response TX Power */
+       btdev->commands[18] |= 0x02;    /* Write Inquiry Response TX Power */
+       btdev->commands[23] |= 0x04;    /* Read Data Block Size */
+}
 
-       btdev->manufacturer = 63;
-       btdev->version = 0x06;
-       btdev->revision = 0x0000;
+static void set_le_commands(struct btdev *btdev)
+{
+       set_common_commands_all(btdev);
+       set_common_commands_bredrle(btdev);
+
+       btdev->commands[24] |= 0x20;    /* Read LE Host Supported */
+       btdev->commands[24] |= 0x20;    /* Write LE Host Supported */
+       btdev->commands[25] |= 0x01;    /* LE Set Event Mask */
+       btdev->commands[25] |= 0x02;    /* LE Read Buffer Size */
+       btdev->commands[25] |= 0x04;    /* LE Read Local Features */
+       btdev->commands[25] |= 0x20;    /* LE Set Adv Parameters */
+       btdev->commands[25] |= 0x40;    /* LE Read Adv TX Power */
+       btdev->commands[25] |= 0x80;    /* LE Set Adv Data */
+       btdev->commands[26] |= 0x02;    /* LE Set Adv Enable */
+       btdev->commands[26] |= 0x04;    /* LE Set Scan Parameters */
+       btdev->commands[26] |= 0x08;    /* LE Set Scan Enable */
+       btdev->commands[26] |= 0x40;    /* LE Read White List Size */
+       btdev->commands[27] |= 0x80;    /* LE Rand */
+       btdev->commands[28] |= 0x08;    /* LE Read Supported States */
+       btdev->commands[28] |= 0x10;    /* LE Receiver Test */
+       btdev->commands[28] |= 0x20;    /* LE Transmitter Test */
+       btdev->commands[28] |= 0x40;    /* LE Test End */
+}
+
+static void set_bredrle_commands(struct btdev *btdev)
+{
+       set_bredr_commands(btdev);
+       set_le_commands(btdev);
+
+       /* Extra BR/EDR commands we want to only support for >= 4.0
+        * adapters.
+        */
+       btdev->commands[22] |= 0x04;    /* Set Event Mask Page 2 */
+       btdev->commands[31] |= 0x80;    /* Read Sync Train Parameters */
+}
+
+static void set_amp_commands(struct btdev *btdev)
+{
+       set_common_commands_all(btdev);
+
+       btdev->commands[22] |= 0x20;    /* Read Local AMP Info */
+}
 
+static void set_bredrle_features(struct btdev *btdev)
+{
        btdev->features[0] |= 0x04;     /* Encryption */
        btdev->features[0] |= 0x20;     /* Role switch */
        btdev->features[0] |= 0x80;     /* Sniff mode */
@@ -207,14 +384,113 @@ struct btdev *btdev_create(uint16_t id)
        btdev->features[7] |= 0x02;     /* Inquiry TX Power Level */
        btdev->features[7] |= 0x80;     /* Extended features */
 
+       btdev->feat_page_2[0] |= 0x01;  /* CSB - Master Operation */
+       btdev->feat_page_2[0] |= 0x02;  /* CSB - Slave Operation */
+       btdev->feat_page_2[0] |= 0x04;  /* Synchronization Train */
+       btdev->feat_page_2[0] |= 0x08;  /* Synchronization Scan */
+       btdev->feat_page_2[0] |= 0x10;  /* Inquiry Response Notification */
+
+       btdev->max_page = 2;
+}
+
+static void set_bredr_features(struct btdev *btdev)
+{
+       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[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] |= 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->max_page = 1;
+}
+
+static void set_le_features(struct btdev *btdev)
+{
+       btdev->features[4] |= 0x20;     /* BR/EDR Not Supported */
+       btdev->features[4] |= 0x40;     /* LE Supported */
+
+       btdev->max_page = 1;
+}
+
+static void set_amp_features(struct btdev *btdev)
+{
+}
+
+struct btdev *btdev_create(enum btdev_type type, uint16_t id)
+{
+       struct btdev *btdev;
+       int index;
+
+       btdev = malloc(sizeof(*btdev));
+       if (!btdev)
+               return NULL;
+
+       memset(btdev, 0, sizeof(*btdev));
+       btdev->type = type;
+
+       btdev->manufacturer = 63;
+
+       if (type == BTDEV_TYPE_BREDR)
+               btdev->version = 0x05;
+       else
+               btdev->version = 0x06;
+
+       btdev->revision = 0x0000;
+
+       switch (btdev->type) {
+       case BTDEV_TYPE_BREDRLE:
+               set_bredrle_features(btdev);
+               set_bredrle_commands(btdev);
+               break;
+       case BTDEV_TYPE_BREDR:
+               set_bredr_features(btdev);
+               set_bredr_commands(btdev);
+               break;
+       case BTDEV_TYPE_LE:
+               set_le_features(btdev);
+               set_le_commands(btdev);
+               break;
+       case BTDEV_TYPE_AMP:
+               set_amp_features(btdev);
+               set_amp_commands(btdev);
+               break;
+       }
+
+       btdev->page_scan_interval = 0x0800;
+       btdev->page_scan_window = 0x0012;
+       btdev->page_scan_type = 0x00;
+
+       btdev->sync_train_interval = 0x0080;
+       btdev->sync_train_timeout = 0x0002ee00;
+       btdev->sync_train_service_data = 0x00;
+
        btdev->acl_mtu = 192;
        btdev->acl_max_pkt = 1;
 
        btdev->country_code = 0x00;
 
-       get_bdaddr(id, btdev->bdaddr);
+       index = add_btdev(btdev);
+       if (index < 0) {
+               free(btdev);
+               return NULL;
+       }
 
-       add_btdev(btdev);
+       get_bdaddr(id, index, btdev->bdaddr);
 
        return btdev;
 }
@@ -229,6 +505,26 @@ void btdev_destroy(struct btdev *btdev)
        free(btdev);
 }
 
+const uint8_t *btdev_get_bdaddr(struct btdev *btdev)
+{
+       return btdev->bdaddr;
+}
+
+uint8_t *btdev_get_features(struct btdev *btdev)
+{
+       return btdev->features;
+}
+
+void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
+                                                       void *user_data)
+{
+       if (!btdev)
+               return;
+
+       btdev->command_handler = handler;
+       btdev->command_data = user_data;
+}
+
 void btdev_set_send_handler(struct btdev *btdev, btdev_send_func handler,
                                                        void *user_data)
 {
@@ -269,7 +565,8 @@ static void send_event(struct btdev *btdev, uint8_t event,
        if (len > 0)
                memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
 
-       send_packet(btdev, pkt_data, pkt_len);
+       if (run_hooks(btdev, BTDEV_HOOK_POST_EVT, event, pkt_data, pkt_len))
+               send_packet(btdev, pkt_data, pkt_len);
 
        free(pkt_data);
 }
@@ -301,20 +598,40 @@ static void cmd_complete(struct btdev *btdev, uint16_t opcode,
        if (len > 0)
                memcpy(pkt_data + 1 + sizeof(*hdr) + sizeof(*cc), data, len);
 
-       send_packet(btdev, pkt_data, pkt_len);
+       if (run_hooks(btdev, BTDEV_HOOK_POST_CMD, opcode, pkt_data, pkt_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;
+       struct bt_hci_evt_hdr *hdr;
+       struct bt_hci_evt_cmd_status *cs;
+       uint16_t pkt_len;
+       void *pkt_data;
+
+       pkt_len = 1 + sizeof(*hdr) + sizeof(*cs);
+
+       pkt_data = malloc(pkt_len);
+       if (!pkt_data)
+               return;
+
+       ((uint8_t *) pkt_data)[0] = BT_H4_EVT_PKT;
 
-       cs.status = status;
-       cs.ncmd = 0x01;
-       cs.opcode = cpu_to_le16(opcode);
+       hdr = pkt_data + 1;
+       hdr->evt = BT_HCI_EVT_CMD_STATUS;
+       hdr->plen = sizeof(*cs);
+
+       cs = pkt_data + 1 + sizeof(*hdr);
+       cs->status = status;
+       cs->ncmd = 0x01;
+       cs->opcode = cpu_to_le16(opcode);
 
-       send_event(btdev, BT_HCI_EVT_CMD_STATUS, &cs, sizeof(cs));
+       if (run_hooks(btdev, BTDEV_HOOK_POST_CMD, opcode, pkt_data, pkt_len))
+               send_packet(btdev, pkt_data, pkt_len);
+
+       free(pkt_data);
 }
 
 static void num_completed_packets(struct btdev *btdev)
@@ -349,7 +666,10 @@ static void inquiry_complete(struct btdev *btdev, uint8_t status)
 
                        ir.num_resp = 0x01;
                        memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       ir.pscan_rep_mode = 0x00;
+                       ir.pscan_period_mode = 0x00;
                        memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+                       ir.clock_offset = 0x0000;
                        ir.rssi = -60;
                        memcpy(ir.data, btdev_list[i]->ext_inquiry_rsp, 240);
 
@@ -363,7 +683,10 @@ static void inquiry_complete(struct btdev *btdev, uint8_t status)
 
                        ir.num_resp = 0x01;
                        memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       ir.pscan_rep_mode = 0x00;
+                       ir.pscan_period_mode = 0x00;
                        memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+                       ir.clock_offset = 0x0000;
                        ir.rssi = -60;
 
                        send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI,
@@ -373,7 +696,11 @@ static void inquiry_complete(struct btdev *btdev, uint8_t status)
 
                        ir.num_resp = 0x01;
                        memcpy(ir.bdaddr, btdev_list[i]->bdaddr, 6);
+                       ir.pscan_rep_mode = 0x00;
+                       ir.pscan_period_mode = 0x00;
+                       ir.pscan_mode = 0x00;
                        memcpy(ir.dev_class, btdev_list[i]->dev_class, 3);
+                       ir.clock_offset = 0x0000;
 
                        send_event(btdev, BT_HCI_EVT_INQUIRY_RESULT,
                                                        &ir, sizeof(ir));
@@ -419,12 +746,95 @@ static void conn_complete(struct btdev *btdev,
        send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
 }
 
+static void sync_conn_complete(struct btdev *btdev, uint16_t voice_setting,
+                                                               uint8_t status)
+{
+       struct bt_hci_evt_sync_conn_complete cc;
+
+       if (!btdev->conn)
+               return;
+
+       cc.status = status;
+       memcpy(cc.bdaddr, btdev->conn->bdaddr, 6);
+
+       cc.handle = cpu_to_le16(status == BT_HCI_ERR_SUCCESS ? 257 : 0);
+       cc.link_type = 0x02;
+       cc.tx_interval = 0x000c;
+       cc.retrans_window = 0x06;
+       cc.rx_pkt_len = 60;
+       cc.tx_pkt_len = 60;
+       cc.air_mode = (voice_setting == 0x0060) ? 0x02 : 0x03;
+
+       send_event(btdev, BT_HCI_EVT_SYNC_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
+static void sco_conn_complete(struct btdev *btdev, uint8_t status)
+{
+       struct bt_hci_evt_conn_complete cc;
+
+       if (!btdev->conn)
+               return;
+
+       cc.status = status;
+       memcpy(cc.bdaddr, btdev->conn->bdaddr, 6);
+       cc.handle = cpu_to_le16(status == BT_HCI_ERR_SUCCESS ? 257 : 0);
+       cc.link_type = 0x00;
+       cc.encr_mode = 0x00;
+
+       send_event(btdev, BT_HCI_EVT_CONN_COMPLETE, &cc, sizeof(cc));
+}
+
+static void le_conn_complete(struct btdev *btdev,
+                                       const uint8_t *bdaddr, uint8_t status)
+{
+       char buf[1 + sizeof(struct bt_hci_evt_le_conn_complete)];
+       struct bt_hci_evt_le_conn_complete *cc = (void *) &buf[1];
+
+       memset(buf, 0, sizeof(buf));
+
+       buf[0] = BT_HCI_EVT_LE_CONN_COMPLETE;
+
+       if (!status) {
+               struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+               btdev->conn = remote;
+               remote->conn = btdev;
+
+               cc->status = status;
+               memcpy(cc->peer_addr, btdev->bdaddr, 6);
+
+               cc->role = 0x01;
+               cc->handle = cpu_to_le16(42);
+
+               send_event(remote, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+
+               cc->handle = cpu_to_le16(42);
+       }
+
+       cc->status = status;
+       memcpy(cc->peer_addr, bdaddr, 6);
+       cc->role = 0x00;
+
+       send_event(btdev, BT_HCI_EVT_LE_META_EVENT, buf, sizeof(buf));
+}
+
+static void le_conn_request(struct btdev *btdev, const uint8_t *bdaddr)
+{
+       struct btdev *remote = find_btdev_by_bdaddr(bdaddr);
+
+       if (remote && remote->le_adv_enable)
+               le_conn_complete(btdev, bdaddr, 0);
+       else
+               le_conn_complete(btdev, bdaddr,
+                                       BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH);
+}
+
 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) {
+               if (remote->scan_enable & 0x02) {
                        struct bt_hci_evt_conn_request cr;
 
                        memcpy(cr.bdaddr, btdev->bdaddr, 6);
@@ -471,7 +881,7 @@ static void disconnect_complete(struct btdev *btdev, uint16_t handle,
 static void name_request_complete(struct btdev *btdev,
                                        const uint8_t *bdaddr, uint8_t status)
 {
-        struct bt_hci_evt_remote_name_req_complete nc;
+        struct bt_hci_evt_remote_name_request_complete nc;
 
        nc.status = status;
        memcpy(nc.bdaddr, bdaddr, 6);
@@ -566,19 +976,64 @@ static void remote_version_complete(struct btdev *btdev, uint16_t handle)
                                                        &rvc, sizeof(rvc));
 }
 
-static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
+static void le_send_adv_report(struct btdev *btdev, const struct btdev *remote)
+{
+       struct __packed {
+               uint8_t subevent;
+               union {
+                       struct bt_hci_evt_le_adv_report lar;
+                       uint8_t raw[10 + 31 + 1];
+               };
+       } meta_event;
+
+       meta_event.subevent = BT_HCI_EVT_LE_ADV_REPORT;
+
+       memset(&meta_event.lar, 0, sizeof(meta_event.lar));
+       meta_event.lar.num_reports = 1;
+       memcpy(meta_event.lar.addr, remote->bdaddr, 6);
+       meta_event.lar.data_len = remote->le_adv_data_len;
+       memcpy(meta_event.lar.data, remote->le_adv_data,
+                                               meta_event.lar.data_len);
+       /* Not available */
+       meta_event.raw[10 + meta_event.lar.data_len] = 127;
+       send_event(btdev, BT_HCI_EVT_LE_META_EVENT, &meta_event,
+                                       1 + 10 + meta_event.lar.data_len + 1);
+}
+
+static void le_set_adv_enable_complete(struct btdev *btdev)
+{
+       int i;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (!btdev_list[i] || btdev_list[i] == btdev)
+                       continue;
+
+               if (!btdev_list[i]->le_scan_enable)
+                       continue;
+
+               le_send_adv_report(btdev_list[i], btdev);
+       }
+}
+
+static void le_set_scan_enable_complete(struct btdev *btdev)
+{
+       int i;
+
+       for (i = 0; i < MAX_BTDEV_ENTRIES; i++) {
+               if (!btdev_list[i] || btdev_list[i] == btdev)
+                       continue;
+
+               if (!btdev_list[i]->le_adv_enable)
+                       continue;
+
+               le_send_adv_report(btdev, btdev_list[i]);
+       }
+}
+
+static void default_cmd(struct btdev *btdev, uint16_t opcode,
+                                               const void *data, uint8_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;
@@ -586,15 +1041,24 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
        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_page_scan_activity *wpsa;
+       const struct bt_hci_cmd_write_inquiry_scan_activity *wisa;
+       const struct bt_hci_cmd_write_page_scan_type *wpst;
        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_afh_assessment_mode *waam;
+       const struct bt_hci_cmd_write_ext_inquiry_response *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_set_event_mask_page2 *semp2;
        const struct bt_hci_cmd_le_set_event_mask *lsem;
+       const struct bt_hci_cmd_le_set_adv_data *lsad;
+       const struct bt_hci_cmd_setup_sync_conn *ssc;
+       const struct bt_hci_cmd_le_set_adv_enable *lsae;
+       const struct bt_hci_cmd_le_set_scan_enable *lsse;
+       const struct bt_hci_cmd_read_local_amp_assoc *rlaa_cmd;
        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;
@@ -603,15 +1067,22 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
        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_page_scan_activity rpsa;
+       struct bt_hci_rsp_read_inquiry_scan_activity risa;
+       struct bt_hci_rsp_read_page_scan_type rpst;
        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_num_supported_iac rnsi;
+       struct bt_hci_rsp_read_current_iac_lap *rcil;
        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_afh_assessment_mode raam;
+       struct bt_hci_rsp_read_ext_inquiry_response 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_local_oob_data rlod;
+       struct bt_hci_rsp_read_inquiry_resp_tx_power rirtp;
        struct bt_hci_rsp_read_le_host_supported rlhs;
+       struct bt_hci_rsp_read_sync_train_params rstp;
        struct bt_hci_rsp_read_local_version rlv;
        struct bt_hci_rsp_read_local_commands rlc;
        struct bt_hci_rsp_read_local_features rlf;
@@ -620,106 +1091,110 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
        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_read_local_amp_info rlai;
+       struct bt_hci_rsp_read_local_amp_assoc rlaa_rsp;
        struct bt_hci_rsp_le_read_buffer_size lrbs;
        struct bt_hci_rsp_le_read_local_features lrlf;
+       struct bt_hci_rsp_le_read_adv_tx_power lratp;
        struct bt_hci_rsp_le_read_supported_states lrss;
-       uint16_t opcode;
+       struct bt_hci_rsp_le_read_white_list_size lrwls;
+       struct bt_hci_rsp_le_rand lr;
+       struct bt_hci_rsp_le_test_end lte;
+       struct bt_hci_rsp_remote_name_request_cancel rnrc_rsp;
        uint8_t status, page;
 
-       if (len < sizeof(*hdr))
-               return;
-
-       opcode = le16_to_cpu(hdr->opcode);
-
        switch (opcode) {
        case BT_HCI_CMD_INQUIRY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
-               inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
                break;
 
        case BT_HCI_CMD_INQUIRY_CANCEL:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                status = BT_HCI_ERR_SUCCESS;
                cmd_complete(btdev, opcode, &status, sizeof(status));
                break;
 
        case BT_HCI_CMD_CREATE_CONN:
-               cc = data + sizeof(*hdr);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rnrc = data;
+               rnrc_rsp.status = BT_HCI_ERR_SUCCESS;
+               memcpy(rnrc_rsp.bdaddr, rnrc->bdaddr, 6);
+               cmd_complete(btdev, opcode, &rnrc_rsp, sizeof(rnrc_rsp));
                break;
 
        case BT_HCI_CMD_READ_REMOTE_FEATURES:
-               rrf = data + sizeof(*hdr);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wdlp = data;
                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);
+               sem = data;
                memcpy(btdev->event_mask, sem->mask, 8);
                status = BT_HCI_ERR_SUCCESS;
                cmd_complete(btdev, opcode, &status, sizeof(status));
@@ -731,13 +1206,17 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_SET_EVENT_FILTER:
-               sef = data + sizeof(*hdr);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               sef = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                rslk.status = BT_HCI_ERR_SUCCESS;
                rslk.max_num_keys = cpu_to_le16(0);
                rslk.num_keys = cpu_to_le16(0);
@@ -745,143 +1224,274 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_WRITE_STORED_LINK_KEY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wln = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wcat = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wpt = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wse = data;
                btdev->scan_enable = wse->enable;
                status = BT_HCI_ERR_SUCCESS;
                cmd_complete(btdev, opcode, &status, sizeof(status));
                break;
 
+       case BT_HCI_CMD_READ_PAGE_SCAN_ACTIVITY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rpsa.status = BT_HCI_ERR_SUCCESS;
+               rpsa.interval = cpu_to_le16(btdev->page_scan_interval);
+               rpsa.window = cpu_to_le16(btdev->page_scan_window);
+               cmd_complete(btdev, opcode, &rpsa, sizeof(rpsa));
+               break;
+
+       case BT_HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wpsa = data;
+               btdev->page_scan_interval = le16_to_cpu(wpsa->interval);
+               btdev->page_scan_window = le16_to_cpu(wpsa->window);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               risa.status = BT_HCI_ERR_SUCCESS;
+               risa.interval = cpu_to_le16(btdev->inquiry_scan_interval);
+               risa.window = cpu_to_le16(btdev->inquiry_scan_window);
+               cmd_complete(btdev, opcode, &risa, sizeof(risa));
+               break;
+
+       case BT_HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wisa = data;
+               btdev->inquiry_scan_interval = le16_to_cpu(wisa->interval);
+               btdev->inquiry_scan_window = le16_to_cpu(wisa->window);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_PAGE_SCAN_TYPE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rpst.status = BT_HCI_ERR_SUCCESS;
+               rpst.type = btdev->page_scan_type;
+               cmd_complete(btdev, opcode, &rpst, sizeof(rpst));
+               break;
+
+       case BT_HCI_CMD_WRITE_PAGE_SCAN_TYPE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wpst = data;
+               btdev->page_scan_type = wpst->type;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
        case BT_HCI_CMD_READ_AUTH_ENABLE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wae = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wcod = data;
                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:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wvs = data;
                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_HOST_BUFFER_SIZE:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_READ_NUM_SUPPORTED_IAC:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rnsi.status = BT_HCI_ERR_SUCCESS;
+               rnsi.num_iac = 0x01;
+               cmd_complete(btdev, opcode, &rnsi, sizeof(rnsi));
+               break;
+
+       case BT_HCI_CMD_READ_CURRENT_IAC_LAP:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rcil = alloca(sizeof(*rcil) + 3);
+               rcil->status = BT_HCI_ERR_SUCCESS;
+               rcil->num_iac = 0x01;
+               rcil->iac_lap[0] = 0x33;
+               rcil->iac_lap[1] = 0x8b;
+               rcil->iac_lap[2] = 0x9e;
+               cmd_complete(btdev, opcode, rcil, sizeof(*rcil) + 3);
+               break;
+
+       case BT_HCI_CMD_WRITE_CURRENT_IAC_LAP:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
        case BT_HCI_CMD_READ_INQUIRY_MODE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wim = data;
                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:
+       case BT_HCI_CMD_READ_AFH_ASSESSMENT_MODE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                raam.status = BT_HCI_ERR_SUCCESS;
-               raam.mode = btdev->afh_assess_mode;
+               raam.mode = btdev->afh_assessment_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;
+       case BT_HCI_CMD_WRITE_AFH_ASSESSMENT_MODE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               waam = data;
+               btdev->afh_assessment_mode = waam->mode;
                status = BT_HCI_ERR_SUCCESS;
                cmd_complete(btdev, opcode, &status, sizeof(status));
                break;
 
-       case BT_HCI_CMD_READ_EXT_INQUIRY_RSP:
+       case BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+       case BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               weir = data;
                btdev->ext_inquiry_fec = weir->fec;
                memcpy(btdev->ext_inquiry_rsp, weir->data, 240);
                status = BT_HCI_ERR_SUCCESS;
@@ -889,25 +1499,40 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               wspm = data;
                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:
+       case BT_HCI_CMD_READ_LOCAL_OOB_DATA:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               rlod.status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &rlod, sizeof(rlod));
+               break;
+
+       case BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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:
+               if (btdev->type != BTDEV_TYPE_BREDRLE)
+                       goto unsupported;
                rlhs.status = BT_HCI_ERR_SUCCESS;
                rlhs.supported = btdev->le_supported;
                rlhs.simultaneous = btdev->le_simultaneous;
@@ -915,13 +1540,25 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED:
-               wlhs = data + sizeof(*hdr);
+               if (btdev->type != BTDEV_TYPE_BREDRLE)
+                       goto unsupported;
+               wlhs = data;
                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_SYNC_TRAIN_PARAMS:
+               if (btdev->type != BTDEV_TYPE_BREDRLE)
+                       goto unsupported;
+               rstp.status = BT_HCI_ERR_SUCCESS;
+               rstp.interval = cpu_to_le16(btdev->sync_train_interval);
+               rstp.timeout = cpu_to_le32(btdev->sync_train_timeout);
+               rstp.service_data = btdev->sync_train_service_data;
+               cmd_complete(btdev, opcode, &rstp, sizeof(rstp));
+               break;
+
        case BT_HCI_CMD_READ_LOCAL_VERSION:
                rlv.status = BT_HCI_ERR_SUCCESS;
                rlv.hci_ver = btdev->version;
@@ -945,18 +1582,28 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_READ_LOCAL_EXT_FEATURES:
-               page = ((const uint8_t *) data)[sizeof(*hdr)];
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+
+               page = ((const uint8_t *) data)[0];
+
+               rlef.page = page;
+               rlef.max_page = btdev->max_page;
+
+               if (page > btdev->max_page) {
+                       rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
+                       memset(rlef.features, 0, 8);
+                       cmd_complete(btdev, opcode, &rlef, sizeof(rlef));
+                       break;
+               }
+
                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;
@@ -965,10 +1612,12 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                        if (btdev->le_simultaneous)
                                rlef.features[0] |= 0x04;
                        break;
+               case 0x02:
+                       rlef.status = BT_HCI_ERR_SUCCESS;
+                       memcpy(rlef.features, btdev->feat_page_2, 8);
+                       break;
                default:
                        rlef.status = BT_HCI_ERR_INVALID_PARAMETERS;
-                       rlef.page = page;
-                       rlef.max_page = 0x01;
                        memset(rlef.features, 0, 8);
                        break;
                }
@@ -997,6 +1646,8 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_READ_DATA_BLOCK_SIZE:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
                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);
@@ -1004,14 +1655,57 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                cmd_complete(btdev, opcode, &rdbs, sizeof(rdbs));
                break;
 
+       case BT_HCI_CMD_READ_LOCAL_AMP_INFO:
+               if (btdev->type != BTDEV_TYPE_AMP)
+                       goto unsupported;
+               rlai.status = BT_HCI_ERR_SUCCESS;
+               rlai.amp_status = 0x01;         /* Used for Bluetooth only */
+               rlai.total_bw = cpu_to_le32(0);
+               rlai.max_bw = cpu_to_le32(0);
+               rlai.min_latency = cpu_to_le32(0);
+               rlai.max_pdu = cpu_to_le32(672);
+               rlai.amp_type = 0x01;           /* 802.11 AMP Controller */
+               rlai.pal_cap = cpu_to_le16(0x0000);
+               rlai.max_assoc_len = cpu_to_le16(672);
+               rlai.max_flush_to = cpu_to_le32(0xffffffff);
+               rlai.be_flush_to = cpu_to_le32(0xffffffff);
+               cmd_complete(btdev, opcode, &rlai, sizeof(rlai));
+               break;
+
+       case BT_HCI_CMD_READ_LOCAL_AMP_ASSOC:
+               if (btdev->type != BTDEV_TYPE_AMP)
+                       goto unsupported;
+               rlaa_cmd = data;
+               rlaa_rsp.status = BT_HCI_ERR_SUCCESS;
+               rlaa_rsp.phy_handle = rlaa_cmd->phy_handle;
+               rlaa_rsp.remain_assoc_len = cpu_to_le16(1);
+               rlaa_rsp.assoc_fragment[0] = 0x42;
+               memset(rlaa_rsp.assoc_fragment + 1, 0,
+                                       sizeof(rlaa_rsp.assoc_fragment) - 1);
+               cmd_complete(btdev, opcode, &rlaa_rsp, sizeof(rlaa_rsp));
+               break;
+
+       case BT_HCI_CMD_SET_EVENT_MASK_PAGE2:
+               if (btdev->type != BTDEV_TYPE_BREDRLE)
+                       goto unsupported;
+               semp2 = data;
+               memcpy(btdev->event_mask_page2, semp2->mask, 8);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
        case BT_HCI_CMD_LE_SET_EVENT_MASK:
-               lsem = data + sizeof(*hdr);
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lsem = data;
                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:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
                lrbs.status = BT_HCI_ERR_SUCCESS;
                lrbs.le_mtu = cpu_to_le16(btdev->acl_mtu);
                lrbs.le_max_pkt = btdev->acl_max_pkt;
@@ -1019,35 +1713,353 @@ static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
                break;
 
        case BT_HCI_CMD_LE_READ_LOCAL_FEATURES:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
                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_ADV_PARAMETERS:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               if (btdev->le_adv_enable)
+                       status = BT_HCI_ERR_COMMAND_DISALLOWED;
+               else
+                       status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_READ_ADV_TX_POWER:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lratp.status = BT_HCI_ERR_SUCCESS;
+               lratp.level = 0;
+               cmd_complete(btdev, opcode, &lratp, sizeof(lratp));
+               break;
+
+       case BT_HCI_CMD_LE_SET_ADV_ENABLE:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lsae = data;
+               if (btdev->le_adv_enable == lsae->enable)
+                       status = BT_HCI_ERR_COMMAND_DISALLOWED;
+               else {
+                       btdev->le_adv_enable = lsae->enable;
+                       status = BT_HCI_ERR_SUCCESS;
+               }
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               if (status == BT_HCI_ERR_SUCCESS && btdev->le_adv_enable)
+                       le_set_adv_enable_complete(btdev);
+               break;
+
        case BT_HCI_CMD_LE_SET_SCAN_PARAMETERS:
-               status = BT_HCI_ERR_SUCCESS;
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               if (btdev->le_scan_enable)
+                       status = BT_HCI_ERR_COMMAND_DISALLOWED;
+               else
+                       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;
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lsse = data;
+               if (btdev->le_scan_enable == lsse->enable)
+                       status = BT_HCI_ERR_COMMAND_DISALLOWED;
+               else {
+                       btdev->le_scan_enable = lsse->enable;
+                       btdev->le_filter_dup = lsse->filter_dup;
+                       status = BT_HCI_ERR_SUCCESS;
+               }
                cmd_complete(btdev, opcode, &status, sizeof(status));
+               if (status == BT_HCI_ERR_SUCCESS && btdev->le_scan_enable)
+                       le_set_scan_enable_complete(btdev);
+               break;
+
+       case BT_HCI_CMD_LE_CREATE_CONN:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               break;
+
+       case BT_HCI_CMD_LE_READ_WHITE_LIST_SIZE:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lrwls.status = BT_HCI_ERR_SUCCESS;
+               lrwls.size = 0;
+               cmd_complete(btdev, opcode, &lrwls, sizeof(lrwls));
                break;
 
        case BT_HCI_CMD_LE_READ_SUPPORTED_STATES:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
                lrss.status = BT_HCI_ERR_SUCCESS;
                memcpy(lrss.states, btdev->le_states, 8);
                cmd_complete(btdev, opcode, &lrss, sizeof(lrss));
                break;
 
+       case BT_HCI_CMD_LE_SET_ADV_DATA:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lsad = data;
+               btdev->le_adv_data_len = lsad->len;
+               memcpy(btdev->le_adv_data, lsad->data, 31);
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_RAND:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lr.status = BT_HCI_ERR_SUCCESS;
+               lr.number[0] = rand();
+               lr.number[1] = rand();
+               lr.number[2] = rand();
+               lr.number[3] = rand();
+               lr.number[4] = rand();
+               lr.number[5] = rand();
+               lr.number[6] = rand();
+               lr.number[7] = rand();
+               cmd_complete(btdev, opcode, &lr, sizeof(lr));
+               break;
+
+       case BT_HCI_CMD_SETUP_SYNC_CONN:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               ssc = data;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_status(btdev, BT_HCI_ERR_SUCCESS, opcode);
+               sync_conn_complete(btdev, ssc->voice_setting,
+                                                       BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_ADD_SCO_CONN:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       goto unsupported;
+               sco_conn_complete(btdev, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_ENABLE_DUT_MODE:
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_RECEIVER_TEST:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_TRANSMITTER_TEST:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               status = BT_HCI_ERR_SUCCESS;
+               cmd_complete(btdev, opcode, &status, sizeof(status));
+               break;
+
+       case BT_HCI_CMD_LE_TEST_END:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       goto unsupported;
+               lte.status = BT_HCI_ERR_SUCCESS;
+               lte.num_packets = 0;
+               cmd_complete(btdev, opcode, &lte, sizeof(lte));
+               break;
+
        default:
-               printf("Unsupported command 0x%4.4x\n", opcode);
-               hexdump(data, len);
-               cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+               goto unsupported;
+       }
+
+       return;
+
+unsupported:
+       printf("Unsupported command 0x%4.4x\n", opcode);
+       hexdump(data, len);
+       cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND, opcode);
+}
+
+static void default_cmd_completion(struct btdev *btdev, uint16_t opcode,
+                                               const void *data, uint8_t len)
+{
+       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_le_create_conn *lecc;
+
+       switch (opcode) {
+       case BT_HCI_CMD_INQUIRY:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               inquiry_complete(btdev, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_CREATE_CONN:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               cc = data;
+               conn_request(btdev, cc->bdaddr);
+               break;
+
+       case BT_HCI_CMD_DISCONNECT:
+               dc = data;
+               disconnect_complete(btdev, le16_to_cpu(dc->handle), dc->reason);
+               break;
+
+       case BT_HCI_CMD_CREATE_CONN_CANCEL:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               ccc = data;
+               conn_complete(btdev, ccc->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_ACCEPT_CONN_REQUEST:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               acr = data;
+               conn_complete(btdev, acr->bdaddr, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_REJECT_CONN_REQUEST:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               rcr = data;
+               conn_complete(btdev, rcr->bdaddr, BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_REMOTE_NAME_REQUEST:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               rnr = data;
+               name_request_complete(btdev, rnr->bdaddr, BT_HCI_ERR_SUCCESS);
+               break;
+
+       case BT_HCI_CMD_REMOTE_NAME_REQUEST_CANCEL:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               rnrc = data;
+               name_request_complete(btdev, rnrc->bdaddr,
+                                               BT_HCI_ERR_UNKNOWN_CONN_ID);
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_FEATURES:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               rrf = data;
+               remote_features_complete(btdev, le16_to_cpu(rrf->handle));
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_EXT_FEATURES:
+               if (btdev->type == BTDEV_TYPE_LE)
+                       return;
+               rref = data;
+               remote_ext_features_complete(btdev, le16_to_cpu(rref->handle),
+                                                               rref->page);
+               break;
+
+       case BT_HCI_CMD_READ_REMOTE_VERSION:
+               rrv = data;
+               remote_version_complete(btdev, le16_to_cpu(rrv->handle));
+               break;
+
+       case BT_HCI_CMD_LE_CREATE_CONN:
+               if (btdev->type == BTDEV_TYPE_BREDR)
+                       return;
+               lecc = data;
+               le_conn_request(btdev, lecc->peer_addr);
+               break;
+       }
+}
+
+struct btdev_callback {
+       void (*function)(btdev_callback callback, uint8_t response,
+                               uint8_t status, const void *data, uint8_t len);
+       void *user_data;
+       uint16_t opcode;
+       const void *data;
+       uint8_t len;
+};
+
+void btdev_command_response(btdev_callback callback, uint8_t response,
+                                uint8_t status, const void *data, uint8_t len)
+{
+       callback->function(callback, response, status, data, len);
+}
+
+static void handler_callback(btdev_callback callback, uint8_t response,
+                               uint8_t status, const void *data, uint8_t len)
+{
+       struct btdev *btdev = callback->user_data;
+
+       switch (response) {
+       case BTDEV_RESPONSE_DEFAULT:
+               if (!run_hooks(btdev, BTDEV_HOOK_PRE_CMD, callback->opcode,
+                                               callback->data, callback->len))
+                       return;
+               default_cmd(btdev, callback->opcode,
+                                       callback->data, callback->len);
+
+               if (!run_hooks(btdev, BTDEV_HOOK_PRE_EVT, callback->opcode,
+                                               callback->data, callback->len))
+                       return;
+               default_cmd_completion(btdev, callback->opcode,
+                                       callback->data, callback->len);
+               break;
+       case BTDEV_RESPONSE_COMMAND_STATUS:
+               cmd_status(btdev, status, callback->opcode);
+               break;
+       case BTDEV_RESPONSE_COMMAND_COMPLETE:
+               cmd_complete(btdev, callback->opcode, data, len);
+               break;
+       default:
+               cmd_status(btdev, BT_HCI_ERR_UNKNOWN_COMMAND,
+                                               callback->opcode);
                break;
        }
 }
 
+static void process_cmd(struct btdev *btdev, const void *data, uint16_t len)
+{
+       struct btdev_callback callback;
+       const struct bt_hci_cmd_hdr *hdr = data;
+
+       if (len < sizeof(*hdr))
+               return;
+
+       callback.function = handler_callback;
+       callback.user_data = btdev;
+       callback.opcode = le16_to_cpu(hdr->opcode);
+       callback.data = data + sizeof(*hdr);
+       callback.len = hdr->plen;
+
+       if (btdev->command_handler)
+               btdev->command_handler(callback.opcode,
+                                       callback.data, callback.len,
+                                       &callback, btdev->command_data);
+       else {
+               if (!run_hooks(btdev, BTDEV_HOOK_PRE_CMD, callback.opcode,
+                                               callback.data, callback.len))
+                       return;
+               default_cmd(btdev, callback.opcode,
+                                       callback.data, callback.len);
+
+               if (!run_hooks(btdev, BTDEV_HOOK_PRE_EVT, callback.opcode,
+                                               callback.data, callback.len))
+                       return;
+               default_cmd_completion(btdev, callback.opcode,
+                                       callback.data, callback.len);
+       }
+}
+
 void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
 {
        uint8_t pkt_type;
@@ -1074,3 +2086,57 @@ void btdev_receive_h4(struct btdev *btdev, const void *data, uint16_t len)
                break;
        }
 }
+
+int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
+                               uint16_t opcode, btdev_hook_func handler,
+                               void *user_data)
+{
+       int i;
+
+       if (!btdev)
+               return -1;
+
+       if (get_hook_index(btdev, type, opcode) > 0)
+               return -1;
+
+       for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+               if (btdev->hook_list[i] == NULL) {
+                       btdev->hook_list[i] = malloc(sizeof(struct hook));
+                       if (btdev->hook_list[i] == NULL)
+                               return -1;
+
+                       btdev->hook_list[i]->handler = handler;
+                       btdev->hook_list[i]->user_data = user_data;
+                       btdev->hook_list[i]->opcode = opcode;
+                       btdev->hook_list[i]->type = type;
+                       return i;
+               }
+       }
+
+       return -1;
+}
+
+bool btdev_del_hook(struct btdev *btdev, enum btdev_hook_type type,
+                                                               uint16_t opcode)
+{
+       int i;
+
+       if (!btdev)
+               return false;
+
+       for (i = 0; i < MAX_HOOK_ENTRIES; i++) {
+               if (btdev->hook_list[i] == NULL)
+                       continue;
+
+               if (btdev->hook_list[i]->type != type ||
+                                       btdev->hook_list[i]->opcode != opcode)
+                       continue;
+
+               free(btdev->hook_list[i]);
+               btdev->hook_list[i] = NULL;
+
+               return true;
+       }
+
+       return false;
+}
index 7b211a2..1e623f4 100644 (file)
@@ -6,33 +6,90 @@
  *  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 library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  This library is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
 #include <stdint.h>
+#include <stdbool.h>
+
+#define BTDEV_RESPONSE_DEFAULT         0
+#define BTDEV_RESPONSE_COMMAND_STATUS  1
+#define BTDEV_RESPONSE_COMMAND_COMPLETE        2
+
+typedef struct btdev_callback * btdev_callback;
+
+void btdev_command_response(btdev_callback callback, uint8_t response,
+                               uint8_t status, const void *data, uint8_t len);
+
+#define btdev_command_default(callback) \
+               btdev_command_response(callback, \
+                       BTDEV_RESPONSE_DEFAULT, 0x00, NULL, 0);
+
+#define btdev_command_status(callback, status) \
+               btdev_command_response(callback, \
+                       BTDEV_RESPONSE_COMMAND_STATUS, status, NULL, 0);
+
+#define btdev_command_complete(callback, data, len) \
+                btdev_command_response(callback, \
+                       BTDEV_RESPONSE_COMMAND_COMPLETE, 0x00, data, len);
+
+
+typedef void (*btdev_command_func) (uint16_t opcode,
+                               const void *data, uint8_t len,
+                               btdev_callback callback, void *user_data);
 
 typedef void (*btdev_send_func) (const void *data, uint16_t len,
                                                        void *user_data);
 
+typedef bool (*btdev_hook_func) (const void *data, uint16_t len,
+                                                       void *user_data);
+
+enum btdev_type {
+       BTDEV_TYPE_BREDRLE,
+       BTDEV_TYPE_BREDR,
+       BTDEV_TYPE_LE,
+       BTDEV_TYPE_AMP,
+};
+
+enum btdev_hook_type {
+       BTDEV_HOOK_PRE_CMD,
+       BTDEV_HOOK_POST_CMD,
+       BTDEV_HOOK_PRE_EVT,
+       BTDEV_HOOK_POST_EVT,
+};
+
 struct btdev;
 
-struct btdev *btdev_create(uint16_t id);
+struct btdev *btdev_create(enum btdev_type type, uint16_t id);
 void btdev_destroy(struct btdev *btdev);
 
+const uint8_t *btdev_get_bdaddr(struct btdev *btdev);
+uint8_t *btdev_get_features(struct btdev *btdev);
+
+void btdev_set_command_handler(struct btdev *btdev, btdev_command_func handler,
+                                                       void *user_data);
+
 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);
+
+int btdev_add_hook(struct btdev *btdev, enum btdev_hook_type type,
+                               uint16_t opcode, btdev_hook_func handler,
+                               void *user_data);
+
+bool btdev_del_hook(struct btdev *btdev, enum btdev_hook_type type,
+                                                       uint16_t opcode);
diff --git a/emulator/bthost.c b/emulator/bthost.c
new file mode 100644 (file)
index 0000000..da56b5c
--- /dev/null
@@ -0,0 +1,1111 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdlib.h>
+#include <string.h>
+#include <endian.h>
+#include <stdbool.h>
+
+#include "bluetooth/bluetooth.h"
+
+#include "monitor/bt.h"
+#include "bthost.h"
+
+/* ACL handle and flags pack/unpack */
+#define acl_handle_pack(h, f)  (uint16_t)((h & 0x0fff)|(f << 12))
+#define acl_handle(h)          (h & 0x0fff)
+#define acl_flags(h)           (h >> 12)
+
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+
+struct cmd {
+       struct cmd *next;
+       struct cmd *prev;
+       uint8_t data[256 + sizeof(struct bt_hci_cmd_hdr)];
+       uint16_t len;
+};
+
+struct cmd_queue {
+       struct cmd *head;
+       struct cmd *tail;
+};
+
+struct btconn {
+       uint16_t handle;
+       uint8_t addr_type;
+       uint16_t next_cid;
+       struct l2conn *l2conns;
+       struct btconn *next;
+};
+
+struct l2conn {
+       uint16_t scid;
+       uint16_t dcid;
+       struct l2conn *next;
+};
+
+struct l2cap_pending_req {
+       uint8_t ident;
+       bthost_l2cap_rsp_cb cb;
+       void *user_data;
+       struct l2cap_pending_req *next;
+};
+
+struct bthost {
+       uint8_t bdaddr[6];
+       bthost_send_func send_handler;
+       void *send_data;
+       struct cmd_queue cmd_q;
+       uint8_t ncmd;
+       struct btconn *conns;
+       bthost_cmd_complete_cb cmd_complete_cb;
+       void *cmd_complete_data;
+       bthost_new_conn_cb new_conn_cb;
+       void *new_conn_data;
+       uint16_t server_psm;
+       struct l2cap_pending_req *l2reqs;
+};
+
+struct bthost *bthost_create(void)
+{
+       struct bthost *bthost;
+
+       bthost = malloc(sizeof(*bthost));
+       if (!bthost)
+               return NULL;
+
+       memset(bthost, 0, sizeof(*bthost));
+
+       return bthost;
+}
+
+static void l2conn_free(struct l2conn *conn)
+{
+       free(conn);
+}
+
+static void btconn_free(struct btconn *conn)
+{
+       while (conn->l2conns) {
+               struct l2conn *l2conn = conn->l2conns;
+
+               conn->l2conns = l2conn->next;
+               l2conn_free(l2conn);
+       }
+
+       free(conn);
+}
+
+static struct btconn *bthost_find_conn(struct bthost *bthost, uint16_t handle)
+{
+       struct btconn *conn;
+
+       for (conn = bthost->conns; conn != NULL; conn = conn->next) {
+               if (conn->handle == handle)
+                       return conn;
+       }
+
+       return NULL;
+}
+
+static void bthost_add_l2cap_conn(struct bthost *bthost, struct btconn *conn,
+                                               uint16_t scid, uint16_t dcid)
+{
+       struct l2conn *l2conn;
+
+       l2conn = malloc(sizeof(*l2conn));
+       if (!l2conn)
+               return;
+
+       memset(l2conn, 0, sizeof(*l2conn));
+
+       l2conn->scid = scid;
+       l2conn->dcid = dcid;
+
+       l2conn->next = conn->l2conns;
+       conn->l2conns = l2conn;
+}
+
+static struct l2conn *btconn_find_l2cap_conn_by_scid(struct btconn *conn,
+                                                               uint16_t scid)
+{
+       struct l2conn *l2conn;
+
+       for (l2conn = conn->l2conns; l2conn != NULL; l2conn = l2conn->next) {
+               if (l2conn->scid == scid)
+                       return l2conn;
+       }
+
+       return NULL;
+}
+
+void bthost_destroy(struct bthost *bthost)
+{
+       struct cmd *cmd;
+
+       if (!bthost)
+               return;
+
+       for (cmd = bthost->cmd_q.tail; cmd != NULL; cmd = cmd->next)
+               free(cmd);
+
+       while (bthost->conns) {
+               struct btconn *conn = bthost->conns;
+
+               bthost->conns = conn->next;
+               btconn_free(conn);
+       }
+
+       while (bthost->l2reqs) {
+               struct l2cap_pending_req *req = bthost->l2reqs;
+
+               bthost->l2reqs = req->next;
+               req->cb(0, NULL, 0, req->user_data);
+               free(req);
+       }
+
+       free(bthost);
+}
+
+void bthost_set_send_handler(struct bthost *bthost, bthost_send_func handler,
+                                                       void *user_data)
+{
+       if (!bthost)
+               return;
+
+       bthost->send_handler = handler;
+       bthost->send_data = user_data;
+}
+
+static void queue_command(struct bthost *bthost, const void *data,
+                                                               uint16_t len)
+{
+       struct cmd_queue *cmd_q = &bthost->cmd_q;
+       struct cmd *cmd;
+
+       cmd = malloc(sizeof(*cmd));
+       if (!cmd)
+               return;
+
+       memset(cmd, 0, sizeof(*cmd));
+
+       memcpy(cmd->data, data, len);
+       cmd->len = len;
+
+       if (cmd_q->tail)
+               cmd_q->tail->next = cmd;
+
+       cmd->prev = cmd_q->tail;
+       cmd_q->tail = cmd;
+}
+
+static void send_packet(struct bthost *bthost, const void *data, uint16_t len)
+{
+       if (!bthost->send_handler)
+               return;
+
+       bthost->send_handler(data, len, bthost->send_data);
+}
+
+static void send_acl(struct bthost *bthost, uint16_t handle, uint16_t cid,
+                                               const void *data, uint16_t len)
+{
+       struct bt_hci_acl_hdr *acl_hdr;
+       struct bt_l2cap_hdr *l2_hdr;
+       uint16_t pkt_len;
+       void *pkt_data;
+
+       pkt_len = 1 + sizeof(*acl_hdr) + sizeof(*l2_hdr) + len;
+
+       pkt_data = malloc(pkt_len);
+       if (!pkt_data)
+               return;
+
+       ((uint8_t *) pkt_data)[0] = BT_H4_ACL_PKT;
+
+       acl_hdr = pkt_data + 1;
+       acl_hdr->handle = acl_handle_pack(handle, 0);
+       acl_hdr->dlen = cpu_to_le16(len + sizeof(*l2_hdr));
+
+       l2_hdr = pkt_data + 1 + sizeof(*acl_hdr);
+       l2_hdr->cid = cpu_to_le16(cid);
+       l2_hdr->len = cpu_to_le16(len);
+
+       if (len > 0)
+               memcpy(pkt_data + 1 + sizeof(*acl_hdr) + sizeof(*l2_hdr),
+                                                               data, len);
+
+       send_packet(bthost, pkt_data, pkt_len);
+
+       free(pkt_data);
+}
+
+static uint8_t l2cap_sig_send(struct bthost *bthost, struct btconn *conn,
+                                       uint8_t code, uint8_t ident,
+                                       const void *data, uint16_t len)
+{
+       static uint8_t next_ident = 1;
+       struct bt_l2cap_hdr_sig *hdr;
+       uint16_t pkt_len, cid;
+       void *pkt_data;
+
+       pkt_len = sizeof(*hdr) + len;
+
+       pkt_data = malloc(pkt_len);
+       if (!pkt_data)
+               return 0;
+
+       if (!ident) {
+               ident = next_ident++;
+               if (!ident)
+                       ident = next_ident++;
+       }
+
+       hdr = pkt_data;
+       hdr->code  = code;
+       hdr->ident = ident;
+       hdr->len   = cpu_to_le16(len);
+
+       if (len > 0)
+               memcpy(pkt_data + sizeof(*hdr), data, len);
+
+       if (conn->addr_type == BDADDR_BREDR)
+               cid = 0x0001;
+       else
+               cid = 0x0005;
+
+       send_acl(bthost, conn->handle, cid, pkt_data, pkt_len);
+
+       free(pkt_data);
+
+       return ident;
+}
+
+bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t code,
+                               const void *data, uint16_t len,
+                               bthost_l2cap_rsp_cb cb, void *user_data)
+{
+       struct l2cap_pending_req *req;
+       struct btconn *conn;
+       uint8_t ident;
+
+       conn = bthost_find_conn(bthost, handle);
+       if (!conn)
+               return false;
+
+       ident = l2cap_sig_send(bthost, conn, code, 0, data, len);
+       if (!ident)
+               return false;
+
+       if (!cb)
+               return true;
+
+       req = malloc(sizeof(*req));
+       if (!req)
+               return false;
+
+       memset(req, 0, sizeof(*req));
+       req->ident = ident;
+       req->cb = cb;
+       req->user_data = user_data;
+
+       req->next = bthost->l2reqs;
+       bthost->l2reqs = req;
+
+       return true;
+}
+
+static void send_command(struct bthost *bthost, uint16_t opcode,
+                                               const void *data, uint8_t len)
+{
+       struct bt_hci_cmd_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_CMD_PKT;
+
+       hdr = pkt_data + 1;
+       hdr->opcode = cpu_to_le16(opcode);
+       hdr->plen = len;
+
+       if (len > 0)
+               memcpy(pkt_data + 1 + sizeof(*hdr), data, len);
+
+       if (bthost->ncmd) {
+               send_packet(bthost, pkt_data, pkt_len);
+               bthost->ncmd--;
+       } else {
+               queue_command(bthost, pkt_data, pkt_len);
+       }
+
+       free(pkt_data);
+}
+
+static void next_cmd(struct bthost *bthost)
+{
+       struct cmd_queue *cmd_q = &bthost->cmd_q;
+       struct cmd *cmd = cmd_q->tail;
+       struct cmd *next;
+
+       if (!cmd)
+               return;
+
+       next = cmd->next;
+
+       if (!bthost->ncmd)
+               return;
+
+       send_packet(bthost, cmd->data, cmd->len);
+       bthost->ncmd--;
+
+       if (next)
+               next->prev = NULL;
+
+       cmd_q->tail = next;
+
+       free(cmd);
+}
+
+static void read_bd_addr_complete(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_rsp_read_bd_addr *ev = data;
+
+       if (len < sizeof(*ev))
+               return;
+
+       if (ev->status)
+               return;
+
+       memcpy(bthost->bdaddr, ev->bdaddr, 6);
+}
+
+static void evt_cmd_complete(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_cmd_complete *ev = data;
+       const void *param;
+       uint16_t opcode;
+
+       if (len < sizeof(*ev))
+               return;
+
+       param = data + sizeof(*ev);
+
+       bthost->ncmd = ev->ncmd;
+
+       opcode = le16toh(ev->opcode);
+
+       switch (opcode) {
+       case BT_HCI_CMD_RESET:
+               break;
+       case BT_HCI_CMD_READ_BD_ADDR:
+               read_bd_addr_complete(bthost, param, len - sizeof(*ev));
+               break;
+       case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+               break;
+       case BT_HCI_CMD_LE_SET_ADV_ENABLE:
+               break;
+       default:
+               printf("Unhandled cmd_complete opcode 0x%04x\n", opcode);
+               break;
+       }
+
+       if (bthost->cmd_complete_cb)
+               bthost->cmd_complete_cb(opcode, 0, param, len - sizeof(*ev),
+                                               bthost->cmd_complete_data);
+
+       next_cmd(bthost);
+}
+
+static void evt_cmd_status(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_cmd_status *ev = data;
+       uint16_t opcode;
+
+       if (len < sizeof(*ev))
+               return;
+
+       bthost->ncmd = ev->ncmd;
+
+       opcode = le16toh(ev->opcode);
+
+       if (ev->status && bthost->cmd_complete_cb)
+               bthost->cmd_complete_cb(opcode, ev->status, NULL, 0,
+                                               bthost->cmd_complete_data);
+
+       next_cmd(bthost);
+}
+
+static void evt_conn_request(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_conn_request *ev = data;
+       struct bt_hci_cmd_accept_conn_request cmd;
+
+       if (len < sizeof(*ev))
+               return;
+
+       memset(&cmd, 0, sizeof(cmd));
+       memcpy(cmd.bdaddr, ev->bdaddr, sizeof(ev->bdaddr));
+
+       send_command(bthost, BT_HCI_CMD_ACCEPT_CONN_REQUEST, &cmd,
+                                                               sizeof(cmd));
+}
+
+static void init_conn(struct bthost *bthost, uint16_t handle, uint8_t addr_type)
+{
+       struct btconn *conn;
+
+       conn = malloc(sizeof(*conn));
+       if (!conn)
+               return;
+
+       memset(conn, 0, sizeof(*conn));
+       conn->handle = handle;
+       conn->addr_type = addr_type;
+       conn->next_cid = 0x0040;
+
+       conn->next = bthost->conns;
+       bthost->conns = conn;
+
+       if (bthost->new_conn_cb)
+               bthost->new_conn_cb(conn->handle, bthost->new_conn_data);
+}
+
+static void evt_conn_complete(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_conn_complete *ev = data;
+
+       if (len < sizeof(*ev))
+               return;
+
+       if (ev->status)
+               return;
+
+       init_conn(bthost, le16_to_cpu(ev->handle), BDADDR_BREDR);
+}
+
+static void evt_disconn_complete(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_disconnect_complete *ev = data;
+       struct btconn **curr;
+       uint16_t handle;
+
+       if (len < sizeof(*ev))
+               return;
+
+       if (ev->status)
+               return;
+
+       handle = le16_to_cpu(ev->handle);
+
+       for (curr = &bthost->conns; *curr;) {
+               struct btconn *conn = *curr;
+
+               if (conn->handle == handle) {
+                       *curr = conn->next;
+                       btconn_free(conn);
+               } else {
+                       curr = &conn->next;
+               }
+       }
+}
+
+static void evt_num_completed_packets(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_num_completed_packets *ev = data;
+
+       if (len < sizeof(*ev))
+               return;
+}
+
+static void evt_le_conn_complete(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const struct bt_hci_evt_le_conn_complete *ev = data;
+       uint8_t addr_type;
+
+       if (len < sizeof(*ev))
+               return;
+
+       if (ev->status)
+               return;
+
+       if (ev->peer_addr_type == 0x00)
+               addr_type = BDADDR_LE_PUBLIC;
+       else
+               addr_type = BDADDR_LE_RANDOM;
+
+       init_conn(bthost, le16_to_cpu(ev->handle), addr_type);
+}
+
+static void evt_le_meta_event(struct bthost *bthost, const void *data,
+                                                               uint8_t len)
+{
+       const uint8_t *event = data;
+       const void *evt_data = data + 1;
+
+       if (len < 1)
+               return;
+
+       switch (*event) {
+       case BT_HCI_EVT_LE_CONN_COMPLETE:
+               evt_le_conn_complete(bthost, evt_data, len - 1);
+               break;
+       default:
+               break;
+       }
+}
+
+static void process_evt(struct bthost *bthost, const void *data, uint16_t len)
+{
+       const struct bt_hci_evt_hdr *hdr = data;
+       const void *param;
+
+       if (len < sizeof(*hdr))
+               return;
+
+       if (sizeof(*hdr) + hdr->plen != len)
+               return;
+
+       param = data + sizeof(*hdr);
+
+       switch (hdr->evt) {
+       case BT_HCI_EVT_CMD_COMPLETE:
+               evt_cmd_complete(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_CMD_STATUS:
+               evt_cmd_status(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_CONN_REQUEST:
+               evt_conn_request(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_CONN_COMPLETE:
+               evt_conn_complete(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_DISCONNECT_COMPLETE:
+               evt_disconn_complete(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_NUM_COMPLETED_PACKETS:
+               evt_num_completed_packets(bthost, param, hdr->plen);
+               break;
+
+       case BT_HCI_EVT_LE_META_EVENT:
+               evt_le_meta_event(bthost, param, hdr->plen);
+               break;
+
+       default:
+               printf("Unsupported event 0x%2.2x\n", hdr->evt);
+               break;
+       }
+}
+
+static bool l2cap_cmd_rej(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_cmd_reject *rsp = data;
+
+       if (len < sizeof(*rsp))
+               return false;
+
+       return true;
+}
+
+static bool l2cap_conn_req(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_conn_req *req = data;
+       struct bt_l2cap_pdu_conn_rsp rsp;
+       uint16_t psm;
+
+       if (len < sizeof(*req))
+               return false;
+
+       psm = le16_to_cpu(req->psm);
+
+       memset(&rsp, 0, sizeof(rsp));
+       rsp.scid = req->scid;
+
+       if (bthost->server_psm && bthost->server_psm == psm)
+               rsp.dcid = cpu_to_le16(conn->next_cid++);
+       else
+               rsp.result = cpu_to_le16(0x0002); /* PSM Not Supported */
+
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONN_RSP, ident, &rsp,
+                                                               sizeof(rsp));
+
+       if (!rsp.result) {
+               struct bt_l2cap_pdu_config_req conf_req;
+
+               bthost_add_l2cap_conn(bthost, conn, le16_to_cpu(rsp.dcid),
+                                                       le16_to_cpu(rsp.scid));
+
+               memset(&conf_req, 0, sizeof(conf_req));
+               conf_req.dcid = rsp.dcid;
+
+               l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_REQ, 0,
+                                               &conf_req, sizeof(conf_req));
+       }
+
+       return true;
+}
+
+static bool l2cap_conn_rsp(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_conn_rsp *rsp = data;
+
+       if (len < sizeof(*rsp))
+               return false;
+
+       bthost_add_l2cap_conn(bthost, conn, le16_to_cpu(rsp->scid),
+                                               le16_to_cpu(rsp->dcid));
+
+       if (le16_to_cpu(rsp->result) == 0x0001) {
+               struct bt_l2cap_pdu_config_req req;
+
+               memset(&req, 0, sizeof(req));
+               req.dcid = rsp->dcid;
+
+               l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_REQ, 0,
+                                                       &req, sizeof(req));
+       }
+
+       return true;
+}
+
+static bool l2cap_config_req(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_config_req *req = data;
+       struct bt_l2cap_pdu_config_rsp rsp;
+       struct l2conn *l2conn;
+       uint16_t dcid;
+
+       if (len < sizeof(*req))
+               return false;
+
+       dcid = le16_to_cpu(req->dcid);
+
+       l2conn = btconn_find_l2cap_conn_by_scid(conn, dcid);
+       if (!l2conn)
+               return false;
+
+       memset(&rsp, 0, sizeof(rsp));
+       rsp.scid  = cpu_to_le16(l2conn->dcid);
+       rsp.flags = req->flags;
+
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONFIG_RSP, ident, &rsp,
+                                                               sizeof(rsp));
+
+       return true;
+}
+
+static bool l2cap_config_rsp(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_config_rsp *rsp = data;
+
+       if (len < sizeof(*rsp))
+               return false;
+
+       return true;
+}
+
+static bool l2cap_disconn_req(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_disconn_req *req = data;
+       struct bt_l2cap_pdu_disconn_rsp rsp;
+
+       if (len < sizeof(*req))
+               return false;
+
+       memset(&rsp, 0, sizeof(rsp));
+       rsp.dcid = req->dcid;
+       rsp.scid = req->scid;
+
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_DISCONN_RSP, ident, &rsp,
+                                                               sizeof(rsp));
+
+       return true;
+}
+
+static bool l2cap_info_req(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_info_req *req = data;
+       struct bt_l2cap_pdu_info_rsp rsp;
+
+       if (len < sizeof(*req))
+               return false;
+
+       rsp.type = req->type;
+       rsp.result = cpu_to_le16(0x0001); /* Not Supported */
+
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_INFO_RSP, ident, &rsp,
+                                                               sizeof(rsp));
+
+       return true;
+}
+
+static void handle_pending_l2reqs(struct bthost *bthost, struct btconn *conn,
+                                               uint8_t ident, uint8_t code,
+                                               const void *data, uint16_t len)
+{
+       struct l2cap_pending_req **curr;
+
+       for (curr = &bthost->l2reqs; *curr != NULL;) {
+               struct l2cap_pending_req *req = *curr;
+
+               if (req->ident != ident) {
+                       curr = &req->next;
+                       continue;
+               }
+
+               *curr = req->next;
+               req->cb(code, data, len, req->user_data);
+               free(req);
+       }
+}
+
+static void l2cap_sig(struct bthost *bthost, struct btconn *conn,
+                                               const void *data, uint16_t len)
+{
+       const struct bt_l2cap_hdr_sig *hdr = data;
+       struct bt_l2cap_pdu_cmd_reject rej;
+       uint16_t hdr_len;
+       bool ret;
+
+       if (len < sizeof(*hdr))
+               goto reject;
+
+       hdr_len = le16_to_cpu(hdr->len);
+
+       if (sizeof(*hdr) + hdr_len != len)
+               goto reject;
+
+       switch (hdr->code) {
+       case BT_L2CAP_PDU_CMD_REJECT:
+               ret = l2cap_cmd_rej(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONN_REQ:
+               ret = l2cap_conn_req(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONN_RSP:
+               ret = l2cap_conn_rsp(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONFIG_REQ:
+               ret = l2cap_config_req(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONFIG_RSP:
+               ret = l2cap_config_rsp(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_DISCONN_REQ:
+               ret = l2cap_disconn_req(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_INFO_REQ:
+               ret = l2cap_info_req(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       default:
+               printf("Unknown L2CAP code 0x%02x\n", hdr->code);
+               ret = false;
+       }
+
+       handle_pending_l2reqs(bthost, conn, hdr->ident, hdr->code,
+                                               data + sizeof(*hdr), hdr_len);
+
+       if (ret)
+               return;
+
+reject:
+       memset(&rej, 0, sizeof(rej));
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CMD_REJECT, 0,
+                                                       &rej, sizeof(rej));
+}
+
+static bool l2cap_conn_param_req(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_conn_param_req *req = data;
+       struct bt_l2cap_pdu_conn_param_rsp rsp;
+       struct bt_hci_cmd_le_conn_update hci_cmd;
+
+       if (len < sizeof(*req))
+               return false;
+
+       memset(&hci_cmd, 0, sizeof(hci_cmd));
+       hci_cmd.handle = cpu_to_le16(conn->handle);
+       hci_cmd.min_interval = req->min_interval;
+       hci_cmd.max_interval = req->max_interval;
+       hci_cmd.latency = req->latency;
+       hci_cmd.supv_timeout = req->timeout;
+       hci_cmd.min_length = cpu_to_le16(0x0001);
+       hci_cmd.max_length = cpu_to_le16(0x0001);
+
+       send_command(bthost, BT_HCI_CMD_LE_CONN_UPDATE,
+                                               &hci_cmd, sizeof(hci_cmd));
+
+       memset(&rsp, 0, sizeof(rsp));
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CONN_PARAM_RSP, ident,
+                                                       &rsp, sizeof(rsp));
+
+       return true;
+}
+
+static bool l2cap_conn_param_rsp(struct bthost *bthost, struct btconn *conn,
+                               uint8_t ident, const void *data, uint16_t len)
+{
+       const struct bt_l2cap_pdu_conn_param_req *rsp = data;
+
+       if (len < sizeof(*rsp))
+               return false;
+
+       return true;
+}
+
+static void l2cap_le_sig(struct bthost *bthost, struct btconn *conn,
+                                               const void *data, uint16_t len)
+{
+       const struct bt_l2cap_hdr_sig *hdr = data;
+       struct bt_l2cap_pdu_cmd_reject rej;
+       uint16_t hdr_len;
+       bool ret;
+
+       if (len < sizeof(*hdr))
+               goto reject;
+
+       hdr_len = le16_to_cpu(hdr->len);
+
+       if (sizeof(*hdr) + hdr_len != len)
+               goto reject;
+
+       switch (hdr->code) {
+       case BT_L2CAP_PDU_CMD_REJECT:
+               ret = l2cap_cmd_rej(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONN_PARAM_REQ:
+               ret = l2cap_conn_param_req(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       case BT_L2CAP_PDU_CONN_PARAM_RSP:
+               ret = l2cap_conn_param_rsp(bthost, conn, hdr->ident,
+                                               data + sizeof(*hdr), hdr_len);
+               break;
+
+       default:
+               printf("Unknown L2CAP code 0x%02x\n", hdr->code);
+               ret = false;
+       }
+
+       handle_pending_l2reqs(bthost, conn, hdr->ident, hdr->code,
+                                               data + sizeof(*hdr), hdr_len);
+
+       if (ret)
+               return;
+
+reject:
+       memset(&rej, 0, sizeof(rej));
+       l2cap_sig_send(bthost, conn, BT_L2CAP_PDU_CMD_REJECT, 0,
+                                                       &rej, sizeof(rej));
+}
+
+static void process_acl(struct bthost *bthost, const void *data, uint16_t len)
+{
+       const struct bt_hci_acl_hdr *acl_hdr = data;
+       const struct bt_l2cap_hdr *l2_hdr = data + sizeof(*acl_hdr);
+       uint16_t handle, cid, acl_len, l2_len;
+       struct btconn *conn;
+       const void *l2_data;
+
+       if (len < sizeof(*acl_hdr) + sizeof(*l2_hdr))
+               return;
+
+       acl_len = le16_to_cpu(acl_hdr->dlen);
+       if (len != sizeof(*acl_hdr) + acl_len)
+               return;
+
+       handle = acl_handle(acl_hdr->handle);
+       conn = bthost_find_conn(bthost, handle);
+       if (!conn) {
+               printf("ACL data for unknown handle 0x%04x\n", handle);
+               return;
+       }
+
+       l2_len = le16_to_cpu(l2_hdr->len);
+       if (len - sizeof(*acl_hdr) != sizeof(*l2_hdr) + l2_len)
+               return;
+
+       l2_data = data + sizeof(*acl_hdr) + sizeof(*l2_hdr);
+
+       cid = le16_to_cpu(l2_hdr->cid);
+
+       switch (cid) {
+       case 0x0001:
+               l2cap_sig(bthost, conn, l2_data, l2_len);
+               break;
+       case 0x0005:
+               l2cap_le_sig(bthost, conn, l2_data, l2_len);
+               break;
+       default:
+               printf("Packet for unknown CID 0x%04x (%u)\n", cid, cid);
+               break;
+       }
+}
+
+void bthost_receive_h4(struct bthost *bthost, const void *data, uint16_t len)
+{
+       uint8_t pkt_type;
+
+       if (!bthost)
+               return;
+
+       if (len < 1)
+               return;
+
+       pkt_type = ((const uint8_t *) data)[0];
+
+       switch (pkt_type) {
+       case BT_H4_EVT_PKT:
+               process_evt(bthost, data + 1, len - 1);
+               break;
+       case BT_H4_ACL_PKT:
+               process_acl(bthost, data + 1, len - 1);
+               break;
+       default:
+               printf("Unsupported packet 0x%2.2x\n", pkt_type);
+               break;
+       }
+}
+
+void bthost_set_cmd_complete_cb(struct bthost *bthost,
+                               bthost_cmd_complete_cb cb, void *user_data)
+{
+       bthost->cmd_complete_cb = cb;
+       bthost->cmd_complete_data = user_data;
+}
+
+void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb,
+                                                       void *user_data)
+{
+       bthost->new_conn_cb = cb;
+       bthost->new_conn_data = user_data;
+}
+
+void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr,
+                                                       uint8_t addr_type)
+{
+       if (addr_type == BDADDR_BREDR) {
+               struct bt_hci_cmd_create_conn cc;
+
+               memset(&cc, 0, sizeof(cc));
+               memcpy(cc.bdaddr, bdaddr, sizeof(cc.bdaddr));
+
+               send_command(bthost, BT_HCI_CMD_CREATE_CONN, &cc, sizeof(cc));
+       } else {
+               struct bt_hci_cmd_le_create_conn cc;
+
+               memset(&cc, 0, sizeof(cc));
+               memcpy(cc.peer_addr, bdaddr, sizeof(cc.peer_addr));
+
+               if (addr_type == BDADDR_LE_RANDOM)
+                       cc.peer_addr_type = 0x01;
+
+               send_command(bthost, BT_HCI_CMD_LE_CREATE_CONN,
+                                                       &cc, sizeof(cc));
+       }
+}
+
+void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan)
+{
+       send_command(bthost, BT_HCI_CMD_WRITE_SCAN_ENABLE, &scan, 1);
+}
+
+void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable)
+{
+       send_command(bthost, BT_HCI_CMD_LE_SET_ADV_ENABLE, &enable, 1);
+}
+
+void bthost_set_server_psm(struct bthost *bthost, uint16_t psm)
+{
+       bthost->server_psm = psm;
+}
+
+void bthost_start(struct bthost *bthost)
+{
+       if (!bthost)
+               return;
+
+       bthost->ncmd = 1;
+
+       send_command(bthost, BT_HCI_CMD_RESET, NULL, 0);
+
+       send_command(bthost, BT_HCI_CMD_READ_BD_ADDR, NULL, 0);
+}
+
+void bthost_stop(struct bthost *bthost)
+{
+}
diff --git a/emulator/bthost.h b/emulator/bthost.h
new file mode 100644 (file)
index 0000000..cd5bf1c
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+
+typedef void (*bthost_send_func) (const void *data, uint16_t len,
+                                                       void *user_data);
+
+struct bthost;
+
+struct bthost *bthost_create(void);
+void bthost_destroy(struct bthost *bthost);
+
+void bthost_set_send_handler(struct bthost *bthost, bthost_send_func handler,
+                                                       void *user_data);
+
+void bthost_receive_h4(struct bthost *bthost, const void *data, uint16_t len);
+
+typedef void (*bthost_cmd_complete_cb) (uint16_t opcode, uint8_t status,
+                                       const void *param, uint8_t len,
+                                       void *user_data);
+
+void bthost_set_cmd_complete_cb(struct bthost *bthost,
+                               bthost_cmd_complete_cb cb, void *user_data);
+
+typedef void (*bthost_new_conn_cb) (uint16_t handle, void *user_data);
+
+void bthost_set_connect_cb(struct bthost *bthost, bthost_new_conn_cb cb,
+                                                       void *user_data);
+
+void bthost_hci_connect(struct bthost *bthost, const uint8_t *bdaddr,
+                                                       uint8_t addr_type);
+
+typedef void (*bthost_l2cap_rsp_cb) (uint8_t code, const void *data,
+                                               uint16_t len, void *user_data);
+
+bool bthost_l2cap_req(struct bthost *bthost, uint16_t handle, uint8_t req,
+                               const void *data, uint16_t len,
+                               bthost_l2cap_rsp_cb cb, void *user_data);
+
+void bthost_write_scan_enable(struct bthost *bthost, uint8_t scan);
+
+void bthost_set_adv_enable(struct bthost *bthost, uint8_t enable);
+
+void bthost_set_server_psm(struct bthost *bthost, uint16_t psm);
+
+void bthost_start(struct bthost *bthost);
+void bthost_stop(struct bthost *bthost);
index 125460d..85b10f1 100644 (file)
 #endif
 
 #include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <getopt.h>
 
-#include "mainloop.h"
+#include "monitor/mainloop.h"
 #include "server.h"
 #include "vhci.h"
+#include "amp.h"
 
 static void signal_callback(int signum, void *user_data)
 {
@@ -42,31 +46,149 @@ static void signal_callback(int signum, void *user_data)
        }
 }
 
+static void usage(void)
+{
+       printf("btvirt - Bluetooth emulator\n"
+               "Usage:\n");
+       printf("\tbtvirt [options]\n");
+       printf("options:\n"
+               "\t-s                    Create local server sockets\n"
+               "\t-l [num]              Number of local controllers\n"
+               "\t-L                    Create LE only controller\n"
+               "\t-B                    Create BR/EDR only controller\n"
+               "\t-A                    Create AMP controller\n"
+               "\t-h, --help            Show help options\n");
+}
+
+static const struct option main_options[] = {
+       { "server",  no_argument,       NULL, 's' },
+       { "local",   optional_argument, NULL, 'l' },
+       { "le",      no_argument,       NULL, 'L' },
+       { "bredr",   no_argument,       NULL, 'B' },
+       { "amp",     no_argument,       NULL, 'A' },
+       { "amptest", optional_argument, NULL, 'T' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
 int main(int argc, char *argv[])
 {
-       struct vhci *vhci;
-       struct server *server;
+       struct server *server1;
+       struct server *server2;
+       struct server *server3;
+       struct server *server4;
+       struct server *server5;
+       bool server_enabled = false;
+       int amptest_count = 0;
+       int vhci_count = 0;
+       enum vhci_type vhci_type = VHCI_TYPE_BREDRLE;
        sigset_t mask;
+       int i;
 
        mainloop_init();
 
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "sl::LBATvh", main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 's':
+                       server_enabled = true;
+                       break;
+               case 'l':
+                       if (optarg)
+                               vhci_count = atoi(optarg);
+                       else
+                               vhci_count = 1;
+                       break;
+               case 'L':
+                       vhci_type = VHCI_TYPE_LE;
+                       break;
+               case 'B':
+                       vhci_type = VHCI_TYPE_BREDR;
+                       break;
+               case 'A':
+                       vhci_type = VHCI_TYPE_AMP;
+                       break;
+               case 'T':
+                       if (optarg)
+                               amptest_count = atoi(optarg);
+                       else
+                               amptest_count = 1;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (amptest_count < 1 && vhci_count < 1 && !server_enabled) {
+               fprintf(stderr, "No emulator specified\n");
+               return EXIT_FAILURE;
+       }
+
        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;
+       printf("Bluetooth emulator ver %s\n", VERSION);
+
+       for (i = 0; i < amptest_count; i++) {
+               struct bt_amp *amp;
+
+               amp = bt_amp_new();
+               if (!amp) {
+                       fprintf(stderr, "Failed to create AMP controller\n");
+                       return EXIT_FAILURE;
+               }
+       }
+
+       for (i = 0; i < vhci_count; i++) {
+               struct vhci *vhci;
+
+               vhci = vhci_open(vhci_type);
+               if (!vhci) {
+                       fprintf(stderr, "Failed to open Virtual HCI device\n");
+                       return EXIT_FAILURE;
+               }
        }
 
-       server = server_open_unix("/tmp/bt-server-bredr", 0x42);
-       if (!server) {
-               fprintf(stderr, "Failed to open server channel\n");
-               vhci_close(vhci);
-               return 1;
+       if (server_enabled) {
+               server1 = server_open_unix(SERVER_TYPE_BREDRLE,
+                                               "/tmp/bt-server-bredrle");
+               if (!server1)
+                       fprintf(stderr, "Failed to open BR/EDR/LE server\n");
+
+               server2 = server_open_unix(SERVER_TYPE_BREDR,
+                                               "/tmp/bt-server-bredr");
+               if (!server2)
+                       fprintf(stderr, "Failed to open BR/EDR server\n");
+
+               server3 = server_open_unix(SERVER_TYPE_AMP,
+                                               "/tmp/bt-server-amp");
+               if (!server3)
+                       fprintf(stderr, "Failed to open AMP server\n");
+
+               server4 = server_open_unix(SERVER_TYPE_LE,
+                                               "/tmp/bt-server-le");
+               if (!server4)
+                       fprintf(stderr, "Failed to open LE server\n");
+
+               server5 = server_open_unix(SERVER_TYPE_MONITOR,
+                                               "/tmp/bt-server-mon");
+               if (!server5)
+                       fprintf(stderr, "Failed to open monitor server\n");
        }
 
        return mainloop_run();
index 1ff9904..b2a4b02 100644 (file)
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 #include <sys/un.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 
-#include "mainloop.h"
+#include "monitor/mainloop.h"
 #include "btdev.h"
 #include "server.h"
 
+#define uninitialized_var(x) x = x
+
 struct server {
+       enum server_type type;
        uint16_t id;
        int fd;
 };
@@ -98,8 +103,10 @@ static void client_read_callback(int fd, uint32_t events, void *user_data)
        ssize_t len;
        uint16_t count;
 
-       if (events & (EPOLLERR | EPOLLHUP))
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(client->fd);
                return;
+       }
 
 again:
        len = recv(fd, buf + client->pkt_offset,
@@ -110,6 +117,9 @@ again:
                return;
        }
 
+       if (!client->btdev)
+               return;
+
        count = client->pkt_offset + len;
 
        while (count > 0) {
@@ -187,9 +197,12 @@ static void server_accept_callback(int fd, uint32_t events, void *user_data)
 {
        struct server *server = user_data;
        struct client *client;
+       enum btdev_type uninitialized_var(type);
 
-       if (events & (EPOLLERR | EPOLLHUP))
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(server->fd);
                return;
+       }
 
        client = malloc(sizeof(*client));
        if (!client)
@@ -203,7 +216,24 @@ static void server_accept_callback(int fd, uint32_t events, void *user_data)
                return;
        }
 
-       client->btdev = btdev_create(server->id);
+       switch (server->type) {
+       case SERVER_TYPE_BREDRLE:
+               type = BTDEV_TYPE_BREDRLE;
+               break;
+       case SERVER_TYPE_BREDR:
+               type = BTDEV_TYPE_BREDR;
+               break;
+       case SERVER_TYPE_LE:
+               type = BTDEV_TYPE_LE;
+               break;
+       case SERVER_TYPE_AMP:
+               type = BTDEV_TYPE_AMP;
+               break;
+       case SERVER_TYPE_MONITOR:
+               goto done;
+       }
+
+       client->btdev = btdev_create(type, server->id);
        if (!client->btdev) {
                close(client->fd);
                free(client);
@@ -212,6 +242,7 @@ static void server_accept_callback(int fd, uint32_t events, void *user_data)
 
        btdev_set_send_handler(client->btdev, client_write_callback, client);
 
+done:
        if (mainloop_add_fd(client->fd, EPOLLIN, client_read_callback,
                                                client, client_destroy) < 0) {
                btdev_destroy(client->btdev);
@@ -220,7 +251,7 @@ static void server_accept_callback(int fd, uint32_t events, void *user_data)
        }
 }
 
-static int open_server(const char *path)
+static int open_unix(const char *path)
 {
        struct sockaddr_un addr;
        int fd;
@@ -252,7 +283,7 @@ static int open_server(const char *path)
        return fd;
 }
 
-struct server *server_open_unix(const char *path, uint16_t id)
+struct server *server_open_unix(enum server_type type, const char *path)
 {
        struct server *server;
 
@@ -261,9 +292,72 @@ struct server *server_open_unix(const char *path, uint16_t id)
                return NULL;
 
        memset(server, 0, sizeof(*server));
-       server->id = id;
+       server->type = type;
+       server->id = 0x42;
+
+       server->fd = open_unix(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;
+}
+
+static int open_tcp(void)
+{
+       struct sockaddr_in addr;
+       int fd, opt = 1;
+
+       fd = socket(PF_INET, SOCK_STREAM, 0);
+       if (fd < 0) {
+               perror("Failed to open server socket");
+               return -1;
+       }
+
+       setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sin_family = AF_INET;
+       addr.sin_addr.s_addr = INADDR_ANY;
+       addr.sin_addr.s_addr = inet_addr("127.0.0.1");
+       addr.sin_port = htons(45550);
+
+       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_tcp(enum server_type type)
+{
+       struct server *server;
+
+       server = malloc(sizeof(*server));
+       if (!server)
+               return server;
+
+       memset(server, 0, sizeof(*server));
+       server->type = type;
+       server->id = 0x43;
 
-       server->fd = open_server(path);
+       server->fd = open_tcp();
        if (server->fd < 0) {
                free(server);
                return NULL;
index 836db5f..f0b3727 100644 (file)
 
 #include <stdint.h>
 
+enum server_type {
+       SERVER_TYPE_BREDRLE,
+       SERVER_TYPE_BREDR,
+       SERVER_TYPE_LE,
+       SERVER_TYPE_AMP,
+       SERVER_TYPE_MONITOR,
+};
+
 struct server;
 
-struct server *server_open_unix(const char *path, uint16_t id);
+struct server *server_open_unix(enum server_type type, const char *path);
+struct server *server_open_tcp(enum server_type type);
 void server_close(struct server *server);
index 940e562..d32d5e5 100644 (file)
 #include <stdlib.h>
 #include <string.h>
 
-#include "mainloop.h"
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/mainloop.h"
+#include "monitor/bt.h"
 #include "btdev.h"
 #include "vhci.h"
 
+#define uninitialized_var(x) x = x
+
 struct vhci {
        enum vhci_type type;
        int fd;
@@ -74,21 +80,43 @@ static void vhci_read_callback(int fd, uint32_t events, void *user_data)
                return;
 
        len = read(vhci->fd, buf, sizeof(buf));
-       if (len < 0)
+       if (len < 1)
                return;
 
-       btdev_receive_h4(vhci->btdev, buf, len);
+       switch (buf[0]) {
+       case BT_H4_CMD_PKT:
+       case BT_H4_ACL_PKT:
+       case BT_H4_SCO_PKT:
+               btdev_receive_h4(vhci->btdev, buf, len);
+               break;
+       }
 }
 
-struct vhci *vhci_open(enum vhci_type type, uint16_t id)
+struct vhci *vhci_open(enum vhci_type type)
 {
        struct vhci *vhci;
+       enum btdev_type uninitialized_var(btdev_type);
+       unsigned char uninitialized_var(ctrl_type);
+       unsigned char setup_cmd[2];
+       static uint8_t id = 0x23;
 
        switch (type) {
+       case VHCI_TYPE_BREDRLE:
+               btdev_type = BTDEV_TYPE_BREDRLE;
+               ctrl_type = HCI_BREDR;
+               break;
        case VHCI_TYPE_BREDR:
+               btdev_type = BTDEV_TYPE_BREDR;
+               ctrl_type = HCI_BREDR;
+               break;
+       case VHCI_TYPE_LE:
+               btdev_type = BTDEV_TYPE_LE;
+               ctrl_type = HCI_BREDR;
                break;
        case VHCI_TYPE_AMP:
-               return NULL;
+               btdev_type = BTDEV_TYPE_AMP;
+               ctrl_type = HCI_AMP;
+               break;
        }
 
        vhci = malloc(sizeof(*vhci));
@@ -104,7 +132,16 @@ struct vhci *vhci_open(enum vhci_type type, uint16_t id)
                return NULL;
        }
 
-       vhci->btdev = btdev_create(id);
+       setup_cmd[0] = HCI_VENDOR_PKT;
+       setup_cmd[1] = ctrl_type;
+
+       if (write(vhci->fd, setup_cmd, sizeof(setup_cmd)) < 0) {
+               close(vhci->fd);
+               free(vhci);
+               return NULL;
+       }
+
+       vhci->btdev = btdev_create(btdev_type, id++);
        if (!vhci->btdev) {
                close(vhci->fd);
                free(vhci);
index 4abb183..b9ae63f 100644 (file)
 #include <stdint.h>
 
 enum vhci_type {
-       VHCI_TYPE_BREDR = 0,
-       VHCI_TYPE_AMP   = 1,
+       VHCI_TYPE_BREDRLE,
+       VHCI_TYPE_BREDR,
+       VHCI_TYPE_LE,
+       VHCI_TYPE_AMP,
 };
 
 struct vhci;
 
-struct vhci *vhci_open(enum vhci_type type, uint16_t id);
+struct vhci *vhci_open(enum vhci_type type);
 void vhci_close(struct vhci *vhci);
diff --git a/gdbus/client.c b/gdbus/client.c
new file mode 100644 (file)
index 0000000..be8cc29
--- /dev/null
@@ -0,0 +1,1263 @@
+/*
+ *
+ *  D-Bus helper library
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <glib.h>
+#include <dbus/dbus.h>
+
+#include "gdbus.h"
+
+#define METHOD_CALL_TIMEOUT (300 * 1000)
+
+#ifndef DBUS_INTERFACE_OBJECT_MANAGER
+#define DBUS_INTERFACE_OBJECT_MANAGER DBUS_INTERFACE_DBUS ".ObjectManager"
+#endif
+
+struct GDBusClient {
+       int ref_count;
+       DBusConnection *dbus_conn;
+       char *service_name;
+       char *base_path;
+       guint watch;
+       guint added_watch;
+       guint removed_watch;
+       GPtrArray *match_rules;
+       DBusPendingCall *pending_call;
+       DBusPendingCall *get_objects_call;
+       GDBusWatchFunction connect_func;
+       void *connect_data;
+       GDBusWatchFunction disconn_func;
+       void *disconn_data;
+       GDBusMessageFunction signal_func;
+       void *signal_data;
+       GDBusProxyFunction proxy_added;
+       GDBusProxyFunction proxy_removed;
+       GDBusPropertyFunction property_changed;
+       void *user_data;
+       GList *proxy_list;
+};
+
+struct GDBusProxy {
+       int ref_count;
+       GDBusClient *client;
+       char *obj_path;
+       char *interface;
+       GHashTable *prop_list;
+       guint watch;
+       GDBusPropertyFunction prop_func;
+       void *prop_data;
+       GDBusProxyFunction removed_func;
+       void *removed_data;
+};
+
+struct prop_entry {
+       char *name;
+       int type;
+       DBusMessage *msg;
+};
+
+static void modify_match_reply(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE)
+               dbus_error_free(&error);
+
+       dbus_message_unref(reply);
+}
+
+static gboolean modify_match(DBusConnection *conn, const char *member,
+                                                       const char *rule)
+{
+       DBusMessage *msg;
+       DBusPendingCall *call;
+
+       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+                                       DBUS_INTERFACE_DBUS, member);
+       if (msg == NULL)
+               return FALSE;
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &rule,
+                                               DBUS_TYPE_INVALID);
+
+       if (g_dbus_send_message_with_reply(conn, msg, &call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               return FALSE;
+       }
+
+       dbus_pending_call_set_notify(call, modify_match_reply, NULL, NULL);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+
+       return TRUE;
+}
+
+static void iter_append_iter(DBusMessageIter *base, DBusMessageIter *iter)
+{
+       int type;
+
+       type = dbus_message_iter_get_arg_type(iter);
+
+       if (dbus_type_is_basic(type)) {
+               const void *value;
+
+               dbus_message_iter_get_basic(iter, &value);
+               dbus_message_iter_append_basic(base, type, &value);
+       } else if (dbus_type_is_container(type)) {
+               DBusMessageIter iter_sub, base_sub;
+               char *sig;
+
+               dbus_message_iter_recurse(iter, &iter_sub);
+
+               switch (type) {
+               case DBUS_TYPE_ARRAY:
+               case DBUS_TYPE_VARIANT:
+                       sig = dbus_message_iter_get_signature(&iter_sub);
+                       break;
+               default:
+                       sig = NULL;
+                       break;
+               }
+
+               dbus_message_iter_open_container(base, type, sig, &base_sub);
+
+               if (sig != NULL)
+                       dbus_free(sig);
+
+               while (dbus_message_iter_get_arg_type(&iter_sub) !=
+                                                       DBUS_TYPE_INVALID) {
+                       iter_append_iter(&base_sub, &iter_sub);
+                       dbus_message_iter_next(&iter_sub);
+               }
+
+               dbus_message_iter_close_container(base, &base_sub);
+       }
+}
+
+static void prop_entry_update(struct prop_entry *prop, DBusMessageIter *iter)
+{
+       DBusMessage *msg;
+       DBusMessageIter base;
+
+       msg = dbus_message_new(DBUS_MESSAGE_TYPE_METHOD_RETURN);
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &base);
+       iter_append_iter(&base, iter);
+
+       if (prop->msg != NULL)
+               dbus_message_unref(prop->msg);
+
+       prop->msg = dbus_message_copy(msg);
+       dbus_message_unref(msg);
+}
+
+static struct prop_entry *prop_entry_new(const char *name,
+                                               DBusMessageIter *iter)
+{
+       struct prop_entry *prop;
+
+       prop = g_try_new0(struct prop_entry, 1);
+       if (prop == NULL)
+               return NULL;
+
+       prop->name = g_strdup(name);
+       prop->type = dbus_message_iter_get_arg_type(iter);
+
+       prop_entry_update(prop, iter);
+
+       return prop;
+}
+
+static void prop_entry_free(gpointer data)
+{
+       struct prop_entry *prop = data;
+
+       if (prop->msg != NULL)
+               dbus_message_unref(prop->msg);
+
+       g_free(prop->name);
+
+       g_free(prop);
+}
+
+static void add_property(GDBusProxy *proxy, const char *name,
+                               DBusMessageIter *iter, gboolean send_changed)
+{
+       GDBusClient *client = proxy->client;
+       DBusMessageIter value;
+       struct prop_entry *prop;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_VARIANT)
+               return;
+
+       dbus_message_iter_recurse(iter, &value);
+
+       prop = g_hash_table_lookup(proxy->prop_list, name);
+       if (prop != NULL) {
+               prop_entry_update(prop, &value);
+               goto done;
+       }
+
+       prop = prop_entry_new(name, &value);
+       if (prop == NULL)
+               return;
+
+       g_hash_table_replace(proxy->prop_list, prop->name, prop);
+
+done:
+       if (proxy->prop_func)
+               proxy->prop_func(proxy, name, &value, proxy->prop_data);
+
+       if (client == NULL || send_changed == FALSE)
+               return;
+
+       if (client->property_changed)
+               client->property_changed(proxy, name, &value,
+                                                       client->user_data);
+}
+
+static void update_properties(GDBusProxy *proxy, DBusMessageIter *iter,
+                                                       gboolean send_changed)
+{
+       DBusMessageIter dict;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(iter, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry;
+               const char *name;
+
+               dbus_message_iter_recurse(&dict, &entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       break;
+
+               dbus_message_iter_get_basic(&entry, &name);
+               dbus_message_iter_next(&entry);
+
+               add_property(proxy, name, &entry, send_changed);
+
+               dbus_message_iter_next(&dict);
+       }
+}
+
+static void get_all_properties_reply(DBusPendingCall *call, void *user_data)
+{
+       GDBusProxy *proxy = user_data;
+       GDBusClient *client = proxy->client;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusMessageIter iter;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       dbus_message_iter_init(reply, &iter);
+
+       update_properties(proxy, &iter, FALSE);
+
+done:
+       if (g_list_find(client->proxy_list, proxy) == NULL) {
+               if (client->proxy_added)
+                       client->proxy_added(proxy, client->user_data);
+
+               client->proxy_list = g_list_append(client->proxy_list, proxy);
+       }
+
+       dbus_message_unref(reply);
+
+       g_dbus_client_unref(client);
+}
+
+static void get_all_properties(GDBusProxy *proxy)
+{
+       GDBusClient *client = proxy->client;
+       const char *service_name = client->service_name;
+       DBusMessage *msg;
+       DBusPendingCall *call;
+
+       msg = dbus_message_new_method_call(service_name, proxy->obj_path,
+                                       DBUS_INTERFACE_PROPERTIES, "GetAll");
+       if (msg == NULL)
+               return;
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &proxy->interface,
+                                                       DBUS_TYPE_INVALID);
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                                                       &call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               return;
+       }
+
+       g_dbus_client_ref(client);
+
+       dbus_pending_call_set_notify(call, get_all_properties_reply,
+                                                       proxy, NULL);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+}
+
+static GDBusProxy *proxy_lookup(GDBusClient *client, const char *path,
+                                               const char *interface)
+{
+       GList *list;
+
+       for (list = g_list_first(client->proxy_list); list;
+                                               list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+
+               if (g_str_equal(proxy->interface, interface) == TRUE &&
+                               g_str_equal(proxy->obj_path, path) == TRUE)
+                       return proxy;
+        }
+
+       return NULL;
+}
+
+static gboolean properties_changed(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       GDBusProxy *proxy = user_data;
+       GDBusClient *client = proxy->client;
+       DBusMessageIter iter, entry;
+       const char *interface;
+
+       if (dbus_message_iter_init(msg, &iter) == FALSE)
+               return TRUE;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &interface);
+       dbus_message_iter_next(&iter);
+
+       update_properties(proxy, &iter, TRUE);
+
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return TRUE;
+
+       dbus_message_iter_recurse(&iter, &entry);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *name;
+
+               dbus_message_iter_get_basic(&entry, &name);
+
+               g_hash_table_remove(proxy->prop_list, name);
+
+               if (proxy->prop_func)
+                       proxy->prop_func(proxy, name, NULL, proxy->prop_data);
+
+               if (client->property_changed)
+                       client->property_changed(proxy, name, NULL,
+                                                       client->user_data);
+
+               dbus_message_iter_next(&entry);
+       }
+
+       return TRUE;
+}
+
+static GDBusProxy *proxy_new(GDBusClient *client, const char *path,
+                                               const char *interface)
+{
+       GDBusProxy *proxy;
+
+       proxy = g_try_new0(GDBusProxy, 1);
+       if (proxy == NULL)
+               return NULL;
+
+       proxy->client = client;
+       proxy->obj_path = g_strdup(path);
+       proxy->interface = g_strdup(interface);
+
+       proxy->prop_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       NULL, prop_entry_free);
+       proxy->watch = g_dbus_add_properties_watch(client->dbus_conn,
+                                                       client->service_name,
+                                                       proxy->obj_path,
+                                                       proxy->interface,
+                                                       properties_changed,
+                                                       proxy, NULL);
+
+       return g_dbus_proxy_ref(proxy);
+}
+
+static void proxy_free(gpointer data)
+{
+       GDBusProxy *proxy = data;
+
+       if (proxy->client) {
+               GDBusClient *client = proxy->client;
+
+               if (client->proxy_removed)
+                       client->proxy_removed(proxy, client->user_data);
+
+               g_dbus_remove_watch(client->dbus_conn, proxy->watch);
+
+               g_hash_table_remove_all(proxy->prop_list);
+
+               proxy->client = NULL;
+       }
+
+       if (proxy->removed_func)
+               proxy->removed_func(proxy, proxy->removed_data);
+
+       g_dbus_proxy_unref(proxy);
+}
+
+static void proxy_remove(GDBusClient *client, const char *path,
+                                               const char *interface)
+{
+       GList *list;
+
+       for (list = g_list_first(client->proxy_list); list;
+                                               list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+
+               if (g_str_equal(proxy->interface, interface) == TRUE &&
+                               g_str_equal(proxy->obj_path, path) == TRUE) {
+                       client->proxy_list =
+                               g_list_delete_link(client->proxy_list, list);
+                       proxy_free(proxy);
+                       break;
+               }
+       }
+}
+
+GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
+                                                       const char *interface)
+{
+       GDBusProxy *proxy;
+
+       if (client == NULL)
+               return NULL;
+
+       proxy = proxy_lookup(client, path, interface);
+       if (proxy)
+               return g_dbus_proxy_ref(proxy);
+
+       proxy = proxy_new(client, path, interface);
+       if (proxy == NULL)
+               return NULL;
+
+       get_all_properties(proxy);
+
+       return g_dbus_proxy_ref(proxy);
+}
+
+GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy)
+{
+       if (proxy == NULL)
+               return NULL;
+
+       __sync_fetch_and_add(&proxy->ref_count, 1);
+
+       return proxy;
+}
+
+void g_dbus_proxy_unref(GDBusProxy *proxy)
+{
+       if (proxy == NULL)
+               return;
+
+       if (__sync_sub_and_fetch(&proxy->ref_count, 1) > 0)
+               return;
+
+       g_hash_table_destroy(proxy->prop_list);
+
+       g_free(proxy->obj_path);
+       g_free(proxy->interface);
+
+       g_free(proxy);
+}
+
+const char *g_dbus_proxy_get_path(GDBusProxy *proxy)
+{
+       if (proxy == NULL)
+               return NULL;
+
+       return proxy->obj_path;
+}
+
+const char *g_dbus_proxy_get_interface(GDBusProxy *proxy)
+{
+       if (proxy == NULL)
+               return NULL;
+
+       return proxy->interface;
+}
+
+gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
+                                                        DBusMessageIter *iter)
+{
+       struct prop_entry *prop;
+
+       if (proxy == NULL || name == NULL)
+               return FALSE;
+
+       prop = g_hash_table_lookup(proxy->prop_list, name);
+       if (prop == NULL)
+               return FALSE;
+
+       if (prop->msg == NULL)
+               return FALSE;
+
+       if (dbus_message_iter_init(prop->msg, iter) == FALSE)
+               return FALSE;
+
+       return TRUE;
+}
+
+struct refresh_property_data {
+       GDBusProxy *proxy;
+       char *name;
+};
+
+static void refresh_property_free(gpointer user_data)
+{
+       struct refresh_property_data *data = user_data;
+
+       g_free(data->name);
+       g_free(data);
+}
+
+static void refresh_property_reply(DBusPendingCall *call, void *user_data)
+{
+       struct refresh_property_data *data = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == FALSE) {
+               DBusMessageIter iter;
+
+               dbus_message_iter_init(reply, &iter);
+
+               add_property(data->proxy, data->name, &iter, TRUE);
+       } else
+               dbus_error_free(&error);
+
+       dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name)
+{
+       struct refresh_property_data *data;
+       GDBusClient *client;
+       DBusMessage *msg;
+       DBusMessageIter iter;
+       DBusPendingCall *call;
+
+       if (proxy == NULL || name == NULL)
+               return FALSE;
+
+       client = proxy->client;
+       if (client == NULL)
+               return FALSE;
+
+       data = g_try_new0(struct refresh_property_data, 1);
+       if (data == NULL)
+               return FALSE;
+
+       data->proxy = proxy;
+       data->name = g_strdup(name);
+
+       msg = dbus_message_new_method_call(client->service_name,
+                       proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Get");
+       if (msg == NULL) {
+               refresh_property_free(data);
+               return FALSE;
+       }
+
+       dbus_message_iter_init_append(msg, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+                                                       &proxy->interface);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                                                       &call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               refresh_property_free(data);
+               return FALSE;
+       }
+
+       dbus_pending_call_set_notify(call, refresh_property_reply,
+                                               data, refresh_property_free);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+
+       return TRUE;
+}
+
+struct set_property_data {
+       GDBusResultFunction function;
+       void *user_data;
+       GDBusDestroyFunction destroy;
+};
+
+static void set_property_reply(DBusPendingCall *call, void *user_data)
+{
+       struct set_property_data *data = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       dbus_set_error_from_message(&error, reply);
+
+       if (data->function)
+               data->function(&error, data->user_data);
+
+       if (data->destroy)
+               data->destroy(data->user_data);
+
+       dbus_error_free(&error);
+
+       dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
+                               const char *name, int type, const void *value,
+                               GDBusResultFunction function, void *user_data,
+                               GDBusDestroyFunction destroy)
+{
+       struct set_property_data *data;
+       GDBusClient *client;
+       DBusMessage *msg;
+       DBusMessageIter iter, variant;
+       DBusPendingCall *call;
+       char type_as_str[2];
+
+       if (proxy == NULL || name == NULL || value == NULL)
+               return FALSE;
+
+       if (dbus_type_is_basic(type) == FALSE)
+               return FALSE;
+
+       client = proxy->client;
+       if (client == NULL)
+               return FALSE;
+
+       data = g_try_new0(struct set_property_data, 1);
+       if (data == NULL)
+               return FALSE;
+
+       data->function = function;
+       data->user_data = user_data;
+       data->destroy = destroy;
+
+       msg = dbus_message_new_method_call(client->service_name,
+                       proxy->obj_path, DBUS_INTERFACE_PROPERTIES, "Set");
+       if (msg == NULL) {
+               g_free(data);
+               return FALSE;
+       }
+
+       type_as_str[0] = (char) type;
+       type_as_str[1] = '\0';
+
+       dbus_message_iter_init_append(msg, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+                                                       &proxy->interface);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                               type_as_str, &variant);
+       dbus_message_iter_append_basic(&variant, type, value);
+       dbus_message_iter_close_container(&iter, &variant);
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                                                       &call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               g_free(data);
+               return FALSE;
+       }
+
+       dbus_pending_call_set_notify(call, set_property_reply, data, g_free);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+
+       return TRUE;
+}
+
+struct method_call_data {
+       GDBusReturnFunction function;
+       void *user_data;
+       GDBusDestroyFunction destroy;
+};
+
+static void method_call_reply(DBusPendingCall *call, void *user_data)
+{
+       struct method_call_data *data = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+
+       if (data->function)
+               data->function(reply, data->user_data);
+
+       if (data->destroy)
+               data->destroy(data->user_data);
+
+       dbus_message_unref(reply);
+}
+
+gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
+                               GDBusSetupFunction setup,
+                               GDBusReturnFunction function, void *user_data,
+                               GDBusDestroyFunction destroy)
+{
+       struct method_call_data *data;
+       GDBusClient *client;
+       DBusMessage *msg;
+       DBusPendingCall *call;
+
+       if (proxy == NULL || method == NULL)
+               return FALSE;
+
+       client = proxy->client;
+       if (client == NULL)
+               return FALSE;
+
+       data = g_try_new0(struct method_call_data, 1);
+       if (data == NULL)
+               return FALSE;
+
+       data->function = function;
+       data->user_data = user_data;
+       data->destroy = destroy;
+
+       msg = dbus_message_new_method_call(client->service_name,
+                               proxy->obj_path, proxy->interface, method);
+       if (msg == NULL) {
+               g_free(data);
+               return FALSE;
+       }
+
+       if (setup) {
+               DBusMessageIter iter;
+
+               dbus_message_iter_init_append(msg, &iter);
+               setup(&iter, data->user_data);
+       }
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                                       &call, METHOD_CALL_TIMEOUT) == FALSE) {
+               dbus_message_unref(msg);
+               g_free(data);
+               return FALSE;
+       }
+
+       dbus_pending_call_set_notify(call, method_call_reply, data, g_free);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(msg);
+
+       return TRUE;
+}
+
+gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
+                       GDBusPropertyFunction function, void *user_data)
+{
+       if (proxy == NULL)
+               return FALSE;
+
+       proxy->prop_func = function;
+       proxy->prop_data = user_data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
+                               GDBusProxyFunction function, void *user_data)
+{
+       if (proxy == NULL)
+               return FALSE;
+
+       proxy->removed_func = function;
+       proxy->removed_data = user_data;
+
+       return TRUE;
+}
+
+static void refresh_properties(GDBusClient *client)
+{
+       GList *list;
+
+       for (list = g_list_first(client->proxy_list); list;
+                                               list = g_list_next(list)) {
+               GDBusProxy *proxy = list->data;
+
+               get_all_properties(proxy);
+        }
+}
+
+static void parse_properties(GDBusClient *client, const char *path,
+                               const char *interface, DBusMessageIter *iter)
+{
+       GDBusProxy *proxy;
+
+       if (g_str_equal(interface, DBUS_INTERFACE_INTROSPECTABLE) == TRUE)
+               return;
+
+       if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
+               return;
+
+       proxy = proxy_lookup(client, path, interface);
+       if (proxy) {
+               update_properties(proxy, iter, FALSE);
+               return;
+       }
+
+       proxy = proxy_new(client, path, interface);
+       if (proxy == NULL)
+               return;
+
+       update_properties(proxy, iter, FALSE);
+
+       if (client->proxy_added)
+               client->proxy_added(proxy, client->user_data);
+
+       client->proxy_list = g_list_append(client->proxy_list, proxy);
+}
+
+static void parse_interfaces(GDBusClient *client, const char *path,
+                                               DBusMessageIter *iter)
+{
+       DBusMessageIter dict;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(iter, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry;
+               const char *interface;
+
+               dbus_message_iter_recurse(&dict, &entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       break;
+
+               dbus_message_iter_get_basic(&entry, &interface);
+               dbus_message_iter_next(&entry);
+
+               parse_properties(client, path, interface, &entry);
+
+               dbus_message_iter_next(&dict);
+       }
+}
+
+static gboolean interfaces_added(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       GDBusClient *client = user_data;
+       DBusMessageIter iter;
+       const char *path;
+
+       if (dbus_message_iter_init(msg, &iter) == FALSE)
+               return TRUE;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &path);
+       dbus_message_iter_next(&iter);
+
+       g_dbus_client_ref(client);
+
+       parse_interfaces(client, path, &iter);
+
+       g_dbus_client_unref(client);
+
+       return TRUE;
+}
+
+static gboolean interfaces_removed(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       GDBusClient *client = user_data;
+       DBusMessageIter iter, entry;
+       const char *path;
+
+       if (dbus_message_iter_init(msg, &iter) == FALSE)
+               return TRUE;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_OBJECT_PATH)
+               return TRUE;
+
+       dbus_message_iter_get_basic(&iter, &path);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return TRUE;
+
+       dbus_message_iter_recurse(&iter, &entry);
+
+       g_dbus_client_ref(client);
+
+       while (dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING) {
+               const char *interface;
+
+               dbus_message_iter_get_basic(&entry, &interface);
+               proxy_remove(client, path, interface);
+               dbus_message_iter_next(&entry);
+       }
+
+       g_dbus_client_unref(client);
+
+       return TRUE;
+}
+
+static void parse_managed_objects(GDBusClient *client, DBusMessage *msg)
+{
+       DBusMessageIter iter, dict;
+
+       if (dbus_message_iter_init(msg, &iter) == FALSE)
+               return;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(&iter, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry;
+               const char *path;
+
+               dbus_message_iter_recurse(&dict, &entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) !=
+                                                       DBUS_TYPE_OBJECT_PATH)
+                       break;
+
+               dbus_message_iter_get_basic(&entry, &path);
+               dbus_message_iter_next(&entry);
+
+               parse_interfaces(client, path, &entry);
+
+               dbus_message_iter_next(&dict);
+       }
+}
+
+static void get_managed_objects_reply(DBusPendingCall *call, void *user_data)
+{
+       GDBusClient *client = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError error;
+
+       g_dbus_client_ref(client);
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, reply) == TRUE) {
+               dbus_error_free(&error);
+               goto done;
+       }
+
+       parse_managed_objects(client, reply);
+
+done:
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(client->get_objects_call);
+       client->get_objects_call = NULL;
+
+       g_dbus_client_unref(client);
+}
+
+static void get_managed_objects(GDBusClient *client)
+{
+       DBusMessage *msg;
+
+       if (!client->proxy_added && !client->proxy_removed) {
+               refresh_properties(client);
+               return;
+       }
+
+       if (client->get_objects_call != NULL)
+               return;
+
+       msg = dbus_message_new_method_call(client->service_name, "/",
+                                       DBUS_INTERFACE_DBUS ".ObjectManager",
+                                                       "GetManagedObjects");
+       if (msg == NULL)
+               return;
+
+       dbus_message_append_args(msg, DBUS_TYPE_INVALID);
+
+       if (g_dbus_send_message_with_reply(client->dbus_conn, msg,
+                               &client->get_objects_call, -1) == FALSE) {
+               dbus_message_unref(msg);
+               return;
+       }
+
+       dbus_pending_call_set_notify(client->get_objects_call,
+                                               get_managed_objects_reply,
+                                               client, NULL);
+
+       dbus_message_unref(msg);
+}
+
+static void service_connect(DBusConnection *conn, void *user_data)
+{
+       GDBusClient *client = user_data;
+
+       g_dbus_client_ref(client);
+
+       if (client->connect_func)
+               client->connect_func(conn, client->connect_data);
+
+       get_managed_objects(client);
+
+       g_dbus_client_unref(client);
+}
+
+static void service_disconnect(DBusConnection *conn, void *user_data)
+{
+       GDBusClient *client = user_data;
+
+       g_list_free_full(client->proxy_list, proxy_free);
+       client->proxy_list = NULL;
+
+       if (client->disconn_func)
+               client->disconn_func(conn, client->disconn_data);
+}
+
+static DBusHandlerResult message_filter(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       GDBusClient *client = user_data;
+       const char *sender, *path, *interface;
+
+       if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       sender = dbus_message_get_sender(message);
+       if (sender == NULL)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       path = dbus_message_get_path(message);
+       interface = dbus_message_get_interface(message);
+
+       if (g_str_has_prefix(path, client->base_path) == FALSE)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       if (g_str_equal(interface, DBUS_INTERFACE_PROPERTIES) == TRUE)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       if (client->signal_func)
+               client->signal_func(connection, message, client->signal_data);
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+GDBusClient *g_dbus_client_new(DBusConnection *connection,
+                                       const char *service, const char *path)
+{
+       GDBusClient *client;
+       unsigned int i;
+
+       if (connection == NULL)
+               return NULL;
+
+       client = g_try_new0(GDBusClient, 1);
+       if (client == NULL)
+               return NULL;
+
+       if (dbus_connection_add_filter(connection, message_filter,
+                                               client, NULL) == FALSE) {
+               g_free(client);
+               return NULL;
+       }
+
+       client->dbus_conn = dbus_connection_ref(connection);
+       client->service_name = g_strdup(service);
+       client->base_path = g_strdup(path);
+
+       client->match_rules = g_ptr_array_sized_new(1);
+       g_ptr_array_set_free_func(client->match_rules, g_free);
+
+       client->watch = g_dbus_add_service_watch(connection, service,
+                                               service_connect,
+                                               service_disconnect,
+                                               client, NULL);
+       client->added_watch = g_dbus_add_signal_watch(connection, service,
+                                               "/",
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "InterfacesAdded",
+                                               interfaces_added,
+                                               client, NULL);
+       client->removed_watch = g_dbus_add_signal_watch(connection, service,
+                                               "/",
+                                               DBUS_INTERFACE_OBJECT_MANAGER,
+                                               "InterfacesRemoved",
+                                               interfaces_removed,
+                                               client, NULL);
+       g_ptr_array_add(client->match_rules, g_strdup_printf("type='signal',"
+                               "sender='%s',path_namespace='%s'",
+                               client->service_name, client->base_path));
+
+       for (i = 0; i < client->match_rules->len; i++) {
+               modify_match(client->dbus_conn, "AddMatch",
+                               g_ptr_array_index(client->match_rules, i));
+       }
+
+       return g_dbus_client_ref(client);
+}
+
+GDBusClient *g_dbus_client_ref(GDBusClient *client)
+{
+       if (client == NULL)
+               return NULL;
+
+       __sync_fetch_and_add(&client->ref_count, 1);
+
+       return client;
+}
+
+void g_dbus_client_unref(GDBusClient *client)
+{
+       unsigned int i;
+
+       if (client == NULL)
+               return;
+
+       if (__sync_sub_and_fetch(&client->ref_count, 1) > 0)
+               return;
+
+       if (client->pending_call != NULL) {
+               dbus_pending_call_cancel(client->pending_call);
+               dbus_pending_call_unref(client->pending_call);
+       }
+
+       if (client->get_objects_call != NULL) {
+               dbus_pending_call_cancel(client->get_objects_call);
+               dbus_pending_call_unref(client->get_objects_call);
+       }
+
+       for (i = 0; i < client->match_rules->len; i++) {
+               modify_match(client->dbus_conn, "RemoveMatch",
+                               g_ptr_array_index(client->match_rules, i));
+       }
+
+       g_ptr_array_free(client->match_rules, TRUE);
+
+       dbus_connection_remove_filter(client->dbus_conn,
+                                               message_filter, client);
+
+       g_list_free_full(client->proxy_list, proxy_free);
+
+       if (client->disconn_func)
+               client->disconn_func(client->dbus_conn, client->disconn_data);
+
+       g_dbus_remove_watch(client->dbus_conn, client->watch);
+       g_dbus_remove_watch(client->dbus_conn, client->added_watch);
+       g_dbus_remove_watch(client->dbus_conn, client->removed_watch);
+
+       dbus_connection_unref(client->dbus_conn);
+
+       g_free(client->service_name);
+       g_free(client->base_path);
+
+       g_free(client);
+}
+
+gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
+                               GDBusWatchFunction function, void *user_data)
+{
+       if (client == NULL)
+               return FALSE;
+
+       client->connect_func = function;
+       client->connect_data = user_data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
+                               GDBusWatchFunction function, void *user_data)
+{
+       if (client == NULL)
+               return FALSE;
+
+       client->disconn_func = function;
+       client->disconn_data = user_data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
+                               GDBusMessageFunction function, void *user_data)
+{
+       if (client == NULL)
+               return FALSE;
+
+       client->signal_func = function;
+       client->signal_data = user_data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
+                                       GDBusProxyFunction proxy_added,
+                                       GDBusProxyFunction proxy_removed,
+                                       GDBusPropertyFunction property_changed,
+                                       void *user_data)
+{
+       if (client == NULL)
+               return FALSE;
+
+       client->proxy_added = proxy_added;
+       client->proxy_removed = proxy_removed;
+       client->property_changed = property_changed;
+       client->user_data = user_data;
+
+       get_managed_objects(client);
+
+       return TRUE;
+}
index 0a8a27c..9542109 100644 (file)
@@ -31,9 +31,23 @@ extern "C" {
 #include <dbus/dbus.h>
 #include <glib.h>
 
+typedef enum GDBusMethodFlags GDBusMethodFlags;
+typedef enum GDBusSignalFlags GDBusSignalFlags;
+typedef enum GDBusPropertyFlags GDBusPropertyFlags;
+typedef enum GDBusSecurityFlags GDBusSecurityFlags;
+
+typedef struct GDBusArgInfo GDBusArgInfo;
+typedef struct GDBusMethodTable GDBusMethodTable;
+typedef struct GDBusSignalTable GDBusSignalTable;
+typedef struct GDBusPropertyTable GDBusPropertyTable;
+typedef struct GDBusSecurityTable GDBusSecurityTable;
+
 typedef void (* GDBusWatchFunction) (DBusConnection *connection,
                                                        void *user_data);
 
+typedef void (* GDBusMessageFunction) (DBusConnection *connection,
+                                        DBusMessage *message, void *user_data);
+
 typedef gboolean (* GDBusSignalFunction) (DBusConnection *connection,
                                        DBusMessage *message, void *user_data);
 
@@ -55,6 +69,18 @@ typedef void (* GDBusDestroyFunction) (void *user_data);
 typedef DBusMessage * (* GDBusMethodFunction) (DBusConnection *connection,
                                        DBusMessage *message, void *user_data);
 
+typedef gboolean (*GDBusPropertyGetter)(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data);
+
+typedef guint32 GDBusPendingPropertySet;
+
+typedef void (*GDBusPropertySetter)(const GDBusPropertyTable *property,
+                       DBusMessageIter *value, GDBusPendingPropertySet id,
+                       void *data);
+
+typedef gboolean (*GDBusPropertyExists)(const GDBusPropertyTable *property,
+                                                               void *data);
+
 typedef guint32 GDBusPendingReply;
 
 typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
@@ -62,58 +88,68 @@ typedef void (* GDBusSecurityFunction) (DBusConnection *connection,
                                                gboolean interaction,
                                                GDBusPendingReply pending);
 
-typedef enum {
-       G_DBUS_METHOD_FLAG_DEPRECATED = (1 << 0),
-       G_DBUS_METHOD_FLAG_NOREPLY    = (1 << 1),
-       G_DBUS_METHOD_FLAG_ASYNC      = (1 << 2),
-} GDBusMethodFlags;
+enum GDBusFlags {
+       G_DBUS_FLAG_ENABLE_EXPERIMENTAL = (1 << 0),
+};
 
-typedef enum {
-       G_DBUS_SIGNAL_FLAG_DEPRECATED = (1 << 0),
-} GDBusSignalFlags;
+enum GDBusMethodFlags {
+       G_DBUS_METHOD_FLAG_DEPRECATED   = (1 << 0),
+       G_DBUS_METHOD_FLAG_NOREPLY      = (1 << 1),
+       G_DBUS_METHOD_FLAG_ASYNC        = (1 << 2),
+       G_DBUS_METHOD_FLAG_EXPERIMENTAL = (1 << 3),
+};
 
-typedef enum {
-       G_DBUS_PROPERTY_FLAG_DEPRECATED = (1 << 0),
-} GDBusPropertyFlags;
+enum GDBusSignalFlags {
+       G_DBUS_SIGNAL_FLAG_DEPRECATED   = (1 << 0),
+       G_DBUS_SIGNAL_FLAG_EXPERIMENTAL = (1 << 1),
+};
 
-typedef enum {
+enum GDBusPropertyFlags {
+       G_DBUS_PROPERTY_FLAG_DEPRECATED   = (1 << 0),
+       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL = (1 << 1),
+};
+
+enum GDBusSecurityFlags {
        G_DBUS_SECURITY_FLAG_DEPRECATED        = (1 << 0),
        G_DBUS_SECURITY_FLAG_BUILTIN           = (1 << 1),
        G_DBUS_SECURITY_FLAG_ALLOW_INTERACTION = (1 << 2),
-} GDBusSecurityFlags;
+};
 
-typedef struct {
+struct GDBusArgInfo {
        const char *name;
        const char *signature;
-} GDBusArgInfo;
+};
 
-typedef struct {
+struct GDBusMethodTable {
        const char *name;
        GDBusMethodFunction function;
        GDBusMethodFlags flags;
        unsigned int privilege;
        const GDBusArgInfo *in_args;
        const GDBusArgInfo *out_args;
-} GDBusMethodTable;
+};
 
-typedef struct {
+struct GDBusSignalTable {
        const char *name;
        GDBusSignalFlags flags;
        const GDBusArgInfo *args;
-} GDBusSignalTable;
+};
 
-typedef struct {
+struct GDBusPropertyTable {
        const char *name;
        const char *type;
+       GDBusPropertyGetter get;
+       GDBusPropertySetter set;
+       GDBusPropertyExists exists;
        GDBusPropertyFlags flags;
-} GDBusPropertyTable;
+};
 
-typedef struct {
+struct GDBusSecurityTable {
        unsigned int privilege;
        const char *action;
        GDBusSecurityFlags flags;
        GDBusSecurityFunction function;
-} GDBusSecurityTable;
+};
 
 #define GDBUS_ARGS(args...) (const GDBusArgInfo[]) { args, { } }
 
@@ -144,6 +180,20 @@ typedef struct {
        .function = _function, \
        .flags = G_DBUS_METHOD_FLAG_ASYNC | G_DBUS_METHOD_FLAG_DEPRECATED
 
+#define GDBUS_EXPERIMENTAL_METHOD(_name, _in_args, _out_args, _function) \
+       .name = _name, \
+       .in_args = _in_args, \
+       .out_args = _out_args, \
+       .function = _function, \
+       .flags = G_DBUS_METHOD_FLAG_EXPERIMENTAL
+
+#define GDBUS_EXPERIMENTAL_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_EXPERIMENTAL
+
 #define GDBUS_NOREPLY_METHOD(_name, _in_args, _out_args, _function) \
        .name = _name, \
        .in_args = _in_args, \
@@ -160,6 +210,13 @@ typedef struct {
        .args = _args, \
        .flags = G_DBUS_SIGNAL_FLAG_DEPRECATED
 
+#define GDBUS_EXPERIMENTAL_SIGNAL(_name, _args) \
+       .name = _name, \
+       .args = _args, \
+       .flags = G_DBUS_SIGNAL_FLAG_EXPERIMENTAL
+
+void g_dbus_set_flags(int flags);
+
 gboolean g_dbus_register_interface(DBusConnection *connection,
                                        const char *path, const char *name,
                                        const GDBusMethodTable *methods,
@@ -193,6 +250,15 @@ DBusMessage *g_dbus_create_reply_valist(DBusMessage *message,
                                                int type, va_list args);
 
 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message);
+gboolean g_dbus_send_message_with_reply(DBusConnection *connection,
+                                       DBusMessage *message,
+                                       DBusPendingCall **call, int timeout);
+gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
+                               const char *name, const char *format, ...)
+                                        __attribute__((format(printf, 4, 5)));
+gboolean g_dbus_send_error_valist(DBusConnection *connection,
+                                       DBusMessage *message, const char *name,
+                                       const char *format, va_list args);
 gboolean g_dbus_send_reply(DBusConnection *connection,
                                DBusMessage *message, int type, ...);
 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
@@ -217,9 +283,89 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
                                const char *interface, const char *member,
                                GDBusSignalFunction function, void *user_data,
                                GDBusDestroyFunction destroy);
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+                               const char *sender, const char *path,
+                               const char *interface,
+                               GDBusSignalFunction function, void *user_data,
+                               GDBusDestroyFunction destroy);
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint tag);
 void g_dbus_remove_all_watches(DBusConnection *connection);
 
+void g_dbus_pending_property_success(GDBusPendingPropertySet id);
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+                       const char *name, const char *format, va_list args);
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+                                               const char *format, ...);
+void g_dbus_emit_property_changed(DBusConnection *connection,
+                               const char *path, const char *interface,
+                               const char *name);
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+                               const char *interface, DBusMessageIter *iter);
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection);
+gboolean g_dbus_detach_object_manager(DBusConnection *connection);
+
+typedef struct GDBusClient GDBusClient;
+typedef struct GDBusProxy GDBusProxy;
+
+GDBusProxy *g_dbus_proxy_new(GDBusClient *client, const char *path,
+                                                       const char *interface);
+
+GDBusProxy *g_dbus_proxy_ref(GDBusProxy *proxy);
+void g_dbus_proxy_unref(GDBusProxy *proxy);
+
+const char *g_dbus_proxy_get_path(GDBusProxy *proxy);
+const char *g_dbus_proxy_get_interface(GDBusProxy *proxy);
+
+gboolean g_dbus_proxy_get_property(GDBusProxy *proxy, const char *name,
+                                                       DBusMessageIter *iter);
+
+gboolean g_dbus_proxy_refresh_property(GDBusProxy *proxy, const char *name);
+
+typedef void (* GDBusResultFunction) (const DBusError *error, void *user_data);
+
+gboolean g_dbus_proxy_set_property_basic(GDBusProxy *proxy,
+                               const char *name, int type, const void *value,
+                               GDBusResultFunction function, void *user_data,
+                               GDBusDestroyFunction destroy);
+
+typedef void (* GDBusSetupFunction) (DBusMessageIter *iter, void *user_data);
+typedef void (* GDBusReturnFunction) (DBusMessage *message, void *user_data);
+
+gboolean g_dbus_proxy_method_call(GDBusProxy *proxy, const char *method,
+                               GDBusSetupFunction setup,
+                               GDBusReturnFunction function, void *user_data,
+                               GDBusDestroyFunction destroy);
+
+typedef void (* GDBusProxyFunction) (GDBusProxy *proxy, void *user_data);
+typedef void (* GDBusPropertyFunction) (GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data);
+
+gboolean g_dbus_proxy_set_property_watch(GDBusProxy *proxy,
+                       GDBusPropertyFunction function, void *user_data);
+
+gboolean g_dbus_proxy_set_removed_watch(GDBusProxy *proxy,
+                       GDBusProxyFunction destroy, void *user_data);
+
+GDBusClient *g_dbus_client_new(DBusConnection *connection,
+                                       const char *service, const char *path);
+
+GDBusClient *g_dbus_client_ref(GDBusClient *client);
+void g_dbus_client_unref(GDBusClient *client);
+
+gboolean g_dbus_client_set_connect_watch(GDBusClient *client,
+                               GDBusWatchFunction function, void *user_data);
+gboolean g_dbus_client_set_disconnect_watch(GDBusClient *client,
+                               GDBusWatchFunction function, void *user_data);
+gboolean g_dbus_client_set_signal_watch(GDBusClient *client,
+                               GDBusMessageFunction function, void *user_data);
+
+gboolean g_dbus_client_set_proxy_handlers(GDBusClient *client,
+                                       GDBusProxyFunction proxy_added,
+                                       GDBusProxyFunction proxy_removed,
+                                       GDBusPropertyFunction property_changed,
+                                       void *user_data);
+
 #ifdef __cplusplus
 }
 #endif
index cff326f..099b67f 100644 (file)
@@ -92,8 +92,9 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
        struct watch_info *info = data;
        unsigned int flags = 0;
        DBusDispatchStatus status;
+       DBusConnection *conn;
 
-       dbus_connection_ref(info->conn);
+       conn = dbus_connection_ref(info->conn);
 
        if (cond & G_IO_IN)  flags |= DBUS_WATCH_READABLE;
        if (cond & G_IO_OUT) flags |= DBUS_WATCH_WRITABLE;
@@ -102,10 +103,10 @@ static gboolean watch_func(GIOChannel *chan, GIOCondition cond, gpointer data)
 
        dbus_watch_handle(info->watch, flags);
 
-       status = dbus_connection_get_dispatch_status(info->conn);
-       queue_dispatch(info->conn, status);
+       status = dbus_connection_get_dispatch_status(conn);
+       queue_dispatch(conn, status);
 
-       dbus_connection_unref(info->conn);
+       dbus_connection_unref(conn);
 
        return TRUE;
 }
index 900e7ab..268fed5 100644 (file)
 #define error(fmt...)
 #define debug(fmt...)
 
+#define DBUS_INTERFACE_OBJECT_MANAGER "org.freedesktop.DBus.ObjectManager"
+
+#ifndef DBUS_ERROR_UNKNOWN_PROPERTY
+#define DBUS_ERROR_UNKNOWN_PROPERTY "org.freedesktop.DBus.Error.UnknownProperty"
+#endif
+
+#ifndef DBUS_ERROR_PROPERTY_READ_ONLY
+#define DBUS_ERROR_PROPERTY_READ_ONLY "org.freedesktop.DBus.Error.PropertyReadOnly"
+#endif
+
 struct generic_data {
        unsigned int refcount;
+       DBusConnection *conn;
+       char *path;
        GSList *interfaces;
+       GSList *objects;
+       GSList *added;
+       GSList *removed;
+       guint process_id;
+       gboolean pending_prop;
        char *introspect;
+       struct generic_data *parent;
 };
 
 struct interface_data {
@@ -48,6 +66,7 @@ struct interface_data {
        const GDBusMethodTable *methods;
        const GDBusSignalTable *signals;
        const GDBusPropertyTable *properties;
+       GSList *pending_prop;
        void *user_data;
        GDBusDestroyFunction destroy;
 };
@@ -59,12 +78,27 @@ struct security_data {
        void *iface_user_data;
 };
 
+struct property_data {
+       DBusConnection *conn;
+       GDBusPendingPropertySet id;
+       DBusMessage *message;
+};
+
+static int global_flags = 0;
+static struct generic_data *root;
+static GSList *pending = NULL;
+
+static gboolean process_changes(gpointer user_data);
+static void process_properties_from_interface(struct generic_data *data,
+                                               struct interface_data *iface);
+static void process_property_changes(struct generic_data *data);
+
 static void print_arguments(GString *gstr, const GDBusArgInfo *args,
                                                const char *direction)
 {
        for (; args && args->name; args++) {
                g_string_append_printf(gstr,
-                                       "\t\t\t<arg name=\"%s\" type=\"%s\"",
+                                       "<arg name=\"%s\" type=\"%s\"",
                                        args->name, args->signature);
 
                if (direction)
@@ -76,55 +110,83 @@ static void print_arguments(GString *gstr, const GDBusArgInfo *args,
        }
 }
 
+#define G_DBUS_ANNOTATE(name_, value_)                         \
+       "<annotation name=\"org.freedesktop.DBus." name_ "\" "  \
+       "value=\"" value_ "\"/>"
+
+#define G_DBUS_ANNOTATE_DEPRECATED \
+       G_DBUS_ANNOTATE("Deprecated", "true")
+
+#define G_DBUS_ANNOTATE_NOREPLY \
+       G_DBUS_ANNOTATE("Method.NoReply", "true")
+
+static gboolean check_experimental(int flags, int flag)
+{
+       if (!(flags & flag))
+               return FALSE;
+
+       return !(global_flags & G_DBUS_FLAG_ENABLE_EXPERIMENTAL);
+}
+
 static void generate_interface_xml(GString *gstr, struct interface_data *iface)
 {
        const GDBusMethodTable *method;
        const GDBusSignalTable *signal;
+       const GDBusPropertyTable *property;
 
        for (method = iface->methods; method && method->name; method++) {
-               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",
+               if (check_experimental(method->flags,
+                                       G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+                       continue;
+
+               g_string_append_printf(gstr, "<method name=\"%s\">",
                                                                method->name);
-                       print_arguments(gstr, method->in_args, "in");
-                       print_arguments(gstr, method->out_args, "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 (method->flags & G_DBUS_METHOD_FLAG_DEPRECATED)
+                       g_string_append_printf(gstr,
+                                               G_DBUS_ANNOTATE_DEPRECATED);
 
-                       if (noreply)
-                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Method.NoReply\" value=\"true\"/>\n");
+               if (method->flags & G_DBUS_METHOD_FLAG_NOREPLY)
+                       g_string_append_printf(gstr, G_DBUS_ANNOTATE_NOREPLY);
 
-                       g_string_append_printf(gstr, "\t\t</method>\n");
-               }
+               g_string_append_printf(gstr, "</method>");
        }
 
        for (signal = iface->signals; signal && signal->name; signal++) {
-               gboolean deprecated = signal->flags &
-                                               G_DBUS_SIGNAL_FLAG_DEPRECATED;
+               if (check_experimental(signal->flags,
+                                       G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
+                       continue;
 
-               if (!deprecated && !(signal->args && signal->args->name))
-                       g_string_append_printf(gstr, "\t\t<signal name=\"%s\"/>\n",
+               g_string_append_printf(gstr, "<signal name=\"%s\">",
                                                                signal->name);
-               else {
-                       g_string_append_printf(gstr, "\t\t<signal name=\"%s\">\n",
-                                                               signal->name);
-                       print_arguments(gstr, signal->args, NULL);
+               print_arguments(gstr, signal->args, NULL);
+
+               if (signal->flags & G_DBUS_SIGNAL_FLAG_DEPRECATED)
+                       g_string_append_printf(gstr,
+                                               G_DBUS_ANNOTATE_DEPRECATED);
 
-                       if (deprecated)
-                               g_string_append_printf(gstr, "\t\t\t<annotation name=\"org.freedesktop.DBus.Deprecated\" value=\"true\"/>\n");
+               g_string_append_printf(gstr, "</signal>\n");
+       }
 
-                       g_string_append_printf(gstr, "\t\t</signal>\n");
-               }
+       for (property = iface->properties; property && property->name;
+                                                               property++) {
+               if (check_experimental(property->flags,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+                       continue;
+
+               g_string_append_printf(gstr, "<property name=\"%s\""
+                                       " type=\"%s\" access=\"%s%s\">",
+                                       property->name, property->type,
+                                       property->get ? "read" : "",
+                                       property->set ? "write" : "");
+
+               if (property->flags & G_DBUS_PROPERTY_FLAG_DEPRECATED)
+                       g_string_append_printf(gstr,
+                                               G_DBUS_ANNOTATE_DEPRECATED);
+
+               g_string_append_printf(gstr, "</property>");
        }
 }
 
@@ -140,30 +202,30 @@ static void generate_introspection_xml(DBusConnection *conn,
 
        gstr = g_string_new(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE);
 
-       g_string_append_printf(gstr, "<node>\n");
+       g_string_append_printf(gstr, "<node>");
 
        for (list = data->interfaces; list; list = list->next) {
                struct interface_data *iface = list->data;
 
-               g_string_append_printf(gstr, "\t<interface name=\"%s\">\n",
+               g_string_append_printf(gstr, "<interface name=\"%s\">",
                                                                iface->name);
 
                generate_interface_xml(gstr, iface);
 
-               g_string_append_printf(gstr, "\t</interface>\n");
+               g_string_append_printf(gstr, "</interface>");
        }
 
        if (!dbus_connection_list_registered(conn, path, &children))
                goto done;
 
        for (i = 0; children[i]; i++)
-               g_string_append_printf(gstr, "\t<node name=\"%s\"/>\n",
+               g_string_append_printf(gstr, "<node name=\"%s\"/>",
                                                                children[i]);
 
        dbus_free_string_array(children);
 
 done:
-       g_string_append_printf(gstr, "</node>\n");
+       g_string_append_printf(gstr, "</node>");
 
        data->introspect = g_string_free(gstr, FALSE);
 }
@@ -210,8 +272,7 @@ static DBusHandlerResult process_message(DBusConnection *connection,
        if (reply == NULL)
                return DBUS_HANDLER_RESULT_NEED_MEMORY;
 
-       dbus_connection_send(connection, reply, NULL);
-       dbus_message_unref(reply);
+       g_dbus_send_message(connection, reply);
 
        return DBUS_HANDLER_RESULT_HANDLED;
 }
@@ -226,7 +287,7 @@ void g_dbus_pending_success(DBusConnection *connection,
 {
        GSList *list;
 
-        for (list = pending_security; list; list = list->next) {
+       for (list = pending_security; list; list = list->next) {
                struct security_data *secdata = list->data;
 
                if (secdata->pending != pending)
@@ -240,7 +301,7 @@ void g_dbus_pending_success(DBusConnection *connection,
                dbus_message_unref(secdata->message);
                g_free(secdata);
                return;
-        }
+       }
 }
 
 void g_dbus_pending_error_valist(DBusConnection *connection,
@@ -249,26 +310,21 @@ void g_dbus_pending_error_valist(DBusConnection *connection,
 {
        GSList *list;
 
-        for (list = pending_security; list; list = list->next) {
+       for (list = pending_security; list; list = list->next) {
                struct security_data *secdata = list->data;
-               DBusMessage *reply;
 
                if (secdata->pending != pending)
                        continue;
 
                pending_security = g_slist_remove(pending_security, secdata);
 
-               reply = g_dbus_create_error_valist(secdata->message,
+               g_dbus_send_error_valist(connection, secdata->message,
                                                        name, format, args);
-               if (reply != NULL) {
-                       dbus_connection_send(connection, reply, NULL);
-                       dbus_message_unref(reply);
-               }
 
                dbus_message_unref(secdata->message);
                g_free(secdata);
                return;
-        }
+       }
 }
 
 void g_dbus_pending_error(DBusConnection *connection,
@@ -364,12 +420,178 @@ static gboolean check_privilege(DBusConnection *conn, DBusMessage *msg,
        return FALSE;
 }
 
-static void generic_unregister(DBusConnection *connection, void *user_data)
+static GDBusPendingPropertySet next_pending_property = 1;
+static GSList *pending_property_set;
+
+static struct property_data *remove_pending_property_data(
+                                               GDBusPendingPropertySet id)
 {
-       struct generic_data *data = user_data;
+       struct property_data *propdata;
+       GSList *l;
 
-       g_free(data->introspect);
-       g_free(data);
+       for (l = pending_property_set; l != NULL; l = l->next) {
+               propdata = l->data;
+               if (propdata->id != id)
+                       continue;
+
+               break;
+       }
+
+       if (l == NULL)
+               return NULL;
+
+       pending_property_set = g_slist_delete_link(pending_property_set, l);
+
+       return propdata;
+}
+
+void g_dbus_pending_property_success(GDBusPendingPropertySet id)
+{
+       struct property_data *propdata;
+
+       propdata = remove_pending_property_data(id);
+       if (propdata == NULL)
+               return;
+
+       g_dbus_send_reply(propdata->conn, propdata->message,
+                                                       DBUS_TYPE_INVALID);
+       dbus_message_unref(propdata->message);
+       g_free(propdata);
+}
+
+void g_dbus_pending_property_error_valist(GDBusPendingReply id,
+                                       const char *name, const char *format,
+                                       va_list args)
+{
+       struct property_data *propdata;
+
+       propdata = remove_pending_property_data(id);
+       if (propdata == NULL)
+               return;
+
+       g_dbus_send_error_valist(propdata->conn, propdata->message, name,
+                                                               format, args);
+
+       dbus_message_unref(propdata->message);
+       g_free(propdata);
+}
+
+void g_dbus_pending_property_error(GDBusPendingReply id, const char *name,
+                                               const char *format, ...)
+{
+       va_list args;
+
+       va_start(args, format);
+
+       g_dbus_pending_property_error_valist(id, name, format, args);
+
+       va_end(args);
+}
+
+static void reset_parent(gpointer data, gpointer user_data)
+{
+       struct generic_data *child = data;
+       struct generic_data *parent = user_data;
+
+       child->parent = parent;
+}
+
+static void append_property(struct interface_data *iface,
+                       const GDBusPropertyTable *p, DBusMessageIter *dict)
+{
+       DBusMessageIter entry, value;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
+                                                               &value);
+
+       p->get(p, &value, iface->user_data);
+
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_properties(struct interface_data *data,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter dict;
+       const GDBusPropertyTable *p;
+
+       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);
+
+       for (p = data->properties; p && p->name; p++) {
+               if (check_experimental(p->flags,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+                       continue;
+
+               if (p->get == NULL)
+                       continue;
+
+               if (p->exists != NULL && !p->exists(p, data->user_data))
+                       continue;
+
+               append_property(data, p, &dict);
+       }
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void append_interface(gpointer data, gpointer user_data)
+{
+       struct interface_data *iface = data;
+       DBusMessageIter *array = user_data;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &iface->name);
+       append_properties(data, &entry);
+       dbus_message_iter_close_container(array, &entry);
+}
+
+static void emit_interfaces_added(struct generic_data *data)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, array;
+
+       if (root == NULL || data == root)
+               return;
+
+       signal = dbus_message_new_signal(root->path,
+                                       DBUS_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesAdded");
+       if (signal == NULL)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                               &data->path);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_ARRAY_AS_STRING
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+       g_slist_foreach(data->added, append_interface, &array);
+       g_slist_free(data->added);
+       data->added = NULL;
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+       dbus_connection_send(data->conn, signal, NULL);
+       dbus_message_unref(signal);
 }
 
 static struct interface_data *find_interface(GSList *interfaces,
@@ -410,49 +632,62 @@ static gboolean g_dbus_args_have_signature(const GDBusArgInfo *args,
        return TRUE;
 }
 
-static DBusHandlerResult generic_message(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
+static void add_pending(struct generic_data *data)
 {
-       struct generic_data *data = user_data;
-       struct interface_data *iface;
-       const GDBusMethodTable *method;
-       const char *interface;
+       if (data->process_id > 0)
+               return;
 
-       interface = dbus_message_get_interface(message);
+       data->process_id = g_idle_add(process_changes, data);
 
-       iface = find_interface(data->interfaces, interface);
+       pending = g_slist_append(pending, data);
+}
+
+static gboolean remove_interface(struct generic_data *data, const char *name)
+{
+       struct interface_data *iface;
+
+       iface = find_interface(data->interfaces, name);
        if (iface == NULL)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+               return FALSE;
 
-       for (method = iface->methods; method &&
-                       method->name && method->function; method++) {
-               if (dbus_message_is_method_call(message, iface->name,
-                                                       method->name) == FALSE)
-                       continue;
+       process_properties_from_interface(data, iface);
 
-               if (g_dbus_args_have_signature(method->in_args,
-                                                       message) == FALSE)
-                       continue;
+       data->interfaces = g_slist_remove(data->interfaces, iface);
 
-               if (check_privilege(connection, message, method,
-                                               iface->user_data) == TRUE)
-                       return DBUS_HANDLER_RESULT_HANDLED;
+       if (iface->destroy) {
+               iface->destroy(iface->user_data);
+               iface->user_data = NULL;
+       }
 
-               return process_message(connection, message, method,
-                                                       iface->user_data);
+       /*
+        * Interface being removed was just added, on the same mainloop
+        * iteration? Don't send any signal
+        */
+       if (g_slist_find(data->added, iface)) {
+               data->added = g_slist_remove(data->added, iface);
+               g_free(iface->name);
+               g_free(iface);
+               return TRUE;
        }
 
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
+       if (data->parent == NULL) {
+               g_free(iface->name);
+               g_free(iface);
+               return TRUE;
+       }
 
-static DBusObjectPathVTable generic_table = {
-       .unregister_function    = generic_unregister,
-       .message_function       = generic_message,
-};
+       data->removed = g_slist_prepend(data->removed, iface->name);
+       g_free(iface);
+
+       add_pending(data);
+
+       return TRUE;
+}
 
-static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
+static struct generic_data *invalidate_parent_data(DBusConnection *conn,
+                                               const char *child_path)
 {
-       struct generic_data *data = NULL;
+       struct generic_data *data = NULL, *child = NULL, *parent = NULL;
        char *parent_path, *slash;
 
        parent_path = g_strdup(child_path);
@@ -473,101 +708,566 @@ static void invalidate_parent_data(DBusConnection *conn, const char *child_path)
                goto done;
        }
 
-       invalidate_parent_data(conn, parent_path);
+       parent = invalidate_parent_data(conn, parent_path);
 
-       if (data == NULL)
-               goto done;
+       if (data == NULL) {
+               data = parent;
+               if (data == NULL)
+                       goto done;
+       }
 
        g_free(data->introspect);
        data->introspect = NULL;
 
+       if (!dbus_connection_get_object_path_data(conn, child_path,
+                                                       (void *) &child))
+               goto done;
+
+       if (child == NULL || g_slist_find(data->objects, child) != NULL)
+               goto done;
+
+       data->objects = g_slist_prepend(data->objects, child);
+       child->parent = data;
+
 done:
        g_free(parent_path);
+       return data;
 }
 
-static const GDBusMethodTable introspect_methods[] = {
-       { GDBUS_METHOD("Introspect", NULL,
-                       GDBUS_ARGS({ "xml", "s" }), introspect) },
-       { }
-};
-
-static void add_interface(struct generic_data *data, const char *name,
-                               const GDBusMethodTable *methods,
-                               const GDBusSignalTable *signals,
-                               const GDBusPropertyTable *properties,
-                               void *user_data,
-                               GDBusDestroyFunction destroy)
+static inline const GDBusPropertyTable *find_property(const GDBusPropertyTable *properties,
+                                                       const char *name)
 {
-       struct interface_data *iface;
+       const GDBusPropertyTable *p;
 
-       iface = g_new0(struct interface_data, 1);
-       iface->name = g_strdup(name);
-       iface->methods = methods;
-       iface->signals = signals;
-       iface->properties = properties;
-       iface->user_data = user_data;
-       iface->destroy = destroy;
+       for (p = properties; p && p->name; p++) {
+               if (strcmp(name, p->name) != 0)
+                       continue;
 
-       data->interfaces = g_slist_append(data->interfaces, iface);
+               if (check_experimental(p->flags,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+                       break;
+
+               return p;
+       }
+
+       return NULL;
 }
 
-static struct generic_data *object_path_ref(DBusConnection *connection,
-                                                       const char *path)
+static DBusMessage *properties_get(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
 {
-       struct generic_data *data;
+       struct generic_data *data = user_data;
+       struct interface_data *iface;
+       const GDBusPropertyTable *property;
+       const char *interface, *name;
+       DBusMessageIter iter, value;
+       DBusMessage *reply;
 
-       if (dbus_connection_get_object_path_data(connection, path,
-                                               (void *) &data) == TRUE) {
-               if (data != NULL) {
-                       data->refcount++;
-                       return data;
-               }
-       }
+       if (!dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &interface,
+                                       DBUS_TYPE_STRING, &name,
+                                       DBUS_TYPE_INVALID))
+               return NULL;
 
-       data = g_new0(struct generic_data, 1);
-       data->refcount = 1;
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "No such interface '%s'", interface);
 
-       data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
+       property = find_property(iface->properties, name);
+       if (property == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "No such property '%s'", name);
 
-       if (!dbus_connection_register_object_path(connection, path,
-                                               &generic_table, data)) {
-               g_free(data->introspect);
-               g_free(data);
+       if (property->exists != NULL &&
+                       !property->exists(property, iface->user_data))
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such property '%s'", name);
+
+       if (property->get == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                               "Property '%s' is not readable", name);
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
                return NULL;
-       }
 
-       invalidate_parent_data(connection, path);
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
+                                               property->type, &value);
+
+       if (!property->get(property, &value, iface->user_data)) {
+               dbus_message_unref(reply);
+               return NULL;
+       }
 
-       add_interface(data, DBUS_INTERFACE_INTROSPECTABLE,
-                       introspect_methods, NULL, NULL, data, NULL);
+       dbus_message_iter_close_container(&iter, &value);
 
-       return data;
+       return reply;
 }
 
-static gboolean remove_interface(struct generic_data *data, const char *name)
+static DBusMessage *properties_get_all(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
 {
+       struct generic_data *data = user_data;
        struct interface_data *iface;
+       const char *interface;
+       DBusMessageIter iter;
+       DBusMessage *reply;
 
-       iface = find_interface(data->interfaces, name);
+       if (!dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &interface,
+                                       DBUS_TYPE_INVALID))
+               return NULL;
+
+       iface = find_interface(data->interfaces, interface);
        if (iface == NULL)
-               return FALSE;
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such interface '%s'", interface);
 
-       data->interfaces = g_slist_remove(data->interfaces, iface);
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
 
-       if (iface->destroy)
-               iface->destroy(iface->user_data);
+       dbus_message_iter_init_append(reply, &iter);
 
-       g_free(iface->name);
-       g_free(iface);
+       append_properties(iface, &iter);
 
-       return TRUE;
+       return reply;
 }
 
-static void object_path_unref(DBusConnection *connection, const char *path)
+static DBusMessage *properties_set(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
 {
-       struct generic_data *data = NULL;
+       struct generic_data *data = user_data;
+       DBusMessageIter iter, sub;
+       struct interface_data *iface;
+       const GDBusPropertyTable *property;
+       const char *name, *interface;
+       struct property_data *propdata;
+       gboolean valid_signature;
+       char *signature;
 
-       if (dbus_connection_get_object_path_data(connection, path,
+       if (!dbus_message_iter_init(message, &iter))
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                                       "No arguments given");
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_get_basic(&iter, &interface);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_get_basic(&iter, &name);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "Invalid argument type: '%c'",
+                                       dbus_message_iter_get_arg_type(&iter));
+
+       dbus_message_iter_recurse(&iter, &sub);
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return g_dbus_create_error(message, DBUS_ERROR_INVALID_ARGS,
+                                       "No such interface '%s'", interface);
+
+       property = find_property(iface->properties, name);
+       if (property == NULL)
+               return g_dbus_create_error(message,
+                                               DBUS_ERROR_UNKNOWN_PROPERTY,
+                                               "No such property '%s'", name);
+
+       if (property->set == NULL)
+               return g_dbus_create_error(message,
+                                       DBUS_ERROR_PROPERTY_READ_ONLY,
+                                       "Property '%s' is not writable", name);
+
+       if (property->exists != NULL &&
+                       !property->exists(property, iface->user_data))
+               return g_dbus_create_error(message,
+                                               DBUS_ERROR_UNKNOWN_PROPERTY,
+                                               "No such property '%s'", name);
+
+       signature = dbus_message_iter_get_signature(&sub);
+       valid_signature = strcmp(signature, property->type) ? FALSE : TRUE;
+       dbus_free(signature);
+       if (!valid_signature)
+               return g_dbus_create_error(message,
+                                       DBUS_ERROR_INVALID_SIGNATURE,
+                                       "Invalid signature for '%s'", name);
+
+       propdata = g_new(struct property_data, 1);
+       propdata->id = next_pending_property++;
+       propdata->message = dbus_message_ref(message);
+       propdata->conn = connection;
+       pending_property_set = g_slist_prepend(pending_property_set, propdata);
+
+       property->set(property, &sub, propdata->id, iface->user_data);
+
+       return NULL;
+}
+
+static const GDBusMethodTable properties_methods[] = {
+       { GDBUS_METHOD("Get",
+                       GDBUS_ARGS({ "interface", "s" }, { "name", "s" }),
+                       GDBUS_ARGS({ "value", "v" }),
+                       properties_get) },
+       { GDBUS_ASYNC_METHOD("Set",
+                       GDBUS_ARGS({ "interface", "s" }, { "name", "s" },
+                                                       { "value", "v" }),
+                       NULL,
+                       properties_set) },
+       { GDBUS_METHOD("GetAll",
+                       GDBUS_ARGS({ "interface", "s" }),
+                       GDBUS_ARGS({ "properties", "a{sv}" }),
+                       properties_get_all) },
+       { }
+};
+
+static const GDBusSignalTable properties_signals[] = {
+       { GDBUS_SIGNAL("PropertiesChanged",
+                       GDBUS_ARGS({ "interface", "s" },
+                                       { "changed_properties", "a{sv}" },
+                                       { "invalidated_properties", "as"})) },
+       { }
+};
+
+static void append_name(gpointer data, gpointer user_data)
+{
+       char *name = data;
+       DBusMessageIter *iter = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
+}
+
+static void emit_interfaces_removed(struct generic_data *data)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, array;
+
+       if (root == NULL || data == root)
+               return;
+
+       signal = dbus_message_new_signal(root->path,
+                                       DBUS_INTERFACE_OBJECT_MANAGER,
+                                       "InterfacesRemoved");
+       if (signal == NULL)
+               return;
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                               &data->path);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &array);
+
+       g_slist_foreach(data->removed, append_name, &array);
+       g_slist_free_full(data->removed, g_free);
+       data->removed = NULL;
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+       dbus_connection_send(data->conn, signal, NULL);
+       dbus_message_unref(signal);
+}
+
+static void remove_pending(struct generic_data *data)
+{
+       if (data->process_id > 0) {
+               g_source_remove(data->process_id);
+               data->process_id = 0;
+       }
+
+       pending = g_slist_remove(pending, data);
+}
+
+static gboolean process_changes(gpointer user_data)
+{
+       struct generic_data *data = user_data;
+
+       remove_pending(data);
+
+       if (data->added != NULL)
+               emit_interfaces_added(data);
+
+       /* Flush pending properties */
+       if (data->pending_prop == TRUE)
+               process_property_changes(data);
+
+       if (data->removed != NULL)
+               emit_interfaces_removed(data);
+
+       return FALSE;
+}
+
+static void generic_unregister(DBusConnection *connection, void *user_data)
+{
+       struct generic_data *data = user_data;
+       struct generic_data *parent = data->parent;
+
+       if (parent != NULL)
+               parent->objects = g_slist_remove(parent->objects, data);
+
+       if (data->process_id > 0) {
+               g_source_remove(data->process_id);
+               process_changes(data);
+       }
+
+       g_slist_foreach(data->objects, reset_parent, data->parent);
+       g_slist_free(data->objects);
+
+       dbus_connection_unref(data->conn);
+       g_free(data->introspect);
+       g_free(data->path);
+       g_free(data);
+}
+
+static DBusHandlerResult generic_message(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       struct interface_data *iface;
+       const GDBusMethodTable *method;
+       const char *interface;
+
+       interface = dbus_message_get_interface(message);
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       for (method = iface->methods; method &&
+                       method->name && method->function; method++) {
+
+               if (dbus_message_is_method_call(message, iface->name,
+                                                       method->name) == FALSE)
+                       continue;
+
+               if (check_experimental(method->flags,
+                                       G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+                       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+               if (g_dbus_args_have_signature(method->in_args,
+                                                       message) == FALSE)
+                       continue;
+
+               if (check_privilege(connection, message, method,
+                                               iface->user_data) == TRUE)
+                       return DBUS_HANDLER_RESULT_HANDLED;
+
+               return process_message(connection, message, method,
+                                                       iface->user_data);
+       }
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static DBusObjectPathVTable generic_table = {
+       .unregister_function    = generic_unregister,
+       .message_function       = generic_message,
+};
+
+static const GDBusMethodTable introspect_methods[] = {
+       { GDBUS_METHOD("Introspect", NULL,
+                       GDBUS_ARGS({ "xml", "s" }), introspect) },
+       { }
+};
+
+static void append_interfaces(struct generic_data *data, DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       GSList *l;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_ARRAY_AS_STRING
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+
+       for (l = data->interfaces; l != NULL; l = l->next) {
+               if (g_slist_find(data->added, l->data))
+                       continue;
+
+               append_interface(l->data, &array);
+       }
+
+       dbus_message_iter_close_container(iter, &array);
+}
+
+static void append_object(gpointer data, gpointer user_data)
+{
+       struct generic_data *child = data;
+       DBusMessageIter *array = user_data;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+                                                               &child->path);
+       append_interfaces(child, &entry);
+       dbus_message_iter_close_container(array, &entry);
+
+       g_slist_foreach(child->objects, append_object, user_data);
+}
+
+static DBusMessage *get_objects(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct generic_data *data = user_data;
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusMessageIter array;
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &array);
+
+       g_slist_foreach(data->objects, append_object, &array);
+
+       dbus_message_iter_close_container(&iter, &array);
+
+       return reply;
+}
+
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_METHOD("GetManagedObjects", NULL,
+               GDBUS_ARGS({ "objects", "a{oa{sa{sv}}}" }), get_objects) },
+       { }
+};
+
+static const GDBusSignalTable manager_signals[] = {
+       { GDBUS_SIGNAL("InterfacesAdded",
+               GDBUS_ARGS({ "object", "o" },
+                               { "interfaces", "a{sa{sv}}" })) },
+       { GDBUS_SIGNAL("InterfacesRemoved",
+               GDBUS_ARGS({ "object", "o" }, { "interfaces", "as" })) },
+       { }
+};
+
+static gboolean add_interface(struct generic_data *data,
+                               const char *name,
+                               const GDBusMethodTable *methods,
+                               const GDBusSignalTable *signals,
+                               const GDBusPropertyTable *properties,
+                               void *user_data,
+                               GDBusDestroyFunction destroy)
+{
+       struct interface_data *iface;
+       const GDBusMethodTable *method;
+       const GDBusSignalTable *signal;
+       const GDBusPropertyTable *property;
+
+       for (method = methods; method && method->name; method++) {
+               if (!check_experimental(method->flags,
+                                       G_DBUS_METHOD_FLAG_EXPERIMENTAL))
+                       goto done;
+       }
+
+       for (signal = signals; signal && signal->name; signal++) {
+               if (!check_experimental(signal->flags,
+                                       G_DBUS_SIGNAL_FLAG_EXPERIMENTAL))
+                       goto done;
+       }
+
+       for (property = properties; property && property->name; property++) {
+               if (!check_experimental(property->flags,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL))
+                       goto done;
+       }
+
+       /* Nothing to register */
+       return FALSE;
+
+done:
+       iface = g_new0(struct interface_data, 1);
+       iface->name = g_strdup(name);
+       iface->methods = methods;
+       iface->signals = signals;
+       iface->properties = properties;
+       iface->user_data = user_data;
+       iface->destroy = destroy;
+
+       data->interfaces = g_slist_append(data->interfaces, iface);
+       if (data->parent == NULL)
+               return TRUE;
+
+       data->added = g_slist_append(data->added, iface);
+
+       add_pending(data);
+
+       return TRUE;
+}
+
+static struct generic_data *object_path_ref(DBusConnection *connection,
+                                                       const char *path)
+{
+       struct generic_data *data;
+
+       if (dbus_connection_get_object_path_data(connection, path,
+                                               (void *) &data) == TRUE) {
+               if (data != NULL) {
+                       data->refcount++;
+                       return data;
+               }
+       }
+
+       data = g_new0(struct generic_data, 1);
+       data->conn = dbus_connection_ref(connection);
+       data->path = g_strdup(path);
+       data->refcount = 1;
+
+       data->introspect = g_strdup(DBUS_INTROSPECT_1_0_XML_DOCTYPE_DECL_NODE "<node></node>");
+
+       if (!dbus_connection_register_object_path(connection, path,
+                                               &generic_table, data)) {
+               g_free(data->introspect);
+               g_free(data);
+               return NULL;
+       }
+
+       invalidate_parent_data(connection, path);
+
+       add_interface(data, DBUS_INTERFACE_INTROSPECTABLE, introspect_methods,
+                                               NULL, NULL, data, NULL);
+
+       return data;
+}
+
+static void object_path_unref(DBusConnection *connection, const char *path)
+{
+       struct generic_data *data = NULL;
+
+       if (dbus_connection_get_object_path_data(connection, path,
                                                (void *) &data) == FALSE)
                return;
 
@@ -580,10 +1280,11 @@ static void object_path_unref(DBusConnection *connection, const char *path)
                return;
 
        remove_interface(data, DBUS_INTERFACE_INTROSPECTABLE);
+       remove_interface(data, DBUS_INTERFACE_PROPERTIES);
 
-       invalidate_parent_data(connection, path);
+       invalidate_parent_data(data->conn, data->path);
 
-       dbus_connection_unregister_object_path(connection, path);
+       dbus_connection_unregister_object_path(data->conn, data->path);
 }
 
 static gboolean check_signal(DBusConnection *conn, const char *path,
@@ -610,55 +1311,23 @@ static gboolean check_signal(DBusConnection *conn, const char *path,
        }
 
        for (signal = iface->signals; signal && signal->name; signal++) {
-               if (!strcmp(signal->name, name)) {
-                       *args = signal->args;
-                       return TRUE;
+               if (strcmp(signal->name, name) != 0)
+                       continue;
+
+               if (signal->flags & G_DBUS_SIGNAL_FLAG_EXPERIMENTAL) {
+                       const char *env = g_getenv("GDBUS_EXPERIMENTAL");
+                       if (g_strcmp0(env, "1") != 0)
+                               break;
                }
+
+               *args = signal->args;
+               return TRUE;
        }
 
        error("No signal named %s on interface %s", name, interface);
        return FALSE;
 }
 
-static dbus_bool_t emit_signal_valist(DBusConnection *conn,
-                                               const char *path,
-                                               const char *interface,
-                                               const char *name,
-                                               int first,
-                                               va_list var_args)
-{
-       DBusMessage *signal;
-       dbus_bool_t ret;
-       const GDBusArgInfo *args;
-
-       if (!check_signal(conn, path, interface, name, &args))
-               return FALSE;
-
-       signal = dbus_message_new_signal(path, interface, name);
-       if (signal == NULL) {
-               error("Unable to allocate new %s.%s signal", interface,  name);
-               return FALSE;
-       }
-
-       ret = dbus_message_append_args_valist(signal, first, var_args);
-       if (!ret)
-               goto fail;
-
-       if (g_dbus_args_have_signature(args, signal) == FALSE) {
-               error("%s.%s: expected signature'%s' but got '%s'",
-                               interface, name, args, signature);
-               ret = FALSE;
-               goto fail;
-       }
-
-       ret = dbus_connection_send(conn, signal, NULL);
-
-fail:
-       dbus_message_unref(signal);
-
-       return ret;
-}
-
 gboolean g_dbus_register_interface(DBusConnection *connection,
                                        const char *path, const char *name,
                                        const GDBusMethodTable *methods,
@@ -678,8 +1347,17 @@ gboolean g_dbus_register_interface(DBusConnection *connection,
                return FALSE;
        }
 
-       add_interface(data, name, methods, signals,
-                       properties, user_data, destroy);
+       if (!add_interface(data, name, methods, signals, properties, user_data,
+                                                               destroy)) {
+               object_path_unref(connection, path);
+               return FALSE;
+       }
+
+       if (properties != NULL && !find_interface(data->interfaces,
+                                               DBUS_INTERFACE_PROPERTIES))
+               add_interface(data, DBUS_INTERFACE_PROPERTIES,
+                               properties_methods, properties_signals, NULL,
+                               data, NULL);
 
        g_free(data->introspect);
        data->introspect = NULL;
@@ -708,7 +1386,7 @@ gboolean g_dbus_unregister_interface(DBusConnection *connection,
        g_free(data->introspect);
        data->introspect = NULL;
 
-       object_path_unref(connection, path);
+       object_path_unref(connection, data->path);
 
        return TRUE;
 }
@@ -786,20 +1464,100 @@ DBusMessage *g_dbus_create_reply(DBusMessage *message, int type, ...)
        return reply;
 }
 
+static void g_dbus_flush(DBusConnection *connection)
+{
+       GSList *l;
+
+       for (l = pending; l;) {
+               struct generic_data *data = l->data;
+
+               l = l->next;
+               if (data->conn != connection)
+                       continue;
+
+               process_changes(data);
+       }
+}
+
 gboolean g_dbus_send_message(DBusConnection *connection, DBusMessage *message)
 {
-       dbus_bool_t result;
+       dbus_bool_t result = FALSE;
 
        if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_METHOD_CALL)
                dbus_message_set_no_reply(message, TRUE);
+       else if (dbus_message_get_type(message) == DBUS_MESSAGE_TYPE_SIGNAL) {
+               const char *path = dbus_message_get_path(message);
+               const char *interface = dbus_message_get_interface(message);
+               const char *name = dbus_message_get_member(message);
+               const GDBusArgInfo *args;
+
+               if (!check_signal(connection, path, interface, name, &args))
+                       goto out;
+       }
+
+       /* Flush pending signal to guarantee message order */
+       g_dbus_flush(connection);
 
        result = dbus_connection_send(connection, message, NULL);
 
+out:
        dbus_message_unref(message);
 
        return result;
 }
 
+gboolean g_dbus_send_message_with_reply(DBusConnection *connection,
+                                       DBusMessage *message,
+                                       DBusPendingCall **call, int timeout)
+{
+       dbus_bool_t ret;
+
+       /* Flush pending signal to guarantee message order */
+       g_dbus_flush(connection);
+
+       ret = dbus_connection_send_with_reply(connection, message, call,
+                                                               timeout);
+
+       if (ret == TRUE && call != NULL && *call == NULL) {
+               error("Unable to send message (passing fd blocked?)");
+               return FALSE;
+       }
+
+       return ret;
+}
+
+gboolean g_dbus_send_error_valist(DBusConnection *connection,
+                                       DBusMessage *message, const char *name,
+                                       const char *format, va_list args)
+{
+       DBusMessage *error;
+       char str[1024];
+
+       vsnprintf(str, sizeof(str), format, args);
+
+       error = dbus_message_new_error(message, name, str);
+       if (error == NULL)
+               return FALSE;
+
+       return g_dbus_send_message(connection, error);
+}
+
+gboolean g_dbus_send_error(DBusConnection *connection, DBusMessage *message,
+                               const char *name, const char *format, ...)
+{
+       va_list args;
+       gboolean result;
+
+       va_start(args, format);
+
+       result = g_dbus_send_error_valist(connection, message, name,
+                                                       format, args);
+
+       va_end(args);
+
+       return result;
+}
+
 gboolean g_dbus_send_reply_valist(DBusConnection *connection,
                                DBusMessage *message, int type, va_list args)
 {
@@ -841,7 +1599,7 @@ gboolean g_dbus_emit_signal(DBusConnection *connection,
 
        va_start(args, type);
 
-       result = emit_signal_valist(connection, path, interface,
+       result = g_dbus_emit_signal_valist(connection, path, interface,
                                                        name, type, args);
 
        va_end(args);
@@ -853,6 +1611,209 @@ gboolean g_dbus_emit_signal_valist(DBusConnection *connection,
                                const char *path, const char *interface,
                                const char *name, int type, va_list args)
 {
-       return emit_signal_valist(connection, path, interface,
-                                                       name, type, args);
+       DBusMessage *signal;
+       dbus_bool_t ret;
+       const GDBusArgInfo *args_info;
+
+       if (!check_signal(connection, path, interface, name, &args_info))
+               return FALSE;
+
+       signal = dbus_message_new_signal(path, interface, name);
+       if (signal == NULL) {
+               error("Unable to allocate new %s.%s signal", interface,  name);
+               return FALSE;
+       }
+
+       ret = dbus_message_append_args_valist(signal, type, args);
+       if (!ret)
+               goto fail;
+
+       if (g_dbus_args_have_signature(args_info, signal) == FALSE) {
+               error("%s.%s: got unexpected signature '%s'", interface, name,
+                                       dbus_message_get_signature(signal));
+               ret = FALSE;
+               goto fail;
+       }
+
+       return g_dbus_send_message(connection, signal);
+
+fail:
+       dbus_message_unref(signal);
+
+       return ret;
+}
+
+static void process_properties_from_interface(struct generic_data *data,
+                                               struct interface_data *iface)
+{
+       GSList *l;
+       DBusMessage *signal;
+       DBusMessageIter iter, dict, array;
+       GSList *invalidated;
+
+       data->pending_prop = FALSE;
+
+       if (iface->pending_prop == NULL)
+               return;
+
+       signal = dbus_message_new_signal(data->path,
+                       DBUS_INTERFACE_PROPERTIES, "PropertiesChanged");
+       if (signal == NULL) {
+               error("Unable to allocate new " DBUS_INTERFACE_PROPERTIES
+                                               ".PropertiesChanged signal");
+               return;
+       }
+
+       iface->pending_prop = g_slist_reverse(iface->pending_prop);
+
+       dbus_message_iter_init_append(signal, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface->name);
+       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);
+
+       invalidated = NULL;
+
+       for (l = iface->pending_prop; l != NULL; l = l->next) {
+               GDBusPropertyTable *p = l->data;
+
+               if (p->get == NULL)
+                       continue;
+
+               if (p->exists != NULL && !p->exists(p, iface->user_data)) {
+                       invalidated = g_slist_prepend(invalidated, p);
+                       continue;
+               }
+
+               append_property(iface, p, &dict);
+       }
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING_AS_STRING, &array);
+       for (l = invalidated; l != NULL; l = g_slist_next(l)) {
+               GDBusPropertyTable *p = l->data;
+
+               dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING,
+                                                               &p->name);
+       }
+       g_slist_free(invalidated);
+       dbus_message_iter_close_container(&iter, &array);
+
+       g_slist_free(iface->pending_prop);
+       iface->pending_prop = NULL;
+
+       /* Use dbus_connection_send to avoid recursive calls to g_dbus_flush */
+       dbus_connection_send(data->conn, signal, NULL);
+       dbus_message_unref(signal);
+}
+
+static void process_property_changes(struct generic_data *data)
+{
+       GSList *l;
+
+       for (l = data->interfaces; l != NULL; l = l->next) {
+               struct interface_data *iface = l->data;
+
+               process_properties_from_interface(data, iface);
+       }
+}
+
+void g_dbus_emit_property_changed(DBusConnection *connection,
+                               const char *path, const char *interface,
+                               const char *name)
+{
+       const GDBusPropertyTable *property;
+       struct generic_data *data;
+       struct interface_data *iface;
+
+       if (path == NULL)
+               return;
+
+       if (!dbus_connection_get_object_path_data(connection, path,
+                                       (void **) &data) || data == NULL)
+               return;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return;
+
+       /*
+        * If ObjectManager is attached, don't emit property changed if
+        * interface is not yet published
+        */
+       if (root && g_slist_find(data->added, iface))
+               return;
+
+       property = find_property(iface->properties, name);
+       if (property == NULL) {
+               error("Could not find property %s in %p", name,
+                                                       iface->properties);
+               return;
+       }
+
+       if (g_slist_find(iface->pending_prop, (void *) property) != NULL)
+               return;
+
+       data->pending_prop = TRUE;
+       iface->pending_prop = g_slist_prepend(iface->pending_prop,
+                                               (void *) property);
+
+       add_pending(data);
+}
+
+gboolean g_dbus_get_properties(DBusConnection *connection, const char *path,
+                               const char *interface, DBusMessageIter *iter)
+{
+       struct generic_data *data;
+       struct interface_data *iface;
+
+       if (path == NULL)
+               return FALSE;
+
+       if (!dbus_connection_get_object_path_data(connection, path,
+                                       (void **) &data) || data == NULL)
+               return FALSE;
+
+       iface = find_interface(data->interfaces, interface);
+       if (iface == NULL)
+               return FALSE;
+
+       append_properties(iface, iter);
+
+       return TRUE;
+}
+
+gboolean g_dbus_attach_object_manager(DBusConnection *connection)
+{
+       struct generic_data *data;
+
+       data = object_path_ref(connection, "/");
+       if (data == NULL)
+               return FALSE;
+
+       add_interface(data, DBUS_INTERFACE_OBJECT_MANAGER,
+                                       manager_methods, manager_signals,
+                                       NULL, data, NULL);
+       root = data;
+
+       return TRUE;
+}
+
+gboolean g_dbus_detach_object_manager(DBusConnection *connection)
+{
+       if (!g_dbus_unregister_interface(connection, "/",
+                                       DBUS_INTERFACE_OBJECT_MANAGER))
+               return FALSE;
+
+       root = NULL;
+
+       return TRUE;
+}
+
+void g_dbus_set_flags(int flags)
+{
+       global_flags = flags;
 }
index 9a716b0..0f99f4f 100644 (file)
@@ -78,7 +78,7 @@ struct filter_data {
        gboolean registered;
 };
 
-static struct filter_data *filter_data_find(DBusConnection *connection,
+static struct filter_data *filter_data_find_match(DBusConnection *connection,
                                                        const char *name,
                                                        const char *owner,
                                                        const char *path,
@@ -95,28 +95,39 @@ static struct filter_data *filter_data_find(DBusConnection *connection,
                if (connection != data->connection)
                        continue;
 
-               if (name && data->name &&
-                               g_str_equal(name, data->name) == FALSE)
+               if (g_strcmp0(name, data->name) != 0)
                        continue;
 
-               if (owner && data->owner &&
-                               g_str_equal(owner, data->owner) == FALSE)
+               if (g_strcmp0(owner, data->owner) != 0)
                        continue;
 
-               if (path && data->path &&
-                               g_str_equal(path, data->path) == FALSE)
+               if (g_strcmp0(path, data->path) != 0)
                        continue;
 
-               if (interface && data->interface &&
-                               g_str_equal(interface, data->interface) == FALSE)
+               if (g_strcmp0(interface, data->interface) != 0)
                        continue;
 
-               if (member && data->member &&
-                               g_str_equal(member, data->member) == FALSE)
+               if (g_strcmp0(member, data->member) != 0)
                        continue;
 
-               if (argument && data->argument &&
-                               g_str_equal(argument, data->argument) == FALSE)
+               if (g_strcmp0(argument, data->argument) != 0)
+                       continue;
+
+               return data;
+       }
+
+       return NULL;
+}
+
+static struct filter_data *filter_data_find(DBusConnection *connection)
+{
+       GSList *current;
+
+       for (current = listeners;
+                       current != NULL; current = current->next) {
+               struct filter_data *data = current->data;
+
+               if (connection != data->connection)
                        continue;
 
                return data;
@@ -204,7 +215,7 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
        struct filter_data *data;
        const char *name = NULL, *owner = NULL;
 
-       if (filter_data_find(connection, NULL, NULL, NULL, NULL, NULL, NULL) == NULL) {
+       if (filter_data_find(connection) == NULL) {
                if (!dbus_connection_add_filter(connection,
                                        message_filter, NULL, NULL)) {
                        error("dbus_connection_add_filter() failed");
@@ -221,16 +232,16 @@ static struct filter_data *filter_data_get(DBusConnection *connection,
                name = sender;
 
 proceed:
-       data = filter_data_find(connection, name, owner, path, interface,
-                                       member, argument);
+       data = filter_data_find_match(connection, name, owner, path,
+                                               interface, member, argument);
        if (data)
                return data;
 
        data = g_new0(struct filter_data, 1);
 
        data->connection = dbus_connection_ref(connection);
-       data->name = name ? g_strdup(name) : NULL;
-       data->owner = owner ? g_strdup(owner) : NULL;
+       data->name = g_strdup(name);
+       data->owner = g_strdup(owner);
        data->path = g_strdup(path);
        data->interface = g_strdup(interface);
        data->member = g_strdup(member);
@@ -270,6 +281,11 @@ static void filter_data_free(struct filter_data *data)
 {
        GSList *l;
 
+       /* Remove filter if there are no listeners left for the connection */
+       if (filter_data_find(data->connection) == NULL)
+               dbus_connection_remove_filter(data->connection, message_filter,
+                                                                       NULL);
+
        for (l = data->callbacks; l != NULL; l = l->next)
                g_free(l->data);
 
@@ -349,8 +365,6 @@ static void service_data_free(struct service_data *data)
 static gboolean filter_data_remove_callback(struct filter_data *data,
                                                struct filter_callback *cb)
 {
-       DBusConnection *connection;
-
        data->callbacks = g_slist_remove(data->callbacks, cb);
        data->processed = g_slist_remove(data->processed, cb);
 
@@ -374,19 +388,9 @@ static gboolean filter_data_remove_callback(struct filter_data *data,
        if (data->registered && !remove_match(data))
                return FALSE;
 
-       connection = dbus_connection_ref(data->connection);
        listeners = g_slist_remove(listeners, data);
        filter_data_free(data);
 
-       /* Remove filter if there are no listeners left for the connection */
-       data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-                                       NULL);
-       if (data == NULL)
-               dbus_connection_remove_filter(connection, message_filter,
-                                               NULL);
-
-       dbus_connection_unref(connection);
-
        return TRUE;
 }
 
@@ -502,6 +506,7 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
 {
        struct filter_data *data;
        const char *sender, *path, *iface, *member, *arg = NULL;
+       GSList *current, *delete_listener = NULL;
 
        /* Only filter signals */
        if (dbus_message_get_type(message) != DBUS_MESSAGE_TYPE_SIGNAL)
@@ -513,38 +518,68 @@ static DBusHandlerResult message_filter(DBusConnection *connection,
        member = dbus_message_get_member(message);
        dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &arg, DBUS_TYPE_INVALID);
 
-       /* Sender is always bus name */
-       data = filter_data_find(connection, NULL, sender, path, iface, member,
-                                       arg);
-       if (data == NULL) {
-               error("Got %s.%s signal which has no listeners", iface, member);
+       /* Sender is always the owner */
+       if (sender == NULL)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
 
-       if (data->handle_func) {
-               data->lock = TRUE;
+       for (current = listeners; current != NULL; current = current->next) {
+               data = current->data;
+
+               if (connection != data->connection)
+                       continue;
+
+               if (data->owner && g_str_equal(sender, data->owner) == FALSE)
+                       continue;
+
+               if (data->path && g_str_equal(path, data->path) == FALSE)
+                       continue;
+
+               if (data->interface && g_str_equal(iface,
+                                               data->interface) == FALSE)
+                       continue;
+
+               if (data->member && g_str_equal(member, data->member) == FALSE)
+                       continue;
+
+               if (data->argument && g_str_equal(arg,
+                                               data->argument) == FALSE)
+                       continue;
 
-               data->handle_func(connection, message, data);
+               if (data->handle_func) {
+                       data->lock = TRUE;
 
-               data->callbacks = data->processed;
-               data->processed = NULL;
-               data->lock = FALSE;
+                       data->handle_func(connection, message, data);
+
+                       data->callbacks = data->processed;
+                       data->processed = NULL;
+                       data->lock = FALSE;
+               }
+
+               if (!data->callbacks)
+                       delete_listener = g_slist_prepend(delete_listener,
+                                                               current);
        }
 
-       if (data->callbacks)
+       if (delete_listener == NULL)
                return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 
-       remove_match(data);
+       for (current = delete_listener; current != NULL;
+                                       current = delete_listener->next) {
+               GSList *l = current->data;
 
-       listeners = g_slist_remove(listeners, data);
-       filter_data_free(data);
+               data = l->data;
 
-       /* Remove filter if there no listener left for the connection */
-       data = filter_data_find(connection, NULL, NULL, NULL, NULL, NULL,
-                                       NULL);
-       if (data == NULL)
-               dbus_connection_remove_filter(connection, message_filter,
-                                               NULL);
+               /* Has any other callback added callbacks back to this data? */
+               if (data->callbacks != NULL)
+                       continue;
+
+               remove_match(data);
+               listeners = g_slist_delete_link(listeners, l);
+
+               filter_data_free(data);
+       }
+
+       g_slist_free(delete_listener);
 
        return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
 }
@@ -553,12 +588,16 @@ static gboolean update_service(void *user_data)
 {
        struct service_data *data = user_data;
        struct filter_callback *cb = data->callback;
+       DBusConnection *conn;
 
        update_name_cache(data->name, data->owner);
+       conn = dbus_connection_ref(data->conn);
+       service_data_free(data);
+
        if (cb->conn_func)
-               cb->conn_func(data->conn, cb->user_data);
+               cb->conn_func(conn, cb->user_data);
 
-       service_data_free(data);
+       dbus_connection_unref(conn);
 
        return FALSE;
 }
@@ -712,6 +751,34 @@ guint g_dbus_add_signal_watch(DBusConnection *connection,
        return cb->id;
 }
 
+guint g_dbus_add_properties_watch(DBusConnection *connection,
+                               const char *sender, const char *path,
+                               const char *interface,
+                               GDBusSignalFunction function, void *user_data,
+                               GDBusDestroyFunction destroy)
+{
+       struct filter_data *data;
+       struct filter_callback *cb;
+
+       data = filter_data_get(connection, signal_filter, sender, path,
+                               DBUS_INTERFACE_PROPERTIES, "PropertiesChanged",
+                               interface);
+       if (data == NULL)
+               return 0;
+
+       cb = filter_data_add_callback(data, NULL, NULL, function, destroy,
+                                       user_data);
+       if (cb == NULL)
+               return 0;
+
+       if (data->name != NULL && data->name_watch == 0)
+               data->name_watch = g_dbus_add_service_watch(connection,
+                                                       data->name, NULL,
+                                                       NULL, NULL, NULL);
+
+       return cb->id;
+}
+
 gboolean g_dbus_remove_watch(DBusConnection *connection, guint id)
 {
        struct filter_data *data;
@@ -738,11 +805,8 @@ void g_dbus_remove_all_watches(DBusConnection *connection)
 {
        struct filter_data *data;
 
-       while ((data = filter_data_find(connection, NULL, NULL, NULL, NULL,
-                                       NULL, NULL))) {
+       while ((data = filter_data_find(connection))) {
                listeners = g_slist_remove(listeners, data);
                filter_data_call_and_free(data);
        }
-
-       dbus_connection_remove_filter(connection, message_filter, NULL);
 }
diff --git a/gobex/gobex-apparam.c b/gobex/gobex-apparam.c
new file mode 100644 (file)
index 0000000..4328172
--- /dev/null
@@ -0,0 +1,365 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <unistd.h>
+#include <errno.h>
+
+#include "gobex-apparam.h"
+#include "gobex-debug.h"
+
+struct _GObexApparam {
+       GHashTable *tags;
+};
+
+struct apparam_tag {
+       guint8 id;
+       guint8 len;
+       union {
+               /* Data is stored in network order */
+               char string[0];
+               guint8 data[0];
+               guint8 u8;
+               guint16 u16;
+               guint32 u32;
+               guint64 u64;
+       } value;
+} __attribute__ ((packed));
+
+static struct apparam_tag *tag_new(guint8 id, guint8 len, const void *data)
+{
+       struct apparam_tag *tag;
+
+       tag = g_malloc0(2 + len);
+       tag->id = id;
+       tag->len = len;
+       memcpy(tag->value.data, data, len);
+
+       return tag;
+}
+
+static GObexApparam *g_obex_apparam_new(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_new0(GObexApparam, 1);
+       apparam->tags = g_hash_table_new_full(g_direct_hash, g_direct_equal,
+                                                       NULL, g_free);
+
+       return apparam;
+}
+
+static struct apparam_tag *apparam_tag_decode(const void *data, gsize size,
+                                                       gsize *parsed)
+{
+       struct apparam_tag *tag;
+       const guint8 *ptr = data;
+       guint8 id;
+       guint8 len;
+
+       if (size < 2)
+               return NULL;
+
+       id = ptr[0];
+       len = ptr[1];
+
+       if (len > size - 2)
+               return NULL;
+
+       tag = tag_new(id, len, ptr + 2);
+       if (tag == NULL)
+               return NULL;
+
+       *parsed = 2 + tag->len;
+
+       return tag;
+}
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size)
+{
+       GObexApparam *apparam;
+       GHashTable *tags;
+       gsize count = 0;
+
+       if (size < 2)
+               return NULL;
+
+       apparam = g_obex_apparam_new();
+
+       tags = apparam->tags;
+       while (count < size) {
+               struct apparam_tag *tag;
+               gsize parsed;
+               guint id;
+
+               tag = apparam_tag_decode(data + count, size - count, &parsed);
+               if (tag == NULL)
+                       break;
+
+               id = tag->id;
+               g_hash_table_insert(tags, GUINT_TO_POINTER(id), tag);
+
+               count += parsed;
+       }
+
+       if (count != size) {
+               g_obex_apparam_free(apparam);
+               return NULL;
+       }
+
+       return apparam;
+}
+
+static gssize tag_encode(struct apparam_tag *tag, void *buf, gsize len)
+{
+       gsize count = 2 + tag->len;
+
+       if (len < count)
+               return -ENOBUFS;
+
+       memcpy(buf, tag, count);
+
+       return count;
+}
+
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize len)
+{
+       gsize count = 0;
+       gssize ret;
+       GHashTableIter iter;
+       gpointer key, value;
+
+       g_hash_table_iter_init(&iter, apparam->tags);
+       while (g_hash_table_iter_next(&iter, &key, &value)) {
+               struct apparam_tag *tag = value;
+
+               ret = tag_encode(tag, buf + count, len - count);
+               if (ret < 0)
+                       return ret;
+
+               count += ret;
+       }
+
+       return count;
+}
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+                                               const void *value, gsize len)
+{
+       struct apparam_tag *tag;
+       guint uid = id;
+
+       if (apparam == NULL)
+               apparam = g_obex_apparam_new();
+
+       tag = tag_new(id, len, value);
+       g_hash_table_replace(apparam->tags, GUINT_TO_POINTER(uid), tag);
+
+       return apparam;
+}
+
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 value)
+{
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &value, 1);
+}
+
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 value)
+{
+       guint16 num = g_htons(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 2);
+}
+
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 value)
+{
+       guint32 num = g_htonl(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %u", id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 4);
+}
+
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 value)
+{
+       guint64 num = GUINT64_TO_BE(value);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %"
+                                               G_GUINT64_FORMAT, id, value);
+
+       return g_obex_apparam_set_bytes(apparam, id, &num, 8);
+}
+
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+                                                       const char *value)
+{
+       gsize len;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x value %s", id, value);
+
+       len = strlen(value) + 1;
+       if (len > G_MAXUINT8) {
+               ((char *) value)[G_MAXUINT8 - 1] = '\0';
+               len = G_MAXUINT8;
+       }
+
+       return g_obex_apparam_set_bytes(apparam, id, value, len);
+}
+
+static struct apparam_tag *g_obex_apparam_find_tag(GObexApparam *apparam,
+                                                               guint id)
+{
+       return g_hash_table_lookup(apparam->tags, GUINT_TO_POINTER(id));
+}
+
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       *dest = tag->value.u8;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = g_ntohs(tag->value.u16);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = g_ntohl(tag->value.u32);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%u", *dest);
+
+       return TRUE;
+}
+
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 *dest)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       if (tag->len < sizeof(*dest))
+               return FALSE;
+
+       *dest = GUINT64_FROM_BE(tag->value.u64);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%" G_GUINT64_FORMAT, *dest);
+
+       return TRUE;
+}
+
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id)
+{
+       struct apparam_tag *tag;
+       char *string;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return NULL;
+
+       string = g_strndup(tag->value.string, tag->len);
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "%s", string);
+
+       return string;
+}
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+                                       const guint8 **val, gsize *len)
+{
+       struct apparam_tag *tag;
+
+       g_obex_debug(G_OBEX_DEBUG_APPARAM, "tag 0x%02x", id);
+
+       tag = g_obex_apparam_find_tag(apparam, id);
+       if (tag == NULL)
+               return FALSE;
+
+       *len = tag->len;
+       *val = tag->value.data;
+
+       return TRUE;
+}
+
+void g_obex_apparam_free(GObexApparam *apparam)
+{
+       g_hash_table_unref(apparam->tags);
+       g_free(apparam);
+}
diff --git a/gobex/gobex-apparam.h b/gobex/gobex-apparam.h
new file mode 100644 (file)
index 0000000..6c08609
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_APPARAM_H
+#define __GOBEX_APPARAM_H
+
+#include <glib.h>
+
+typedef struct _GObexApparam GObexApparam;
+
+GObexApparam *g_obex_apparam_decode(const void *data, gsize size);
+gssize g_obex_apparam_encode(GObexApparam *apparam, void *buf, gsize size);
+
+GObexApparam *g_obex_apparam_set_bytes(GObexApparam *apparam, guint8 id,
+                                               const void *value, gsize size);
+GObexApparam *g_obex_apparam_set_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 value);
+GObexApparam *g_obex_apparam_set_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 value);
+GObexApparam *g_obex_apparam_set_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 value);
+GObexApparam *g_obex_apparam_set_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 value);
+GObexApparam *g_obex_apparam_set_string(GObexApparam *apparam, guint8 id,
+                                                       const char *value);
+
+gboolean g_obex_apparam_get_bytes(GObexApparam *apparam, guint8 id,
+                                       const guint8 **val, gsize *len);
+gboolean g_obex_apparam_get_uint8(GObexApparam *apparam, guint8 id,
+                                                       guint8 *value);
+gboolean g_obex_apparam_get_uint16(GObexApparam *apparam, guint8 id,
+                                                       guint16 *value);
+gboolean g_obex_apparam_get_uint32(GObexApparam *apparam, guint8 id,
+                                                       guint32 *value);
+gboolean g_obex_apparam_get_uint64(GObexApparam *apparam, guint8 id,
+                                                       guint64 *value);
+char *g_obex_apparam_get_string(GObexApparam *apparam, guint8 id);
+
+void g_obex_apparam_free(GObexApparam *apparam);
+
+#endif /* __GOBEX_APPARAM_H */
diff --git a/gobex/gobex-debug.h b/gobex/gobex-debug.h
new file mode 100644 (file)
index 0000000..a98653d
--- /dev/null
@@ -0,0 +1,78 @@
+/*
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_DEBUG_H
+#define __GOBEX_DEBUG_H
+
+#include <glib.h>
+#include <stdio.h>
+#include <ctype.h>
+
+#define G_OBEX_DEBUG_NONE      1
+#define G_OBEX_DEBUG_ERROR     (1 << 1)
+#define G_OBEX_DEBUG_COMMAND   (1 << 2)
+#define G_OBEX_DEBUG_TRANSFER  (1 << 3)
+#define G_OBEX_DEBUG_HEADER    (1 << 4)
+#define G_OBEX_DEBUG_PACKET    (1 << 5)
+#define G_OBEX_DEBUG_DATA      (1 << 6)
+#define G_OBEX_DEBUG_APPARAM   (1 << 7)
+
+extern guint gobex_debug;
+
+#define g_obex_debug(level, format, ...) \
+       if (gobex_debug & level) \
+               g_log("gobex", G_LOG_LEVEL_DEBUG, "%s:%s() " format, __FILE__, \
+                                               __func__, ## __VA_ARGS__)
+
+static inline void g_obex_dump(guint level, const char *prefix,
+                                       const void *buf, gsize len)
+{
+       const guint8 *data = buf;
+       int n = 0;
+
+       if (!(gobex_debug & level))
+               return;
+
+       while (len > 0) {
+               int i, size;
+
+               printf("%s %04x:", prefix, n);
+
+               size = len > 16 ? 16 : len;
+
+               for (i = 0; i < size; i++)
+                       printf("%02x%s", data[i], (i + 1) % 8 ? " " : "  ");
+
+               for (; i < 16; i++)
+                       printf("  %s", (i + 1) % 8 ? " " : "  ");
+
+               for (i = 0; i < size; i++)
+                       printf("%1c", isprint(data[i]) ? data[i] : '.');
+
+               printf("\n");
+
+               data += size;
+               len -= size;
+               n += size;
+       }
+}
+
+#endif /* __GOBEX_DEBUG_H */
similarity index 76%
rename from alert/server.c
rename to gobex/gobex-defs.c
index d91b156..1c7c39a 100644 (file)
@@ -1,10 +1,8 @@
 /*
  *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *  OBEX library with GLib integration
  *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <config.h>
 #endif
 
-#include "server.h"
+#include <glib.h>
 
-int alert_server_init(void)
-{
-       return 0;
-}
+#include "gobex-defs.h"
 
-void alert_server_exit(void)
+GQuark g_obex_error_quark(void)
 {
+       return g_quark_from_static_string("g-obex-error-quark");
 }
diff --git a/gobex/gobex-defs.h b/gobex/gobex-defs.h
new file mode 100644 (file)
index 0000000..326e3cb
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_DEFS_H
+#define __GOBEX_DEFS_H
+
+#include <glib.h>
+
+typedef enum {
+       G_OBEX_DATA_INHERIT,
+       G_OBEX_DATA_COPY,
+       G_OBEX_DATA_REF,
+} GObexDataPolicy;
+
+#define G_OBEX_ERROR_FIRST (0xff + 1)
+#define G_OBEX_PROTO_ERROR(code) ((code) < G_OBEX_ERROR_FIRST)
+
+typedef enum {
+       G_OBEX_ERROR_PARSE_ERROR = G_OBEX_ERROR_FIRST,
+       G_OBEX_ERROR_INVALID_ARGS,
+       G_OBEX_ERROR_DISCONNECTED,
+       G_OBEX_ERROR_TIMEOUT,
+       G_OBEX_ERROR_CANCELLED,
+       G_OBEX_ERROR_FAILED,
+} GObexError;
+
+typedef gssize (*GObexDataProducer) (void *buf, gsize len, gpointer user_data);
+typedef gboolean (*GObexDataConsumer) (const void *buf, gsize len,
+                                                       gpointer user_data);
+
+#define G_OBEX_ERROR g_obex_error_quark()
+GQuark g_obex_error_quark(void);
+
+#endif /* __GOBEX_DEFS_H */
diff --git a/gobex/gobex-header.c b/gobex/gobex-header.c
new file mode 100644 (file)
index 0000000..281f8ea
--- /dev/null
@@ -0,0 +1,543 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+
+#include "gobex-header.h"
+#include "gobex-debug.h"
+
+/* Header types */
+#define G_OBEX_HDR_ENC_UNICODE (0 << 6)
+#define G_OBEX_HDR_ENC_BYTES   (1 << 6)
+#define G_OBEX_HDR_ENC_UINT8   (2 << 6)
+#define G_OBEX_HDR_ENC_UINT32  (3 << 6)
+
+#define G_OBEX_HDR_ENC(id)     ((id) & 0xc0)
+
+struct _GObexHeader {
+       guint8 id;
+       gboolean extdata;
+       gsize vlen;                     /* Length of value */
+       gsize hlen;                     /* Length of full encoded header */
+       union {
+               char *string;           /* UTF-8 converted from UTF-16 */
+               guint8 *data;           /* Own buffer */
+               const guint8 *extdata;  /* Reference to external buffer */
+               guint8 u8;
+               guint32 u32;
+       } v;
+};
+
+static glong utf8_to_utf16(gunichar2 **utf16, const char *utf8) {
+       glong utf16_len;
+       int i;
+
+       if (*utf8 == '\0') {
+               *utf16 = NULL;
+               return 0;
+       }
+
+       *utf16 = g_utf8_to_utf16(utf8, -1, NULL, &utf16_len, NULL);
+       if (*utf16 == NULL)
+               return -1;
+
+       /* g_utf8_to_utf16 produces host-byteorder UTF-16,
+        * but OBEX requires network byteorder (big endian) */
+       for (i = 0; i < utf16_len; i++)
+               (*utf16)[i] = g_htons((*utf16)[i]);
+
+       utf16_len = (utf16_len + 1) << 1;
+
+       return utf16_len;
+}
+
+static guint8 *put_bytes(guint8 *to, const void *from, gsize count)
+{
+       memcpy(to, from, count);
+       return (to + count);
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
+{
+       memcpy(to, from, count);
+       return (from + count);
+}
+
+gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len)
+{
+       guint8 *ptr = buf;
+       guint16 u16;
+       guint32 u32;
+       gunichar2 *utf16;
+       glong utf16_len;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       if (buf_len < header->hlen)
+               return -1;
+
+       ptr = put_bytes(ptr, &header->id, sizeof(header->id));
+
+       switch (G_OBEX_HDR_ENC(header->id)) {
+       case G_OBEX_HDR_ENC_UNICODE:
+               utf16_len = utf8_to_utf16(&utf16, header->v.string);
+               if (utf16_len < 0 || (guint16) utf16_len > buf_len)
+                       return -1;
+               g_assert_cmpuint(utf16_len + 3, ==, header->hlen);
+               u16 = g_htons(utf16_len + 3);
+               ptr = put_bytes(ptr, &u16, sizeof(u16));
+               put_bytes(ptr, utf16, utf16_len);
+               g_free(utf16);
+               break;
+       case G_OBEX_HDR_ENC_BYTES:
+               u16 = g_htons(header->hlen);
+               ptr = put_bytes(ptr, &u16, sizeof(u16));
+               if (header->extdata)
+                       put_bytes(ptr, header->v.extdata, header->vlen);
+               else
+                       put_bytes(ptr, header->v.data, header->vlen);
+               break;
+       case G_OBEX_HDR_ENC_UINT8:
+               *ptr = header->v.u8;
+               break;
+       case G_OBEX_HDR_ENC_UINT32:
+               u32 = g_htonl(header->v.u32);
+               put_bytes(ptr, &u32, sizeof(u32));
+               break;
+       default:
+               g_assert_not_reached();
+       }
+
+       return header->hlen;
+}
+
+GObexHeader *g_obex_header_decode(const void *data, gsize len,
+                               GObexDataPolicy data_policy, gsize *parsed,
+                               GError **err)
+{
+       GObexHeader *header;
+       const guint8 *ptr = data;
+       guint16 hdr_len;
+       gsize str_len;
+       GError *conv_err = NULL;
+
+       if (len < 2) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                                               "Too short header in packet");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return NULL;
+       }
+
+       header = g_new0(GObexHeader, 1);
+
+       ptr = get_bytes(&header->id, ptr, sizeof(header->id));
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       switch (G_OBEX_HDR_ENC(header->id)) {
+       case G_OBEX_HDR_ENC_UNICODE:
+               if (len < 3) {
+                       g_set_error(err, G_OBEX_ERROR,
+                               G_OBEX_ERROR_PARSE_ERROR,
+                               "Not enough data for unicode header (0x%02x)",
+                               header->id);
+                       goto failed;
+               }
+               ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+               hdr_len = g_ntohs(hdr_len);
+
+               if (hdr_len == 3) {
+                       header->v.string = g_strdup("");
+                       header->vlen = 0;
+                       header->hlen = hdr_len;
+                       *parsed = hdr_len;
+                       break;
+               }
+
+               if (hdr_len > len || hdr_len < 5) {
+                       g_set_error(err, G_OBEX_ERROR,
+                               G_OBEX_ERROR_PARSE_ERROR,
+                               "Invalid unicode header (0x%02x) length (%u)",
+                               header->id, hdr_len);
+                       goto failed;
+               }
+
+               header->v.string = g_convert((const char *) ptr, hdr_len - 5,
+                                               "UTF-8", "UTF-16BE",
+                                               NULL, &str_len, &conv_err);
+               if (header->v.string == NULL) {
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_PARSE_ERROR,
+                                       "Unicode conversion failed: %s",
+                                       conv_err->message);
+                       g_error_free(conv_err);
+                       goto failed;
+               }
+
+               header->vlen = (gsize) str_len;
+               header->hlen = hdr_len;
+
+               *parsed = hdr_len;
+
+               break;
+       case G_OBEX_HDR_ENC_BYTES:
+               if (len < 3) {
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_PARSE_ERROR,
+                                       "Too short byte array header");
+                       goto failed;
+               }
+               ptr = get_bytes(&hdr_len, ptr, sizeof(hdr_len));
+               hdr_len = g_ntohs(hdr_len);
+               if (hdr_len > len) {
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_PARSE_ERROR,
+                                       "Too long byte array header");
+                       goto failed;
+               }
+
+               if (hdr_len < 3) {
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_PARSE_ERROR,
+                                       "Too small byte array length");
+                       goto failed;
+               }
+
+               header->vlen = hdr_len - 3;
+               header->hlen = hdr_len;
+
+               switch (data_policy) {
+               case G_OBEX_DATA_COPY:
+                       header->v.data = g_memdup(ptr, header->vlen);
+                       break;
+               case G_OBEX_DATA_REF:
+                       header->extdata = TRUE;
+                       header->v.extdata = ptr;
+                       break;
+               default:
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_INVALID_ARGS,
+                                       "Invalid data policy");
+                       goto failed;
+               }
+
+               *parsed = hdr_len;
+
+               break;
+       case G_OBEX_HDR_ENC_UINT8:
+               header->vlen = 1;
+               header->hlen = 2;
+               header->v.u8 = *ptr;
+               *parsed = 2;
+               break;
+       case G_OBEX_HDR_ENC_UINT32:
+               if (len < 5) {
+                       g_set_error(err, G_OBEX_ERROR,
+                                       G_OBEX_ERROR_PARSE_ERROR,
+                                       "Too short uint32 header");
+                       goto failed;
+               }
+               header->vlen = 4;
+               header->hlen = 5;
+               get_bytes(&header->v.u32, ptr, sizeof(header->v.u32));
+               header->v.u32 = g_ntohl(header->v.u32);
+               *parsed = 5;
+               break;
+       default:
+               g_assert_not_reached();
+       }
+
+       return header;
+
+failed:
+       if (*err)
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+       g_obex_header_free(header);
+       return NULL;
+}
+
+void g_obex_header_free(GObexHeader *header)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       switch (G_OBEX_HDR_ENC(header->id)) {
+       case G_OBEX_HDR_ENC_UNICODE:
+               g_free(header->v.string);
+               break;
+       case G_OBEX_HDR_ENC_BYTES:
+               if (!header->extdata)
+                       g_free(header->v.data);
+               break;
+       case G_OBEX_HDR_ENC_UINT8:
+       case G_OBEX_HDR_ENC_UINT32:
+               break;
+       default:
+               g_assert_not_reached();
+       }
+
+       g_free(header);
+}
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UNICODE)
+               return FALSE;
+
+       *str = header->v.string;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", *str);
+
+       return TRUE;
+}
+
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+                                                               gsize *len)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_BYTES)
+               return FALSE;
+
+       *len = header->vlen;
+
+       if (header->extdata)
+               *val = header->v.extdata;
+       else
+               *val = header->v.data;
+
+       return TRUE;
+}
+
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header)
+{
+       gboolean ret;
+       const guint8 *val;
+       gsize len;
+
+       ret = g_obex_header_get_bytes(header, &val, &len);
+       if (!ret)
+               return NULL;
+
+       return g_obex_apparam_decode(val, len);
+}
+
+gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT8)
+               return FALSE;
+
+       *val = header->v.u8;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val);
+
+       return TRUE;
+}
+
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x",
+                                               G_OBEX_HDR_ENC(header->id));
+
+       if (G_OBEX_HDR_ENC(header->id) != G_OBEX_HDR_ENC_UINT32)
+               return FALSE;
+
+       *val = header->v.u32;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", *val);
+
+       return TRUE;
+}
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str)
+{
+       GObexHeader *header;
+       gsize len;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id));
+
+       if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UNICODE)
+               return NULL;
+
+       header = g_new0(GObexHeader, 1);
+
+       header->id = id;
+
+       len = g_utf8_strlen(str, -1);
+
+       header->vlen = len;
+       header->hlen = len == 0 ? 3 : 3 + ((len + 1) * 2);
+       header->v.string = g_strdup(str);
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%s", header->v.string);
+
+       return header;
+}
+
+GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len)
+{
+       GObexHeader *header;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id));
+
+       if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_BYTES)
+               return NULL;
+
+       header = g_new0(GObexHeader, 1);
+
+       header->id = id;
+       header->vlen = len;
+       header->hlen = len + 3;
+       header->v.data = g_memdup(data, len);
+
+       return header;
+}
+
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam)
+{
+       guint8 buf[1024];
+       gssize len;
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       if (len < 0)
+               return NULL;
+
+       return g_obex_header_new_bytes(G_OBEX_HDR_APPARAM, buf, len);
+}
+
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val)
+{
+       GObexHeader *header;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id));
+
+       if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT8)
+               return NULL;
+
+       header = g_new0(GObexHeader, 1);
+
+       header->id = id;
+       header->vlen = 1;
+       header->hlen = 2;
+       header->v.u8 = val;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u8);
+
+       return header;
+}
+
+GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val)
+{
+       GObexHeader *header;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x", G_OBEX_HDR_ENC(id));
+
+       if (G_OBEX_HDR_ENC(id) != G_OBEX_HDR_ENC_UINT32)
+               return NULL;
+
+       header = g_new0(GObexHeader, 1);
+
+       header->id = id;
+       header->vlen = 4;
+       header->hlen = 5;
+       header->v.u32 = val;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "%u", header->v.u32);
+
+       return header;
+}
+
+guint8 g_obex_header_get_id(GObexHeader *header)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x id 0x%02x",
+                               G_OBEX_HDR_ENC(header->id), header->id);
+
+       return header->id;
+}
+
+guint16 g_obex_header_get_length(GObexHeader *header)
+{
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "header 0x%02x length %zu",
+                               G_OBEX_HDR_ENC(header->id), header->hlen);
+
+       return header->hlen;
+}
+
+GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args,
+                                                       gsize *total_len)
+{
+       unsigned int id = first_hdr_id;
+       GSList *l = NULL;
+
+       g_obex_debug(G_OBEX_DEBUG_HEADER, "");
+
+       *total_len = 0;
+
+       while (id != G_OBEX_HDR_INVALID) {
+               GObexHeader *hdr;
+               const char *str;
+               const void *bytes;
+               unsigned int val;
+               gsize len;
+
+               switch (G_OBEX_HDR_ENC(id)) {
+               case G_OBEX_HDR_ENC_UNICODE:
+                       str = va_arg(args, const char *);
+                       hdr = g_obex_header_new_unicode(id, str);
+                       break;
+               case G_OBEX_HDR_ENC_BYTES:
+                       bytes = va_arg(args, void *);
+                       len = va_arg(args, gsize);
+                       hdr = g_obex_header_new_bytes(id, bytes, len);
+                       break;
+               case G_OBEX_HDR_ENC_UINT8:
+                       val = va_arg(args, unsigned int);
+                       hdr = g_obex_header_new_uint8(id, val);
+                       break;
+               case G_OBEX_HDR_ENC_UINT32:
+                       val = va_arg(args, unsigned int);
+                       hdr = g_obex_header_new_uint32(id, val);
+                       break;
+               default:
+                       g_assert_not_reached();
+               }
+
+               l = g_slist_append(l, hdr);
+               *total_len += hdr->hlen;
+               id = va_arg(args, int);
+       }
+
+       return l;
+}
diff --git a/gobex/gobex-header.h b/gobex/gobex-header.h
new file mode 100644 (file)
index 0000000..42a2a0c
--- /dev/null
@@ -0,0 +1,102 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_HEADER_H
+#define __GOBEX_HEADER_H
+
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+#include <gobex/gobex-apparam.h>
+
+/* Header ID's */
+#define G_OBEX_HDR_INVALID     0x00
+
+#define G_OBEX_HDR_COUNT               0xc0
+#define G_OBEX_HDR_NAME                        0x01
+#define G_OBEX_HDR_TYPE                        0x42
+#define G_OBEX_HDR_LENGTH              0xc3
+#define G_OBEX_HDR_TIME                        0x44
+#define G_OBEX_HDR_DESCRIPTION         0x05
+#define G_OBEX_HDR_TARGET              0x46
+#define G_OBEX_HDR_HTTP                        0x47
+#define G_OBEX_HDR_BODY                        0x48
+#define G_OBEX_HDR_BODY_END            0x49
+#define G_OBEX_HDR_WHO                 0x4a
+#define G_OBEX_HDR_CONNECTION          0xcb
+#define G_OBEX_HDR_APPARAM             0x4c
+#define G_OBEX_HDR_AUTHCHAL            0x4d
+#define G_OBEX_HDR_AUTHRESP            0x4e
+#define G_OBEX_HDR_CREATOR             0xcf
+#define G_OBEX_HDR_WANUUID             0x50
+#define G_OBEX_HDR_OBJECTCLASS         0x51
+#define G_OBEX_HDR_SESSIONPARAM                0x52
+#define G_OBEX_HDR_SESSIONSEQ          0x93
+#define G_OBEX_HDR_ACTION              0x94
+#define G_OBEX_HDR_DESTNAME            0x15
+#define G_OBEX_HDR_PERMISSIONS         0xd6
+#define G_OBEX_HDR_SRM                 0x97
+#define G_OBEX_HDR_SRMP                        0x98
+
+/* Action header values */
+#define G_OBEX_ACTION_COPY             0x00
+#define G_OBEX_ACTION_MOVE             0x01
+#define G_OBEX_ACTION_SETPERM          0x02
+
+/* SRM header values */
+#define G_OBEX_SRM_DISABLE             0x00
+#define G_OBEX_SRM_ENABLE              0x01
+#define G_OBEX_SRM_INDICATE            0x02
+
+/* SRMP header values */
+#define G_OBEX_SRMP_NEXT               0x00
+#define G_OBEX_SRMP_WAIT               0x01
+#define G_OBEX_SRMP_NEXT_WAIT          0x02
+
+typedef struct _GObexHeader GObexHeader;
+
+gboolean g_obex_header_get_unicode(GObexHeader *header, const char **str);
+gboolean g_obex_header_get_bytes(GObexHeader *header, const guint8 **val,
+                                                               gsize *len);
+gboolean g_obex_header_get_uint8(GObexHeader *header, guint8 *val);
+gboolean g_obex_header_get_uint32(GObexHeader *header, guint32 *val);
+GObexApparam *g_obex_header_get_apparam(GObexHeader *header);
+
+GObexHeader *g_obex_header_new_unicode(guint8 id, const char *str);
+GObexHeader *g_obex_header_new_bytes(guint8 id, const void *data, gsize len);
+GObexHeader *g_obex_header_new_uint8(guint8 id, guint8 val);
+GObexHeader *g_obex_header_new_uint32(guint8 id, guint32 val);
+GObexHeader *g_obex_header_new_apparam(GObexApparam *apparam);
+
+GSList *g_obex_header_create_list(guint8 first_hdr_id, va_list args,
+                                                       gsize *total_len);
+
+guint8 g_obex_header_get_id(GObexHeader *header);
+guint16 g_obex_header_get_length(GObexHeader *header);
+
+gssize g_obex_header_encode(GObexHeader *header, void *buf, gsize buf_len);
+GObexHeader *g_obex_header_decode(const void *data, gsize len,
+                               GObexDataPolicy data_policy, gsize *parsed,
+                               GError **err);
+void g_obex_header_free(GObexHeader *header);
+
+#endif /* __GOBEX_HEADER_H */
diff --git a/gobex/gobex-packet.c b/gobex/gobex-packet.c
new file mode 100644 (file)
index 0000000..4c14cf7
--- /dev/null
@@ -0,0 +1,456 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "gobex-defs.h"
+#include "gobex-packet.h"
+#include "gobex-debug.h"
+
+#define FINAL_BIT 0x80
+
+struct _GObexPacket {
+       guint8 opcode;
+       gboolean final;
+
+       GObexDataPolicy data_policy;
+
+       union {
+               void *buf;              /* Non-header data */
+               const void *buf_ref;    /* Reference to non-header data */
+       } data;
+       gsize data_len;
+
+       gsize hlen;             /* Length of all encoded headers */
+       GSList *headers;
+
+       GObexDataProducer get_body;
+       gpointer get_body_data;
+};
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id)
+{
+       GSList *l;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+               GObexHeader *hdr = l->data;
+
+               if (g_obex_header_get_id(hdr) == id)
+                       return hdr;
+       }
+
+       return NULL;
+}
+
+GObexHeader *g_obex_packet_get_body(GObexPacket *pkt)
+{
+       GObexHeader *body;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       body = g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY);
+       if (body != NULL)
+               return body;
+
+       return g_obex_packet_get_header(pkt, G_OBEX_HDR_BODY_END);
+}
+
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (final)
+               *final = pkt->final;
+
+       return pkt->opcode;
+}
+
+gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       pkt->headers = g_slist_prepend(pkt->headers, header);
+       pkt->hlen += g_obex_header_get_length(header);
+
+       return TRUE;
+}
+
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       pkt->headers = g_slist_append(pkt->headers, header);
+       pkt->hlen += g_obex_header_get_length(header);
+
+       return TRUE;
+}
+
+gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
+                                                       gpointer user_data)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (pkt->get_body != NULL)
+               return FALSE;
+
+       pkt->get_body = func;
+       pkt->get_body_data = user_data;
+
+       return TRUE;
+}
+
+gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
+                                                       const char *str)
+{
+       GObexHeader *hdr;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       hdr = g_obex_header_new_unicode(id, str);
+       if (hdr == NULL)
+               return FALSE;
+
+       return g_obex_packet_add_header(pkt, hdr);
+}
+
+gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
+                                               const void *data, gsize len)
+{
+       GObexHeader *hdr;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       hdr = g_obex_header_new_bytes(id, data, len);
+       if (hdr == NULL)
+               return FALSE;
+
+       return g_obex_packet_add_header(pkt, hdr);
+}
+
+gboolean g_obex_packet_add_uint8(GObexPacket *pkt, guint8 id, guint8 val)
+{
+       GObexHeader *hdr;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       hdr = g_obex_header_new_uint8(id, val);
+       if (hdr == NULL)
+               return FALSE;
+
+       return g_obex_packet_add_header(pkt, hdr);
+}
+
+gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val)
+{
+       GObexHeader *hdr;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       hdr = g_obex_header_new_uint32(id, val);
+       if (hdr == NULL)
+               return FALSE;
+
+       return g_obex_packet_add_header(pkt, hdr);
+}
+
+const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (pkt->data_len == 0) {
+               *len = 0;
+               return NULL;
+       }
+
+       *len = pkt->data_len;
+
+       switch (pkt->data_policy) {
+       case G_OBEX_DATA_INHERIT:
+       case G_OBEX_DATA_COPY:
+               return pkt->data.buf;
+       case G_OBEX_DATA_REF:
+               return pkt->data.buf_ref;
+       }
+
+       g_assert_not_reached();
+}
+
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
+                                               GObexDataPolicy data_policy)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (pkt->data.buf || pkt->data.buf_ref)
+               return FALSE;
+
+       pkt->data_policy = data_policy;
+       pkt->data_len = len;
+
+       switch (data_policy) {
+       case G_OBEX_DATA_COPY:
+               pkt->data.buf = g_memdup(data, len);
+               break;
+       case G_OBEX_DATA_REF:
+               pkt->data.buf_ref = data;
+               break;
+       case G_OBEX_DATA_INHERIT:
+               pkt->data.buf = (void *) data;
+               break;
+       }
+
+       return TRUE;
+}
+
+GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
+                                       guint8 first_hdr_id, va_list args)
+{
+       GObexPacket *pkt;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
+
+       pkt = g_new0(GObexPacket, 1);
+
+       pkt->opcode = opcode;
+       pkt->final = final;
+       pkt->headers = g_obex_header_create_list(first_hdr_id, args,
+                                                               &pkt->hlen);
+       pkt->data_policy = G_OBEX_DATA_COPY;
+
+       return pkt;
+}
+
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
+                                               guint8 first_hdr_id, ...)
+{
+       GObexPacket *pkt;
+       va_list args;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", opcode);
+
+       va_start(args, first_hdr_id);
+       pkt = g_obex_packet_new_valist(opcode, final, first_hdr_id, args);
+       va_end(args);
+
+       return pkt;
+}
+
+void g_obex_packet_free(GObexPacket *pkt)
+{
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       switch (pkt->data_policy) {
+       case G_OBEX_DATA_INHERIT:
+       case G_OBEX_DATA_COPY:
+               g_free(pkt->data.buf);
+               break;
+       case G_OBEX_DATA_REF:
+               break;
+       }
+
+       g_slist_foreach(pkt->headers, (GFunc) g_obex_header_free, NULL);
+       g_slist_free(pkt->headers);
+       g_free(pkt);
+}
+
+static gboolean parse_headers(GObexPacket *pkt, const void *data, gsize len,
+                                               GObexDataPolicy data_policy,
+                                               GError **err)
+{
+       const guint8 *buf = data;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       while (len > 0) {
+               GObexHeader *header;
+               gsize parsed;
+
+               header = g_obex_header_decode(buf, len, data_policy, &parsed,
+                                                                       err);
+               if (header == NULL)
+                       return FALSE;
+
+               pkt->headers = g_slist_append(pkt->headers, header);
+               pkt->hlen += parsed;
+
+               len -= parsed;
+               buf += parsed;
+       }
+
+       return TRUE;
+}
+
+static const guint8 *get_bytes(void *to, const guint8 *from, gsize count)
+{
+       memcpy(to, from, count);
+       return (from + count);
+}
+
+GObexPacket *g_obex_packet_decode(const void *data, gsize len,
+                                               gsize header_offset,
+                                               GObexDataPolicy data_policy,
+                                               GError **err)
+{
+       const guint8 *buf = data;
+       guint16 packet_len;
+       guint8 opcode;
+       GObexPacket *pkt;
+       gboolean final;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "");
+
+       if (data_policy == G_OBEX_DATA_INHERIT) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
+                                                       "Invalid data policy");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return NULL;
+       }
+
+       if (len < 3 + header_offset) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                                       "Not enough data to decode packet");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return NULL;
+       }
+
+       buf = get_bytes(&opcode, buf, sizeof(opcode));
+       buf = get_bytes(&packet_len, buf, sizeof(packet_len));
+
+       packet_len = g_ntohs(packet_len);
+       if (packet_len != len) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "Incorrect packet length (%u != %zu)",
+                               packet_len, len);
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return NULL;
+       }
+
+       final = (opcode & FINAL_BIT) ? TRUE : FALSE;
+       opcode &= ~FINAL_BIT;
+
+       pkt = g_obex_packet_new(opcode, final, G_OBEX_HDR_INVALID);
+
+       if (header_offset == 0)
+               goto headers;
+
+       g_obex_packet_set_data(pkt, buf, header_offset, data_policy);
+       buf += header_offset;
+
+headers:
+       if (!parse_headers(pkt, buf, len - (3 + header_offset),
+                                                       data_policy, err))
+               goto failed;
+
+       return pkt;
+
+failed:
+       g_obex_packet_free(pkt);
+       return NULL;
+}
+
+static gssize get_body(GObexPacket *pkt, guint8 *buf, gsize len)
+{
+       guint16 u16;
+       gssize ret;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (len < 3)
+               return -ENOBUFS;
+
+       ret = pkt->get_body(buf + 3, len - 3, pkt->get_body_data);
+       if (ret < 0)
+               return ret;
+
+       if (ret > 0)
+               buf[0] = G_OBEX_HDR_BODY;
+       else
+               buf[0] = G_OBEX_HDR_BODY_END;
+
+       u16 = g_htons(ret + 3);
+       memcpy(&buf[1], &u16, sizeof(u16));
+
+       return ret;
+}
+
+gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len)
+{
+       gssize ret;
+       gsize count;
+       guint16 u16;
+       GSList *l;
+
+       g_obex_debug(G_OBEX_DEBUG_PACKET, "opcode 0x%02x", pkt->opcode);
+
+       if (3 + pkt->data_len + pkt->hlen > len)
+               return -ENOBUFS;
+
+       buf[0] = pkt->opcode;
+       if (pkt->final)
+               buf[0] |= FINAL_BIT;
+
+       if (pkt->data_len > 0) {
+               if (pkt->data_policy == G_OBEX_DATA_REF)
+                       memcpy(&buf[3], pkt->data.buf_ref, pkt->data_len);
+               else
+                       memcpy(&buf[3], pkt->data.buf, pkt->data_len);
+       }
+
+       count = 3 + pkt->data_len;
+
+       for (l = pkt->headers; l != NULL; l = g_slist_next(l)) {
+               GObexHeader *hdr = l->data;
+
+               if (count >= len)
+                       return -ENOBUFS;
+
+               ret = g_obex_header_encode(hdr, buf + count, len - count);
+               if (ret < 0)
+                       return ret;
+
+               count += ret;
+       }
+
+       if (pkt->get_body) {
+               ret = get_body(pkt, buf + count, len - count);
+               if (ret < 0)
+                       return ret;
+               if (ret == 0) {
+                       if (pkt->opcode == G_OBEX_RSP_CONTINUE)
+                               buf[0] = G_OBEX_RSP_SUCCESS;
+                       buf[0] |= FINAL_BIT;
+               }
+
+               count += ret + 3;
+       }
+
+       u16 = g_htons(count);
+       memcpy(&buf[1], &u16, sizeof(u16));
+
+       return count;
+}
diff --git a/gobex/gobex-packet.h b/gobex/gobex-packet.h
new file mode 100644 (file)
index 0000000..6121fa7
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_PACKET_H
+#define __GOBEX_PACKET_H
+
+#include <stdarg.h>
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+#include <gobex/gobex-header.h>
+
+/* Request opcodes */
+#define G_OBEX_OP_CONNECT                      0x00
+#define G_OBEX_OP_DISCONNECT                   0x01
+#define G_OBEX_OP_PUT                          0x02
+#define G_OBEX_OP_GET                          0x03
+#define G_OBEX_OP_SETPATH                      0x05
+#define G_OBEX_OP_ACTION                       0x06
+#define G_OBEX_OP_SESSION                      0x07
+#define G_OBEX_OP_ABORT                                0x7f
+
+/* Response codes */
+#define G_OBEX_RSP_CONTINUE                    0x10
+#define G_OBEX_RSP_SUCCESS                     0x20
+#define G_OBEX_RSP_CREATED                     0x21
+#define G_OBEX_RSP_ACCEPTED                    0x22
+#define G_OBEX_RSP_NON_AUTHORITATIVE           0x23
+#define G_OBEX_RSP_NO_CONTENT                  0x24
+#define G_OBEX_RSP_RESET_CONTENT               0x25
+#define G_OBEX_RSP_PARTIAL_CONTENT             0x26
+#define G_OBEX_RSP_MULTIPLE_CHOICES            0x30
+#define G_OBEX_RSP_MOVED_PERMANENTLY           0x31
+#define G_OBEX_RSP_MOVED_TEMPORARILY           0x32
+#define G_OBEX_RSP_SEE_OTHER                   0x33
+#define G_OBEX_RSP_NOT_MODIFIED                        0x34
+#define G_OBEX_RSP_USE_PROXY                   0x35
+#define G_OBEX_RSP_BAD_REQUEST                 0x40
+#define G_OBEX_RSP_UNAUTHORIZED                        0x41
+#define G_OBEX_RSP_PAYMENT_REQUIRED            0x42
+#define G_OBEX_RSP_FORBIDDEN                   0x43
+#define G_OBEX_RSP_NOT_FOUND                   0x44
+#define G_OBEX_RSP_METHOD_NOT_ALLOWED          0x45
+#define G_OBEX_RSP_NOT_ACCEPTABLE              0x46
+#define G_OBEX_RSP_PROXY_AUTH_REQUIRED         0x47
+#define G_OBEX_RSP_REQUEST_TIME_OUT            0x48
+#define G_OBEX_RSP_CONFLICT                    0x49
+#define G_OBEX_RSP_GONE                                0x4a
+#define G_OBEX_RSP_LENGTH_REQUIRED             0x4b
+#define G_OBEX_RSP_PRECONDITION_FAILED         0x4c
+#define G_OBEX_RSP_REQ_ENTITY_TOO_LARGE                0x4d
+#define G_OBEX_RSP_REQ_URL_TOO_LARGE           0x4e
+#define G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE      0x4f
+#define G_OBEX_RSP_INTERNAL_SERVER_ERROR       0x50
+#define G_OBEX_RSP_NOT_IMPLEMENTED             0x51
+#define G_OBEX_RSP_BAD_GATEWAY                 0x52
+#define G_OBEX_RSP_SERVICE_UNAVAILABLE         0x53
+#define G_OBEX_RSP_GATEWAY_TIMEOUT             0x54
+#define G_OBEX_RSP_VERSION_NOT_SUPPORTED       0x55
+#define G_OBEX_RSP_DATABASE_FULL               0x60
+#define G_OBEX_RSP_DATABASE_LOCKED             0x61
+
+typedef struct _GObexPacket GObexPacket;
+
+GObexHeader *g_obex_packet_get_header(GObexPacket *pkt, guint8 id);
+GObexHeader *g_obex_packet_get_body(GObexPacket *pkt);
+guint8 g_obex_packet_get_operation(GObexPacket *pkt, gboolean *final);
+gboolean g_obex_packet_prepend_header(GObexPacket *pkt, GObexHeader *header);
+gboolean g_obex_packet_add_header(GObexPacket *pkt, GObexHeader *header);
+gboolean g_obex_packet_add_body(GObexPacket *pkt, GObexDataProducer func,
+                                                       gpointer user_data);
+gboolean g_obex_packet_add_unicode(GObexPacket *pkt, guint8 id,
+                                                       const char *str);
+gboolean g_obex_packet_add_bytes(GObexPacket *pkt, guint8 id,
+                                               const void *data, gsize len);
+gboolean g_obex_packet_add_uint8(GObexPacket *pkt, guint8 id, guint8 val);
+gboolean g_obex_packet_add_uint32(GObexPacket *pkt, guint8 id, guint32 val);
+gboolean g_obex_packet_set_data(GObexPacket *pkt, const void *data, gsize len,
+                                               GObexDataPolicy data_policy);
+const void *g_obex_packet_get_data(GObexPacket *pkt, gsize *len);
+GObexPacket *g_obex_packet_new(guint8 opcode, gboolean final,
+                                               guint8 first_hdr_id, ...);
+GObexPacket *g_obex_packet_new_valist(guint8 opcode, gboolean final,
+                                       guint8 first_hdr_id, va_list args);
+void g_obex_packet_free(GObexPacket *pkt);
+
+GObexPacket *g_obex_packet_decode(const void *data, gsize len,
+                                               gsize header_offset,
+                                               GObexDataPolicy data_policy,
+                                               GError **err);
+gssize g_obex_packet_encode(GObexPacket *pkt, guint8 *buf, gsize len);
+
+#endif /* __GOBEX_PACKET_H */
diff --git a/gobex/gobex-transfer.c b/gobex/gobex-transfer.c
new file mode 100644 (file)
index 0000000..b815d60
--- /dev/null
@@ -0,0 +1,657 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+
+#include "gobex.h"
+#include "gobex-debug.h"
+
+#define FIRST_PACKET_TIMEOUT 60
+
+static GSList *transfers = NULL;
+
+static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data);
+
+struct transfer {
+       guint id;
+       guint8 opcode;
+
+       GObex *obex;
+
+       guint req_id;
+
+       guint put_id;
+       guint get_id;
+       guint abort_id;
+
+       GObexDataProducer data_producer;
+       GObexDataConsumer data_consumer;
+       GObexFunc complete_func;
+
+       gpointer user_data;
+};
+
+static void transfer_free(struct transfer *transfer)
+{
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       transfers = g_slist_remove(transfers, transfer);
+
+       if (transfer->req_id > 0)
+               g_obex_cancel_req(transfer->obex, transfer->req_id, TRUE);
+
+       if (transfer->put_id > 0)
+               g_obex_remove_request_function(transfer->obex,
+                                                       transfer->put_id);
+
+       if (transfer->get_id > 0)
+               g_obex_remove_request_function(transfer->obex,
+                                                       transfer->get_id);
+
+       if (transfer->abort_id > 0)
+               g_obex_remove_request_function(transfer->obex,
+                                                       transfer->abort_id);
+
+       g_obex_unref(transfer->obex);
+       g_free(transfer);
+}
+
+static struct transfer *find_transfer(guint id)
+{
+       GSList *l;
+
+       for (l = transfers; l != NULL; l = g_slist_next(l)) {
+               struct transfer *t = l->data;
+               if (t->id == id)
+                       return t;
+       }
+
+       return NULL;
+}
+
+static void transfer_complete(struct transfer *transfer, GError *err)
+{
+       guint id = transfer->id;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
+
+       transfer->complete_func(transfer->obex, err, transfer->user_data);
+       /* Check if the complete_func removed the transfer */
+       if (find_transfer(id) == NULL)
+               return;
+
+       transfer_free(transfer);
+}
+
+static void transfer_abort_response(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       transfer->req_id = 0;
+
+       /* Intentionally override error */
+       err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                                               "Operation was aborted");
+       g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+       transfer_complete(transfer, err);
+       g_error_free(err);
+}
+
+
+static gssize put_get_data(void *buf, gsize len, gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GObexPacket *req;
+       GError *err = NULL;
+       gssize ret;
+
+       ret = transfer->data_producer(buf, len, transfer->user_data);
+       if (ret == 0 || ret == -EAGAIN)
+               return ret;
+
+       if (ret > 0) {
+               /* Check if SRM is active */
+               if (!g_obex_srm_active(transfer->obex))
+                       return ret;
+
+               /* Generate next packet */
+               req = g_obex_packet_new(transfer->opcode, FALSE,
+                                                       G_OBEX_HDR_INVALID);
+               g_obex_packet_add_body(req, put_get_data, transfer);
+               transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
+                                               transfer_response, transfer,
+                                               &err);
+               goto done;
+       }
+
+       req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
+
+       transfer->req_id = g_obex_send_req(transfer->obex, req, -1,
+                                               transfer_abort_response,
+                                               transfer, &err);
+done:
+       if (err != NULL) {
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+
+       return ret;
+}
+
+static gboolean handle_get_body(struct transfer *transfer, GObexPacket *rsp,
+                                                               GError **err)
+{
+       GObexHeader *body = g_obex_packet_get_body(rsp);
+       gboolean ret;
+       const guint8 *buf;
+       gsize len;
+
+       if (body == NULL)
+               return TRUE;
+
+       g_obex_header_get_bytes(body, &buf, &len);
+       if (len == 0)
+               return TRUE;
+
+       ret = transfer->data_consumer(buf, len, transfer->user_data);
+       if (ret == FALSE)
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                               "Data consumer callback failed");
+
+       return ret;
+}
+
+static void transfer_response(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GObexPacket *req;
+       gboolean rspcode, final;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       transfer->req_id = 0;
+
+       if (err != NULL) {
+               transfer_complete(transfer, err);
+               return;
+       }
+
+       rspcode = g_obex_packet_get_operation(rsp, &final);
+       if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
+               err = g_error_new(G_OBEX_ERROR, rspcode, "%s",
+                                               g_obex_strerror(rspcode));
+               goto failed;
+       }
+
+       if (transfer->opcode == G_OBEX_OP_GET) {
+               handle_get_body(transfer, rsp, &err);
+               if (err != NULL)
+                       goto failed;
+       }
+
+       if (rspcode == G_OBEX_RSP_SUCCESS) {
+               transfer_complete(transfer, NULL);
+               return;
+       }
+
+       if (transfer->opcode == G_OBEX_OP_PUT) {
+               req = g_obex_packet_new(transfer->opcode, FALSE,
+                                                       G_OBEX_HDR_INVALID);
+               g_obex_packet_add_body(req, put_get_data, transfer);
+       } else if (!g_obex_srm_active(transfer->obex)) {
+               req = g_obex_packet_new(transfer->opcode, TRUE,
+                                                       G_OBEX_HDR_INVALID);
+       } else
+               return;
+
+       transfer->req_id = g_obex_send_req(obex, req, -1, transfer_response,
+                                                       transfer, &err);
+failed:
+       if (err != NULL) {
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+}
+
+static struct transfer *transfer_new(GObex *obex, guint8 opcode,
+                               GObexFunc complete_func, gpointer user_data)
+{
+       static guint next_id = 1;
+       struct transfer *transfer;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p opcode %u", obex, opcode);
+
+       transfer = g_new0(struct transfer, 1);
+
+       transfer->id = next_id++;
+       transfer->opcode = opcode;
+       transfer->obex = g_obex_ref(obex);
+       transfer->complete_func = complete_func;
+       transfer->user_data = user_data;
+
+       transfers = g_slist_append(transfers, transfer);
+
+       return transfer;
+}
+
+guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
+                       GObexDataProducer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err)
+{
+       struct transfer *transfer;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_PUT)
+               return 0;
+
+       transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
+       transfer->data_producer = data_func;
+
+       g_obex_packet_add_body(req, put_get_data, transfer);
+
+       transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
+                                       transfer_response, transfer, err);
+       if (transfer->req_id == 0) {
+               transfer_free(transfer);
+               return 0;
+       }
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       return transfer->id;
+}
+
+guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...)
+{
+       GObexPacket *req;
+       va_list args;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       va_start(args, first_hdr_id);
+       req = g_obex_packet_new_valist(G_OBEX_OP_PUT, FALSE,
+                                                       first_hdr_id, args);
+       va_end(args);
+
+       return g_obex_put_req_pkt(obex, req, data_func, complete_func,
+                                                       user_data, err);
+}
+
+static void transfer_abort_req(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GObexPacket *rsp;
+       GError *err;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                                               "Request was aborted");
+       rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
+       g_obex_send(obex, rsp, NULL);
+
+       transfer_complete(transfer, err);
+       g_error_free(err);
+}
+
+static guint8 put_get_bytes(struct transfer *transfer, GObexPacket *req)
+{
+       GObexHeader *body;
+       gboolean final;
+       guint8 rsp;
+       const guint8 *buf;
+       gsize len;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       g_obex_packet_get_operation(req, &final);
+       if (final)
+               rsp = G_OBEX_RSP_SUCCESS;
+       else
+               rsp = G_OBEX_RSP_CONTINUE;
+
+       body = g_obex_packet_get_body(req);
+       if (body == NULL)
+               return rsp;
+
+       g_obex_header_get_bytes(body, &buf, &len);
+       if (len == 0)
+               return rsp;
+
+       if (transfer->data_consumer(buf, len, transfer->user_data) == FALSE)
+               rsp = G_OBEX_RSP_FORBIDDEN;
+
+       return rsp;
+}
+
+static void transfer_put_req_first(struct transfer *transfer, GObexPacket *req,
+                                       guint8 first_hdr_id, va_list args)
+{
+       GError *err = NULL;
+       GObexPacket *rsp;
+       guint8 rspcode;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       rspcode = put_get_bytes(transfer, req);
+
+       rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_id, args);
+
+       if (!g_obex_send(transfer->obex, rsp, &err)) {
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+
+       if (rspcode != G_OBEX_RSP_CONTINUE)
+               transfer_complete(transfer, NULL);
+}
+
+static void transfer_put_req(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GError *err = NULL;
+       GObexPacket *rsp;
+       guint8 rspcode;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       rspcode = put_get_bytes(transfer, req);
+
+       /* Don't send continue while in SRM */
+       if (g_obex_srm_active(transfer->obex) &&
+                               rspcode == G_OBEX_RSP_CONTINUE)
+               goto done;
+
+       rsp = g_obex_packet_new(rspcode, TRUE, G_OBEX_HDR_INVALID);
+
+       if (!g_obex_send(obex, rsp, &err)) {
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+
+done:
+       if (rspcode != G_OBEX_RSP_CONTINUE)
+               transfer_complete(transfer, NULL);
+}
+
+guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
+                       GObexDataConsumer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err,
+                       guint8 first_hdr_id, ...)
+{
+       struct transfer *transfer;
+       va_list args;
+       guint id;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       transfer = transfer_new(obex, G_OBEX_OP_PUT, complete_func, user_data);
+       transfer->data_consumer = data_func;
+
+
+       va_start(args, first_hdr_id);
+       transfer_put_req_first(transfer, req, first_hdr_id, args);
+       va_end(args);
+       if (!g_slist_find(transfers, transfer))
+               return 0;
+
+       id = g_obex_add_request_function(obex, G_OBEX_OP_PUT, transfer_put_req,
+                                                               transfer);
+       transfer->put_id = id;
+
+       id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
+                                               transfer_abort_req, transfer);
+       transfer->abort_id = id;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       return transfer->id;
+}
+
+guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
+                       GObexDataConsumer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err)
+{
+       struct transfer *transfer;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_GET)
+               return 0;
+
+       transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
+       transfer->data_consumer = data_func;
+       transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
+                                       transfer_response, transfer, err);
+       if (transfer->req_id == 0) {
+               transfer_free(transfer);
+               return 0;
+       }
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       return transfer->id;
+}
+
+guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...)
+{
+       struct transfer *transfer;
+       GObexPacket *req;
+       va_list args;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
+       transfer->data_consumer = data_func;
+
+       va_start(args, first_hdr_id);
+       req = g_obex_packet_new_valist(G_OBEX_OP_GET, TRUE,
+                                                       first_hdr_id, args);
+       va_end(args);
+
+       transfer->req_id = g_obex_send_req(obex, req, FIRST_PACKET_TIMEOUT,
+                                       transfer_response, transfer, err);
+       if (transfer->req_id == 0) {
+               transfer_free(transfer);
+               return 0;
+       }
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       return transfer->id;
+}
+
+static gssize get_get_data(void *buf, gsize len, gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GObexPacket *req, *rsp;
+       GError *err = NULL;
+       gssize ret;
+       guint8 op;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       ret = transfer->data_producer(buf, len, transfer->user_data);
+       if (ret > 0) {
+               if (!g_obex_srm_active(transfer->obex))
+                       return ret;
+
+               /* Generate next response */
+               rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
+                                                       G_OBEX_HDR_INVALID);
+               g_obex_packet_add_body(rsp, get_get_data, transfer);
+
+               if (!g_obex_send(transfer->obex, rsp, &err)) {
+                       transfer_complete(transfer, err);
+                       g_error_free(err);
+               }
+
+               return ret;
+       }
+
+       if (ret == -EAGAIN)
+               return ret;
+
+       if (ret == 0) {
+               transfer_complete(transfer, NULL);
+               return ret;
+       }
+
+       op = g_obex_errno_to_rsp(ret);
+
+       req = g_obex_packet_new(op, TRUE, G_OBEX_HDR_INVALID);
+       g_obex_send(transfer->obex, req, NULL);
+
+       err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                               "Data producer function failed");
+       g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+       transfer_complete(transfer, err);
+       g_error_free(err);
+
+       return ret;
+}
+
+static void transfer_get_req_first(struct transfer *transfer, GObexPacket *rsp)
+{
+       GError *err = NULL;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       g_obex_packet_add_body(rsp, get_get_data, transfer);
+
+       if (!g_obex_send(transfer->obex, rsp, &err)) {
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+}
+
+static void transfer_get_req(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct transfer *transfer = user_data;
+       GError *err = NULL;
+       GObexPacket *rsp;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
+       g_obex_packet_add_body(rsp, get_get_data, transfer);
+
+       if (!g_obex_send(obex, rsp, &err)) {
+               transfer_complete(transfer, err);
+               g_error_free(err);
+       }
+}
+
+guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
+                       GObexDataProducer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err)
+{
+       struct transfer *transfer;
+       guint id;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       transfer = transfer_new(obex, G_OBEX_OP_GET, complete_func, user_data);
+       transfer->data_producer = data_func;
+
+       transfer_get_req_first(transfer, rsp);
+
+       if (!g_slist_find(transfers, transfer))
+               return 0;
+
+       id = g_obex_add_request_function(obex, G_OBEX_OP_GET, transfer_get_req,
+                                                               transfer);
+       transfer->get_id = id;
+
+       id = g_obex_add_request_function(obex, G_OBEX_OP_ABORT,
+                                               transfer_abort_req, transfer);
+       transfer->abort_id = id;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", transfer->id);
+
+       return transfer->id;
+}
+
+guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...)
+{
+       GObexPacket *rsp;
+       va_list args;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "obex %p", obex);
+
+       va_start(args, first_hdr_id);
+       rsp = g_obex_packet_new_valist(G_OBEX_RSP_CONTINUE, TRUE,
+                                                       first_hdr_id, args);
+       va_end(args);
+
+       return g_obex_get_rsp_pkt(obex, rsp, data_func, complete_func,
+                                                       user_data, err);
+}
+
+gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
+                       gpointer user_data)
+{
+       struct transfer *transfer = NULL;
+       gboolean ret = TRUE;
+
+       g_obex_debug(G_OBEX_DEBUG_TRANSFER, "transfer %u", id);
+
+       transfer = find_transfer(id);
+
+       if (transfer == NULL)
+               return FALSE;
+
+       if (complete_func == NULL)
+               goto done;
+
+       transfer->complete_func = complete_func;
+       transfer->user_data = user_data;
+
+       if (transfer->req_id == 0)
+               goto done;
+
+       ret = g_obex_cancel_req(transfer->obex, transfer->req_id, FALSE);
+       if (ret)
+               return TRUE;
+
+done:
+       transfer_free(transfer);
+       return ret;
+}
diff --git a/gobex/gobex.c b/gobex/gobex.c
new file mode 100644 (file)
index 0000000..8c08b1e
--- /dev/null
@@ -0,0 +1,1506 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include "gobex.h"
+#include "gobex-debug.h"
+
+#define G_OBEX_DEFAULT_MTU     4096
+#define G_OBEX_MINIMUM_MTU     255
+#define G_OBEX_MAXIMUM_MTU     65535
+
+#define G_OBEX_DEFAULT_TIMEOUT 10
+#define G_OBEX_ABORT_TIMEOUT   5
+
+#define G_OBEX_OP_NONE         0xff
+
+#define FINAL_BIT              0x80
+
+#define CONNID_INVALID         0xffffffff
+
+guint gobex_debug = 0;
+
+struct srm_config {
+       guint8 op;
+       gboolean enabled;
+       guint8 srm;
+       guint8 srmp;
+       gboolean outgoing;
+};
+
+struct _GObex {
+       int ref_count;
+       GIOChannel *io;
+       guint io_source;
+
+       gboolean (*read) (GObex *obex, GError **err);
+       gboolean (*write) (GObex *obex, GError **err);
+
+       guint8 *rx_buf;
+       size_t rx_data;
+       guint16 rx_pkt_len;
+       guint8 rx_last_op;
+
+       guint8 *tx_buf;
+       size_t tx_data;
+       size_t tx_sent;
+
+       gboolean suspended;
+       gboolean use_srm;
+
+       struct srm_config *srm;
+
+       guint write_source;
+
+       gssize io_rx_mtu;
+       gssize io_tx_mtu;
+
+       guint16 rx_mtu;
+       guint16 tx_mtu;
+
+       guint32 conn_id;
+
+       GQueue *tx_queue;
+
+       GSList *req_handlers;
+
+       GObexFunc disconn_func;
+       gpointer disconn_func_data;
+
+       struct pending_pkt *pending_req;
+};
+
+struct pending_pkt {
+       guint id;
+       GObex *obex;
+       GObexPacket *pkt;
+       guint timeout;
+       guint timeout_id;
+       GObexResponseFunc rsp_func;
+       gpointer rsp_data;
+       gboolean cancelled;
+};
+
+struct req_handler {
+       guint id;
+       guint8 opcode;
+       GObexRequestFunc func;
+       gpointer user_data;
+};
+
+struct connect_data {
+       guint8 version;
+       guint8 flags;
+       guint16 mtu;
+} __attribute__ ((packed));
+
+struct setpath_data {
+       guint8 flags;
+       guint8 constants;
+} __attribute__ ((packed));
+
+static struct error_code {
+       guint8 code;
+       const char *name;
+} obex_errors[] = {
+       { G_OBEX_RSP_CONTINUE,                  "Continue" },
+       { G_OBEX_RSP_SUCCESS,                   "Success" },
+       { G_OBEX_RSP_CREATED,                   "Created" },
+       { G_OBEX_RSP_ACCEPTED,                  "Accepted" },
+       { G_OBEX_RSP_NON_AUTHORITATIVE,         "Non Authoritative" },
+       { G_OBEX_RSP_NO_CONTENT,                "No Content" },
+       { G_OBEX_RSP_RESET_CONTENT,             "Reset Content" },
+       { G_OBEX_RSP_PARTIAL_CONTENT,           "Partial Content" },
+       { G_OBEX_RSP_MULTIPLE_CHOICES,          "Multiple Choices" },
+       { G_OBEX_RSP_MOVED_PERMANENTLY,         "Moved Permanently" },
+       { G_OBEX_RSP_MOVED_TEMPORARILY,         "Moved Temporarily" },
+       { G_OBEX_RSP_SEE_OTHER,                 "See Other" },
+       { G_OBEX_RSP_NOT_MODIFIED,              "Not Modified" },
+       { G_OBEX_RSP_USE_PROXY,                 "Use Proxy" },
+       { G_OBEX_RSP_BAD_REQUEST,               "Bad Request" },
+       { G_OBEX_RSP_UNAUTHORIZED,              "Unauthorized" },
+       { G_OBEX_RSP_PAYMENT_REQUIRED,          "Payment Required" },
+       { G_OBEX_RSP_FORBIDDEN,                 "Forbidden" },
+       { G_OBEX_RSP_NOT_FOUND,                 "Not Found" },
+       { G_OBEX_RSP_METHOD_NOT_ALLOWED,        "Method Not Allowed" },
+       { G_OBEX_RSP_NOT_ACCEPTABLE,            "Not Acceptable" },
+       { G_OBEX_RSP_PROXY_AUTH_REQUIRED,       "Proxy Authentication Required" },
+       { G_OBEX_RSP_REQUEST_TIME_OUT,          "Request Time Out" },
+       { G_OBEX_RSP_CONFLICT,                  "Conflict" },
+       { G_OBEX_RSP_GONE,                      "Gone" },
+       { G_OBEX_RSP_LENGTH_REQUIRED,           "Length Required" },
+       { G_OBEX_RSP_PRECONDITION_FAILED,       "Precondition Failed" },
+       { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE,      "Request Entity Too Large" },
+       { G_OBEX_RSP_REQ_URL_TOO_LARGE,         "Request URL Too Large" },
+       { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,    "Unsupported Media Type" },
+       { G_OBEX_RSP_INTERNAL_SERVER_ERROR,     "Internal Server Error" },
+       { G_OBEX_RSP_NOT_IMPLEMENTED,           "Not Implemented" },
+       { G_OBEX_RSP_BAD_GATEWAY,               "Bad Gateway" },
+       { G_OBEX_RSP_SERVICE_UNAVAILABLE,       "Service Unavailable" },
+       { G_OBEX_RSP_GATEWAY_TIMEOUT,           "Gateway Timeout" },
+       { G_OBEX_RSP_VERSION_NOT_SUPPORTED,     "Version Not Supported" },
+       { G_OBEX_RSP_DATABASE_FULL,             "Database Full" },
+       { G_OBEX_RSP_DATABASE_LOCKED,           "Database Locked" },
+       { 0x00,                                 NULL }
+};
+
+const char *g_obex_strerror(guint8 err_code)
+{
+       struct error_code *error;
+
+       for (error = obex_errors; error->name != NULL; error++) {
+               if (error->code == err_code)
+                       return error->name;
+       }
+
+       return "<unknown>";
+}
+
+static ssize_t req_header_offset(guint8 opcode)
+{
+       switch (opcode) {
+       case G_OBEX_OP_CONNECT:
+               return sizeof(struct connect_data);
+       case G_OBEX_OP_SETPATH:
+               return sizeof(struct setpath_data);
+       case G_OBEX_OP_DISCONNECT:
+       case G_OBEX_OP_PUT:
+       case G_OBEX_OP_GET:
+       case G_OBEX_OP_SESSION:
+       case G_OBEX_OP_ABORT:
+       case G_OBEX_OP_ACTION:
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+static ssize_t rsp_header_offset(guint8 opcode)
+{
+       switch (opcode) {
+       case G_OBEX_OP_CONNECT:
+               return sizeof(struct connect_data);
+       case G_OBEX_OP_SETPATH:
+       case G_OBEX_OP_DISCONNECT:
+       case G_OBEX_OP_PUT:
+       case G_OBEX_OP_GET:
+       case G_OBEX_OP_SESSION:
+       case G_OBEX_OP_ABORT:
+       case G_OBEX_OP_ACTION:
+               return 0;
+       default:
+               return -1;
+       }
+}
+
+static void pending_pkt_free(struct pending_pkt *p)
+{
+       if (p->obex != NULL)
+               g_obex_unref(p->obex);
+
+       if (p->timeout_id > 0)
+               g_source_remove(p->timeout_id);
+
+       g_obex_packet_free(p->pkt);
+
+       g_free(p);
+}
+
+static gboolean req_timeout(gpointer user_data)
+{
+       GObex *obex = user_data;
+       struct pending_pkt *p = obex->pending_req;
+       GError *err;
+
+       g_assert(p != NULL);
+
+       obex->pending_req = NULL;
+
+       err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT,
+                                       "Timed out waiting for response");
+
+       g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+
+       if (p->rsp_func)
+               p->rsp_func(obex, err, NULL, p->rsp_data);
+
+       g_error_free(err);
+       pending_pkt_free(p);
+
+       return FALSE;
+}
+
+static gboolean write_stream(GObex *obex, GError **err)
+{
+       GIOStatus status;
+       gsize bytes_written;
+       char *buf;
+
+       buf = (char *) &obex->tx_buf[obex->tx_sent];
+       status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
+                                                       &bytes_written, err);
+       if (status != G_IO_STATUS_NORMAL)
+               return FALSE;
+
+       g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
+
+       obex->tx_sent += bytes_written;
+       obex->tx_data -= bytes_written;
+
+       return TRUE;
+}
+
+static gboolean write_packet(GObex *obex, GError **err)
+{
+       GIOStatus status;
+       gsize bytes_written;
+       char *buf;
+
+       buf = (char *) &obex->tx_buf[obex->tx_sent];
+       status = g_io_channel_write_chars(obex->io, buf, obex->tx_data,
+                                                       &bytes_written, err);
+       if (status != G_IO_STATUS_NORMAL)
+               return FALSE;
+
+       if (bytes_written != obex->tx_data)
+               return FALSE;
+
+       g_obex_dump(G_OBEX_DEBUG_DATA, "<", buf, bytes_written);
+
+       obex->tx_sent += bytes_written;
+       obex->tx_data -= bytes_written;
+
+       return TRUE;
+}
+
+static void set_srmp(GObex *obex, guint8 srmp, gboolean outgoing)
+{
+       struct srm_config *config = obex->srm;
+
+       if (config == NULL)
+               return;
+
+       /* Dont't reset if direction doesn't match */
+       if (srmp > G_OBEX_SRMP_NEXT_WAIT && config->outgoing != outgoing)
+               return;
+
+       config->srmp = srmp;
+       config->outgoing = outgoing;
+}
+
+static void set_srm(GObex *obex, guint8 op, guint8 srm)
+{
+       struct srm_config *config = obex->srm;
+       gboolean enable;
+
+       if (config == NULL) {
+               if (srm == G_OBEX_SRM_DISABLE)
+                       return;
+
+               config = g_new0(struct srm_config, 1);
+               config->op = op;
+               config->srm = srm;
+               obex->srm = config;
+               return;
+       }
+
+       /* Indicate response, treat it as request */
+       if (config->srm == G_OBEX_SRM_INDICATE) {
+               if (srm != G_OBEX_SRM_ENABLE)
+                       goto done;
+               config->srm = srm;
+               return;
+       }
+
+       enable = (srm == G_OBEX_SRM_ENABLE);
+       if (config->enabled == enable)
+               goto done;
+
+       config->enabled = enable;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "SRM %s", config->enabled ?
+                                               "Enabled" : "Disabled");
+
+done:
+       if (config->enabled)
+               return;
+
+       g_free(obex->srm);
+       obex->srm = NULL;
+}
+
+static void check_srm_final(GObex *obex, guint8 op)
+{
+       if (obex->srm == NULL || !obex->srm->enabled)
+               return;
+
+       switch (obex->srm->op) {
+       case G_OBEX_OP_CONNECT:
+               return;
+       default:
+               if (op <= G_OBEX_RSP_CONTINUE)
+                       return;
+       }
+
+       set_srm(obex, op, G_OBEX_SRM_DISABLE);
+}
+
+static void setup_srm(GObex *obex, GObexPacket *pkt, gboolean outgoing)
+{
+       GObexHeader *hdr;
+       guint8 op;
+       gboolean final;
+
+       if (!obex->use_srm)
+               return;
+
+       op = g_obex_packet_get_operation(pkt, &final);
+
+       hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
+       if (hdr != NULL) {
+               guint8 srm;
+               g_obex_header_get_uint8(hdr, &srm);
+               g_obex_debug(G_OBEX_DEBUG_COMMAND, "srm 0x%02x", srm);
+               set_srm(obex, op, srm);
+       }
+
+       hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRMP);
+       if (hdr != NULL) {
+               guint8 srmp;
+               g_obex_header_get_uint8(hdr, &srmp);
+               g_obex_debug(G_OBEX_DEBUG_COMMAND, "srmp 0x%02x", srmp);
+               set_srmp(obex, srmp, outgoing);
+       } else
+               set_srmp(obex, -1, outgoing);
+
+       if (final)
+               check_srm_final(obex, op);
+}
+
+static gboolean write_data(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GObex *obex = user_data;
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & (G_IO_HUP | G_IO_ERR))
+               goto stop_tx;
+
+       if (obex->tx_data == 0) {
+               struct pending_pkt *p = g_queue_pop_head(obex->tx_queue);
+               ssize_t len;
+
+               if (p == NULL)
+                       goto stop_tx;
+
+               setup_srm(obex, p->pkt, TRUE);
+
+               if (g_obex_srm_active(obex))
+                       goto encode;
+
+               /* Can't send a request while there's a pending one */
+               if (obex->pending_req && p->id > 0) {
+                       g_queue_push_head(obex->tx_queue, p);
+                       goto stop_tx;
+               }
+
+encode:
+               len = g_obex_packet_encode(p->pkt, obex->tx_buf, obex->tx_mtu);
+               if (len == -EAGAIN) {
+                       g_queue_push_head(obex->tx_queue, p);
+                       g_obex_suspend(obex);
+                       goto stop_tx;
+               }
+
+               if (len < 0) {
+                       pending_pkt_free(p);
+                       goto done;
+               }
+
+               if (p->id > 0) {
+                       if (obex->pending_req != NULL)
+                               pending_pkt_free(obex->pending_req);
+                       obex->pending_req = p;
+                       p->timeout_id = g_timeout_add_seconds(p->timeout,
+                                                       req_timeout, obex);
+               } else {
+                       /* During packet encode final bit can be set */
+                       if (obex->tx_buf[0] & FINAL_BIT)
+                               check_srm_final(obex,
+                                               obex->tx_buf[0] & ~FINAL_BIT);
+                       pending_pkt_free(p);
+               }
+
+               obex->tx_data = len;
+               obex->tx_sent = 0;
+       }
+
+       if (obex->suspended) {
+               obex->write_source = 0;
+               return FALSE;
+       }
+
+       if (!obex->write(obex, NULL))
+               goto stop_tx;
+
+done:
+       if (obex->tx_data > 0 || g_queue_get_length(obex->tx_queue) > 0)
+               return TRUE;
+
+stop_tx:
+       obex->rx_last_op = G_OBEX_OP_NONE;
+       obex->tx_data = 0;
+       obex->write_source = 0;
+       return FALSE;
+}
+
+static void enable_tx(GObex *obex)
+{
+       GIOCondition cond;
+
+       if (obex->suspended)
+               return;
+
+       if (obex->write_source > 0)
+               return;
+
+       cond = G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       obex->write_source = g_io_add_watch(obex->io, cond, write_data, obex);
+}
+
+static gboolean g_obex_send_internal(GObex *obex, struct pending_pkt *p,
+                                                               GError **err)
+{
+
+       if (obex->io == NULL) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
+                                       "The transport is not connected");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return FALSE;
+       }
+
+       if (g_obex_packet_get_operation(p->pkt, NULL) == G_OBEX_OP_ABORT)
+               g_queue_push_head(obex->tx_queue, p);
+       else
+               g_queue_push_tail(obex->tx_queue, p);
+
+       if (obex->pending_req == NULL || p->id == 0)
+               enable_tx(obex);
+
+       return TRUE;
+}
+
+static void init_connect_data(GObex *obex, struct connect_data *data)
+{
+       guint16 u16;
+
+       memset(data, 0, sizeof(*data));
+
+       data->version = 0x10;
+       data->flags = 0;
+
+       u16 = g_htons(obex->rx_mtu);
+       memcpy(&data->mtu, &u16, sizeof(u16));
+}
+
+static void prepare_connect_rsp(GObex *obex, GObexPacket *rsp)
+{
+       GObexHeader *connid;
+       struct connect_data data;
+       static guint32 next_connid = 1;
+
+       init_connect_data(obex, &data);
+       g_obex_packet_set_data(rsp, &data, sizeof(data), G_OBEX_DATA_COPY);
+
+       connid = g_obex_packet_get_header(rsp, G_OBEX_HDR_CONNECTION);
+       if (connid != NULL) {
+               g_obex_header_get_uint32(connid, &obex->conn_id);
+               return;
+       }
+
+       obex->conn_id = next_connid++;
+
+       connid = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION,
+                                                       obex->conn_id);
+       g_obex_packet_prepend_header(rsp, connid);
+}
+
+static void prepare_srm_rsp(GObex *obex, GObexPacket *pkt)
+{
+       GObexHeader *hdr;
+
+       if (!obex->use_srm || obex->srm == NULL)
+               return;
+
+       if (obex->srm->enabled)
+               return;
+
+       hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
+       if (hdr != NULL)
+               return;
+
+       hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
+       g_obex_packet_prepend_header(pkt, hdr);
+}
+
+gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err)
+{
+       struct pending_pkt *p;
+       gboolean ret;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       if (obex == NULL || pkt == NULL) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_INVALID_ARGS,
+                               "Invalid arguments");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return FALSE;
+       }
+
+       switch (obex->rx_last_op) {
+       case G_OBEX_OP_CONNECT:
+               prepare_connect_rsp(obex, pkt);
+               break;
+       case G_OBEX_OP_GET:
+       case G_OBEX_OP_PUT:
+               prepare_srm_rsp(obex, pkt);
+               break;
+       }
+
+       p = g_new0(struct pending_pkt, 1);
+       p->pkt = pkt;
+
+       ret = g_obex_send_internal(obex, p, err);
+       if (ret == FALSE)
+               pending_pkt_free(p);
+
+       return ret;
+}
+
+static void prepare_srm_req(GObex *obex, GObexPacket *pkt)
+{
+       GObexHeader *hdr;
+
+       if (!obex->use_srm)
+               return;
+
+       if (obex->srm != NULL && obex->srm->enabled)
+               return;
+
+       hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_SRM);
+       if (hdr != NULL)
+               return;
+
+       hdr = g_obex_header_new_uint8(G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE);
+       g_obex_packet_prepend_header(pkt, hdr);
+}
+
+guint g_obex_send_req(GObex *obex, GObexPacket *req, int timeout,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err)
+{
+       GObexHeader *hdr;
+       struct pending_pkt *p;
+       static guint id = 1;
+       guint8 op;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       op = g_obex_packet_get_operation(req, NULL);
+       if (op == G_OBEX_OP_PUT || op == G_OBEX_OP_GET) {
+               /* Only enable SRM automatically for GET and PUT */
+               prepare_srm_req(obex, req);
+       }
+
+       if (obex->conn_id == CONNID_INVALID)
+               goto create_pending;
+
+       if (obex->rx_last_op == G_OBEX_RSP_CONTINUE)
+               goto create_pending;
+
+       if (g_obex_srm_active(obex) && obex->pending_req != NULL)
+               goto create_pending;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_CONNECTION);
+       if (hdr != NULL)
+               goto create_pending;
+
+       hdr = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, obex->conn_id);
+       g_obex_packet_prepend_header(req, hdr);
+
+create_pending:
+       p = g_new0(struct pending_pkt, 1);
+
+       p->pkt = req;
+       p->id = id++;
+       p->rsp_func = func;
+       p->rsp_data = user_data;
+
+       if (timeout < 0)
+               p->timeout = G_OBEX_DEFAULT_TIMEOUT;
+       else
+               p->timeout = timeout;
+
+       if (!g_obex_send_internal(obex, p, err)) {
+               pending_pkt_free(p);
+               return 0;
+       }
+
+       return p->id;
+}
+
+static int pending_pkt_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct pending_pkt *p = a;
+       guint id = GPOINTER_TO_UINT(b);
+
+       return (p->id - id);
+}
+
+static gboolean pending_req_abort(GObex *obex, GError **err)
+{
+       struct pending_pkt *p = obex->pending_req;
+       GObexPacket *req;
+
+       if (p->cancelled)
+               return TRUE;
+
+       p->cancelled = TRUE;
+
+       g_source_remove(p->timeout_id);
+       p->timeout = G_OBEX_ABORT_TIMEOUT;
+       p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout, obex);
+
+       req = g_obex_packet_new(G_OBEX_OP_ABORT, TRUE, G_OBEX_HDR_INVALID);
+
+       return g_obex_send(obex, req, err);
+}
+
+static gboolean cancel_complete(gpointer user_data)
+{
+       struct pending_pkt *p = user_data;
+       GObex *obex = p->obex;
+       GError *err;
+
+       g_assert(p->rsp_func != NULL);
+
+       err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                                       "The request was cancelled");
+       p->rsp_func(obex, err, NULL, p->rsp_data);
+
+       g_error_free(err);
+
+       pending_pkt_free(p);
+
+       return FALSE;
+}
+
+gboolean g_obex_cancel_req(GObex *obex, guint req_id, gboolean remove_callback)
+{
+       GList *match;
+       struct pending_pkt *p;
+
+       if (obex->pending_req && obex->pending_req->id == req_id) {
+               if (!pending_req_abort(obex, NULL)) {
+                       p = obex->pending_req;
+                       obex->pending_req = NULL;
+                       goto immediate_completion;
+               }
+
+               if (remove_callback)
+                       obex->pending_req->rsp_func = NULL;
+
+               return TRUE;
+       }
+
+       match = g_queue_find_custom(obex->tx_queue, GUINT_TO_POINTER(req_id),
+                                                       pending_pkt_cmp);
+       if (match == NULL)
+               return FALSE;
+
+       p = match->data;
+
+       g_queue_delete_link(obex->tx_queue, match);
+
+immediate_completion:
+       p->cancelled = TRUE;
+       p->obex = g_obex_ref(obex);
+
+       if (remove_callback || p->rsp_func == NULL)
+               pending_pkt_free(p);
+       else
+               g_idle_add(cancel_complete, p);
+
+       return TRUE;
+}
+
+gboolean g_obex_send_rsp(GObex *obex, guint8 rspcode, GError **err,
+                                               guint8 first_hdr_type, ...)
+{
+       GObexPacket *rsp;
+       va_list args;
+
+       va_start(args, first_hdr_type);
+       rsp = g_obex_packet_new_valist(rspcode, TRUE, first_hdr_type, args);
+       va_end(args);
+
+       return g_obex_send(obex, rsp, err);
+}
+
+void g_obex_set_disconnect_function(GObex *obex, GObexFunc func,
+                                                       gpointer user_data)
+{
+       obex->disconn_func = func;
+       obex->disconn_func_data = user_data;
+}
+
+static int req_handler_cmpop(gconstpointer a, gconstpointer b)
+{
+       const struct req_handler *handler = a;
+       guint opcode = GPOINTER_TO_UINT(b);
+
+       return (int) handler->opcode - (int) opcode;
+}
+
+static int req_handler_cmpid(gconstpointer a, gconstpointer b)
+{
+       const struct req_handler *handler = a;
+       guint id = GPOINTER_TO_UINT(b);
+
+       return (int) handler->id - (int) id;
+}
+
+guint g_obex_add_request_function(GObex *obex, guint8 opcode,
+                                               GObexRequestFunc func,
+                                               gpointer user_data)
+{
+       struct req_handler *handler;
+       static guint next_id = 1;
+
+       handler = g_new0(struct req_handler, 1);
+       handler->id = next_id++;
+       handler->opcode = opcode;
+       handler->func = func;
+       handler->user_data = user_data;
+
+       obex->req_handlers = g_slist_prepend(obex->req_handlers, handler);
+
+       return handler->id;
+}
+
+gboolean g_obex_remove_request_function(GObex *obex, guint id)
+{
+       struct req_handler *handler;
+       GSList *match;
+
+       match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(id),
+                                                       req_handler_cmpid);
+       if (match == NULL)
+               return FALSE;
+
+       handler = match->data;
+
+       obex->req_handlers = g_slist_delete_link(obex->req_handlers, match);
+       g_free(handler);
+
+       return TRUE;
+}
+
+void g_obex_suspend(GObex *obex)
+{
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       if (obex->write_source > 0) {
+               g_source_remove(obex->write_source);
+               obex->write_source = 0;
+       }
+
+       obex->suspended = TRUE;
+}
+
+void g_obex_resume(GObex *obex)
+{
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       obex->suspended = FALSE;
+
+       if (g_queue_get_length(obex->tx_queue) > 0 || obex->tx_data > 0)
+               enable_tx(obex);
+}
+
+gboolean g_obex_srm_active(GObex *obex)
+{
+       gboolean ret = FALSE;
+
+       if (!obex->use_srm)
+               return FALSE;
+
+       if (obex->srm == NULL || !obex->srm->enabled)
+               goto done;
+
+       if (obex->srm->srmp <= G_OBEX_SRMP_NEXT_WAIT)
+               goto done;
+
+       ret = TRUE;
+done:
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "%s", ret ? "yes" : "no");
+       return ret;
+}
+
+static void parse_connect_data(GObex *obex, GObexPacket *pkt)
+{
+       const struct connect_data *data;
+       GObexHeader *connid;
+       guint16 u16;
+       size_t data_len;
+
+       data = g_obex_packet_get_data(pkt, &data_len);
+       if (data == NULL || data_len != sizeof(*data))
+               return;
+
+       memcpy(&u16, &data->mtu, sizeof(u16));
+
+       obex->tx_mtu = g_ntohs(u16);
+       if (obex->io_tx_mtu > 0 && obex->tx_mtu > obex->io_tx_mtu)
+               obex->tx_mtu = obex->io_tx_mtu;
+       obex->tx_buf = g_realloc(obex->tx_buf, obex->tx_mtu);
+
+       connid = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
+       if (connid != NULL)
+               g_obex_header_get_uint32(connid, &obex->conn_id);
+}
+
+static gboolean parse_response(GObex *obex, GObexPacket *rsp)
+{
+       struct pending_pkt *p = obex->pending_req;
+       guint8 opcode, rspcode;
+       gboolean final;
+
+       rspcode = g_obex_packet_get_operation(rsp, &final);
+
+       opcode = g_obex_packet_get_operation(p->pkt, NULL);
+       if (opcode == G_OBEX_OP_CONNECT)
+               parse_connect_data(obex, rsp);
+
+       setup_srm(obex, rsp, FALSE);
+
+       if (!g_obex_srm_active(obex))
+               return final;
+
+       /*
+        * Resposes have final bit set but in case of GET with SRM
+        * we should not remove the request since the remote side will
+        * continue sending responses until the transfer is finished
+        */
+       if (opcode == G_OBEX_OP_GET && rspcode == G_OBEX_RSP_CONTINUE) {
+               g_source_remove(p->timeout_id);
+               p->timeout_id = g_timeout_add_seconds(p->timeout, req_timeout,
+                                                                       obex);
+               return FALSE;
+       }
+
+       return final;
+}
+
+static void handle_response(GObex *obex, GError *err, GObexPacket *rsp)
+{
+       struct pending_pkt *p = obex->pending_req;
+       gboolean disconn = err ? TRUE : FALSE, final_rsp = TRUE;
+
+       if (rsp != NULL)
+               final_rsp = parse_response(obex, rsp);
+
+       if (p->cancelled)
+               err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED,
+                                       "The operation was cancelled");
+
+       if (err)
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+
+       if (p->rsp_func) {
+               p->rsp_func(obex, err, rsp, p->rsp_data);
+
+               /* Check if user callback removed the request */
+               if (p != obex->pending_req)
+                       return;
+       }
+
+       if (p->cancelled)
+               g_error_free(err);
+
+       if (final_rsp) {
+               pending_pkt_free(p);
+               obex->pending_req = NULL;
+       }
+
+       if (!disconn && g_queue_get_length(obex->tx_queue) > 0)
+               enable_tx(obex);
+}
+
+static gboolean check_connid(GObex *obex, GObexPacket *pkt)
+{
+       GObexHeader *hdr;
+       guint32 id;
+
+       if (obex->conn_id == CONNID_INVALID)
+               return TRUE;
+
+       hdr = g_obex_packet_get_header(pkt, G_OBEX_HDR_CONNECTION);
+       if (hdr == NULL)
+               return TRUE;
+
+       g_obex_header_get_uint32(hdr, &id);
+
+       return obex->conn_id == id;
+}
+
+static int parse_request(GObex *obex, GObexPacket *req)
+{
+       guint8 op;
+       gboolean final;
+
+       op = g_obex_packet_get_operation(req, &final);
+       switch (op) {
+       case G_OBEX_OP_CONNECT:
+               parse_connect_data(obex, req);
+               break;
+       case G_OBEX_OP_ABORT:
+               break;
+       default:
+               if (check_connid(obex, req))
+                       break;
+
+               return -G_OBEX_RSP_SERVICE_UNAVAILABLE;
+       }
+
+       setup_srm(obex, req, FALSE);
+
+       return op;
+}
+
+static void handle_request(GObex *obex, GObexPacket *req)
+{
+       GSList *match;
+       int op;
+
+       op = parse_request(obex, req);
+       if (op < 0)
+               goto fail;
+
+       match = g_slist_find_custom(obex->req_handlers, GUINT_TO_POINTER(op),
+                                                       req_handler_cmpop);
+       if (match) {
+               struct req_handler *handler = match->data;
+               handler->func(obex, req, handler->user_data);
+               return;
+       }
+
+       op = -G_OBEX_RSP_NOT_IMPLEMENTED;
+
+fail:
+       g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", g_obex_strerror(-op));
+       g_obex_send_rsp(obex, -op, NULL, G_OBEX_HDR_INVALID);
+}
+
+static gboolean read_stream(GObex *obex, GError **err)
+{
+       GIOChannel *io = obex->io;
+       GIOStatus status;
+       gsize rbytes, toread;
+       guint16 u16;
+       char *buf;
+
+       if (obex->rx_data >= 3)
+               goto read_body;
+
+       rbytes = 0;
+       toread = 3 - obex->rx_data;
+       buf = (char *) &obex->rx_buf[obex->rx_data];
+
+       status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
+       if (status != G_IO_STATUS_NORMAL)
+               return TRUE;
+
+       obex->rx_data += rbytes;
+       if (obex->rx_data < 3)
+               goto done;
+
+       memcpy(&u16, &buf[1], sizeof(u16));
+       obex->rx_pkt_len = g_ntohs(u16);
+
+       if (obex->rx_pkt_len > obex->rx_mtu) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "Too big incoming packet");
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+               return FALSE;
+       }
+
+read_body:
+       if (obex->rx_data >= obex->rx_pkt_len)
+               goto done;
+
+       do {
+               toread = obex->rx_pkt_len - obex->rx_data;
+               buf = (char *) &obex->rx_buf[obex->rx_data];
+
+               status = g_io_channel_read_chars(io, buf, toread, &rbytes, NULL);
+               if (status != G_IO_STATUS_NORMAL)
+                       goto done;
+
+               obex->rx_data += rbytes;
+       } while (rbytes > 0 && obex->rx_data < obex->rx_pkt_len);
+
+done:
+       g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
+
+       return TRUE;
+}
+
+static gboolean read_packet(GObex *obex, GError **err)
+{
+       GIOChannel *io = obex->io;
+       GError *read_err = NULL;
+       GIOStatus status;
+       gsize rbytes;
+       guint16 u16;
+
+       if (obex->rx_data > 0) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "RX buffer not empty before reading packet");
+               goto fail;
+       }
+
+       status = g_io_channel_read_chars(io, (char *) obex->rx_buf,
+                                       obex->rx_mtu, &rbytes, &read_err);
+       if (status != G_IO_STATUS_NORMAL) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "Unable to read data: %s", read_err->message);
+               g_error_free(read_err);
+               goto fail;
+       }
+
+       obex->rx_data += rbytes;
+
+       if (rbytes < 3) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "Incomplete packet received");
+               goto fail;
+       }
+
+       memcpy(&u16, &obex->rx_buf[1], sizeof(u16));
+       obex->rx_pkt_len = g_ntohs(u16);
+
+       if (obex->rx_pkt_len != rbytes) {
+               g_set_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                       "Data size doesn't match packet size (%zu != %u)",
+                       rbytes, obex->rx_pkt_len);
+               return FALSE;
+       }
+
+       g_obex_dump(G_OBEX_DEBUG_DATA, ">", obex->rx_buf, obex->rx_data);
+
+       return TRUE;
+fail:
+       g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", (*err)->message);
+       return FALSE;
+}
+
+static gboolean incoming_data(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GObex *obex = user_data;
+       GObexPacket *pkt;
+       ssize_t header_offset;
+       GError *err = NULL;
+       guint8 opcode;
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED,
+                                       "Transport got disconnected");
+               goto failed;
+       }
+
+       if (!obex->read(obex, &err))
+               goto failed;
+
+       if (obex->rx_data < 3 || obex->rx_data < obex->rx_pkt_len)
+               return TRUE;
+
+       obex->rx_last_op = obex->rx_buf[0] & ~FINAL_BIT;
+
+       if (obex->pending_req) {
+               struct pending_pkt *p = obex->pending_req;
+               opcode = g_obex_packet_get_operation(p->pkt, NULL);
+               header_offset = rsp_header_offset(opcode);
+       } else {
+               opcode = obex->rx_last_op;
+               /* Unexpected response -- fail silently */
+               if (opcode > 0x1f && opcode != G_OBEX_OP_ABORT) {
+                       obex->rx_data = 0;
+                       return TRUE;
+               }
+               header_offset = req_header_offset(opcode);
+       }
+
+       if (header_offset < 0) {
+               err = g_error_new(G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR,
+                               "Unknown header offset for opcode 0x%02x",
+                               opcode);
+               goto failed;
+       }
+
+       pkt = g_obex_packet_decode(obex->rx_buf, obex->rx_data, header_offset,
+                                                       G_OBEX_DATA_REF, &err);
+       if (pkt == NULL)
+               goto failed;
+
+       /* Protect against user callback freeing the object */
+       g_obex_ref(obex);
+
+       if (obex->pending_req)
+               handle_response(obex, NULL, pkt);
+       else
+               handle_request(obex, pkt);
+
+       obex->rx_data = 0;
+
+       g_obex_unref(obex);
+
+       if (err != NULL)
+               g_error_free(err);
+
+       if (pkt != NULL)
+               g_obex_packet_free(pkt);
+
+       return TRUE;
+
+failed:
+       if (err)
+               g_obex_debug(G_OBEX_DEBUG_ERROR, "%s", err->message);
+
+       g_io_channel_unref(obex->io);
+       obex->io = NULL;
+       obex->io_source = 0;
+       obex->rx_data = 0;
+
+       /* Protect against user callback freeing the object */
+       g_obex_ref(obex);
+
+       if (obex->pending_req)
+               handle_response(obex, err, NULL);
+
+       if (obex->disconn_func)
+               obex->disconn_func(obex, err, obex->disconn_func_data);
+
+       g_obex_unref(obex);
+
+       g_error_free(err);
+
+       return FALSE;
+}
+
+static GDebugKey keys[] = {
+       { "error",      G_OBEX_DEBUG_ERROR },
+       { "command",    G_OBEX_DEBUG_COMMAND },
+       { "transfer",   G_OBEX_DEBUG_TRANSFER },
+       { "header",     G_OBEX_DEBUG_HEADER },
+       { "packet",     G_OBEX_DEBUG_PACKET },
+       { "data",       G_OBEX_DEBUG_DATA },
+       { "apparam",    G_OBEX_DEBUG_APPARAM },
+};
+
+GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
+                                       gssize io_rx_mtu, gssize io_tx_mtu)
+{
+       GObex *obex;
+       GIOCondition cond;
+
+       if (gobex_debug == 0) {
+               const char *env = g_getenv("GOBEX_DEBUG");
+
+               if (env) {
+                       gobex_debug = g_parse_debug_string(env, keys, 7);
+                       g_setenv("G_MESSAGES_DEBUG", "gobex", FALSE);
+               } else
+                       gobex_debug = G_OBEX_DEBUG_NONE;
+       }
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
+
+       if (io == NULL)
+               return NULL;
+
+       if (io_rx_mtu >= 0 && io_rx_mtu < G_OBEX_MINIMUM_MTU)
+               return NULL;
+
+       if (io_tx_mtu >= 0 && io_tx_mtu < G_OBEX_MINIMUM_MTU)
+               return NULL;
+
+       obex = g_new0(GObex, 1);
+
+       obex->io = g_io_channel_ref(io);
+       obex->ref_count = 1;
+       obex->conn_id = CONNID_INVALID;
+       obex->rx_last_op = G_OBEX_OP_NONE;
+
+       obex->io_rx_mtu = io_rx_mtu;
+       obex->io_tx_mtu = io_tx_mtu;
+
+       if (io_rx_mtu > G_OBEX_MAXIMUM_MTU)
+               obex->rx_mtu = G_OBEX_MAXIMUM_MTU;
+       else if (io_rx_mtu < G_OBEX_MINIMUM_MTU)
+               obex->rx_mtu = G_OBEX_DEFAULT_MTU;
+       else
+               obex->rx_mtu = io_rx_mtu;
+
+       obex->tx_mtu = G_OBEX_MINIMUM_MTU;
+
+       obex->tx_queue = g_queue_new();
+       obex->rx_buf = g_malloc(obex->rx_mtu);
+       obex->tx_buf = g_malloc(obex->tx_mtu);
+
+       switch (transport_type) {
+       case G_OBEX_TRANSPORT_STREAM:
+               obex->read = read_stream;
+               obex->write = write_stream;
+               break;
+       case G_OBEX_TRANSPORT_PACKET:
+               obex->use_srm = TRUE;
+               obex->read = read_packet;
+               obex->write = write_packet;
+               break;
+       default:
+               g_obex_unref(obex);
+               return NULL;
+       }
+
+       g_io_channel_set_encoding(io, NULL, NULL);
+       g_io_channel_set_buffered(io, FALSE);
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       obex->io_source = g_io_add_watch(io, cond, incoming_data, obex);
+
+       return obex;
+}
+
+GObex *g_obex_ref(GObex *obex)
+{
+       int refs;
+
+       if (obex == NULL)
+               return NULL;
+
+       refs = __sync_add_and_fetch(&obex->ref_count, 1);
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
+
+       return obex;
+}
+
+void g_obex_unref(GObex *obex)
+{
+       int refs;
+
+       refs = __sync_sub_and_fetch(&obex->ref_count, 1);
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "ref %u", refs);
+
+       if (refs > 0)
+               return;
+
+       g_slist_free_full(obex->req_handlers, g_free);
+
+       g_queue_foreach(obex->tx_queue, (GFunc) pending_pkt_free, NULL);
+       g_queue_free(obex->tx_queue);
+
+       if (obex->io != NULL)
+               g_io_channel_unref(obex->io);
+
+       if (obex->io_source > 0)
+               g_source_remove(obex->io_source);
+
+       if (obex->write_source > 0)
+               g_source_remove(obex->write_source);
+
+       g_free(obex->rx_buf);
+       g_free(obex->tx_buf);
+       g_free(obex->srm);
+
+       if (obex->pending_req)
+               pending_pkt_free(obex->pending_req);
+
+       g_free(obex);
+}
+
+/* Higher level functions */
+
+guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data,
+                                       GError **err, guint8 first_hdr_id, ...)
+{
+       GObexPacket *req;
+       struct connect_data data;
+       va_list args;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "");
+
+       va_start(args, first_hdr_id);
+       req = g_obex_packet_new_valist(G_OBEX_OP_CONNECT, TRUE,
+                                                       first_hdr_id, args);
+       va_end(args);
+
+       init_connect_data(obex, &data);
+       g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func,
+                                       gpointer user_data, GError **err)
+{
+       GObexPacket *req;
+       struct setpath_data data;
+       const char *folder;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_INVALID);
+
+       memset(&data, 0, sizeof(data));
+
+       if (path != NULL && strncmp("..", path, 2) == 0) {
+               data.flags = 0x03;
+               folder = (path[2] == '/') ? &path[3] : NULL;
+       } else {
+               data.flags = 0x02;
+               folder = path;
+       }
+
+       if (folder != NULL) {
+               GObexHeader *hdr;
+               hdr = g_obex_header_new_unicode(G_OBEX_HDR_NAME, folder);
+               g_obex_packet_add_header(req, hdr);
+       }
+
+       g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func,
+                                       gpointer user_data, GError **err)
+{
+       GObexPacket *req;
+       struct setpath_data data;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       req = g_obex_packet_new(G_OBEX_OP_SETPATH, TRUE, G_OBEX_HDR_NAME, path,
+                                                       G_OBEX_HDR_INVALID);
+
+       memset(&data, 0, sizeof(data));
+       g_obex_packet_set_data(req, &data, sizeof(data), G_OBEX_DATA_COPY);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func,
+                                       gpointer user_data, GError **err)
+{
+       GObexPacket *req;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_NAME, name,
+                                                       G_OBEX_HDR_INVALID);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint g_obex_copy(GObex *obex, const char *name, const char *dest,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err)
+{
+       GObexPacket *req;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
+                                       G_OBEX_HDR_ACTION, G_OBEX_ACTION_COPY,
+                                       G_OBEX_HDR_NAME, name,
+                                       G_OBEX_HDR_DESTNAME, dest,
+                                       G_OBEX_HDR_INVALID);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint g_obex_move(GObex *obex, const char *name, const char *dest,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err)
+{
+       GObexPacket *req;
+
+       g_obex_debug(G_OBEX_DEBUG_COMMAND, "conn %u", obex->conn_id);
+
+       req = g_obex_packet_new(G_OBEX_OP_ACTION, TRUE,
+                                       G_OBEX_HDR_ACTION, G_OBEX_ACTION_MOVE,
+                                       G_OBEX_HDR_NAME, name,
+                                       G_OBEX_HDR_DESTNAME, dest,
+                                       G_OBEX_HDR_INVALID);
+
+       return g_obex_send_req(obex, req, -1, func, user_data, err);
+}
+
+guint8 g_obex_errno_to_rsp(int err)
+{
+       switch (err) {
+       case 0:
+               return G_OBEX_RSP_SUCCESS;
+       case -EPERM:
+       case -EACCES:
+               return G_OBEX_RSP_FORBIDDEN;
+       case -ENOENT:
+               return G_OBEX_RSP_NOT_FOUND;
+       case -EINVAL:
+       case -EBADR:
+               return G_OBEX_RSP_BAD_REQUEST;
+       case -EFAULT:
+               return G_OBEX_RSP_SERVICE_UNAVAILABLE;
+       case -ENOSYS:
+               return G_OBEX_RSP_NOT_IMPLEMENTED;
+       case -ENOTEMPTY:
+       case -EEXIST:
+               return G_OBEX_RSP_PRECONDITION_FAILED;
+       default:
+               return G_OBEX_RSP_INTERNAL_SERVER_ERROR;
+       }
+}
diff --git a/gobex/gobex.h b/gobex/gobex.h
new file mode 100644 (file)
index 0000000..76a224e
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __GOBEX_H
+#define __GOBEX_H
+
+#include <stdarg.h>
+#include <glib.h>
+
+#include <gobex/gobex-defs.h>
+#include <gobex/gobex-packet.h>
+
+typedef enum {
+       G_OBEX_TRANSPORT_STREAM,
+       G_OBEX_TRANSPORT_PACKET,
+} GObexTransportType;
+
+typedef struct _GObex GObex;
+
+typedef void (*GObexFunc) (GObex *obex, GError *err, gpointer user_data);
+typedef void (*GObexRequestFunc) (GObex *obex, GObexPacket *req,
+                                                       gpointer user_data);
+typedef void (*GObexResponseFunc) (GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data);
+
+gboolean g_obex_send(GObex *obex, GObexPacket *pkt, GError **err);
+
+guint g_obex_send_req(GObex *obex, GObexPacket *req, int timeout,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err);
+gboolean g_obex_cancel_req(GObex *obex, guint req_id,
+                                               gboolean remove_callback);
+
+gboolean g_obex_send_rsp(GObex *obex, guint8 rspcode, GError **err,
+                                               guint8 first_hdr_type, ...);
+
+void g_obex_set_disconnect_function(GObex *obex, GObexFunc func,
+                                                       gpointer user_data);
+guint g_obex_add_request_function(GObex *obex, guint8 opcode,
+                                               GObexRequestFunc func,
+                                               gpointer user_data);
+gboolean g_obex_remove_request_function(GObex *obex, guint id);
+
+void g_obex_suspend(GObex *obex);
+void g_obex_resume(GObex *obex);
+gboolean g_obex_srm_active(GObex *obex);
+
+GObex *g_obex_new(GIOChannel *io, GObexTransportType transport_type,
+                                               gssize rx_mtu, gssize tx_mtu);
+
+GObex *g_obex_ref(GObex *obex);
+void g_obex_unref(GObex *obex);
+
+/* High level client functions */
+
+guint g_obex_connect(GObex *obex, GObexResponseFunc func, gpointer user_data,
+                               GError **err, guint8 first_hdr_id, ...);
+
+guint g_obex_setpath(GObex *obex, const char *path, GObexResponseFunc func,
+                                       gpointer user_data, GError **err);
+
+guint g_obex_mkdir(GObex *obex, const char *path, GObexResponseFunc func,
+                                       gpointer user_data, GError **err);
+
+guint g_obex_delete(GObex *obex, const char *name, GObexResponseFunc func,
+                                       gpointer user_data, GError **err);
+
+guint g_obex_copy(GObex *obex, const char *name, const char *dest,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err);
+
+guint g_obex_move(GObex *obex, const char *name, const char *dest,
+                       GObexResponseFunc func, gpointer user_data,
+                       GError **err);
+
+/* Transfer related high-level functions */
+
+guint g_obex_put_req(GObex *obex, GObexDataProducer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...);
+
+guint g_obex_put_req_pkt(GObex *obex, GObexPacket *req,
+                       GObexDataProducer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err);
+
+guint g_obex_get_req(GObex *obex, GObexDataConsumer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...);
+
+guint g_obex_get_req_pkt(GObex *obex, GObexPacket *req,
+                       GObexDataConsumer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err);
+
+guint g_obex_put_rsp(GObex *obex, GObexPacket *req,
+                       GObexDataConsumer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err,
+                       guint8 first_hdr_id, ...);
+
+guint g_obex_get_rsp(GObex *obex, GObexDataProducer data_func,
+                       GObexFunc complete_func, gpointer user_data,
+                       GError **err, guint8 first_hdr_id, ...);
+
+guint g_obex_get_rsp_pkt(GObex *obex, GObexPacket *rsp,
+                       GObexDataProducer data_func, GObexFunc complete_func,
+                       gpointer user_data, GError **err);
+
+gboolean g_obex_cancel_transfer(guint id, GObexFunc complete_func,
+                                                       gpointer user_data);
+
+const char *g_obex_strerror(guint8 err_code);
+guint8 g_obex_errno_to_rsp(int err);
+
+#endif /* __GOBEX_H */
diff --git a/input/device.c b/input/device.c
deleted file mode 100644 (file)
index 0e3f4a9..0000000
+++ /dev/null
@@ -1,1308 +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 <stdlib.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hidp.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 "log.h"
-#include "uinput.h"
-
-#include "../src/adapter.h"
-#include "../src/device.h"
-#include "../src/storage.h"
-#include "../src/manager.h"
-#include "../src/dbus-common.h"
-
-#include "device.h"
-#include "error.h"
-#include "fakehid.h"
-#include "btio.h"
-
-#include "sdp-client.h"
-
-#define INPUT_DEVICE_INTERFACE "org.bluez.Input"
-
-#define BUF_SIZE               16
-
-#define UPDOWN_ENABLED         1
-
-#define FI_FLAG_CONNECTED      1
-
-struct input_conn {
-       struct fake_input       *fake;
-       DBusMessage             *pending_connect;
-       char                    *uuid;
-       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;
-};
-
-struct input_device {
-       DBusConnection          *conn;
-       char                    *path;
-       bdaddr_t                src;
-       bdaddr_t                dst;
-       uint32_t                handle;
-       guint                   dc_id;
-       gboolean                disable_sdp;
-       char                    *name;
-       struct btd_device       *device;
-       GSList                  *connections;
-};
-
-static GSList *devices = NULL;
-
-static struct input_device *find_device_by_path(GSList *list, const char *path)
-{
-       for (; list; list = list->next) {
-               struct input_device *idev = list->data;
-
-               if (!strcmp(idev->path, path))
-                       return idev;
-       }
-
-       return NULL;
-}
-
-static struct input_conn *find_connection(GSList *list, const char *pattern)
-{
-       for (; list; list = list->next) {
-               struct input_conn *iconn = list->data;
-
-               if (!strcasecmp(iconn->uuid, pattern))
-                       return iconn;
-       }
-
-       return NULL;
-}
-
-static void input_conn_free(struct input_conn *iconn)
-{
-       if (iconn->pending_connect)
-               dbus_message_unref(iconn->pending_connect);
-
-       if (iconn->ctrl_watch)
-               g_source_remove(iconn->ctrl_watch);
-
-       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);
-
-       if (iconn->ctrl_io)
-               g_io_channel_unref(iconn->ctrl_io);
-
-       g_free(iconn->uuid);
-       g_free(iconn->fake);
-       g_free(iconn);
-}
-
-static void input_device_free(struct input_device *idev)
-{
-       if (idev->dc_id)
-               device_remove_disconnect_watch(idev->device, idev->dc_id);
-
-       dbus_connection_unref(idev->conn);
-       btd_device_unref(idev->device);
-       g_free(idev->name);
-       g_free(idev->path);
-       g_free(idev);
-}
-
-static int uinput_create(char *name)
-{
-       struct uinput_dev dev;
-       int fd, err;
-
-       fd = open("/dev/uinput", O_RDWR);
-       if (fd < 0) {
-               fd = open("/dev/input/uinput", O_RDWR);
-               if (fd < 0) {
-                       fd = open("/dev/misc/uinput", O_RDWR);
-                       if (fd < 0) {
-                               err = -errno;
-                               error("Can't open input device: %s (%d)",
-                                                       strerror(-err), -err);
-                               return err;
-                       }
-               }
-       }
-
-       memset(&dev, 0, sizeof(dev));
-       if (name)
-               strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
-
-       dev.id.bustype = BUS_BLUETOOTH;
-       dev.id.vendor  = 0x0000;
-       dev.id.product = 0x0000;
-       dev.id.version = 0x0000;
-
-       if (write(fd, &dev, sizeof(dev)) < 0) {
-               err = -errno;
-               error("Can't write device information: %s (%d)",
-                                               strerror(-err), -err);
-               close(fd);
-               return err;
-       }
-
-       ioctl(fd, UI_SET_EVBIT, EV_KEY);
-       ioctl(fd, UI_SET_EVBIT, EV_REL);
-       ioctl(fd, UI_SET_EVBIT, EV_REP);
-
-       ioctl(fd, UI_SET_KEYBIT, KEY_UP);
-       ioctl(fd, UI_SET_KEYBIT, KEY_PAGEUP);
-       ioctl(fd, UI_SET_KEYBIT, KEY_DOWN);
-       ioctl(fd, UI_SET_KEYBIT, KEY_PAGEDOWN);
-
-       if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
-               err = -errno;
-               error("Can't create uinput device: %s (%d)",
-                                               strerror(-err), -err);
-               close(fd);
-               return err;
-       }
-
-       return fd;
-}
-
-static int decode_key(const char *str)
-{
-       static int mode = UPDOWN_ENABLED, gain = 0;
-
-       uint16_t key;
-       int new_gain;
-
-       /* Switch from key up/down to page up/down */
-       if (strncmp("AT+CKPD=200", str, 11) == 0) {
-               mode = ~mode;
-               return KEY_RESERVED;
-       }
-
-       if (strncmp("AT+VG", str, 5))
-               return KEY_RESERVED;
-
-       /* Gain key pressed */
-       if (strlen(str) != 10)
-               return KEY_RESERVED;
-
-       new_gain = strtol(&str[7], NULL, 10);
-       if (new_gain <= gain)
-               key = (mode == UPDOWN_ENABLED ? KEY_UP : KEY_PAGEUP);
-       else
-               key = (mode == UPDOWN_ENABLED ? KEY_DOWN : KEY_PAGEDOWN);
-
-       gain = new_gain;
-
-       return key;
-}
-
-static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
-{
-       struct uinput_event event;
-
-       memset(&event, 0, sizeof(event));
-       event.type      = type;
-       event.code      = code;
-       event.value     = value;
-
-       return write(fd, &event, sizeof(event));
-}
-
-static void send_key(int fd, uint16_t key)
-{
-       /* Key press */
-       send_event(fd, EV_KEY, key, 1);
-       send_event(fd, EV_SYN, SYN_REPORT, 0);
-       /* Key release */
-       send_event(fd, EV_KEY, key, 0);
-       send_event(fd, EV_SYN, SYN_REPORT, 0);
-}
-
-static gboolean rfcomm_io_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       struct fake_input *fake = data;
-       const char *ok = "\r\nOK\r\n";
-       char buf[BUF_SIZE];
-       ssize_t bread = 0, bwritten;
-       uint16_t key;
-       int fd;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       if (cond & (G_IO_HUP | G_IO_ERR)) {
-               error("Hangup or error on rfcomm server socket");
-               goto failed;
-       }
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       memset(buf, 0, BUF_SIZE);
-       bread = read(fd, buf, sizeof(buf) - 1);
-       if (bread < 0) {
-               error("IO Channel read error");
-               goto failed;
-       }
-
-       DBG("Received: %s", buf);
-
-       bwritten = write(fd, ok, 6);
-       if (bwritten < 0) {
-               error("IO Channel write error");
-               goto failed;
-       }
-
-       key = decode_key(buf);
-       if (key != KEY_RESERVED)
-               send_key(fake->uinput, key);
-
-       return TRUE;
-
-failed:
-       ioctl(fake->uinput, UI_DEV_DESTROY);
-       close(fake->uinput);
-       fake->uinput = -1;
-       g_io_channel_unref(fake->io);
-
-       return FALSE;
-}
-
-static void rfcomm_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
-{
-       struct input_conn *iconn = user_data;
-       struct input_device *idev = iconn->idev;
-       struct fake_input *fake = iconn->fake;
-       DBusMessage *reply;
-
-       if (err) {
-               reply = btd_error_failed(iconn->pending_connect, err->message);
-               goto failed;
-       }
-
-       fake->rfcomm = g_io_channel_unix_get_fd(chan);
-
-       /*
-        * FIXME: Some headsets required a sco connection
-        * first to report volume gain key events
-        */
-       fake->uinput = uinput_create(idev->name);
-       if (fake->uinput < 0) {
-               int err = fake->uinput;
-
-               g_io_channel_shutdown(chan, TRUE, NULL);
-               reply = btd_error_failed(iconn->pending_connect,
-                                                       strerror(-err));
-               goto failed;
-       }
-
-       fake->io = g_io_channel_unix_new(fake->rfcomm);
-       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,
-                                               (GIOFunc) rfcomm_io_cb, fake);
-
-       /* Replying to the requestor */
-       reply = dbus_message_new_method_return(iconn->pending_connect);
-       g_dbus_send_message(idev->conn, reply);
-
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-
-       return;
-
-failed:
-       g_dbus_send_message(idev->conn, reply);
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-}
-
-static gboolean rfcomm_connect(struct input_conn *iconn, GError **err)
-{
-       struct input_device *idev = iconn->idev;
-       GIOChannel *io;
-
-       io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, iconn,
-                               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;
-
-       g_io_channel_unref(io);
-
-       return TRUE;
-}
-
-static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       struct input_conn *iconn = data;
-       struct input_device *idev = iconn->idev;
-       gboolean connected = FALSE;
-
-       /* Checking for ctrl_watch avoids a double g_io_channel_shutdown since
-        * it's likely that ctrl_watch_cb has been queued for dispatching in
-        * this mainloop iteration */
-       if ((cond & (G_IO_HUP | G_IO_ERR)) && iconn->ctrl_watch)
-               g_io_channel_shutdown(chan, TRUE, NULL);
-
-       emit_property_changed(idev->conn, idev->path, INPUT_DEVICE_INTERFACE,
-                               "Connected", DBUS_TYPE_BOOLEAN, &connected);
-
-       device_remove_disconnect_watch(idev->device, idev->dc_id);
-       idev->dc_id = 0;
-
-       iconn->intr_watch = 0;
-
-       g_io_channel_unref(iconn->intr_io);
-       iconn->intr_io = NULL;
-
-       /* Close control channel */
-       if (iconn->ctrl_io && !(cond & G_IO_NVAL))
-               g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL);
-
-       return FALSE;
-}
-
-static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       struct input_conn *iconn = data;
-
-       /* Checking for intr_watch avoids a double g_io_channel_shutdown since
-        * it's likely that intr_watch_cb has been queued for dispatching in
-        * this mainloop iteration */
-       if ((cond & (G_IO_HUP | G_IO_ERR)) && iconn->intr_watch)
-               g_io_channel_shutdown(chan, TRUE, NULL);
-
-       iconn->ctrl_watch = 0;
-
-       g_io_channel_unref(iconn->ctrl_io);
-       iconn->ctrl_io = NULL;
-
-       /* Close interrupt channel */
-       if (iconn->intr_io && !(cond & G_IO_NVAL))
-               g_io_channel_shutdown(iconn->intr_io, TRUE, NULL);
-
-       return FALSE;
-}
-
-static gboolean fake_hid_connect(struct input_conn *iconn, GError **err)
-{
-       struct fake_hid *fhid = iconn->fake->priv;
-
-       return fhid->connect(iconn->fake, err);
-}
-
-static int fake_hid_disconnect(struct input_conn *iconn)
-{
-       struct fake_hid *fhid = iconn->fake->priv;
-
-       return fhid->disconnect(iconn->fake);
-}
-
-static void epox_endian_quirk(unsigned char *data, int size)
-{
-       /* USAGE_PAGE (Keyboard)        05 07
-        * USAGE_MINIMUM (0)            19 00
-        * USAGE_MAXIMUM (65280)        2A 00 FF   <= must be FF 00
-        * LOGICAL_MINIMUM (0)          15 00
-        * LOGICAL_MAXIMUM (65280)      26 00 FF   <= must be FF 00
-        */
-       unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
-                                               0x15, 0x00, 0x26, 0x00, 0xff };
-       unsigned int i;
-
-       if (!data)
-               return;
-
-       for (i = 0; i < size - sizeof(pattern); i++) {
-               if (!memcmp(data + i, pattern, sizeof(pattern))) {
-                       data[i + 5] = 0xff;
-                       data[i + 6] = 0x00;
-                       data[i + 10] = 0xff;
-                       data[i + 11] = 0x00;
-               }
-       }
-}
-
-static void extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
-{
-       sdp_data_t *pdlist, *pdlist2;
-       uint8_t attr_val;
-
-       pdlist = sdp_data_get(rec, 0x0101);
-       pdlist2 = sdp_data_get(rec, 0x0102);
-       if (pdlist) {
-               if (pdlist2) {
-                       if (strncmp(pdlist->val.str, pdlist2->val.str, 5)) {
-                               strncpy(req->name, pdlist2->val.str, 127);
-                               strcat(req->name, " ");
-                       }
-                       strncat(req->name, pdlist->val.str, 127 - strlen(req->name));
-               } else
-                       strncpy(req->name, pdlist->val.str, 127);
-       } else {
-               pdlist2 = sdp_data_get(rec, 0x0100);
-               if (pdlist2)
-                       strncpy(req->name, pdlist2->val.str, 127);
-       }
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
-       req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
-       req->subclass = pdlist ? pdlist->val.uint8 : 0;
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
-       req->country = pdlist ? pdlist->val.uint8 : 0;
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
-       attr_val = pdlist ? pdlist->val.uint8 : 0;
-       if (attr_val)
-               req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
-       attr_val = pdlist ? pdlist->val.uint8 : 0;
-       if (attr_val)
-               req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
-
-       pdlist = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
-       if (pdlist) {
-               pdlist = pdlist->val.dataseq;
-               pdlist = pdlist->val.dataseq;
-               pdlist = pdlist->next;
-
-               req->rd_data = g_try_malloc0(pdlist->unitSize);
-               if (req->rd_data) {
-                       memcpy(req->rd_data, (unsigned char *) pdlist->val.str,
-                                                               pdlist->unitSize);
-                       req->rd_size = pdlist->unitSize;
-                       epox_endian_quirk(req->rd_data, req->rd_size);
-               }
-       }
-}
-
-static int ioctl_connadd(struct hidp_connadd_req *req)
-{
-       int ctl, err = 0;
-
-       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-       if (ctl < 0)
-               return -errno;
-
-       if (ioctl(ctl, HIDPCONNADD, req) < 0)
-               err = -errno;
-
-       close(ctl);
-
-       return err;
-}
-
-static void encrypt_completed(uint8_t status, gpointer user_data)
-{
-       struct hidp_connadd_req *req = user_data;
-       int err;
-
-       if (status) {
-               error("Encryption failed: %s(0x%x)",
-                               strerror(bt_error(status)), status);
-               goto failed;
-       }
-
-       err = ioctl_connadd(req);
-       if (err == 0)
-               goto cleanup;
-
-       error("ioctl_connadd(): %s(%d)", strerror(-err), -err);
-failed:
-       close(req->intr_sock);
-       close(req->ctrl_sock);
-
-cleanup:
-       free(req->rd_data);
-
-       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,
-                                       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);
-       req->ctrl_sock = g_io_channel_unix_get_fd(iconn->ctrl_io);
-       req->intr_sock = g_io_channel_unix_get_fd(iconn->intr_io);
-       req->flags     = 0;
-       req->idle_to   = iconn->timeout;
-
-       ba2str(&idev->src, src_addr);
-       ba2str(&idev->dst, dst_addr);
-
-       rec = fetch_record(src_addr, dst_addr, idev->handle);
-       if (!rec) {
-               error("Rejected connection from unknown device %s", dst_addr);
-               err = -EPERM;
-               goto cleanup;
-       }
-
-       extract_hid_record(rec, req);
-       sdp_record_free(rec);
-
-       req->vendor = btd_device_get_vendor(idev->device);
-       req->product = btd_device_get_product(idev->device);
-       req->version = btd_device_get_version(idev->device);
-
-       fake_hid = get_fake_hid(req->vendor, req->product);
-       if (fake_hid) {
-               err = 0;
-               fake = g_new0(struct fake_input, 1);
-               fake->connect = fake_hid_connect;
-               fake->disconnect = fake_hid_disconnect;
-               fake->priv = fake_hid;
-               fake->idev = idev;
-               fake = fake_hid_connadd(fake, iconn->intr_io, fake_hid);
-               if (fake == NULL)
-                       err = -ENOMEM;
-               else
-                       fake->flags |= FI_FLAG_CONNECTED;
-               goto cleanup;
-       }
-
-       if (idev->name)
-               strncpy(req->name, idev->name, sizeof(req->name) - 1);
-
-       /* Encryption is mandatory for keyboards */
-       if (req->subclass & 0x40) {
-               struct btd_adapter *adapter = device_get_adapter(idev->device);
-
-               err = btd_adapter_encrypt_link(adapter, (bdaddr_t *) &idev->dst,
-                                               encrypt_completed, req);
-               if (err == 0) {
-                       /* Waiting async encryption */
-                       return 0;
-               }
-
-               if (err == -ENOSYS)
-                       goto nosys;
-
-               if (err != -EALREADY) {
-                       error("encrypt_link: %s (%d)", strerror(-err), -err);
-                       goto cleanup;
-               }
-       }
-
-       err = ioctl_connadd(req);
-
-cleanup:
-       free(req->rd_data);
-       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)
-{
-       struct input_device *idev = iconn->idev;
-       struct fake_input *fake = iconn->fake;
-       struct hidp_conninfo ci;
-       int ctl;
-
-       /* Fake input */
-       if (fake)
-               return fake->flags & FI_FLAG_CONNECTED;
-
-       /* Standard HID */
-       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-       if (ctl < 0)
-               return 0;
-
-       memset(&ci, 0, sizeof(ci));
-       bacpy(&ci.bdaddr, &idev->dst);
-       if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) {
-               close(ctl);
-               return 0;
-       }
-
-       close(ctl);
-
-       if (ci.state != BT_CONNECTED)
-               return 0;
-       else
-               return 1;
-}
-
-static int connection_disconnect(struct input_conn *iconn, uint32_t flags)
-{
-       struct input_device *idev = iconn->idev;
-       struct fake_input *fake = iconn->fake;
-       struct hidp_conndel_req req;
-       struct hidp_conninfo ci;
-       int ctl, err = 0;
-
-       /* Fake input disconnect */
-       if (fake) {
-               err = fake->disconnect(iconn);
-               if (err == 0)
-                       fake->flags &= ~FI_FLAG_CONNECTED;
-               return err;
-       }
-
-       /* Standard HID disconnect */
-       if (iconn->intr_io)
-               g_io_channel_shutdown(iconn->intr_io, TRUE, NULL);
-       if (iconn->ctrl_io)
-               g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL);
-
-       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
-       if (ctl < 0) {
-               error("Can't open HIDP control socket");
-               return -errno;
-       }
-
-       memset(&ci, 0, sizeof(ci));
-       bacpy(&ci.bdaddr, &idev->dst);
-       if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) ||
-                               (ci.state != BT_CONNECTED)) {
-               err = -ENOTCONN;
-               goto fail;
-       }
-
-       memset(&req, 0, sizeof(req));
-       bacpy(&req.bdaddr, &idev->dst);
-       req.flags = flags;
-       if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
-               err = -errno;
-               error("Can't delete the HID device: %s(%d)",
-                               strerror(-err), -err);
-               goto fail;
-       }
-
-fail:
-       close(ctl);
-
-       return err;
-}
-
-static int disconnect(struct input_device *idev, uint32_t flags)
-{
-       struct input_conn *iconn = NULL;
-       GSList *l;
-
-       for (l = idev->connections; l; l = l->next) {
-               iconn = l->data;
-
-               if (is_connected(iconn))
-                       break;
-       }
-
-       if (!iconn)
-               return -ENOTCONN;
-
-       return connection_disconnect(iconn, flags);
-}
-
-static void disconnect_cb(struct btd_device *device, gboolean removal,
-                               void *user_data)
-{
-       struct input_device *idev = user_data;
-       int flags;
-
-       info("Input: disconnect %s", idev->path);
-
-       flags = removal ? (1 << HIDP_VIRTUAL_CABLE_UNPLUG) : 0;
-
-       disconnect(idev, flags);
-}
-
-static int input_device_connected(struct input_device *idev,
-                                               struct input_conn *iconn)
-{
-       dbus_bool_t connected;
-       int err;
-
-       if (iconn->intr_io == NULL || iconn->ctrl_io == NULL)
-               return -ENOTCONN;
-
-       err = hidp_add_connection(idev, iconn);
-       if (err < 0)
-               return err;
-
-       iconn->intr_watch = g_io_add_watch(iconn->intr_io,
-                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                       intr_watch_cb, iconn);
-       iconn->ctrl_watch = g_io_add_watch(iconn->ctrl_io,
-                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                       ctrl_watch_cb, iconn);
-
-       connected = TRUE;
-       emit_property_changed(idev->conn, idev->path, INPUT_DEVICE_INTERFACE,
-                               "Connected", DBUS_TYPE_BOOLEAN, &connected);
-
-       idev->dc_id = device_add_disconnect_watch(idev->device, disconnect_cb,
-                                                       idev, NULL);
-
-       return 0;
-}
-
-static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
-                                                       gpointer user_data)
-{
-       struct input_conn *iconn = user_data;
-       struct input_device *idev = iconn->idev;
-       DBusMessage *reply;
-       int err;
-       const char *err_msg;
-
-       if (conn_err) {
-               err_msg = conn_err->message;
-               goto failed;
-       }
-
-       err = input_device_connected(idev, iconn);
-       if (err < 0) {
-               err_msg = strerror(-err);
-               goto failed;
-       }
-
-       /* Replying to the requestor */
-       g_dbus_send_reply(idev->conn, iconn->pending_connect, DBUS_TYPE_INVALID);
-
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-
-       return;
-
-failed:
-       error("%s", err_msg);
-       reply = btd_error_failed(iconn->pending_connect, err_msg);
-       g_dbus_send_message(idev->conn, reply);
-
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-
-       /* So we guarantee the interrupt channel is closed before the
-        * control channel (if we only do unref GLib will close it only
-        * after returning control to the mainloop */
-       if (!conn_err)
-               g_io_channel_shutdown(iconn->intr_io, FALSE, NULL);
-
-       g_io_channel_unref(iconn->intr_io);
-       iconn->intr_io = NULL;
-
-       if (iconn->ctrl_io) {
-               g_io_channel_unref(iconn->ctrl_io);
-               iconn->ctrl_io = NULL;
-       }
-}
-
-static void control_connect_cb(GIOChannel *chan, GError *conn_err,
-                                                       gpointer user_data)
-{
-       struct input_conn *iconn = user_data;
-       struct input_device *idev = iconn->idev;
-       DBusMessage *reply;
-       GIOChannel *io;
-       GError *err = NULL;
-
-       if (conn_err) {
-               error("%s", conn_err->message);
-               reply = btd_error_failed(iconn->pending_connect,
-                                               conn_err->message);
-               goto failed;
-       }
-
-       /* Connect to the HID interrupt channel */
-       io = bt_io_connect(BT_IO_L2CAP, interrupt_connect_cb, iconn,
-                               NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &idev->src,
-                               BT_IO_OPT_DEST_BDADDR, &idev->dst,
-                               BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
-                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-                               BT_IO_OPT_INVALID);
-       if (!io) {
-               error("%s", err->message);
-               reply = btd_error_failed(iconn->pending_connect,
-                                                       err->message);
-               g_error_free(err);
-               goto failed;
-       }
-
-       iconn->intr_io = io;
-
-       return;
-
-failed:
-       g_io_channel_unref(iconn->ctrl_io);
-       iconn->ctrl_io = NULL;
-       g_dbus_send_message(idev->conn, reply);
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-}
-
-static int fake_disconnect(struct input_conn *iconn)
-{
-       struct fake_input *fake = iconn->fake;
-
-       if (!fake->io)
-               return -ENOTCONN;
-
-       g_io_channel_shutdown(fake->io, TRUE, NULL);
-       g_io_channel_unref(fake->io);
-       fake->io = NULL;
-
-       if (fake->uinput >= 0) {
-               ioctl(fake->uinput, UI_DEV_DESTROY);
-               close(fake->uinput);
-               fake->uinput = -1;
-       }
-
-       return 0;
-}
-
-/*
- * Input Device methods
- */
-static DBusMessage *input_device_connect(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct input_device *idev = data;
-       struct input_conn *iconn;
-       struct fake_input *fake;
-       DBusMessage *reply;
-       GError *err = NULL;
-
-       iconn = find_connection(idev->connections, HID_UUID);
-       if (!iconn)
-               return btd_error_not_supported(msg);
-
-       if (iconn->pending_connect)
-               return btd_error_in_progress(msg);
-
-       if (is_connected(iconn))
-               return btd_error_already_connected(msg);
-
-       iconn->pending_connect = dbus_message_ref(msg);
-       fake = iconn->fake;
-
-       if (fake) {
-               /* Fake input device */
-               if (fake->connect(iconn, &err))
-                       fake->flags |= FI_FLAG_CONNECTED;
-       } else {
-               /* 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,
-                                       BT_IO_OPT_DEST_BDADDR, &idev->dst,
-                                       BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
-                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
-                                       BT_IO_OPT_INVALID);
-               iconn->ctrl_io = io;
-       }
-
-       if (err == NULL)
-               return NULL;
-
-       error("%s", err->message);
-       dbus_message_unref(iconn->pending_connect);
-       iconn->pending_connect = NULL;
-       reply = btd_error_failed(msg, err->message);
-       g_error_free(err);
-       return reply;
-}
-
-static DBusMessage *input_device_disconnect(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct input_device *idev = data;
-       int err;
-
-       err = disconnect(idev, 0);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static void device_unregister(void *data)
-{
-       struct input_device *idev = data;
-
-       DBG("Unregistered interface %s on path %s", INPUT_DEVICE_INTERFACE,
-                                                               idev->path);
-
-       devices = g_slist_remove(devices, idev);
-       input_device_free(idev);
-}
-
-static gint connected_cmp(gpointer a, gpointer b)
-{
-       struct input_conn *iconn = a;
-
-       return !is_connected(iconn);
-}
-
-static DBusMessage *input_device_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct input_device *idev = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       dbus_bool_t connected;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       /* Connected */
-       connected = !!g_slist_find_custom(idev->connections, NULL,
-                                       (GCompareFunc) connected_cmp);
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 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 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);
-       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(&idev->src, src_addr);
-       ba2str(&idev->dst, dst_addr);
-       if (read_device_name(src_addr, dst_addr, name) == 0)
-               idev->name = g_strdup(name);
-
-       if (g_dbus_register_interface(conn, idev->path, INPUT_DEVICE_INTERFACE,
-                                       device_methods, device_signals, NULL,
-                                       idev, device_unregister) == FALSE) {
-               error("Failed to register interface %s on path %s",
-                       INPUT_DEVICE_INTERFACE, path);
-               input_device_free(idev);
-               return NULL;
-       }
-
-       DBG("Registered interface %s on path %s",
-                       INPUT_DEVICE_INTERFACE, idev->path);
-
-       return idev;
-}
-
-static struct input_conn *input_conn_new(struct input_device *idev,
-                                       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->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 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, rec->handle,
-                                       is_device_sdp_disable(rec));
-               if (!idev)
-                       return -EINVAL;
-               devices = g_slist_append(devices, idev);
-       }
-
-       iconn = input_conn_new(idev, uuid, timeout);
-
-       idev->connections = g_slist_append(idev->connections, iconn);
-
-       return 0;
-}
-
-int fake_input_register(DBusConnection *conn, struct btd_device *device,
-                       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, 0, FALSE);
-               if (!idev)
-                       return -EINVAL;
-               devices = g_slist_append(devices, idev);
-       }
-
-       iconn = input_conn_new(idev, uuid, 0);
-       iconn->fake = g_new0(struct fake_input, 1);
-       iconn->fake->ch = channel;
-       iconn->fake->connect = rfcomm_connect;
-       iconn->fake->disconnect = fake_disconnect;
-
-       idev->connections = g_slist_append(idev->connections, iconn);
-
-       return 0;
-}
-
-static struct input_device *find_device(const bdaddr_t *src,
-                                       const bdaddr_t *dst)
-{
-       GSList *list;
-
-       for (list = devices; list != NULL; list = list->next) {
-               struct input_device *idev = list->data;
-
-               if (!bacmp(&idev->src, src) && !bacmp(&idev->dst, dst))
-                       return idev;
-       }
-
-       return NULL;
-}
-
-int input_device_unregister(const char *path, const char *uuid)
-{
-       struct input_device *idev;
-       struct input_conn *iconn;
-
-       idev = find_device_by_path(devices, path);
-       if (idev == NULL)
-               return -EINVAL;
-
-       iconn = find_connection(idev->connections, uuid);
-       if (iconn == NULL)
-               return -EINVAL;
-
-       if (iconn->pending_connect) {
-               /* Pending connection running */
-               return -EBUSY;
-       }
-
-       idev->connections = g_slist_remove(idev->connections, iconn);
-       input_conn_free(iconn);
-       if (idev->connections)
-               return 0;
-
-       g_dbus_unregister_interface(idev->conn, path, INPUT_DEVICE_INTERFACE);
-
-       return 0;
-}
-
-static int input_device_connadd(struct input_device *idev,
-                               struct input_conn *iconn)
-{
-       int err;
-
-       err = input_device_connected(idev, iconn);
-       if (err < 0)
-               goto error;
-
-       return 0;
-
-error:
-       if (iconn->ctrl_io) {
-               g_io_channel_shutdown(iconn->ctrl_io, FALSE, NULL);
-               g_io_channel_unref(iconn->ctrl_io);
-               iconn->ctrl_io = NULL;
-       }
-       if (iconn->intr_io) {
-               g_io_channel_shutdown(iconn->intr_io, FALSE, NULL);
-               g_io_channel_unref(iconn->intr_io);
-               iconn->intr_io = NULL;
-       }
-
-       return err;
-}
-
-int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
-                                                               GIOChannel *io)
-{
-       struct input_device *idev = find_device(src, dst);
-       struct input_conn *iconn;
-
-       if (!idev)
-               return -ENOENT;
-
-       iconn = find_connection(idev->connections, HID_UUID);
-       if (!iconn)
-               return -ENOENT;
-
-       switch (psm) {
-       case L2CAP_PSM_HIDP_CTRL:
-               if (iconn->ctrl_io)
-                       return -EALREADY;
-               iconn->ctrl_io = g_io_channel_ref(io);
-               break;
-       case L2CAP_PSM_HIDP_INTR:
-               if (iconn->intr_io)
-                       return -EALREADY;
-               iconn->intr_io = g_io_channel_ref(io);
-               break;
-       }
-
-       if (iconn->intr_io && iconn->ctrl_io)
-               input_device_connadd(idev, iconn);
-
-       return 0;
-}
-
-int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct input_device *idev = find_device(src, dst);
-       struct input_conn *iconn;
-
-       if (!idev)
-               return -ENOENT;
-
-       iconn = find_connection(idev->connections, HID_UUID);
-       if (!iconn)
-               return -ENOENT;
-
-       if (iconn->intr_io)
-               g_io_channel_shutdown(iconn->intr_io, TRUE, NULL);
-
-       if (iconn->ctrl_io)
-               g_io_channel_shutdown(iconn->ctrl_io, TRUE, NULL);
-
-       return 0;
-}
diff --git a/input/fakehid.c b/input/fakehid.c
deleted file mode 100644 (file)
index 3181538..0000000
+++ /dev/null
@@ -1,408 +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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include <glib.h>
-
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#include "log.h"
-#include "device.h"
-#include "fakehid.h"
-#include "uinput.h"
-
-enum ps3remote_special_keys {
-       PS3R_BIT_PS = 0,
-       PS3R_BIT_ENTER = 3,
-       PS3R_BIT_L2 = 8,
-       PS3R_BIT_R2 = 9,
-       PS3R_BIT_L1 = 10,
-       PS3R_BIT_R1 = 11,
-       PS3R_BIT_TRIANGLE = 12,
-       PS3R_BIT_CIRCLE = 13,
-       PS3R_BIT_CROSS = 14,
-       PS3R_BIT_SQUARE = 15,
-       PS3R_BIT_SELECT = 16,
-       PS3R_BIT_L3 = 17,
-       PS3R_BIT_R3 = 18,
-       PS3R_BIT_START = 19,
-       PS3R_BIT_UP = 20,
-       PS3R_BIT_RIGHT = 21,
-       PS3R_BIT_DOWN = 22,
-       PS3R_BIT_LEFT = 23,
-};
-
-static unsigned int ps3remote_bits[] = {
-       [PS3R_BIT_ENTER] = 0x0b,
-       [PS3R_BIT_PS] = 0x43,
-       [PS3R_BIT_SQUARE] = 0x5f,
-       [PS3R_BIT_CROSS] = 0x5e,
-       [PS3R_BIT_CIRCLE] = 0x5d,
-       [PS3R_BIT_TRIANGLE] = 0x5c,
-       [PS3R_BIT_R1] = 0x5b,
-       [PS3R_BIT_L1] = 0x5a,
-       [PS3R_BIT_R2] = 0x59,
-       [PS3R_BIT_L2] = 0x58,
-       [PS3R_BIT_LEFT] = 0x57,
-       [PS3R_BIT_DOWN] = 0x56,
-       [PS3R_BIT_RIGHT] = 0x55,
-       [PS3R_BIT_UP] = 0x54,
-       [PS3R_BIT_START] = 0x53,
-       [PS3R_BIT_R3] = 0x52,
-       [PS3R_BIT_L3] = 0x51,
-       [PS3R_BIT_SELECT] = 0x50,
-};
-
-static unsigned int ps3remote_keymap[] = {
-       [0x16] = KEY_EJECTCD,
-       [0x64] = KEY_AUDIO,
-       [0x65] = KEY_ANGLE,
-       [0x63] = KEY_SUBTITLE,
-       [0x0f] = KEY_CLEAR,
-       [0x28] = KEY_TIME,
-       [0x00] = KEY_1,
-       [0x01] = KEY_2,
-       [0x02] = KEY_3,
-       [0x03] = KEY_4,
-       [0x04] = KEY_5,
-       [0x05] = KEY_6,
-       [0x06] = KEY_7,
-       [0x07] = KEY_8,
-       [0x08] = KEY_9,
-       [0x09] = KEY_0,
-       [0x81] = KEY_RED,
-       [0x82] = KEY_GREEN,
-       [0x80] = KEY_BLUE,
-       [0x83] = KEY_YELLOW,
-       [0x70] = KEY_INFO,              /* display */
-       [0x1a] = KEY_MENU,              /* top menu */
-       [0x40] = KEY_CONTEXT_MENU,      /* pop up/menu */
-       [0x0e] = KEY_ESC,               /* return */
-       [0x5c] = KEY_OPTION,            /* options/triangle */
-       [0x5d] = KEY_BACK,              /* back/circle */
-       [0x5f] = KEY_SCREEN,            /* view/square */
-       [0x5e] = BTN_0,                 /* cross */
-       [0x54] = KEY_UP,
-       [0x56] = KEY_DOWN,
-       [0x57] = KEY_LEFT,
-       [0x55] = KEY_RIGHT,
-       [0x0b] = KEY_ENTER,
-       [0x5a] = BTN_TL,                /* L1 */
-       [0x58] = BTN_TL2,               /* L2 */
-       [0x51] = BTN_THUMBL,            /* L3 */
-       [0x5b] = BTN_TR,                /* R1 */
-       [0x59] = BTN_TR2,               /* R2 */
-       [0x52] = BTN_THUMBR,            /* R3 */
-       [0x43] = KEY_HOMEPAGE,          /* PS button */
-       [0x50] = KEY_SELECT,
-       [0x53] = BTN_START,
-       [0x33] = KEY_REWIND,            /* scan back */
-       [0x32] = KEY_PLAY,
-       [0x34] = KEY_FORWARD,           /* scan forward */
-       [0x30] = KEY_PREVIOUS,
-       [0x38] = KEY_STOP,
-       [0x31] = KEY_NEXT,
-       [0x60] = KEY_FRAMEBACK,         /* slow/step back */
-       [0x39] = KEY_PAUSE,
-       [0x61] = KEY_FRAMEFORWARD,      /* slow/step forward */
-       [0xff] = KEY_MAX,
-};
-
-static int ps3remote_decode(char *buff, int size, unsigned int *value)
-{
-       static unsigned int lastkey = 0;
-       static unsigned int lastmask = 0;
-       unsigned int i, mask;
-       int retval;
-       guint8 key;
-
-       if (size < 12) {
-               error("Got a shorter packet! (size %i)\n", size);
-               return KEY_RESERVED;
-       }
-
-       mask = (buff[2] << 16) + (buff[3] << 8) + buff[4];
-       key = buff[5];
-
-       /* first, check flags */
-       for (i = 0; i < 24; i++) {
-               if ((lastmask & (1 << i)) == (mask & (1 << i)))
-                       continue;
-               if (ps3remote_bits[i] == 0)
-                       goto error;
-               retval = ps3remote_keymap[ps3remote_bits[i]];
-               if (mask & (1 << i))
-                       /* key pressed */
-                       *value = 1;
-               else
-                       /* key released */
-                       *value = 0;
-
-               goto out;
-       }
-
-       *value = buff[11];
-       if (buff[11] == 1) {
-               retval = ps3remote_keymap[key];
-       } else
-               retval = lastkey;
-
-       if (retval == KEY_RESERVED)
-               goto error;
-       if (retval == KEY_MAX)
-               return retval;
-
-       lastkey = retval;
-
-out:
-       fflush(stdout);
-
-       lastmask = mask;
-
-       return retval;
-
-error:
-       error("ps3remote: unrecognized sequence [%#x][%#x][%#x][%#x] [%#x],"
-                       "last: [%#x][%#x][%#x][%#x]",
-                       buff[2], buff[3], buff[4], buff[5], buff[11],
-                               lastmask >> 16, lastmask >> 8 & 0xff,
-                                               lastmask & 0xff, lastkey);
-       return -1;
-}
-
-static gboolean ps3remote_event(GIOChannel *chan, GIOCondition cond,
-                               gpointer data)
-{
-       struct fake_input *fake = data;
-       struct uinput_event event;
-       unsigned int key, value = 0;
-       ssize_t size;
-       char buff[50];
-       int fd;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       if (cond & (G_IO_HUP | G_IO_ERR)) {
-               error("Hangup or error on rfcomm server socket");
-               goto failed;
-       }
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       memset(buff, 0, sizeof(buff));
-       size = read(fd, buff, sizeof(buff));
-       if (size < 0) {
-               error("IO Channel read error");
-               goto failed;
-       }
-
-       key = ps3remote_decode(buff, size, &value);
-       if (key == KEY_RESERVED) {
-               error("Got invalid key from decode");
-               goto failed;
-       } else if (key == KEY_MAX)
-               return TRUE;
-
-       memset(&event, 0, sizeof(event));
-       gettimeofday(&event.time, NULL);
-       event.type = EV_KEY;
-       event.code = key;
-       event.value = value;
-       if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
-               error("Error writing to uinput device");
-               goto failed;
-       }
-
-       memset(&event, 0, sizeof(event));
-       gettimeofday(&event.time, NULL);
-       event.type = EV_SYN;
-       event.code = SYN_REPORT;
-       if (write(fake->uinput, &event, sizeof(event)) != sizeof(event)) {
-               error("Error writing to uinput device");
-               goto failed;
-       }
-
-       return TRUE;
-
-failed:
-       ioctl(fake->uinput, UI_DEV_DESTROY);
-       close(fake->uinput);
-       fake->uinput = -1;
-       g_io_channel_unref(fake->io);
-
-       return FALSE;
-}
-
-static int ps3remote_setup_uinput(struct fake_input *fake,
-                                               struct fake_hid *fake_hid)
-{
-       struct uinput_dev dev;
-       int i;
-
-       fake->uinput = open("/dev/input/uinput", O_RDWR);
-       if (fake->uinput < 0) {
-               fake->uinput = open("/dev/uinput", O_RDWR);
-               if (fake->uinput < 0) {
-                       fake->uinput = open("/dev/misc/uinput", O_RDWR);
-                       if (fake->uinput < 0) {
-                               error("Error opening uinput device file");
-                               return 1;
-                       }
-               }
-       }
-
-       memset(&dev, 0, sizeof(dev));
-       snprintf(dev.name, sizeof(dev.name), "%s", "PS3 Remote Controller");
-       dev.id.bustype = BUS_BLUETOOTH;
-       dev.id.vendor = fake_hid->vendor;
-       dev.id.product = fake_hid->product;
-
-       if (write(fake->uinput, &dev, sizeof(dev)) != sizeof(dev)) {
-               error("Error creating uinput device");
-               goto err;
-       }
-
-       /* enabling key events */
-       if (ioctl(fake->uinput, UI_SET_EVBIT, EV_KEY) < 0) {
-               error("Error enabling uinput device key events");
-               goto err;
-       }
-
-       /* enabling keys */
-       for (i = 0; i < 256; i++)
-               if (ps3remote_keymap[i] != KEY_RESERVED)
-                       if (ioctl(fake->uinput, UI_SET_KEYBIT,
-                                               ps3remote_keymap[i]) < 0) {
-                               error("Error enabling uinput key %i",
-                                                       ps3remote_keymap[i]);
-                               goto err;
-                       }
-
-       /* creating the device */
-       if (ioctl(fake->uinput, UI_DEV_CREATE) < 0) {
-               error("Error creating uinput device");
-               goto err;
-       }
-
-       return 0;
-
-err:
-       close(fake->uinput);
-       return 1;
-}
-
-static gboolean fake_hid_common_connect(struct fake_input *fake, GError **err)
-{
-       return TRUE;
-}
-
-static int fake_hid_common_disconnect(struct fake_input *fake)
-{
-       return 0;
-}
-
-static struct fake_hid fake_hid_table[] = {
-       /* Sony PS3 remote device */
-       {
-               .vendor         = 0x054c,
-               .product        = 0x0306,
-               .connect        = fake_hid_common_connect,
-               .disconnect     = fake_hid_common_disconnect,
-               .event          = ps3remote_event,
-               .setup_uinput   = ps3remote_setup_uinput,
-               .devices        = NULL,
-       },
-
-       { },
-};
-
-static inline int fake_hid_match_device(uint16_t vendor, uint16_t product,
-                                                       struct fake_hid *fhid)
-{
-       return vendor == fhid->vendor && product == fhid->product;
-}
-
-struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product)
-{
-       int i;
-
-       for (i = 0; fake_hid_table[i].vendor != 0; i++)
-               if (fake_hid_match_device(vendor, product, &fake_hid_table[i]))
-                       return &fake_hid_table[i];
-
-       return NULL;
-}
-
-struct fake_input *fake_hid_connadd(struct fake_input *fake,
-                                               GIOChannel *intr_io,
-                                               struct fake_hid *fake_hid)
-{
-       GList *l;
-       struct fake_input *old = NULL;
-
-       /* Look for an already setup device */
-       for (l = fake_hid->devices; l != NULL; l = l->next) {
-               old = l->data;
-               if (old->idev == fake->idev) {
-                       g_free(fake);
-                       fake = old;
-                       fake_hid->connect(fake, NULL);
-                       break;
-               }
-               old = NULL;
-       }
-
-       /* New device? Add it to the list of known devices,
-        * and create the uinput necessary */
-       if (old == NULL || old->uinput < 0) {
-               if (fake_hid->setup_uinput(fake, fake_hid)) {
-                       error("Error setting up uinput");
-                       g_free(fake);
-                       return NULL;
-               }
-       }
-
-       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,
-                                       (GIOFunc) fake_hid->event, fake);
-
-       return fake;
-}
diff --git a/input/manager.c b/input/manager.c
deleted file mode 100644 (file)
index 5cc552b..0000000
+++ /dev/null
@@ -1,197 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
-
-#include <gdbus.h>
-
-#include "log.h"
-#include "../src/adapter.h"
-#include "../src/device.h"
-
-#include "device.h"
-#include "server.h"
-#include "manager.h"
-
-static int idle_timeout = 0;
-
-static DBusConnection *connection = NULL;
-static GSList *adapters = NULL;
-
-static void input_remove(struct btd_device *device, const char *uuid)
-{
-       const gchar *path = device_get_path(device);
-
-       DBG("path %s", path);
-
-       input_device_unregister(path, uuid);
-}
-
-static int hid_device_probe(struct btd_device *device, GSList *uuids)
-{
-       const gchar *path = device_get_path(device);
-       const sdp_record_t *rec = btd_device_get_record(device, uuids->data);
-
-       DBG("path %s", path);
-
-       if (!rec)
-               return -1;
-
-       return input_device_register(connection, device, path, HID_UUID, rec,
-                                                       idle_timeout * 60);
-}
-
-static void hid_device_remove(struct btd_device *device)
-{
-       input_remove(device, HID_UUID);
-}
-
-static int headset_probe(struct btd_device *device, GSList *uuids)
-{
-       const gchar *path = device_get_path(device);
-       const sdp_record_t *record;
-       sdp_list_t *protos;
-       int ch;
-
-       DBG("path %s", path);
-
-       if (!g_slist_find_custom(uuids, HSP_HS_UUID,
-                                       (GCompareFunc) strcasecmp))
-               return -EINVAL;
-
-       record = btd_device_get_record(device, uuids->data);
-
-       if (!record || sdp_get_access_protos(record, &protos) < 0) {
-               error("Invalid record");
-               return -EINVAL;
-       }
-
-       ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-       sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-       sdp_list_free(protos, NULL);
-
-       if (ch <= 0) {
-               error("Invalid RFCOMM channel");
-               return -EINVAL;
-       }
-
-       return fake_input_register(connection, device, path, HSP_HS_UUID, ch);
-}
-
-static void headset_remove(struct btd_device *device)
-{
-       input_remove(device, HSP_HS_UUID);
-}
-
-static int hid_server_probe(struct btd_adapter *adapter)
-{
-       bdaddr_t src;
-       int ret;
-
-       adapter_get_address(adapter, &src);
-
-       ret = server_start(&src);
-       if (ret < 0)
-               return ret;
-
-       adapters = g_slist_append(adapters, btd_adapter_ref(adapter));
-
-       return 0;
-}
-
-static void hid_server_remove(struct btd_adapter *adapter)
-{
-       bdaddr_t src;
-
-       adapter_get_address(adapter, &src);
-
-       server_stop(&src);
-
-       adapters = g_slist_remove(adapters, adapter);
-       btd_adapter_unref(adapter);
-}
-
-static struct btd_device_driver input_hid_driver = {
-       .name   = "input-hid",
-       .uuids  = BTD_UUIDS(HID_UUID),
-       .probe  = hid_device_probe,
-       .remove = hid_device_remove,
-};
-
-static struct btd_device_driver input_headset_driver = {
-       .name   = "input-headset",
-       .uuids  = BTD_UUIDS(HSP_HS_UUID),
-       .probe  = headset_probe,
-       .remove = headset_remove,
-};
-
-static struct btd_adapter_driver input_server_driver = {
-       .name   = "input-server",
-       .probe  = hid_server_probe,
-       .remove = hid_server_remove,
-};
-
-int input_manager_init(DBusConnection *conn, GKeyFile *config)
-{
-       GError *err = NULL;
-
-       if (config) {
-               idle_timeout = g_key_file_get_integer(config, "General",
-                                               "IdleTimeout", &err);
-               if (err) {
-                       DBG("input.conf: %s", err->message);
-                       g_error_free(err);
-               }
-       }
-
-       connection = dbus_connection_ref(conn);
-
-       btd_register_adapter_driver(&input_server_driver);
-
-       btd_register_device_driver(&input_hid_driver);
-       btd_register_device_driver(&input_headset_driver);
-
-       return 0;
-}
-
-void input_manager_exit(void)
-{
-       btd_unregister_device_driver(&input_hid_driver);
-       btd_unregister_device_driver(&input_headset_driver);
-
-       btd_unregister_adapter_driver(&input_server_driver);
-
-       dbus_connection_unref(connection);
-
-       connection = NULL;
-}
index 61f1c1e..da937d1 100644 (file)
@@ -142,44 +142,6 @@ struct a2mp_disconn_rsp {
 #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
diff --git a/lib/amp.h b/lib/amp.h
new file mode 100644 (file)
index 0000000..27aab1d
--- /dev/null
+++ b/lib/amp.h
@@ -0,0 +1,172 @@
+/*
+ *
+ *     BlueZ - Bluetooth protocol stack for Linux
+ *
+ *     Copyright (C) 2010-2011 Code Aurora Forum.  All rights reserved.
+ *     Copyright (C) 2012 Intel Corporation.
+ *
+ *     This program is free software; you can redistribute it and/or modify
+ *     it under the terms of the GNU General Public License version 2 and
+ *     only version 2 as published by the Free Software Foundation.
+ *
+ *     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.
+ *
+ */
+
+#ifndef __AMP_H
+#define __AMP_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#define AMP_MGR_CID 0x03
+
+/* AMP manager codes */
+#define AMP_COMMAND_REJ                0x01
+#define AMP_DISCOVER_REQ       0x02
+#define AMP_DISCOVER_RSP       0x03
+#define AMP_CHANGE_NOTIFY      0x04
+#define AMP_CHANGE_RSP         0x05
+#define AMP_INFO_REQ           0x06
+#define AMP_INFO_RSP           0x07
+#define AMP_ASSOC_REQ          0x08
+#define AMP_ASSOC_RSP          0x09
+#define AMP_LINK_REQ           0x0a
+#define AMP_LINK_RSP           0x0b
+#define AMP_DISCONN_REQ                0x0c
+#define AMP_DISCONN_RSP                0x0d
+
+typedef struct {
+       uint8_t         code;
+       uint8_t         ident;
+       uint16_t        len;
+} __attribute__ ((packed)) amp_mgr_hdr;
+#define AMP_MGR_HDR_SIZE 4
+
+/* AMP ASSOC structure */
+typedef struct {
+       uint8_t         type_id;
+       uint16_t        len;
+       uint8_t         data[0];
+} __attribute__ ((packed)) amp_assoc_tlv;
+
+typedef struct {
+       uint16_t        reason;
+} __attribute__ ((packed)) amp_cmd_rej_parms;
+
+typedef struct {
+       uint16_t        mtu;
+       uint16_t        mask;
+} __attribute__ ((packed)) amp_discover_req_parms;
+
+typedef struct {
+       uint16_t        mtu;
+       uint16_t        mask;
+       uint8_t         controller_list[0];
+} __attribute__ ((packed)) amp_discover_rsp_parms;
+
+typedef struct {
+       uint8_t         id;
+} __attribute__ ((packed)) amp_info_req_parms;
+
+typedef struct {
+       uint8_t         id;
+       uint8_t         status;
+       uint32_t        total_bandwidth;
+       uint32_t        max_bandwidth;
+       uint32_t        min_latency;
+       uint16_t        pal_caps;
+       uint16_t        assoc_size;
+} __attribute__ ((packed)) amp_info_rsp_parms;
+
+typedef struct {
+       uint8_t         id;
+       uint8_t         status;
+       amp_assoc_tlv   assoc;
+} __attribute__ ((packed)) amp_assoc_rsp_parms;
+
+typedef struct {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+       amp_assoc_tlv   assoc;
+} __attribute__ ((packed)) amp_link_req_parms;
+
+typedef struct {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+       uint8_t         status;
+} __attribute__ ((packed)) amp_link_rsp_parms;
+
+typedef struct {
+       uint8_t         local_id;
+       uint8_t         remote_id;
+} __attribute__ ((packed)) amp_disconn_req_parms;
+
+#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 amp_tlv {
+       uint8_t type;
+       uint16_t len;
+       uint8_t val[0];
+} __attribute__ ((packed));
+
+struct amp_pal_ver {
+       uint8_t ver;
+       uint16_t company_id;
+       uint16_t sub_ver;
+} __attribute__ ((packed));
+
+struct amp_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 amp_chan_list {
+       uint8_t country_code[3];
+       struct amp_country_triplet triplets[0];
+} __attribute__ ((packed));
+
+#define AMP_COMMAND_NOT_RECOGNIZED 0x0000
+
+/* AMP controller status */
+#define AMP_CT_POWERED_DOWN            0x00
+#define AMP_CT_BLUETOOTH_ONLY          0x01
+#define AMP_CT_NO_CAPACITY             0x02
+#define AMP_CT_LOW_CAPACITY            0x03
+#define AMP_CT_MEDIUM_CAPACITY         0x04
+#define AMP_CT_HIGH_CAPACITY           0x05
+#define AMP_CT_FULL_CAPACITY           0x06
+
+/* AMP response status */
+#define AMP_STATUS_SUCCESS                             0x00
+#define AMP_STATUS_INVALID_CTRL_ID                     0x01
+#define AMP_STATUS_UNABLE_START_LINK_CREATION          0x02
+#define AMP_STATUS_NO_PHYSICAL_LINK_EXISTS             0x02
+#define AMP_STATUS_COLLISION_OCCURED                   0x03
+#define AMP_STATUS_DISCONN_REQ_RECVD                   0x04
+#define AMP_STATUS_PHYS_LINK_EXISTS                    0x05
+#define AMP_STATUS_SECURITY_VIOLATION                  0x06
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __AMP_H */
index a0be884..05fe2c3 100644 (file)
@@ -82,7 +82,6 @@ int ba2str(const bdaddr_t *ba, char *str)
 
 int str2ba(const char *str, bdaddr_t *ba)
 {
-       bdaddr_t b;
        int i;
 
        if (bachk(str) < 0) {
@@ -90,10 +89,8 @@ int str2ba(const char *str, bdaddr_t *ba)
                return -1;
        }
 
-       for (i = 0; i < 6; i++, str += 3)
-               b.b[i] = strtol(str, NULL, 16);
-
-       baswap(ba, &b);
+       for (i = 5; i >= 0; i--, str += 3)
+               ba->b[i] = strtol(str, NULL, 16);
 
        return 0;
 }
@@ -261,7 +258,7 @@ int bt_error(uint16_t code)
        }
 }
 
-char *bt_compidtostr(int compid)
+const char *bt_compidtostr(int compid)
 {
        switch (compid) {
        case 0:
@@ -293,13 +290,13 @@ char *bt_compidtostr(int compid)
        case 13:
                return "Texas Instruments Inc.";
        case 14:
-               return "Parthus Technologies Inc.";
+               return "Ceva, Inc. (formerly Parthus Technologies, Inc.)";
        case 15:
                return "Broadcom Corporation";
        case 16:
                return "Mitel Semiconductor";
        case 17:
-               return "Widcomm, Inc.";
+               return "Widcomm, Inc";
        case 18:
                return "Zeevo, Inc.";
        case 19:
@@ -311,11 +308,11 @@ char *bt_compidtostr(int compid)
        case 22:
                return "KC Technology Inc.";
        case 23:
-               return "Newlogic";
+               return "NewLogic";
        case 24:
                return "Transilica, Inc.";
        case 25:
-               return "Rohde & Schwartz GmbH & Co. KG";
+               return "Rohde & Schwarz GmbH & Co. KG";
        case 26:
                return "TTPCom Limited";
        case 27:
@@ -363,7 +360,7 @@ char *bt_compidtostr(int compid)
        case 48:
                return "ST Microelectronics";
        case 49:
-               return "Synopsys";
+               return "Synopsis";
        case 50:
                return "Red-M (Communications) Ltd";
        case 51:
@@ -389,19 +386,19 @@ char *bt_compidtostr(int compid)
        case 61:
                return "IPextreme, Inc.";
        case 62:
-               return "Systems and Chips, Inc";
+               return "Systems and Chips, Inc.";
        case 63:
-               return "Bluetooth SIG, Inc";
+               return "Bluetooth SIG, Inc.";
        case 64:
                return "Seiko Epson Corporation";
        case 65:
-               return "Integrated Silicon Solution Taiwain, Inc.";
+               return "Integrated Silicon Solution Taiwan, Inc.";
        case 66:
                return "CONWISE Technology Corporation Ltd";
        case 67:
                return "PARROT SA";
        case 68:
-               return "Socket Communications";
+               return "Socket Mobile";
        case 69:
                return "Atheros Communications, Inc.";
        case 70:
@@ -423,9 +420,9 @@ char *bt_compidtostr(int compid)
        case 78:
                return "Avago Technologies";
        case 79:
-               return "APT Ltd.";
+               return "APT Licensing Ltd.";
        case 80:
-               return "SiRF Technology, Inc.";
+               return "SiRF Technology";
        case 81:
                return "Tzero Technologies, Inc.";
        case 82:
@@ -515,13 +512,251 @@ char *bt_compidtostr(int compid)
        case 124:
                return "A & R Cambridge";
        case 125:
-               return "Seers Technology Co. Ltd.";
+               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 129:
+               return "WuXi Vimicro";
+       case 130:
+               return "Sennheiser Communications A/S";
+       case 131:
+               return "TimeKeeping Systems, Inc.";
+       case 132:
+               return "Ludus Helsinki Ltd.";
+       case 133:
+               return "BlueRadios, Inc.";
+       case 134:
+               return "equinox AG";
+       case 135:
+               return "Garmin International, Inc.";
+       case 136:
+               return "Ecotest";
+       case 137:
+               return "GN ReSound A/S";
+       case 138:
+               return "Jawbone";
+       case 139:
+               return "Topcorn Positioning Systems, LLC";
+       case 140:
+               return "Qualcomm Labs, Inc.";
+       case 141:
+               return "Zscan Software";
+       case 142:
+               return "Quintic Corp.";
+       case 143:
+               return "Stollman E+V GmbH";
+       case 144:
+               return "Funai Electric Co., Ltd.";
+       case 145:
+               return "Advanced PANMOBIL Systems GmbH & Co. KG";
+       case 146:
+               return "ThinkOptics, Inc.";
+       case 147:
+               return "Universal Electronics, Inc.";
+       case 148:
+               return "Airoha Technology Corp.";
+       case 149:
+               return "NEC Lighting, Ltd.";
+       case 150:
+               return "ODM Technology, Inc.";
+       case 151:
+               return "ConnecteDevice Ltd.";
+       case 152:
+               return "zer01.tv GmbH";
+       case 153:
+               return "i.Tech Dynamic Global Distribution Ltd.";
+       case 154:
+               return "Alpwise";
+       case 155:
+               return "Jiangsu Toppower Automotive Electronics Co., Ltd.";
+       case 156:
+               return "Colorfy, Inc.";
+       case 157:
+               return "Geoforce Inc.";
+       case 158:
+               return "Bose Corporation";
+       case 159:
+               return "Suunto Oy";
+       case 160:
+               return "Kensington Computer Products Group";
+       case 161:
+               return "SR-Medizinelektronik";
+       case 162:
+               return "Vertu Corporation Limited";
+       case 163:
+               return "Meta Watch Ltd.";
+       case 164:
+               return "LINAK A/S";
+       case 165:
+               return "OTL Dynamics LLC";
+       case 166:
+               return "Panda Ocean Inc.";
+       case 167:
+               return "Visteon Corporation";
+       case 168:
+               return "ARP Devices Limited";
+       case 169:
+               return "Magneti Marelli S.p.A";
+       case 170:
+               return "CAEN RFID srl";
+       case 171:
+               return "Ingenieur-Systemgruppe Zahn GmbH";
+       case 172:
+               return "Green Throttle Games";
+       case 173:
+               return "Peter Systemtechnik GmbH";
+       case 174:
+               return "Omegawave Oy";
+       case 175:
+               return "Cinetix";
+       case 176:
+               return "Passif Semiconductor Corp";
+       case 177:
+               return "Saris Cycling Group, Inc";
+       case 178:
+               return "Bekey A/S";
+       case 179:
+               return "Clarinox Technologies Pty. Ltd.";
+       case 180:
+               return "BDE Technology Co., Ltd.";
+       case 181:
+               return "Swirl Networks";
+       case 182:
+               return "Meso international";
+       case 183:
+               return "TreLab Ltd";
+       case 184:
+               return "Qualcomm Innovation Center, Inc. (QuIC)";
+       case 185:
+               return "Johnson Controls, Inc.";
+       case 186:
+               return "Starkey Laboratories Inc.";
+       case 187:
+               return "S-Power Electronics Limited";
+       case 188:
+               return "Ace Sensor Inc";
+       case 189:
+               return "Aplix Corporation";
+       case 190:
+               return "AAMP of America";
+       case 191:
+               return "Stalmart Technology Limited";
+       case 192:
+               return "AMICCOM Electronics Corporation";
+       case 193:
+               return "Shenzhen Excelsecu Data Technology Co.,Ltd";
+       case 194:
+               return "Geneq Inc.";
+       case 195:
+               return "adidas AG";
+       case 196:
+               return "LG Electronics";
+       case 197:
+               return "Onset Computer Corporation";
+       case 198:
+               return "Selfly BV";
+       case 199:
+               return "Quuppa Oy.";
+       case 200:
+               return "GeLo Inc";
+       case 201:
+               return "Evluma";
+       case 202:
+               return "MC10";
+       case 203:
+               return "Binauric SE";
+       case 204:
+               return "Beats Electronics";
+       case 205:
+               return "Microchip Technology Inc.";
+       case 206:
+               return "Elgato Systems GmbH";
+       case 207:
+               return "ARCHOS SA";
+       case 209:
+               return "Polar Electro Europe B.V.";
+       case 210:
+               return "Dialog Semiconductor B.V.";
+       case 211:
+               return "Taixingbang Technology (HK) Co,. LTD.";
+       case 212:
+               return "Kawantech";
+       case 213:
+               return "Austco Communication Systems";
+       case 214:
+               return "Timex Group USA, Inc.";
+       case 215:
+               return "Qualcomm Technologies, Inc.";
+       case 216:
+               return "Qualcomm Connected Experiences, Inc.";
+       case 217:
+               return "Voyetra Turtle Beach";
+       case 218:
+               return "txtr GmbH";
+       case 219:
+               return "Biosentronics";
+       case 220:
+               return "Procter & Gamble";
+       case 221:
+               return "Hosiden Corporation";
+       case 222:
+               return "Muzik LLC";
+       case 223:
+               return "Misfit Wearables Corp";
+       case 224:
+               return "Google";
+       case 225:
+               return "Danlers Ltd";
+       case 226:
+               return "Semilink Inc";
+       case 227:
+               return "inMusic Brands, Inc";
+       case 228:
+               return "L.S. Research Inc.";
+       case 229:
+               return "Eden Software Consultants Ltd.";
+       case 230:
+               return "Freshtemp";
+       case 231:
+               return "KS Technologies";
+       case 232:
+               return "ACTS Technologies";
+       case 233:
+               return "Vtrack Systems";
+       case 234:
+               return "Nielsen-Kellerman Company";
+       case 235:
+               return "Server Technology, Inc.";
+       case 236:
+               return "BioResearch Associates";
+       case 237:
+               return "Jolly Logic, LLC";
+       case 238:
+               return "Above Average Outcomes, Inc.";
+       case 239:
+               return "Bitsplitters GmbH";
+       case 240:
+               return "PayPal, Inc.";
+       case 241:
+               return "Witron Technology Limited";
+       case 242:
+               return "Morse Project Inc.";
+       case 243:
+               return "Kent Displays Inc.";
+       case 244:
+               return "Nautilus Inc.";
+       case 245:
+               return "Smartifier Oy";
+       case 246:
+               return "Elcometer Limited";
+       case 247:
+               return "VSN Technologies Inc.";
+       case 248:
+               return "AceUni Corp., Ltd.";
        case 65535:
                return "internal use";
        default:
index 0fc4508..012fde4 100644 (file)
@@ -104,6 +104,14 @@ struct bt_security {
  */
 #define BT_CHANNEL_POLICY_AMP_PREFERRED                2
 
+#define BT_VOICE               11
+struct bt_voice {
+       uint16_t setting;
+};
+
+#define BT_VOICE_TRANSPARENT                   0x0003
+#define BT_VOICE_CVSD_16BIT                    0x0060
+
 /* Connection and socket states */
 enum {
        BT_CONNECTED = 1, /* Equal to TCP_ESTABLISHED to make net code happy */
@@ -183,6 +191,37 @@ static inline uint16_t bt_get_be16(const void *ptr)
 {
        return bswap_16(bt_get_unaligned((const uint16_t *) ptr));
 }
+
+static inline void bt_put_le64(uint64_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint64_t *) ptr);
+}
+
+static inline void bt_put_be64(uint64_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
+}
+
+static inline void bt_put_le32(uint32_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint32_t *) ptr);
+}
+
+static inline void bt_put_be32(uint32_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
+}
+
+static inline void bt_put_le16(uint16_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint16_t *) ptr);
+}
+
+static inline void bt_put_be16(uint16_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
+}
+
 #elif __BYTE_ORDER == __BIG_ENDIAN
 static inline uint64_t bt_get_le64(const void *ptr)
 {
@@ -213,6 +252,36 @@ static inline uint16_t bt_get_be16(const void *ptr)
 {
        return bt_get_unaligned((const uint16_t *) ptr);
 }
+
+static inline void bt_put_le64(uint64_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_64(val), (uint64_t *) ptr);
+}
+
+static inline void bt_put_be64(uint64_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint64_t *) ptr);
+}
+
+static inline void bt_put_le32(uint32_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_32(val), (uint32_t *) ptr);
+}
+
+static inline void bt_put_be32(uint32_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint32_t *) ptr);
+}
+
+static inline void bt_put_le16(uint16_t val, const void *ptr)
+{
+       bt_put_unaligned(bswap_16(val), (uint16_t *) ptr);
+}
+
+static inline void bt_put_be16(uint16_t val, const void *ptr)
+{
+       bt_put_unaligned(val, (uint16_t *) ptr);
+}
 #else
 #error "Unknown byte order"
 #endif
@@ -258,7 +327,7 @@ void *bt_malloc(size_t size);
 void bt_free(void *ptr);
 
 int bt_error(uint16_t code);
-char *bt_compidtostr(int id);
+const char *bt_compidtostr(int id);
 
 typedef struct {
        uint8_t data[16];
similarity index 100%
rename from bluez.pc.in
rename to lib/bluez.pc.in
index 66b2d5f..6e37836 100644 (file)
--- a/lib/hci.c
+++ b/lib/hci.c
@@ -672,6 +672,21 @@ int lmp_strtover(char *str, unsigned int *ver)
        return hci_str2uint(ver_map, str, ver);
 }
 
+static hci_map pal_map[] = {
+       { "3.0",        0x01 },
+       { NULL }
+};
+
+char *pal_vertostr(unsigned int ver)
+{
+       return hci_uint2str(pal_map, ver);
+}
+
+int pal_strtover(char *str, unsigned int *ver)
+{
+       return hci_str2uint(pal_map, str, ver);
+}
+
 /* LMP features mapping */
 static hci_map lmp_features_map[8][9] = {
        {       /* Byte 0 */
@@ -817,7 +832,7 @@ int hci_for_each_dev(int flag, int (*func)(int dd, int dev_id, long arg),
        int dev_id = -1;
        int i, sk, err = 0;
 
-       sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       sk = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (sk < 0)
                return -1;
 
@@ -909,7 +924,7 @@ int hci_devinfo(int dev_id, struct hci_dev_info *di)
 {
        int dd, err, ret;
 
-       dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       dd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (dd < 0)
                return dd;
 
@@ -965,7 +980,7 @@ int hci_inquiry(int dev_id, int len, int nrsp, const uint8_t *lap,
                }
        }
 
-       dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       dd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (dd < 0)
                return dd;
 
@@ -1021,7 +1036,7 @@ int hci_open_dev(int dev_id)
        int dd, err;
 
        /* Create HCI socket */
-       dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       dd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (dd < 0)
                return dd;
 
index f7be92d..0c94829 100644 (file)
--- a/lib/hci.h
+++ b/lib/hci.h
@@ -34,7 +34,7 @@ extern "C" {
 
 #define HCI_MAX_DEV    16
 
-#define HCI_MAX_ACL_SIZE       1024
+#define HCI_MAX_ACL_SIZE       (1492 + 4)
 #define HCI_MAX_SCO_SIZE       255
 #define HCI_MAX_EVENT_SIZE     260
 #define HCI_MAX_FRAME_SIZE     (HCI_MAX_ACL_SIZE + 4)
@@ -560,6 +560,13 @@ typedef struct {
 #define CREATE_PHYSICAL_LINK_CP_SIZE 35
 
 #define OCF_ACCEPT_PHYSICAL_LINK               0x0036
+typedef struct {
+       uint8_t         handle;
+       uint8_t         key_length;
+       uint8_t         key_type;
+       uint8_t         key[32];
+} __attribute__ ((packed)) accept_physical_link_cp;
+#define ACCEPT_PHYSICAL_LINK_CP_SIZE 35
 
 #define OCF_DISCONNECT_PHYSICAL_LINK           0x0037
 typedef struct {
@@ -650,9 +657,9 @@ typedef struct {
 } __attribute__ ((packed)) hci_qos;
 #define HCI_QOS_CP_SIZE 17
 typedef struct {
-       uint16_t        handle;
-       uint8_t         flags;                  /* Reserved */
-       hci_qos         qos;
+       uint16_t        handle;
+       uint8_t         flags;                  /* Reserved */
+       hci_qos         qos;
 } __attribute__ ((packed)) qos_setup_cp;
 #define QOS_SETUP_CP_SIZE (3 + HCI_QOS_CP_SIZE)
 
@@ -681,7 +688,7 @@ typedef struct {
 } __attribute__ ((packed)) read_link_policy_cp;
 #define READ_LINK_POLICY_CP_SIZE 2
 typedef struct {
-       uint8_t         status;
+       uint8_t         status;
        uint16_t        handle;
        uint16_t        policy;
 } __attribute__ ((packed)) read_link_policy_rp;
@@ -694,7 +701,7 @@ typedef struct {
 } __attribute__ ((packed)) write_link_policy_cp;
 #define WRITE_LINK_POLICY_CP_SIZE 4
 typedef struct {
-       uint8_t         status;
+       uint8_t         status;
        uint16_t        handle;
 } __attribute__ ((packed)) write_link_policy_rp;
 #define WRITE_LINK_POLICY_RP_SIZE 3
@@ -1326,6 +1333,14 @@ typedef struct {
 } __attribute__ ((packed)) read_bd_addr_rp;
 #define READ_BD_ADDR_RP_SIZE 7
 
+#define OCF_READ_DATA_BLOCK_SIZE       0x000A
+typedef struct {
+       uint8_t         status;
+       uint16_t        max_acl_len;
+       uint16_t        data_block_len;
+       uint16_t        num_blocks;
+} __attribute__ ((packed)) read_data_block_size_rp;
+
 /* Status params */
 #define OGF_STATUS_PARAM       0x05
 
@@ -1342,7 +1357,7 @@ typedef struct {
        uint8_t         status;
        uint16_t        handle;
 } __attribute__ ((packed)) reset_failed_contact_counter_rp;
-#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 4
+#define RESET_FAILED_CONTACT_COUNTER_RP_SIZE 3
 
 #define OCF_READ_LINK_QUALITY          0x0003
 typedef struct {
@@ -1402,22 +1417,23 @@ typedef struct {
 #define OCF_READ_LOCAL_AMP_ASSOC       0x000A
 typedef struct {
        uint8_t         handle;
-       uint16_t        len_so_far;
-       uint16_t        max_len;
+       uint16_t        length_so_far;
+       uint16_t        assoc_length;
 } __attribute__ ((packed)) read_local_amp_assoc_cp;
-
+#define READ_LOCAL_AMP_ASSOC_CP_SIZE 5
 typedef struct {
        uint8_t         status;
        uint8_t         handle;
-       uint16_t        rem_len;
-       uint8_t         frag[0];
+       uint16_t        length;
+       uint8_t         fragment[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) read_local_amp_assoc_rp;
+#define READ_LOCAL_AMP_ASSOC_RP_SIZE 252
 
 #define OCF_WRITE_REMOTE_AMP_ASSOC     0x000B
 typedef struct {
        uint8_t         handle;
        uint16_t        length_so_far;
-       uint16_t        assoc_length;
+       uint16_t        remaining_length;
        uint8_t         fragment[HCI_MAX_NAME_LENGTH];
 } __attribute__ ((packed)) write_remote_amp_assoc_cp;
 #define WRITE_REMOTE_AMP_ASSOC_CP_SIZE 253
@@ -1492,7 +1508,7 @@ typedef struct {
 #define OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER       0x0007
 typedef struct {
        uint8_t         status;
-       uint8_t         level;
+       int8_t          level;
 } __attribute__ ((packed)) le_read_advertising_channel_tx_power_rp;
 #define LE_READ_ADVERTISING_CHANNEL_TX_POWER_RP_SIZE 2
 
@@ -1716,7 +1732,7 @@ typedef struct {
        uint8_t         link_type;
        uint8_t         encr_mode;
 } __attribute__ ((packed)) evt_conn_complete;
-#define EVT_CONN_COMPLETE_SIZE 13
+#define EVT_CONN_COMPLETE_SIZE 11
 
 #define EVT_CONN_REQUEST               0x04
 typedef struct {
@@ -1755,7 +1771,7 @@ typedef struct {
        uint16_t        handle;
        uint8_t         encrypt;
 } __attribute__ ((packed)) evt_encrypt_change;
-#define EVT_ENCRYPT_CHANGE_SIZE 5
+#define EVT_ENCRYPT_CHANGE_SIZE 4
 
 #define EVT_CHANGE_CONN_LINK_KEY_COMPLETE      0x09
 typedef struct {
@@ -1799,14 +1815,14 @@ typedef struct {
 } __attribute__ ((packed)) evt_qos_setup_complete;
 #define EVT_QOS_SETUP_COMPLETE_SIZE (4 + HCI_QOS_CP_SIZE)
 
-#define EVT_CMD_COMPLETE               0x0E
+#define EVT_CMD_COMPLETE               0x0E
 typedef struct {
        uint8_t         ncmd;
        uint16_t        opcode;
 } __attribute__ ((packed)) evt_cmd_complete;
 #define EVT_CMD_COMPLETE_SIZE 3
 
-#define EVT_CMD_STATUS                         0x0F
+#define EVT_CMD_STATUS                 0x0F
 typedef struct {
        uint8_t         status;
        uint8_t         ncmd;
@@ -2198,6 +2214,16 @@ typedef struct {
 #define EVT_FLOW_SPEC_MODIFY_COMPLETE_SIZE 3
 
 #define EVT_NUMBER_COMPLETED_BLOCKS            0x48
+typedef struct {
+       uint16_t                handle;
+       uint16_t                num_cmplt_pkts;
+       uint16_t                num_cmplt_blks;
+} __attribute__ ((packed)) cmplt_handle;
+typedef struct {
+       uint16_t                total_num_blocks;
+       uint8_t                 num_handles;
+       cmplt_handle            handles[0];
+}  __attribute__ ((packed)) evt_num_completed_blocks;
 
 #define EVT_AMP_STATUS_CHANGE                  0x4D
 typedef struct {
@@ -2232,25 +2258,25 @@ typedef struct {
        uint16_t        opcode;         /* OCF & OGF */
        uint8_t         plen;
 } __attribute__ ((packed))     hci_command_hdr;
-#define HCI_COMMAND_HDR_SIZE   3
+#define HCI_COMMAND_HDR_SIZE   3
 
 typedef struct {
        uint8_t         evt;
        uint8_t         plen;
 } __attribute__ ((packed))     hci_event_hdr;
-#define HCI_EVENT_HDR_SIZE     2
+#define HCI_EVENT_HDR_SIZE     2
 
 typedef struct {
        uint16_t        handle;         /* Handle & Flags(PB, BC) */
        uint16_t        dlen;
 } __attribute__ ((packed))     hci_acl_hdr;
-#define HCI_ACL_HDR_SIZE       4
+#define HCI_ACL_HDR_SIZE       4
 
 typedef struct {
        uint16_t        handle;
        uint8_t         dlen;
 } __attribute__ ((packed))     hci_sco_hdr;
-#define HCI_SCO_HDR_SIZE       3
+#define HCI_SCO_HDR_SIZE       3
 
 typedef struct {
        uint16_t        device;
@@ -2288,6 +2314,7 @@ struct sockaddr_hci {
 #define HCI_DEV_NONE   0xffff
 
 #define HCI_CHANNEL_RAW                0
+#define HCI_CHANNEL_USER       1
 #define HCI_CHANNEL_MONITOR    2
 #define HCI_CHANNEL_CONTROL    3
 
index cf4a0ff..50744c3 100644 (file)
@@ -158,6 +158,8 @@ char *hci_vertostr(unsigned int ver);
 int hci_strtover(char *str, unsigned int *ver);
 char *lmp_vertostr(unsigned int ver);
 int lmp_strtover(char *str, unsigned int *ver);
+char *pal_vertostr(unsigned int ver);
+int pal_strtover(char *str, unsigned int *ver);
 
 char *lmp_featurestostr(uint8_t *features, char *pref, int width);
 
index a58915b..a896e52 100644 (file)
@@ -45,6 +45,7 @@
 #define MGMT_STATUS_NOT_POWERED                0x0f
 #define MGMT_STATUS_CANCELLED          0x10
 #define MGMT_STATUS_INVALID_INDEX      0x11
+#define MGMT_STATUS_RFKILLED           0x12
 
 struct mgmt_hdr {
        uint16_t opcode;
@@ -79,7 +80,7 @@ struct mgmt_rp_read_index_list {
 
 /* Reserve one extra byte for names in management messages so that they
  * are always guaranteed to be nul-terminated */
-#define MGMT_MAX_NAME_LENGTH           (HCI_MAX_NAME_LENGTH + 1)
+#define MGMT_MAX_NAME_LENGTH           (248 + 1)
 #define MGMT_MAX_SHORT_NAME_LENGTH     (10 + 1)
 
 #define MGMT_SETTING_POWERED           0x00000001
@@ -92,6 +93,7 @@ struct mgmt_rp_read_index_list {
 #define MGMT_SETTING_BREDR             0x00000080
 #define MGMT_SETTING_HS                        0x00000100
 #define MGMT_SETTING_LE                        0x00000200
+#define MGMT_SETTING_ADVERTISING       0x00000400
 
 #define MGMT_OP_READ_INFO              0x0004
 struct mgmt_rp_read_info {
@@ -109,6 +111,10 @@ struct mgmt_mode {
        uint8_t val;
 } __packed;
 
+struct mgmt_cod {
+       uint8_t val[3];
+} __packed;
+
 #define MGMT_OP_SET_POWERED            0x0005
 
 #define MGMT_OP_SET_DISCOVERABLE       0x0006
@@ -314,6 +320,21 @@ struct mgmt_cp_set_device_id {
        uint16_t version;
 } __packed;
 
+#define MGMT_OP_SET_ADVERTISING                0x0029
+
+#define MGMT_OP_SET_BREDR              0x002A
+
+#define MGMT_OP_SET_STATIC_ADDRESS     0x002B
+struct mgmt_cp_set_static_address {
+       bdaddr_t bdaddr;
+} __packed;
+
+#define MGMT_OP_SET_SCAN_PARAMS                0x002C
+struct mgmt_cp_set_scan_params {
+       uint16_t interval;
+       uint16_t window;
+} __packed;
+
 #define MGMT_EV_CMD_COMPLETE           0x0001
 struct mgmt_ev_cmd_complete {
        uint16_t opcode;
@@ -369,9 +390,15 @@ struct mgmt_ev_device_connected {
        uint8_t eir[0];
 } __packed;
 
+#define MGMT_DEV_DISCONN_UNKNOWN       0x00
+#define MGMT_DEV_DISCONN_TIMEOUT       0x01
+#define MGMT_DEV_DISCONN_LOCAL_HOST    0x02
+#define MGMT_DEV_DISCONN_REMOTE                0x03
+
 #define MGMT_EV_DEVICE_DISCONNECTED    0x000C
 struct mgmt_ev_device_disconnected {
        struct mgmt_addr_info addr;
+       uint8_t reason;
 } __packed;
 
 #define MGMT_EV_CONNECT_FAILED         0x000D
@@ -437,6 +464,13 @@ struct mgmt_ev_device_unpaired {
        struct mgmt_addr_info addr;
 } __packed;
 
+#define MGMT_EV_PASSKEY_NOTIFY         0x0017
+struct mgmt_ev_passkey_notify {
+       struct mgmt_addr_info addr;
+       uint32_t passkey;
+       uint8_t entered;
+} __packed;
+
 static const char *mgmt_op[] = {
        "<0x0000>",
        "Read Version",
@@ -479,6 +513,10 @@ static const char *mgmt_op[] = {
        "Block Device",
        "Unblock Device",
        "Set Device ID",
+       "Set Advertising",
+       "Set BR/EDR",
+       "Set Static Address",
+       "Set Scan Parameters",
 };
 
 static const char *mgmt_ev[] = {
@@ -505,6 +543,7 @@ static const char *mgmt_ev[] = {
        "Device Blocked",
        "Device Unblocked",
        "Device Unpaired",
+       "Passkey Notify",
 };
 
 static const char *mgmt_status[] = {
@@ -526,6 +565,7 @@ static const char *mgmt_status[] = {
        "Not Powered",
        "Cancelled",
        "Invalid Index",
+       "Blocked through rfkill",
 };
 
 #ifndef NELEM
index 7cb930f..cbdf15e 100644 (file)
--- a/lib/sdp.c
+++ b/lib/sdp.c
@@ -125,7 +125,7 @@ static struct tupla ServiceClass[] = {
        { AV_REMOTE_TARGET_SVCLASS_ID,          "AV Remote Target"              },
        { ADVANCED_AUDIO_SVCLASS_ID,            "Advanced Audio"                },
        { AV_REMOTE_SVCLASS_ID,                 "AV Remote"                     },
-       { VIDEO_CONF_SVCLASS_ID,                "Video Conferencing"            },
+       { AV_REMOTE_CONTROLLER_SVCLASS_ID,      "AV Remote Controller"          },
        { INTERCOM_SVCLASS_ID,                  "Intercom"                      },
        { FAX_SVCLASS_ID,                       "Fax"                           },
        { HEADSET_AGW_SVCLASS_ID,               "Headset Audio Gateway"         },
@@ -159,6 +159,9 @@ static struct tupla ServiceClass[] = {
        { PBAP_PCE_SVCLASS_ID,                  "Phonebook Access - PCE"        },
        { PBAP_PSE_SVCLASS_ID,                  "Phonebook Access - PSE"        },
        { PBAP_SVCLASS_ID,                      "Phonebook Access"              },
+       { MAP_MSE_SVCLASS_ID,                   "Message Access - MAS"          },
+       { MAP_MCE_SVCLASS_ID,                   "Message Access - MNS"          },
+       { MAP_SVCLASS_ID,                       "Message Access"                },
        { PNP_INFO_SVCLASS_ID,                  "PnP Information"               },
        { GENERIC_NETWORKING_SVCLASS_ID,        "Generic Networking"            },
        { GENERIC_FILETRANS_SVCLASS_ID,         "Generic File Transfer"         },
@@ -193,7 +196,7 @@ static char *string_lookup(struct tupla *pt0, int index)
        return "";
 }
 
-static char *string_lookup_uuid(struct tupla *pt0, const uuid_tuuid)
+static char *string_lookup_uuid(struct tupla *pt0, const uuid_t *uuid)
 {
        uuid_t tmp_uuid;
 
@@ -317,13 +320,13 @@ int sdp_uuid2strn(const uuid_t *uuid, char *str, size_t n)
 void sdp_uuid_print(const uuid_t *uuid)
 {
        if (uuid == NULL) {
-               SDPERR("Null passed to print UUID\n");
+               SDPERR("Null passed to print UUID");
                return;
        }
        if (uuid->type == SDP_UUID16) {
-               SDPDBG("  uint16_t : 0x%.4x\n", uuid->value.uuid16);
+               SDPDBG("  uint16_t : 0x%.4x", uuid->value.uuid16);
        } else if (uuid->type == SDP_UUID32) {
-               SDPDBG("  uint32_t : 0x%.8x\n", uuid->value.uuid32);
+               SDPDBG("  uint32_t : 0x%.8x", uuid->value.uuid32);
        } else if (uuid->type == SDP_UUID128) {
                unsigned int data0;
                unsigned short data1;
@@ -339,14 +342,11 @@ void sdp_uuid_print(const uuid_t *uuid)
                memcpy(&data4, &uuid->value.uuid128.data[10], 4);
                memcpy(&data5, &uuid->value.uuid128.data[14], 2);
 
-               SDPDBG("  uint128_t : 0x%.8x-", ntohl(data0));
-               SDPDBG("%.4x-", ntohs(data1));
-               SDPDBG("%.4x-", ntohs(data2));
-               SDPDBG("%.4x-", ntohs(data3));
-               SDPDBG("%.8x", ntohl(data4));
-               SDPDBG("%.4x\n", ntohs(data5));
+               SDPDBG("  uint128_t : 0x%.8x-%.4x-%.4x-%.4x-%.8x%.4x",
+                               ntohl(data0), ntohs(data1), ntohs(data2),
+                               ntohs(data3), ntohl(data4), ntohs(data5));
        } else
-               SDPERR("Enum type of UUID not set\n");
+               SDPERR("Enum type of UUID not set");
 }
 #endif
 
@@ -438,14 +438,14 @@ sdp_data_t *sdp_data_alloc_with_length(uint8_t dtd, const void *value,
 
                        memcpy(d->val.str, value, length);
                } else {
-                       SDPERR("Strings of size > USHRT_MAX not supported\n");
+                       SDPERR("Strings of size > USHRT_MAX not supported");
                        free(d);
                        d = NULL;
                }
                break;
        case SDP_URL_STR32:
        case SDP_TEXT_STR32:
-               SDPERR("Strings of size > USHRT_MAX not supported\n");
+               SDPERR("Strings of size > USHRT_MAX not supported");
                break;
        case SDP_ALT8:
        case SDP_ALT16:
@@ -532,7 +532,7 @@ sdp_data_t *sdp_seq_alloc_with_length(void **dtds, void **values, int *length,
                curr = data;
        }
 
-       return sdp_data_alloc_with_length(SDP_SEQ8, seq, length[i]);
+       return sdp_data_alloc(SDP_SEQ8, seq);
 }
 
 sdp_data_t *sdp_seq_alloc(void **dtds, void **values, int len)
@@ -567,7 +567,7 @@ static void extract_svclass_uuid(sdp_data_t *data, uuid_t *uuid)
 {
        sdp_data_t *d;
 
-       if (!data || data->dtd < SDP_SEQ8 || data->dtd > SDP_SEQ32)
+       if (!data || !SDP_IS_SEQ(data->dtd))
                return;
 
        d = data->val.dataseq;
@@ -622,60 +622,43 @@ void sdp_set_seq_len(uint8_t *ptr, uint32_t length)
        case SDP_ALT16:
        case SDP_TEXT_STR16:
        case SDP_URL_STR16:
-               bt_put_unaligned(htons(length), (uint16_t *) ptr);
+               bt_put_be16(length, ptr);
                break;
        case SDP_SEQ32:
        case SDP_ALT32:
        case SDP_TEXT_STR32:
        case SDP_URL_STR32:
-               bt_put_unaligned(htonl(length), (uint32_t *) ptr);
+               bt_put_be32(length, ptr);
                break;
        }
 }
 
-static int sdp_get_data_type(sdp_buf_t *buf, uint8_t dtd)
+static int sdp_get_data_type_size(uint8_t dtd)
 {
-       int data_type = 0;
-
-       data_type += sizeof(uint8_t);
+       int size = sizeof(uint8_t);
 
        switch (dtd) {
        case SDP_SEQ8:
        case SDP_TEXT_STR8:
        case SDP_URL_STR8:
        case SDP_ALT8:
-               data_type += sizeof(uint8_t);
+               size += sizeof(uint8_t);
                break;
        case SDP_SEQ16:
        case SDP_TEXT_STR16:
        case SDP_URL_STR16:
        case SDP_ALT16:
-               data_type += sizeof(uint16_t);
+               size += sizeof(uint16_t);
                break;
        case SDP_SEQ32:
        case SDP_TEXT_STR32:
        case SDP_URL_STR32:
        case SDP_ALT32:
-               data_type += sizeof(uint32_t);
+               size += sizeof(uint32_t);
                break;
        }
 
-       if (!buf->data)
-               buf->buf_size += data_type;
-
-       return data_type;
-}
-
-static int sdp_set_data_type(sdp_buf_t *buf, uint8_t dtd)
-{
-       int data_type = 0;
-       uint8_t *p = buf->data + buf->data_size;
-
-       *p = dtd;
-       data_type = sdp_get_data_type(buf, dtd);
-       buf->data_size += data_type;
-
-       return data_type;
+       return size;
 }
 
 void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr)
@@ -685,7 +668,7 @@ void sdp_set_attrid(sdp_buf_t *buf, uint16_t attr)
        /* data type for attr */
        *p++ = SDP_UINT16;
        buf->data_size = sizeof(uint8_t);
-       bt_put_unaligned(htons(attr), (uint16_t *) p);
+       bt_put_be16(attr, p);
        buf->data_size += sizeof(uint16_t);
 }
 
@@ -774,9 +757,6 @@ static int sdp_get_data_size(sdp_buf_t *buf, sdp_data_t *d)
                break;
        }
 
-       if (!buf->data)
-               buf->buf_size += data_size;
-
        return data_size;
 }
 
@@ -795,8 +775,8 @@ static int sdp_gen_buffer(sdp_buf_t *buf, sdp_data_t *d)
        /* attribute length */
        buf->buf_size += sizeof(uint8_t) + sizeof(uint16_t);
 
-       sdp_get_data_type(buf, d->dtd);
-       sdp_get_data_size(buf, d);
+       buf->buf_size += sdp_get_data_type_size(d->dtd);
+       buf->buf_size += sdp_get_data_size(buf, d);
 
        if (buf->buf_size > UCHAR_MAX && d->dtd == SDP_SEQ8)
                buf->buf_size += sizeof(uint8_t);
@@ -806,19 +786,29 @@ static int sdp_gen_buffer(sdp_buf_t *buf, sdp_data_t *d)
 
 int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d)
 {
-       uint32_t pdu_size = 0, data_size = 0;
+       uint32_t pdu_size, data_size;
        unsigned char *src = NULL, is_seq = 0, is_alt = 0;
-       uint8_t dtd = d->dtd;
        uint16_t u16;
        uint32_t u32;
        uint64_t u64;
        uint128_t u128;
        uint8_t *seqp = buf->data + buf->data_size;
+       uint32_t orig_data_size = buf->data_size;
+
+recalculate:
+       pdu_size = sdp_get_data_type_size(d->dtd);
+       buf->data_size += pdu_size;
 
-       pdu_size = sdp_set_data_type(buf, dtd);
        data_size = sdp_get_data_size(buf, d);
+       if (data_size > UCHAR_MAX && d->dtd == SDP_SEQ8) {
+               buf->data_size = orig_data_size;
+               d->dtd = SDP_SEQ16;
+               goto recalculate;
+       }
 
-       switch (dtd) {
+       *seqp = d->dtd;
+
+       switch (d->dtd) {
        case SDP_DATA_NIL:
                break;
        case SDP_UINT8:
@@ -900,8 +890,8 @@ int sdp_gen_pdu(sdp_buf_t *buf, sdp_data_t *d)
                if (src && buf->buf_size >= buf->data_size + data_size) {
                        memcpy(buf->data + buf->data_size, src, data_size);
                        buf->data_size += data_size;
-               } else if (dtd != SDP_DATA_NIL) {
-                       SDPDBG("Gen PDU : Can't copy from invalid source or dest\n");
+               } else if (d->dtd != SDP_DATA_NIL) {
+                       SDPDBG("Gen PDU : Can't copy from invalid source or dest");
                }
        }
 
@@ -1005,7 +995,7 @@ int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)
        type = *(const uint8_t *) p;
 
        if (!SDP_IS_UUID(type)) {
-               SDPERR("Unknown data type : %d expecting a svc UUID\n", type);
+               SDPERR("Unknown data type : %d expecting a svc UUID", type);
                return -1;
        }
        p += sizeof(uint8_t);
@@ -1016,14 +1006,14 @@ int sdp_uuid_extract(const uint8_t *p, int bufsize, uuid_t *uuid, int *scanned)
                        SDPERR("Not enough room for 16-bit UUID");
                        return -1;
                }
-               sdp_uuid16_create(uuid, ntohs(bt_get_unaligned((uint16_t *) p)));
+               sdp_uuid16_create(uuid, bt_get_be16(p));
                *scanned += sizeof(uint16_t);
        } else if (type == SDP_UUID32) {
                if (bufsize < (int) sizeof(uint32_t)) {
                        SDPERR("Not enough room for 32-bit UUID");
                        return -1;
                }
-               sdp_uuid32_create(uuid, ntohl(bt_get_unaligned((uint32_t *) p)));
+               sdp_uuid32_create(uuid, bt_get_be32(p));
                *scanned += sizeof(uint32_t);
        } else {
                if (bufsize < (int) sizeof(uint128_t)) {
@@ -1049,7 +1039,7 @@ static sdp_data_t *extract_int(const void *p, int bufsize, int *len)
        if (!d)
                return NULL;
 
-       SDPDBG("Extracting integer\n");
+       SDPDBG("Extracting integer");
        memset(d, 0, sizeof(sdp_data_t));
        d->dtd = *(uint8_t *) p;
        p += sizeof(uint8_t);
@@ -1078,7 +1068,7 @@ static sdp_data_t *extract_int(const void *p, int bufsize, int *len)
                        return NULL;
                }
                *len += sizeof(uint16_t);
-               d->val.uint16 = ntohs(bt_get_unaligned((uint16_t *) p));
+               d->val.uint16 = bt_get_be16(p);
                break;
        case SDP_INT32:
        case SDP_UINT32:
@@ -1088,7 +1078,7 @@ static sdp_data_t *extract_int(const void *p, int bufsize, int *len)
                        return NULL;
                }
                *len += sizeof(uint32_t);
-               d->val.uint32 = ntohl(bt_get_unaligned((uint32_t *) p));
+               d->val.uint32 = bt_get_be32(p);
                break;
        case SDP_INT64:
        case SDP_UINT64:
@@ -1098,7 +1088,7 @@ static sdp_data_t *extract_int(const void *p, int bufsize, int *len)
                        return NULL;
                }
                *len += sizeof(uint64_t);
-               d->val.uint64 = ntoh64(bt_get_unaligned((uint64_t *) p));
+               d->val.uint64 = bt_get_be64(p);
                break;
        case SDP_INT128:
        case SDP_UINT128:
@@ -1181,13 +1171,13 @@ static sdp_data_t *extract_str(const void *p, int bufsize, int *len)
                        free(d);
                        return NULL;
                }
-               n = ntohs(bt_get_unaligned((uint16_t *) p));
+               n = bt_get_be16(p);
                p += sizeof(uint16_t);
-               *len += sizeof(uint16_t) + n;
+               *len += sizeof(uint16_t);
                bufsize -= sizeof(uint16_t);
                break;
        default:
-               SDPERR("Sizeof text string > UINT16_MAX\n");
+               SDPERR("Sizeof text string > UINT16_MAX");
                free(d);
                return NULL;
        }
@@ -1209,8 +1199,8 @@ static sdp_data_t *extract_str(const void *p, int bufsize, int *len)
 
        *len += n;
 
-       SDPDBG("Len : %d\n", n);
-       SDPDBG("Str : %s\n", s);
+       SDPDBG("Len : %d", n);
+       SDPDBG("Str : %s", s);
 
        d->val.str = s;
        d->unitSize = n + sizeof(uint8_t);
@@ -1251,7 +1241,7 @@ int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *siz
                        SDPERR("Unexpected end of packet");
                        return 0;
                }
-               *size = ntohs(bt_get_unaligned((uint16_t *) buf));
+               *size = bt_get_be16(buf);
                scanned += sizeof(uint16_t);
                break;
        case SDP_SEQ32:
@@ -1260,11 +1250,11 @@ int sdp_extract_seqtype(const uint8_t *buf, int bufsize, uint8_t *dtdp, int *siz
                        SDPERR("Unexpected end of packet");
                        return 0;
                }
-               *size = ntohl(bt_get_unaligned((uint32_t *) buf));
+               *size = bt_get_be32(buf);
                scanned += sizeof(uint32_t);
                break;
        default:
-               SDPERR("Unknown sequence type, aborting\n");
+               SDPERR("Unknown sequence type, aborting");
                return 0;
        }
        return scanned;
@@ -1283,7 +1273,7 @@ static sdp_data_t *extract_seq(const void *p, int bufsize, int *len,
        SDPDBG("Extracting SEQ");
        memset(d, 0, sizeof(sdp_data_t));
        *len = sdp_extract_seqtype(p, bufsize, &d->dtd, &seqlen);
-       SDPDBG("Sequence Type : 0x%x length : 0x%x\n", d->dtd, seqlen);
+       SDPDBG("Sequence Type : 0x%x length : 0x%x", d->dtd, seqlen);
 
        if (*len == 0)
                return d;
@@ -1371,7 +1361,7 @@ sdp_data_t *sdp_extract_attr(const uint8_t *p, int bufsize, int *size,
                elem = extract_seq(p, bufsize, &n, rec);
                break;
        default:
-               SDPERR("Unknown data descriptor : 0x%x terminating\n", dtd);
+               SDPERR("Unknown data descriptor : 0x%x terminating", dtd);
                return NULL;
        }
        *size += n;
@@ -1383,21 +1373,21 @@ static void attr_print_func(void *value, void *userData)
 {
        sdp_data_t *d = (sdp_data_t *)value;
 
-       SDPDBG("=====================================\n");
-       SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x\n",  d->attrId);
-       SDPDBG("ATTRIBUTE VALUE PTR : %p\n", value);
+       SDPDBG("=====================================");
+       SDPDBG("ATTRIBUTE IDENTIFIER : 0x%x",  d->attrId);
+       SDPDBG("ATTRIBUTE VALUE PTR : %p", value);
        if (d)
                sdp_data_print(d);
        else
-               SDPDBG("NULL value\n");
-       SDPDBG("=====================================\n");
+               SDPDBG("NULL value");
+       SDPDBG("=====================================");
 }
 
 void sdp_print_service_attr(sdp_list_t *svcAttrList)
 {
-       SDPDBG("Printing service attr list %p\n", svcAttrList);
+       SDPDBG("Printing service attr list %p", svcAttrList);
        sdp_list_foreach(svcAttrList, attr_print_func, NULL);
-       SDPDBG("Printed service attr list %p\n", svcAttrList);
+       SDPDBG("Printed service attr list %p", svcAttrList);
 }
 #endif
 
@@ -1427,14 +1417,14 @@ sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int bufsize, int *scanned)
                }
 
                dtd = *(uint8_t *) p;
-               attr = ntohs(bt_get_unaligned((uint16_t *) (p + n)));
+               attr = bt_get_be16(p + n);
                n += sizeof(uint16_t);
 
-               SDPDBG("DTD of attrId : %d Attr id : 0x%x \n", dtd, attr);
+               SDPDBG("DTD of attrId : %d Attr id : 0x%x ", dtd, attr);
 
                data = sdp_extract_attr(p + n, bufsize - n, &attrlen, rec);
 
-               SDPDBG("Attr id : 0x%x attrValueLength : %d\n", attr, attrlen);
+               SDPDBG("Attr id : 0x%x attrValueLength : %d", attr, attrlen);
 
                n += attrlen;
                if (data == NULL) {
@@ -1457,7 +1447,7 @@ sdp_record_t *sdp_extract_pdu(const uint8_t *buf, int bufsize, int *scanned)
                                                        seqlen, extracted);
        }
 #ifdef SDP_DEBUG
-       SDPDBG("Successful extracting of Svc Rec attributes\n");
+       SDPDBG("Successful extracting of Svc Rec attributes");
        sdp_print_service_attr(rec->attrlist);
 #endif
        *scanned += seqlen;
@@ -1610,14 +1600,14 @@ static void print_dataseq(sdp_data_t *p)
 void sdp_record_print(const sdp_record_t *rec)
 {
        sdp_data_t *d = sdp_data_get(rec, SDP_ATTR_SVCNAME_PRIMARY);
-       if (d)
-               printf("Service Name: %.*s\n", d->unitSize, d->val.str);
+       if (d && SDP_IS_TEXT_STR(d->dtd))
+               printf("Service Name: %.*s", d->unitSize, d->val.str);
        d = sdp_data_get(rec, SDP_ATTR_SVCDESC_PRIMARY);
-       if (d)
-               printf("Service Description: %.*s\n", d->unitSize, d->val.str);
+       if (d && SDP_IS_TEXT_STR(d->dtd))
+               printf("Service Description: %.*s", d->unitSize, d->val.str);
        d = sdp_data_get(rec, SDP_ATTR_PROVNAME_PRIMARY);
-       if (d)
-               printf("Service Provider: %.*s\n", d->unitSize, d->val.str);
+       if (d && SDP_IS_TEXT_STR(d->dtd))
+               printf("Service Provider: %.*s", d->unitSize, d->val.str);
 }
 
 #ifdef SDP_DEBUG
@@ -1625,7 +1615,7 @@ void sdp_data_print(sdp_data_t *d)
 {
        switch (d->dtd) {
        case SDP_DATA_NIL:
-               SDPDBG("NIL\n");
+               SDPDBG("NIL");
                break;
        case SDP_BOOL:
        case SDP_UINT8:
@@ -1638,23 +1628,23 @@ void sdp_data_print(sdp_data_t *d)
        case SDP_INT32:
        case SDP_INT64:
        case SDP_INT128:
-               SDPDBG("Integer : 0x%x\n", d->val.uint32);
+               SDPDBG("Integer : 0x%x", d->val.uint32);
                break;
        case SDP_UUID16:
        case SDP_UUID32:
        case SDP_UUID128:
-               SDPDBG("UUID\n");
+               SDPDBG("UUID");
                sdp_uuid_print(&d->val.uuid);
                break;
        case SDP_TEXT_STR8:
        case SDP_TEXT_STR16:
        case SDP_TEXT_STR32:
-               SDPDBG("Text : %s\n", d->val.str);
+               SDPDBG("Text : %s", d->val.str);
                break;
        case SDP_URL_STR8:
        case SDP_URL_STR16:
        case SDP_URL_STR32:
-               SDPDBG("URL : %s\n", d->val.str);
+               SDPDBG("URL : %s", d->val.str);
                break;
        case SDP_SEQ8:
        case SDP_SEQ16:
@@ -1664,7 +1654,7 @@ void sdp_data_print(sdp_data_t *d)
        case SDP_ALT8:
        case SDP_ALT16:
        case SDP_ALT32:
-               SDPDBG("Data Sequence Alternates\n");
+               SDPDBG("Data Sequence Alternates");
                print_dataseq(d->val.dataseq);
                break;
        }
@@ -1705,9 +1695,9 @@ static int sdp_read_rsp(sdp_session_t *session, uint8_t *buf, uint32_t size)
 
        FD_ZERO(&readFds);
        FD_SET(session->sock, &readFds);
-       SDPDBG("Waiting for response\n");
+       SDPDBG("Waiting for response");
        if (select(session->sock + 1, &readFds, NULL, NULL, &timeout) == 0) {
-               SDPERR("Client timed out\n");
+               SDPERR("Client timed out");
                errno = ETIMEDOUT;
                return -1;
        }
@@ -1726,13 +1716,13 @@ int sdp_send_req_w4_rsp(sdp_session_t *session, uint8_t *reqbuf,
 
        SDPDBG("");
        if (0 > sdp_send_req(session, reqbuf, reqsize)) {
-               SDPERR("Error sending data:%s", strerror(errno));
+               SDPERR("Error sending data:%m");
                return -1;
        }
        n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE);
        if (0 > n)
                return -1;
-       SDPDBG("Read : %d\n", n);
+       SDPDBG("Read : %d", n);
        if (n == 0 || reqhdr->tid != rsphdr->tid) {
                errno = EPROTO;
                return -1;
@@ -1867,50 +1857,65 @@ sdp_data_t *sdp_get_proto_desc(sdp_list_t *list, int proto)
        return NULL;
 }
 
-int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **pap)
+static int sdp_get_proto_descs(uint16_t attr_id, const sdp_record_t *rec,
+                                                       sdp_list_t **pap)
 {
        sdp_data_t *pdlist, *curr;
-       sdp_list_t *ap = 0;
+       sdp_list_t *ap = NULL;
 
-       pdlist = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
+       pdlist = sdp_data_get(rec, attr_id);
        if (pdlist == NULL) {
                errno = ENODATA;
                return -1;
        }
-       SDPDBG("AP type : 0%x\n", pdlist->dtd);
+
+       SDPDBG("Attribute value type: 0x%02x", pdlist->dtd);
+
+       if (attr_id == SDP_ATTR_ADD_PROTO_DESC_LIST) {
+               if (!SDP_IS_SEQ(pdlist->dtd)) {
+                       errno = EINVAL;
+                       return -1;
+               }
+               pdlist = pdlist->val.dataseq;
+       }
 
        for (; pdlist; pdlist = pdlist->next) {
-               sdp_list_t *pds = 0;
-               for (curr = pdlist->val.dataseq; curr; curr = curr->next)
+               sdp_list_t *pds = NULL;
+
+               if (!SDP_IS_SEQ(pdlist->dtd) && !SDP_IS_ALT(pdlist->dtd))
+                       goto failed;
+
+               for (curr = pdlist->val.dataseq; curr; curr = curr->next) {
+                       if (!SDP_IS_SEQ(curr->dtd)) {
+                               sdp_list_free(pds, NULL);
+                               goto failed;
+                       }
                        pds = sdp_list_append(pds, curr->val.dataseq);
+               }
+
                ap = sdp_list_append(ap, pds);
        }
+
        *pap = ap;
+
        return 0;
-}
 
-int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap)
-{
-       sdp_data_t *pdlist, *curr;
-       sdp_list_t *ap = 0;
+failed:
+       sdp_list_foreach(ap, (sdp_list_func_t) sdp_list_free, NULL);
+       sdp_list_free(ap, NULL);
+       errno = EINVAL;
 
-       pdlist = sdp_data_get(rec, SDP_ATTR_ADD_PROTO_DESC_LIST);
-       if (pdlist == NULL) {
-               errno = ENODATA;
-               return -1;
-       }
-       SDPDBG("AP type : 0%x\n", pdlist->dtd);
+       return -1;
+}
 
-       pdlist = pdlist->val.dataseq;
+int sdp_get_access_protos(const sdp_record_t *rec, sdp_list_t **pap)
+{
+       return sdp_get_proto_descs(SDP_ATTR_PROTO_DESC_LIST, rec, pap);
+}
 
-       for (; pdlist; pdlist = pdlist->next) {
-               sdp_list_t *pds = 0;
-               for (curr = pdlist->val.dataseq; curr; curr = curr->next)
-                       pds = sdp_list_append(pds, curr->val.dataseq);
-               ap = sdp_list_append(ap, pds);
-       }
-       *pap = ap;
-       return 0;
+int sdp_get_add_access_protos(const sdp_record_t *rec, sdp_list_t **pap)
+{
+       return sdp_get_proto_descs(SDP_ATTR_ADD_PROTO_DESC_LIST, rec, pap);
 }
 
 int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr,
@@ -1919,7 +1924,7 @@ int sdp_get_uuidseq_attr(const sdp_record_t *rec, uint16_t attr,
        sdp_data_t *sdpdata = sdp_data_get(rec, attr);
 
        *seqp = NULL;
-       if (sdpdata && sdpdata->dtd >= SDP_SEQ8 && sdpdata->dtd <= SDP_SEQ32) {
+       if (sdpdata && SDP_IS_SEQ(sdpdata->dtd)) {
                sdp_data_t *d;
                for (d = sdpdata->val.dataseq; d; d = d->next) {
                        uuid_t *u;
@@ -2011,19 +2016,30 @@ int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq)
                errno = ENODATA;
                return -1;
        }
+
+       if (!SDP_IS_SEQ(sdpdata->dtd))
+               goto invalid;
        curr_data = sdpdata->val.dataseq;
+
        while (curr_data) {
-               sdp_data_t *pCode = curr_data;
-               sdp_data_t *pEncoding;
-               sdp_data_t *pOffset;
+               sdp_data_t *pCode, *pEncoding, *pOffset;
+
+               pCode = curr_data;
+               if (pCode->dtd != SDP_UINT16)
+                       goto invalid;
+
+               /* LanguageBaseAttributeIDList entries are always grouped as
+                * triplets */
+               if (!pCode->next || !pCode->next->next)
+                       goto invalid;
 
                pEncoding = pCode->next;
-               if (!pEncoding)
-                       break;
+               if (pEncoding->dtd != SDP_UINT16)
+                       goto invalid;
 
                pOffset = pEncoding->next;
-               if (!pOffset)
-                       break;
+               if (pOffset->dtd != SDP_UINT16)
+                       goto invalid;
 
                lang = malloc(sizeof(sdp_lang_attr_t));
                if (!lang) {
@@ -2034,15 +2050,22 @@ int sdp_get_lang_attr(const sdp_record_t *rec, sdp_list_t **langSeq)
                lang->code_ISO639 = pCode->val.uint16;
                lang->encoding = pEncoding->val.uint16;
                lang->base_offset = pOffset->val.uint16;
-               SDPDBG("code_ISO639 :  0x%02x\n", lang->code_ISO639);
-               SDPDBG("encoding :     0x%02x\n", lang->encoding);
-               SDPDBG("base_offfset : 0x%02x\n", lang->base_offset);
+               SDPDBG("code_ISO639 :  0x%02x", lang->code_ISO639);
+               SDPDBG("encoding :     0x%02x", lang->encoding);
+               SDPDBG("base_offfset : 0x%02x", lang->base_offset);
                *langSeq = sdp_list_append(*langSeq, lang);
 
                curr_data = pOffset->next;
        }
 
        return 0;
+
+invalid:
+       sdp_list_free(*langSeq, free);
+       *langSeq = NULL;
+       errno = EINVAL;
+
+       return -1;
 }
 
 int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)
@@ -2052,15 +2075,24 @@ int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)
 
        *profDescSeq = NULL;
        sdpdata = sdp_data_get(rec, SDP_ATTR_PFILE_DESC_LIST);
-       if (!sdpdata || !sdpdata->val.dataseq) {
+       if (sdpdata == NULL) {
                errno = ENODATA;
                return -1;
        }
-       for (seq = sdpdata->val.dataseq; seq && seq->val.dataseq; seq = seq->next) {
+
+       if (!SDP_IS_SEQ(sdpdata->dtd) || sdpdata->val.dataseq == NULL)
+               goto invalid;
+
+       for (seq = sdpdata->val.dataseq; seq; seq = seq->next) {
                uuid_t *uuid = NULL;
                uint16_t version = 0x100;
 
                if (SDP_IS_UUID(seq->dtd)) {
+                       /* Mac OS X 10.7.3 and old Samsung phones do not comply
+                        * to the SDP specification for
+                        * BluetoothProfileDescriptorList. This workaround
+                        * allows to properly parse UUID/version from SDP
+                        * record published by these systems. */
                        sdp_data_t *next = seq->next;
                        uuid = &seq->val.uuid;
                        if (next && next->dtd == SDP_UINT16) {
@@ -2068,13 +2100,21 @@ int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)
                                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) {
-                               uuid = &puuid->val.uuid;
-                               version = pVnum->val.uint16;
-                       }
-               }
+                       sdp_data_t *puuid, *pVnum;
+
+                       puuid = seq->val.dataseq;
+                       if (puuid == NULL || !SDP_IS_UUID(puuid->dtd))
+                               goto invalid;
+
+                       uuid = &puuid->val.uuid;
+
+                       pVnum = puuid->next;
+                       if (pVnum == NULL || pVnum->dtd != SDP_UINT16)
+                               goto invalid;
+
+                       version = pVnum->val.uint16;
+               } else
+                       goto invalid;
 
                if (uuid != NULL) {
                        profDesc = malloc(sizeof(sdp_profile_desc_t));
@@ -2087,12 +2127,19 @@ int sdp_get_profile_descs(const sdp_record_t *rec, sdp_list_t **profDescSeq)
                        profDesc->version = version;
 #ifdef SDP_DEBUG
                        sdp_uuid_print(&profDesc->uuid);
-                       SDPDBG("Vnum : 0x%04x\n", profDesc->version);
+                       SDPDBG("Vnum : 0x%04x", profDesc->version);
 #endif
                        *profDescSeq = sdp_list_append(*profDescSeq, profDesc);
                }
        }
        return 0;
+
+invalid:
+       sdp_list_free(*profDescSeq, free);
+       *profDescSeq = NULL;
+       errno = EINVAL;
+
+       return -1;
 }
 
 int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **u16)
@@ -2105,9 +2152,24 @@ int sdp_get_server_ver(const sdp_record_t *rec, sdp_list_t **u16)
                errno = ENODATA;
                return -1;
        }
-       for (curr = d->val.dataseq; curr; curr = curr->next)
+
+       if (!SDP_IS_SEQ(d->dtd) || d->val.dataseq == NULL)
+               goto invalid;
+
+       for (curr = d->val.dataseq; curr; curr = curr->next) {
+               if (curr->dtd != SDP_UINT16)
+                       goto invalid;
                *u16 = sdp_list_append(*u16, &curr->val.uint16);
+       }
+
        return 0;
+
+invalid:
+       sdp_list_free(*u16, NULL);
+       *u16 = NULL;
+       errno = EINVAL;
+
+       return -1;
 }
 
 /* flexible extraction of basic attributes - Jean II */
@@ -2135,9 +2197,7 @@ int sdp_get_string_attr(const sdp_record_t *rec, uint16_t attrid, char *value,
        sdp_data_t *sdpdata = sdp_data_get(rec, attrid);
        if (sdpdata)
                /* Verify that it is what the caller expects */
-               if (sdpdata->dtd == SDP_TEXT_STR8 ||
-                               sdpdata->dtd == SDP_TEXT_STR16 ||
-                               sdpdata->dtd == SDP_TEXT_STR32)
+               if (SDP_IS_TEXT_STR(sdpdata->dtd))
                        if ((int) strlen(sdpdata->val.str) < valuelen) {
                                strcpy(value, sdpdata->val.str);
                                return 0;
@@ -2486,6 +2546,7 @@ int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *profiles)
        int i = 0, seqlen = sdp_list_len(profiles);
        void **seqDTDs, **seqs;
        const sdp_list_t *p;
+       sdp_data_t *pAPSeq;
 
        seqDTDs = malloc(seqlen * sizeof(void *));
        if (!seqDTDs)
@@ -2503,7 +2564,7 @@ int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *profiles)
                sdp_profile_desc_t *profile = p->data;
                if (!profile) {
                        status = -1;
-                       break;
+                       goto end;
                }
                switch (profile->uuid.type) {
                case SDP_UUID16:
@@ -2520,22 +2581,26 @@ int sdp_set_profile_descs(sdp_record_t *rec, const sdp_list_t *profiles)
                        break;
                default:
                        status = -1;
-                       break;
+                       goto end;
                }
                dtds[1] = &uint16;
                values[1] = &profile->version;
                seq = sdp_seq_alloc(dtds, values, 2);
-               if (seq) {
-                       seqDTDs[i] = &seq->dtd;
-                       seqs[i] = seq;
-                       sdp_pattern_add_uuid(rec, &profile->uuid);
+
+               if (seq == NULL) {
+                       status = -1;
+                       goto end;
                }
+
+               seqDTDs[i] = &seq->dtd;
+               seqs[i] = seq;
+               sdp_pattern_add_uuid(rec, &profile->uuid);
                i++;
        }
-       if (status == 0) {
-               sdp_data_t *pAPSeq = sdp_seq_alloc(seqDTDs, seqs, seqlen);
-               sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, pAPSeq);
-       }
+
+       pAPSeq = sdp_seq_alloc(seqDTDs, seqs, seqlen);
+       sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, pAPSeq);
+end:
        free(seqDTDs);
        free(seqs);
        return status;
@@ -2758,9 +2823,9 @@ void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
        uint8_t *p = dst->data;
        uint8_t dtd = *p;
 
-       SDPDBG("Append src size: %d\n", len);
-       SDPDBG("Append dst size: %d\n", dst->data_size);
-       SDPDBG("Dst buffer size: %d\n", dst->buf_size);
+       SDPDBG("Append src size: %d", len);
+       SDPDBG("Append dst size: %d", dst->data_size);
+       SDPDBG("Dst buffer size: %d", dst->buf_size);
        if (dst->data_size == 0 && dtd == 0) {
                /* create initial sequence */
                *p = SDP_SEQ8;
@@ -2787,10 +2852,10 @@ void sdp_append_to_buf(sdp_buf_t *dst, uint8_t *data, uint32_t len)
                *(uint8_t *) p = dst->data_size - sizeof(uint8_t) - sizeof(uint8_t);
                break;
        case SDP_SEQ16:
-               bt_put_unaligned(htons(dst->data_size - sizeof(uint8_t) - sizeof(uint16_t)), (uint16_t *) p);
+               bt_put_be16(dst->data_size - sizeof(uint8_t) - sizeof(uint16_t), p);
                break;
        case SDP_SEQ32:
-               bt_put_unaligned(htonl(dst->data_size - sizeof(uint8_t) - sizeof(uint32_t)), (uint32_t *) p);
+               bt_put_be32(dst->data_size - sizeof(uint8_t) - sizeof(uint32_t), p);
                break;
        }
 }
@@ -2887,7 +2952,7 @@ int sdp_device_record_register_binary(sdp_session_t *session, bdaddr_t *device,
                        goto end;
                }
                if (handle)
-                       *handle  = ntohl(bt_get_unaligned((uint32_t *) p));
+                       *handle  = bt_get_be32(p);
        }
 
 end:
@@ -2970,7 +3035,7 @@ int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device
 
        p = reqbuf + sizeof(sdp_pdu_hdr_t);
        reqsize = sizeof(sdp_pdu_hdr_t);
-       bt_put_unaligned(htonl(handle), (uint32_t *) p);
+       bt_put_be32(handle, p);
        reqsize += sizeof(uint32_t);
 
        reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
@@ -2987,7 +3052,6 @@ int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device
 
        rsphdr = (sdp_pdu_hdr_t *) rspbuf;
        p = rspbuf + sizeof(sdp_pdu_hdr_t);
-       status = bt_get_unaligned((uint16_t *) p);
 
        if (rsphdr->pdu_id == SDP_ERROR_RSP) {
                /* For this case the status always is invalid record handle */
@@ -2996,6 +3060,12 @@ int sdp_device_record_unregister_binary(sdp_session_t *session, bdaddr_t *device
        } else if (rsphdr->pdu_id != SDP_SVC_REMOVE_RSP) {
                errno = EPROTO;
                status = -1;
+       } else {
+               uint16_t tmp;
+
+               memcpy(&tmp, p, sizeof(tmp));
+
+               status = tmp;
        }
 end:
        free(reqbuf);
@@ -3063,7 +3133,7 @@ int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp
        p = reqbuf + sizeof(sdp_pdu_hdr_t);
        reqsize = sizeof(sdp_pdu_hdr_t);
 
-       bt_put_unaligned(htonl(handle), (uint32_t *) p);
+       bt_put_be32(handle, p);
        reqsize += sizeof(uint32_t);
        p += sizeof(uint32_t);
 
@@ -3088,11 +3158,10 @@ int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp
                goto end;
        }
 
-       SDPDBG("Send req status : %d\n", status);
+       SDPDBG("Send req status : %d", status);
 
        rsphdr = (sdp_pdu_hdr_t *) rspbuf;
        p = rspbuf + sizeof(sdp_pdu_hdr_t);
-       status = bt_get_unaligned((uint16_t *) p);
 
        if (rsphdr->pdu_id == SDP_ERROR_RSP) {
                /* The status can be invalid sintax or invalid record handle */
@@ -3101,6 +3170,12 @@ int sdp_device_record_update(sdp_session_t *session, bdaddr_t *device, const sdp
        } else if (rsphdr->pdu_id != SDP_SVC_UPDATE_RSP) {
                errno = EPROTO;
                status = -1;
+       } else {
+               uint16_t tmp;
+
+               memcpy(&tmp, p, sizeof(tmp));
+
+               status = tmp;
        }
 end:
        free(reqbuf);
@@ -3139,15 +3214,15 @@ void sdp_pattern_add_uuid(sdp_record_t *rec, uuid_t *uuid)
 {
        uuid_t *uuid128 = sdp_uuid_to_uuid128(uuid);
 
-       SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern));
-       SDPDBG("Trying to add : 0x%lx\n", (unsigned long) uuid128);
+       SDPDBG("Elements in target pattern : %d", sdp_list_len(rec->pattern));
+       SDPDBG("Trying to add : 0x%lx", (unsigned long) uuid128);
 
        if (sdp_list_find(rec->pattern, uuid128, sdp_uuid128_cmp) == NULL)
                rec->pattern = sdp_list_insert_sorted(rec->pattern, uuid128, sdp_uuid128_cmp);
        else
                bt_free(uuid128);
 
-       SDPDBG("Elements in target pattern : %d\n", sdp_list_len(rec->pattern));
+       SDPDBG("Elements in target pattern : %d", sdp_list_len(rec->pattern));
 }
 
 void sdp_pattern_add_uuidseq(sdp_record_t *rec, sdp_list_t *seq)
@@ -3179,7 +3254,7 @@ static void extract_record_handle_seq(uint8_t *pdu, int bufsize, sdp_list_t **se
                pSvcRec = malloc(sizeof(uint32_t));
                if (!pSvcRec)
                        break;
-               *pSvcRec = ntohl(bt_get_unaligned((uint32_t *) pdata));
+               *pSvcRec = bt_get_be32(pdata);
                pSeq = sdp_list_append(pSeq, pSvcRec);
                pdata += sizeof(uint32_t);
                *scanned += sizeof(uint32_t);
@@ -3201,7 +3276,7 @@ static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)
        /* Fill up the value and the dtd arrays */
        SDPDBG("");
 
-       SDPDBG("Seq length : %d\n", seqlen);
+       SDPDBG("Seq length : %d", seqlen);
 
        types = malloc(seqlen * sizeof(void *));
        if (!types)
@@ -3240,9 +3315,9 @@ static int gen_dataseq_pdu(uint8_t *dst, const sdp_list_t *seq, uint8_t dtd)
                return -ENOMEM;
        }
 
-       SDPDBG("Data Seq : 0x%p\n", seq);
+       SDPDBG("Data Seq : 0x%p", seq);
        seqlen = sdp_gen_pdu(&buf, dataseq);
-       SDPDBG("Copying : %d\n", buf.data_size);
+       SDPDBG("Copying : %d", buf.data_size);
        memcpy(dst, buf.data, buf.data_size);
 
        sdp_data_free(dataseq);
@@ -3343,14 +3418,14 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
        /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
-       SDPDBG("Data seq added : %d\n", seqlen);
+       SDPDBG("Data seq added : %d", seqlen);
 
        /* set the length and increment the pointer */
        reqsize += seqlen;
        pdata += seqlen;
 
        /* specify the maximum svc rec count that client expects */
-       bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata);
+       bt_put_be16(max_rec_num, pdata);
        reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
@@ -3385,7 +3460,7 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
                rsplen = ntohs(rsphdr->plen);
 
                if (rsphdr->pdu_id == SDP_ERROR_RSP) {
-                       SDPDBG("Status : 0x%x\n", rsphdr->pdu_id);
+                       SDPDBG("Status : 0x%x", rsphdr->pdu_id);
                        status = -1;
                        goto end;
                }
@@ -3403,20 +3478,20 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
                pdata += sizeof(uint16_t);
                scanned += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
-               rec_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
+               rec_count = bt_get_be16(pdata);
                pdata += sizeof(uint16_t);
                scanned += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
 
-               SDPDBG("Current svc count: %d\n", rec_count);
-               SDPDBG("ResponseLength: %d\n", rsplen);
+               SDPDBG("Current svc count: %d", rec_count);
+               SDPDBG("ResponseLength: %d", rsplen);
 
                if (!rec_count) {
                        status = -1;
                        goto end;
                }
                extract_record_handle_seq(pdata, pdata_len, rsp, rec_count, &scanned);
-               SDPDBG("BytesScanned : %d\n", scanned);
+               SDPDBG("BytesScanned : %d", scanned);
 
                if (rsplen > scanned) {
                        uint8_t cstate_len;
@@ -3431,7 +3506,7 @@ int sdp_service_search_req(sdp_session_t *session, const sdp_list_t *search,
                        cstate_len = *(uint8_t *) pdata;
                        if (cstate_len > 0) {
                                cstate = (sdp_cstate_t *)pdata;
-                               SDPDBG("Cont state length: %d\n", cstate_len);
+                               SDPDBG("Cont state length: %d", cstate_len);
                        } else
                                cstate = NULL;
                }
@@ -3512,12 +3587,12 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
        reqsize = sizeof(sdp_pdu_hdr_t);
 
        /* add the service record handle */
-       bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
+       bt_put_be32(handle, pdata);
        reqsize += sizeof(uint32_t);
        pdata += sizeof(uint32_t);
 
        /* specify the response limit */
-       bt_put_unaligned(htons(65535), (uint16_t *) pdata);
+       bt_put_be16(65535, pdata);
        reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
@@ -3530,7 +3605,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
        }
        pdata += seqlen;
        reqsize += seqlen;
-       SDPDBG("Attr list length : %d\n", seqlen);
+       SDPDBG("Attr list length : %d", seqlen);
 
        /* save before Continuation State */
        _pdata = pdata;
@@ -3558,7 +3633,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
 
                rsphdr = (sdp_pdu_hdr_t *) rspbuf;
                if (rsphdr->pdu_id == SDP_ERROR_RSP) {
-                       SDPDBG("PDU ID : 0x%x\n", rsphdr->pdu_id);
+                       SDPDBG("PDU ID : 0x%x", rsphdr->pdu_id);
                        goto end;
                }
                pdata = rspbuf + sizeof(sdp_pdu_hdr_t);
@@ -3569,7 +3644,7 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
                        goto end;
                }
 
-               rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
+               rsp_count = bt_get_be16(pdata);
                attr_list_len += rsp_count;
                pdata += sizeof(uint16_t);
                pdata_len -= sizeof(uint16_t);
@@ -3584,9 +3659,9 @@ sdp_record_t *sdp_service_attr_req(sdp_session_t *session, uint32_t handle,
                }
                cstate_len = *(uint8_t *) (pdata + rsp_count);
 
-               SDPDBG("Response id : %d\n", rsphdr->pdu_id);
-               SDPDBG("Attrlist byte count : %d\n", rsp_count);
-               SDPDBG("sdp_cstate_t length : %d\n", cstate_len);
+               SDPDBG("Response id : %d", rsphdr->pdu_id);
+               SDPDBG("Attrlist byte count : %d", rsp_count);
+               SDPDBG("sdp_cstate_t length : %d", cstate_len);
 
                /*
                 * a split response: concatenate intermediate responses
@@ -3765,13 +3840,13 @@ int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, u
        /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
-       SDPDBG("Data seq added : %d\n", seqlen);
+       SDPDBG("Data seq added : %d", seqlen);
 
        /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
 
-       bt_put_unaligned(htons(max_rec_num), (uint16_t *) pdata);
+       bt_put_be16(max_rec_num, pdata);
        t->reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
@@ -3780,7 +3855,7 @@ int sdp_service_search_async(sdp_session_t *session, const sdp_list_t *search, u
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
        if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
-               SDPERR("Error sendind data:%s", strerror(errno));
+               SDPERR("Error sendind data:%m");
                t->err = errno;
                goto end;
        }
@@ -3864,12 +3939,12 @@ int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_
        t->reqsize = sizeof(sdp_pdu_hdr_t);
 
        /* add the service record handle */
-       bt_put_unaligned(htonl(handle), (uint32_t *) pdata);
+       bt_put_be32(handle, pdata);
        t->reqsize += sizeof(uint32_t);
        pdata += sizeof(uint32_t);
 
        /* specify the response limit */
-       bt_put_unaligned(htons(65535), (uint16_t *) pdata);
+       bt_put_be16(65535, pdata);
        t->reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
@@ -3884,14 +3959,14 @@ int sdp_service_attr_async(sdp_session_t *session, uint32_t handle, sdp_attrreq_
        /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
-       SDPDBG("Attr list length : %d\n", seqlen);
+       SDPDBG("Attr list length : %d", seqlen);
 
        /* set the request header's param length */
        cstate_len = copy_cstate(pdata, SDP_REQ_BUFFER_SIZE - t->reqsize, NULL);
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
        if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
-               SDPERR("Error sendind data:%s", strerror(errno));
+               SDPERR("Error sendind data:%m");
                t->err = errno;
                goto end;
        }
@@ -3978,17 +4053,17 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
        /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
 
-       SDPDBG("Data seq added : %d\n", seqlen);
+       SDPDBG("Data seq added : %d", seqlen);
 
        /* now set the length and increment the pointer */
        t->reqsize += seqlen;
        pdata += seqlen;
 
-       bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata);
+       bt_put_be16(SDP_MAX_ATTR_LEN, pdata);
        t->reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
-       SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN);
+       SDPDBG("Max attr byte count : %d", SDP_MAX_ATTR_LEN);
 
        /* get attr seq PDU form */
        seqlen = gen_attridseq_pdu(pdata, attrid_list,
@@ -3999,7 +4074,7 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
        }
 
        pdata += seqlen;
-       SDPDBG("Attr list length : %d\n", seqlen);
+       SDPDBG("Attr list length : %d", seqlen);
        t->reqsize += seqlen;
 
        /* set the request header's param length */
@@ -4007,7 +4082,7 @@ int sdp_service_search_attr_async(sdp_session_t *session, const sdp_list_t *sear
        reqhdr->plen = htons((t->reqsize + cstate_len) - sizeof(sdp_pdu_hdr_t));
 
        if (sdp_send_req(session, t->reqbuf, t->reqsize + cstate_len) < 0) {
-               SDPERR("Error sendind data:%s", strerror(errno));
+               SDPERR("Error sendind data:%m");
                t->err = errno;
                goto end;
        }
@@ -4083,8 +4158,7 @@ int sdp_process(sdp_session_t *session)
 
        rspbuf = malloc(SDP_RSP_BUFFER_SIZE);
        if (!rspbuf) {
-               SDPERR("Response buffer alloc failure:%s (%d)",
-                               strerror(errno), errno);
+               SDPERR("Response buffer alloc failure:%m (%d)", errno);
                return -1;
        }
 
@@ -4098,7 +4172,7 @@ int sdp_process(sdp_session_t *session)
 
        n = sdp_read_rsp(session, rspbuf, SDP_RSP_BUFFER_SIZE);
        if (n < 0) {
-               SDPERR("Read response:%s (%d)", strerror(errno), errno);
+               SDPERR("Read response:%m (%d)", errno);
                t->err = errno;
                goto end;
        }
@@ -4120,9 +4194,9 @@ int sdp_process(sdp_session_t *session)
                 * CSRC: Current Service Record Count (2 bytes)
                 */
                ssr_pdata = pdata;
-               tsrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata));
+               tsrc = bt_get_be16(ssr_pdata);
                ssr_pdata += sizeof(uint16_t);
-               csrc = ntohs(bt_get_unaligned((uint16_t *) ssr_pdata));
+               csrc = bt_get_be16(ssr_pdata);
 
                /* csrc should never be larger than tsrc */
                if (csrc > tsrc) {
@@ -4131,8 +4205,8 @@ int sdp_process(sdp_session_t *session)
                        goto end;
                }
 
-               SDPDBG("Total svc count: %d\n", tsrc);
-               SDPDBG("Current svc count: %d\n", csrc);
+               SDPDBG("Total svc count: %d", tsrc);
+               SDPDBG("Current svc count: %d", csrc);
 
                /* parameter length without continuation state */
                plen = sizeof(tsrc) + sizeof(csrc) + csrc * 4;
@@ -4140,26 +4214,43 @@ int sdp_process(sdp_session_t *session)
                if (t->rsp_concat_buf.data_size == 0) {
                        /* first fragment */
                        rsp_count = sizeof(tsrc) + sizeof(csrc) + csrc * 4;
-               } else {
+               } else if (t->rsp_concat_buf.data_size >= sizeof(uint16_t) * 2) {
                        /* point to the first csrc */
-                       uint16_t *pcsrc = (uint16_t *) (t->rsp_concat_buf.data + 2);
+                       uint8_t *pcsrc = t->rsp_concat_buf.data + 2;
+                       uint16_t tcsrc, tcsrc2;
 
                        /* FIXME: update the interface later. csrc doesn't need be passed to clients */
 
                        pdata += sizeof(uint16_t); /* point to csrc */
 
                        /* the first csrc contains the sum of partial csrc responses */
-                       *pcsrc += bt_get_unaligned((uint16_t *) pdata);
+                       memcpy(&tcsrc, pcsrc, sizeof(tcsrc));
+                       memcpy(&tcsrc2, pdata, sizeof(tcsrc2));
+                       tcsrc += tcsrc2;
+                       memcpy(pcsrc, &tcsrc, sizeof(tcsrc));
 
                        pdata += sizeof(uint16_t); /* point to the first handle */
                        rsp_count = csrc * 4;
+               } else {
+                       t->err = EPROTO;
+                       SDPERR("Protocol error: invalid PDU size");
+                       status = SDP_INVALID_PDU_SIZE;
+                       goto end;
                }
                status = 0x0000;
                break;
        case SDP_SVC_ATTR_RSP:
        case SDP_SVC_SEARCH_ATTR_RSP:
-               rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
-               SDPDBG("Attrlist byte count : %d\n", rsp_count);
+               rsp_count = bt_get_be16(pdata);
+               SDPDBG("Attrlist byte count : %d", rsp_count);
+
+               /* Valid range for rsp_count is 0x0002-0xFFFF */
+               if (t->rsp_concat_buf.data_size == 0 && rsp_count < 0x0002) {
+                       t->err = EPROTO;
+                       SDPERR("Protocol error: invalid AttrList size");
+                       status = SDP_INVALID_PDU_SIZE;
+                       goto end;
+               }
 
                /*
                 * Number of bytes in the AttributeLists parameter(without
@@ -4171,7 +4262,7 @@ int sdp_process(sdp_session_t *session)
                status = 0x0000;
                break;
        case SDP_ERROR_RSP:
-               status = ntohs(bt_get_unaligned((uint16_t *) pdata));
+               status = bt_get_be16(pdata);
                size = ntohs(rsphdr->plen);
 
                goto end;
@@ -4181,9 +4272,20 @@ int sdp_process(sdp_session_t *session)
                goto end;
        }
 
+       /* Out of bound check before using rsp_count as offset for
+        * continuation state, which has at least a one byte size
+        * field.
+        */
+       if ((n - (int) sizeof(sdp_pdu_hdr_t)) < plen + 1) {
+               t->err = EPROTO;
+               SDPERR("Protocol error: invalid PDU size");
+               status = SDP_INVALID_PDU_SIZE;
+               goto end;
+       }
+
        pcstate = (sdp_cstate_t *) (pdata + rsp_count);
 
-       SDPDBG("Cstate length : %d\n", pcstate->length);
+       SDPDBG("Cstate length : %d", pcstate->length);
 
        /*
         * Check out of bound. Continuation state must have at least
@@ -4221,7 +4323,7 @@ int sdp_process(sdp_session_t *session)
                reqhdr->plen = htons(reqsize - sizeof(sdp_pdu_hdr_t));
 
                if (sdp_send_req(session, t->reqbuf, reqsize) < 0) {
-                       SDPERR("Error sendind data:%s(%d)", strerror(errno), errno);
+                       SDPERR("Error sendind data:%m(%d)", errno);
                        status = 0xffff;
                        t->err = errno;
                        goto end;
@@ -4325,28 +4427,34 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
 
        /* add service class IDs for search */
        seqlen = gen_searchseq_pdu(pdata, search);
+       if (seqlen < 0) {
+               errno = EINVAL;
+               status = -1;
+               goto end;
+       }
 
-       SDPDBG("Data seq added : %d\n", seqlen);
+       SDPDBG("Data seq added : %d", seqlen);
 
        /* now set the length and increment the pointer */
        reqsize += seqlen;
        pdata += seqlen;
 
-       bt_put_unaligned(htons(SDP_MAX_ATTR_LEN), (uint16_t *) pdata);
+       bt_put_be16(SDP_MAX_ATTR_LEN, pdata);
        reqsize += sizeof(uint16_t);
        pdata += sizeof(uint16_t);
 
-       SDPDBG("Max attr byte count : %d\n", SDP_MAX_ATTR_LEN);
+       SDPDBG("Max attr byte count : %d", SDP_MAX_ATTR_LEN);
 
        /* get attr seq PDU form */
        seqlen = gen_attridseq_pdu(pdata, attrids,
                reqtype == SDP_ATTR_REQ_INDIVIDUAL ? SDP_UINT16 : SDP_UINT32);
        if (seqlen == -1) {
-               status = EINVAL;
+               errno = EINVAL;
+               status = -1;
                goto end;
        }
        pdata += seqlen;
-       SDPDBG("Attr list length : %d\n", seqlen);
+       SDPDBG("Attr list length : %d", seqlen);
        reqsize += seqlen;
        *rsp = 0;
 
@@ -4372,7 +4480,7 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
                }
 
                if (status < 0) {
-                       SDPDBG("Status : 0x%x\n", rsphdr->pdu_id);
+                       SDPDBG("Status : 0x%x", rsphdr->pdu_id);
                        goto end;
                }
 
@@ -4390,7 +4498,7 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
                        goto end;
                }
 
-               rsp_count = ntohs(bt_get_unaligned((uint16_t *) pdata));
+               rsp_count = bt_get_be16(pdata);
                attr_list_len += rsp_count;
                pdata += sizeof(uint16_t); /* pdata points to attribute list */
                pdata_len -= sizeof(uint16_t);
@@ -4403,9 +4511,9 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
 
                cstate_len = *(uint8_t *) (pdata + rsp_count);
 
-               SDPDBG("Attrlist byte count : %d\n", attr_list_len);
-               SDPDBG("Response byte count : %d\n", rsp_count);
-               SDPDBG("Cstate length : %d\n", cstate_len);
+               SDPDBG("Attrlist byte count : %d", attr_list_len);
+               SDPDBG("Response byte count : %d", rsp_count);
+               SDPDBG("Cstate length : %d", cstate_len);
                /*
                 * This is a split response, need to concatenate intermediate
                 * responses and the last one which will have cstate_len == 0
@@ -4439,8 +4547,8 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
                 */
                scanned = sdp_extract_seqtype(pdata, pdata_len, &dataType, &seqlen);
 
-               SDPDBG("Bytes scanned : %d\n", scanned);
-               SDPDBG("Seq length : %d\n", seqlen);
+               SDPDBG("Bytes scanned : %d", scanned);
+               SDPDBG("Seq length : %d", seqlen);
 
                if (scanned && seqlen) {
                        pdata += scanned;
@@ -4449,7 +4557,7 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
                                int recsize = 0;
                                sdp_record_t *rec = sdp_extract_pdu(pdata, pdata_len, &recsize);
                                if (rec == NULL) {
-                                       SDPERR("SVC REC is null\n");
+                                       SDPERR("SVC REC is null");
                                        status = -1;
                                        goto end;
                                }
@@ -4461,14 +4569,14 @@ int sdp_service_search_attr_req(sdp_session_t *session, const sdp_list_t *search
                                pdata += recsize;
                                pdata_len -= recsize;
 
-                               SDPDBG("Loc seq length : %d\n", recsize);
-                               SDPDBG("Svc Rec Handle : 0x%x\n", rec->handle);
-                               SDPDBG("Bytes scanned : %d\n", scanned);
-                               SDPDBG("Attrlist byte count : %d\n", attr_list_len);
+                               SDPDBG("Loc seq length : %d", recsize);
+                               SDPDBG("Svc Rec Handle : 0x%x", rec->handle);
+                               SDPDBG("Bytes scanned : %d", scanned);
+                               SDPDBG("Attrlist byte count : %d", attr_list_len);
                                rec_list = sdp_list_append(rec_list, rec);
                        } while (scanned < attr_list_len && pdata_len > 0);
 
-                       SDPDBG("Successful scan of service attr lists\n");
+                       SDPDBG("Successful scan of service attr lists");
                        *rsp = rec_list;
                }
        }
@@ -4486,7 +4594,7 @@ int sdp_general_inquiry(inquiry_info *ii, int num_dev, int duration, uint8_t *fo
 {
        int n = hci_inquiry(-1, 10, num_dev, NULL, &ii, 0);
        if (n < 0) {
-               SDPERR("Inquiry failed:%s", strerror(errno));
+               SDPERR("Inquiry failed:%m");
                return -1;
        }
        *found = n;
@@ -4525,7 +4633,7 @@ static int sdp_connect_local(sdp_session_t *session)
 {
        struct sockaddr_un sa;
 
-       session->sock = socket(PF_UNIX, SOCK_STREAM, 0);
+       session->sock = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
        if (session->sock < 0)
                return -1;
        session->local = 1;
@@ -4542,19 +4650,18 @@ static int sdp_connect_l2cap(const bdaddr_t *src,
        uint32_t flags = session->flags;
        struct sockaddr_l2 sa;
        int sk;
+       int sockflags = SOCK_SEQPACKET | SOCK_CLOEXEC;
+
+       if (flags & SDP_NON_BLOCKING)
+               sockflags |= SOCK_NONBLOCK;
 
-       session->sock = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+       session->sock = socket(PF_BLUETOOTH, sockflags, BTPROTO_L2CAP);
        if (session->sock < 0)
                return -1;
        session->local = 0;
 
        sk = session->sock;
 
-       if (flags & SDP_NON_BLOCKING) {
-               long arg = fcntl(sk, F_GETFL, 0);
-               fcntl(sk, F_SETFL, arg | O_NONBLOCK);
-       }
-
        memset(&sa, 0, sizeof(sa));
 
        sa.l2_family = AF_BLUETOOTH;
@@ -4673,7 +4780,7 @@ int sdp_set_supp_feat(sdp_record_t *rec, const sdp_list_t *sf)
                        goto fail;
                }
                for (r = p->data, j = 0; r; r = r->next, j++) {
-                       sdp_data_t *data = (sdp_data_t*)r->data;
+                       sdp_data_t *data = (sdp_data_t *) r->data;
                        dtds[j] = &data->dtd;
                        switch (data->dtd) {
                        case SDP_URL_STR8:
@@ -4734,7 +4841,7 @@ int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
 
        sdpdata = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
 
-       if (!sdpdata || sdpdata->dtd < SDP_SEQ8 || sdpdata->dtd > SDP_SEQ32)
+       if (!sdpdata || !SDP_IS_SEQ(sdpdata->dtd))
                return sdp_get_uuidseq_attr(rec,
                                        SDP_ATTR_SUPPORTED_FEATURES_LIST, seqp);
 
@@ -4742,7 +4849,7 @@ int sdp_get_supp_feat(const sdp_record_t *rec, sdp_list_t **seqp)
                sdp_data_t *dd;
                sdp_list_t *subseq;
 
-               if (d->dtd < SDP_SEQ8 || d->dtd > SDP_SEQ32)
+               if (!SDP_IS_SEQ(d->dtd))
                        goto fail;
 
                subseq = NULL;
index 2fe74d5..f2f2484 100644 (file)
--- a/lib/sdp.h
+++ b/lib/sdp.h
@@ -95,7 +95,7 @@ extern "C" {
 #define AV_REMOTE_TARGET_SVCLASS_ID    0x110c
 #define ADVANCED_AUDIO_SVCLASS_ID      0x110d
 #define AV_REMOTE_SVCLASS_ID           0x110e
-#define VIDEO_CONF_SVCLASS_ID          0x110f
+#define AV_REMOTE_CONTROLLER_SVCLASS_ID        0x110f
 #define INTERCOM_SVCLASS_ID            0x1110
 #define FAX_SVCLASS_ID                 0x1111
 #define HEADSET_AGW_SVCLASS_ID         0x1112
@@ -129,6 +129,11 @@ extern "C" {
 #define PBAP_PCE_SVCLASS_ID            0x112e
 #define PBAP_PSE_SVCLASS_ID            0x112f
 #define PBAP_SVCLASS_ID                        0x1130
+#define MAP_MSE_SVCLASS_ID             0x1132
+#define MAP_MCE_SVCLASS_ID             0x1133
+#define MAP_SVCLASS_ID                 0x1134
+#define GNSS_SVCLASS_ID                        0x1135
+#define GNSS_SERVER_SVCLASS_ID         0x1136
 #define PNP_INFO_SVCLASS_ID            0x1200
 #define GENERIC_NETWORKING_SVCLASS_ID  0x1201
 #define GENERIC_FILETRANS_SVCLASS_ID   0x1202
@@ -260,12 +265,14 @@ extern "C" {
 #define SDP_ATTR_IP_SUBNET                     0x0200
 #define SDP_ATTR_VERSION_NUM_LIST              0x0200
 #define SDP_ATTR_SUPPORTED_FEATURES_LIST       0x0200
+#define SDP_ATTR_GOEP_L2CAP_PSM                        0x0200
 #define SDP_ATTR_SVCDB_STATE                   0x0201
 
 #define SDP_ATTR_SERVICE_VERSION               0x0300
 #define SDP_ATTR_EXTERNAL_NETWORK              0x0301
 #define SDP_ATTR_SUPPORTED_DATA_STORES_LIST    0x0301
 #define SDP_ATTR_DATA_EXCHANGE_SPEC            0x0301
+#define SDP_ATTR_NETWORK                       0x0301
 #define SDP_ATTR_FAX_CLASS1_SUPPORT            0x0302
 #define SDP_ATTR_REMOTE_AUDIO_VOLUME_CONTROL   0x0302
 #define SDP_ATTR_MCAP_SUPPORTED_PROCEDURES     0x0302
@@ -287,6 +294,8 @@ extern "C" {
 #define SDP_ATTR_SUPPORTED_FUNCTIONS           0x0312
 #define SDP_ATTR_TOTAL_IMAGING_DATA_CAPACITY   0x0313
 #define SDP_ATTR_SUPPORTED_REPOSITORIES                0x0314
+#define SDP_ATTR_MAS_INSTANCE_ID               0x0315
+#define SDP_ATTR_SUPPORTED_MESSAGE_TYPES       0x0316
 
 #define SDP_ATTR_SPECIFICATION_ID              0x0200
 #define SDP_ATTR_VENDOR_ID                     0x0201
@@ -431,8 +440,12 @@ typedef struct {
        } value;
 } uuid_t;
 
-#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || (x) ==SDP_UUID128)
+#define SDP_IS_UUID(x) ((x) == SDP_UUID16 || (x) == SDP_UUID32 || \
+                                                       (x) == SDP_UUID128)
+#define SDP_IS_ALT(x)  ((x) == SDP_ALT8 || (x) == SDP_ALT16 || (x) == SDP_ALT32)
 #define SDP_IS_SEQ(x)  ((x) == SDP_SEQ8 || (x) == SDP_SEQ16 || (x) == SDP_SEQ32)
+#define SDP_IS_TEXT_STR(x) ((x) == SDP_TEXT_STR8 || (x) == SDP_TEXT_STR16 || \
+                                                       (x) == SDP_TEXT_STR32)
 
 typedef struct _sdp_list sdp_list_t;
 struct _sdp_list {
index a3e2a1a..4363aee 100644 (file)
@@ -271,3 +271,8 @@ int bt_string_to_uuid(bt_uuid_t *uuid, const char *string)
 
        return -EINVAL;
 }
+
+int bt_uuid_strcmp(const void *a, const void *b)
+{
+       return strcasecmp(a, b);
+}
index 2c2b351..95e5a9a 100644 (file)
@@ -63,26 +63,48 @@ extern "C" {
 
 #define SAP_UUID               "0000112D-0000-1000-8000-00805f9b34fb"
 
+#define HEART_RATE_UUID                        "0000180d-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_MEASUREMENT_UUID    "00002a37-0000-1000-8000-00805f9b34fb"
+#define BODY_SENSOR_LOCATION_UUID      "00002a38-0000-1000-8000-00805f9b34fb"
+#define HEART_RATE_CONTROL_POINT_UUID  "00002a39-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 CYCLING_SC_UUID                "00001816-0000-1000-8000-00805f9b34fb"
+#define CSC_MEASUREMENT_UUID   "00002a5b-0000-1000-8000-00805f9b34fb"
+#define CSC_FEATURE_UUID       "00002a5c-0000-1000-8000-00805f9b34fb"
+#define SENSOR_LOCATION_UUID   "00002a5d-0000-1000-8000-00805f9b34fb"
+#define SC_CONTROL_POINT_UUID  "00002a55-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 GAP_UUID               "00001800-0000-1000-8000-00805f9b34fb"
 #define PNP_UUID               "00001200-0000-1000-8000-00805f9b34fb"
 
+#define SPP_UUID               "00001101-0000-1000-8000-00805f9b34fb"
+
+#define OBEX_SYNC_UUID         "00001104-0000-1000-8000-00805f9b34fb"
+#define OBEX_OPP_UUID          "00001105-0000-1000-8000-00805f9b34fb"
+#define OBEX_FTP_UUID          "00001106-0000-1000-8000-00805f9b34fb"
+#define OBEX_PCE_UUID          "0000112e-0000-1000-8000-00805f9b34fb"
+#define OBEX_PSE_UUID          "0000112f-0000-1000-8000-00805f9b34fb"
+#define OBEX_PBAP_UUID         "00001130-0000-1000-8000-00805f9b34fb"
+#define OBEX_MAS_UUID          "00001132-0000-1000-8000-00805f9b34fb"
+#define OBEX_MNS_UUID          "00001133-0000-1000-8000-00805f9b34fb"
+#define OBEX_MAP_UUID          "00001134-0000-1000-8000-00805f9b34fb"
+
 typedef struct {
        enum {
                BT_UUID_UNSPEC = 0,
@@ -97,6 +119,8 @@ typedef struct {
        } value;
 } bt_uuid_t;
 
+int bt_uuid_strcmp(const void *a, const void *b);
+
 int bt_uuid16_create(bt_uuid_t *btuuid, uint16_t value);
 int bt_uuid32_create(bt_uuid_t *btuuid, uint32_t value);
 int bt_uuid128_create(bt_uuid_t *btuuid, uint128_t value);
index c7d06c3..33f642a 100644 (file)
--- a/ltmain.sh
+++ b/ltmain.sh
@@ -70,7 +70,7 @@
 #         compiler:            $LTCC
 #         compiler flags:              $LTCFLAGS
 #         linker:              $LD (gnu? $with_gnu_ld)
-#         $progname:   (GNU libtool) 2.4.2 Debian-2.4.2-1
+#         $progname:   (GNU libtool) 2.4.2 Debian-2.4.2-1.1
 #         automake:    $automake_version
 #         autoconf:    $autoconf_version
 #
@@ -80,7 +80,7 @@
 
 PROGRAM=libtool
 PACKAGE=libtool
-VERSION="2.4.2 Debian-2.4.2-1"
+VERSION="2.4.2 Debian-2.4.2-1.1"
 TIMESTAMP=""
 package_revision=1.3337
 
index 3a6735b..2245ab3 100644 (file)
  *  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 library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
  *
- *  This program is distributed in the hope that it will be useful,
+ *  This library is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
  *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  *
  */
 
 #include <stdint.h>
 
+struct bt_ll_hdr {
+       uint8_t  preamble;
+       uint32_t access_addr;
+} __attribute__ ((packed));
+
+#define BT_LL_CONN_UPDATE_REQ  0x00
+struct bt_ll_conn_update_req {
+       uint8_t  win_size;
+       uint16_t win_offset;
+       uint16_t interval;
+       uint16_t latency;
+       uint16_t timeout;
+       uint16_t instant;
+} __attribute__ ((packed));
+
+#define BT_LL_CHANNEL_MAP_REQ  0x01
+struct bt_ll_channel_map_req {
+       uint8_t  map[5];
+       uint16_t instant;
+} __attribute__ ((packed));
+
+#define BT_LL_TERMINATE_IND    0x02
+struct bt_ll_terminate_ind {
+       uint8_t  error;
+} __attribute__ ((packed));
+
+#define BT_LL_ENC_REQ          0x03
+struct bt_ll_enc_req {
+       uint64_t rand;
+       uint16_t ediv;
+       uint64_t skd;
+       uint32_t iv;
+} __attribute__ ((packed));
+
+#define BT_LL_ENC_RSP          0x04
+struct bt_ll_enc_rsp {
+       uint64_t skd;
+       uint32_t iv;
+} __attribute__ ((packed));
+
+#define BT_LL_START_ENC_REQ    0x05
+
+#define BT_LL_START_ENC_RSP    0x06
+
+#define BT_LL_UNKNOWN_RSP      0x07
+struct bt_ll_unknown_rsp {
+       uint8_t  type;
+} __attribute__ ((packed));
+
+#define BT_LL_FEATURE_REQ      0x08
+struct bt_ll_feature_req {
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_LL_FEATURE_RSP      0x09
+struct bt_ll_feature_rsp {
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_LL_PAUSE_ENC_REQ    0x0a
+
+#define BT_LL_PAUSE_ENC_RSP    0x0b
+
+#define BT_LL_VERSION_IND      0x0c
+struct bt_ll_version_ind {
+       uint8_t  version;
+       uint16_t company;
+       uint16_t subversion;
+} __attribute__ ((packed));
+
+#define BT_LL_REJECT_IND       0x0d
+struct bt_ll_reject_ind {
+       uint8_t  error;
+} __attribute__ ((packed));
+
 #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_acl_hdr {
+       uint16_t handle;
+       uint16_t dlen;
+} __attribute__ ((packed));
+
 struct bt_hci_cmd_hdr {
        uint16_t opcode;
-       uint8_t  plen;
+       uint8_t  plen;
 } __attribute__ ((packed));
 
 struct bt_hci_evt_hdr {
@@ -45,11 +125,22 @@ struct bt_hci_evt_hdr {
 struct bt_hci_cmd_inquiry {
        uint8_t  lap[3];
        uint8_t  length;
-       uint8_t  num_rsp;
+       uint8_t  num_resp;
 } __attribute__ ((packed));
 
 #define BT_HCI_CMD_INQUIRY_CANCEL              0x0402
 
+#define BT_HCI_CMD_PERIODIC_INQUIRY            0x0403
+struct bt_hci_cmd_periodic_inquiry {
+       uint16_t max_period;
+       uint16_t min_period;
+       uint8_t  lap[3];
+       uint8_t  length;
+       uint8_t  num_resp;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_EXIT_PERIODIC_INQUIRY       0x0404
+
 #define BT_HCI_CMD_CREATE_CONN                 0x0405
 struct bt_hci_cmd_create_conn {
        uint8_t  bdaddr[6];
@@ -89,12 +180,56 @@ struct bt_hci_cmd_reject_conn_request {
        uint8_t  reason;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_LINK_KEY_REQUEST_REPLY      0x040b
+struct bt_hci_cmd_link_key_request_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  link_key[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LINK_KEY_REQUEST_NEG_REPLY  0x040c
+struct bt_hci_cmd_link_key_request_neg_reply {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_PIN_CODE_REQUEST_REPLY      0x040d
+struct bt_hci_cmd_pin_code_request_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  pin_len;
+       uint8_t  pin_code[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_PIN_CODE_REQUEST_NEG_REPLY  0x040e
+struct bt_hci_cmd_pin_code_request_neg_reply {
+       uint8_t  bdaddr[6];
+} __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_AUTH_REQUESTED              0x0411
+struct bt_hci_cmd_auth_requested {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SET_CONN_ENCRYPT            0x0413
+struct bt_hci_cmd_set_conn_encrypt {
+       uint16_t handle;
+       uint8_t  encr_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CHANGE_CONN_LINK_KEY                0x0415
+struct bt_hci_cmd_change_conn_link_key {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_MASTER_LINK_KEY             0x0417
+struct bt_hci_cmd_master_link_key {
+       uint8_t  key_flag;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_REMOTE_NAME_REQUEST         0x0419
 struct bt_hci_cmd_remote_name_request {
        uint8_t  bdaddr[6];
@@ -107,6 +242,10 @@ struct bt_hci_cmd_remote_name_request {
 struct bt_hci_cmd_remote_name_request_cancel {
        uint8_t  bdaddr[6];
 } __attribute__ ((packed));
+struct bt_hci_rsp_remote_name_request_cancel {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
 
 #define BT_HCI_CMD_READ_REMOTE_FEATURES                0x041b
 struct bt_hci_cmd_read_remote_features {
@@ -124,6 +263,234 @@ struct bt_hci_cmd_read_remote_version {
        uint16_t handle;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_CLOCK_OFFSET           0x041f
+struct bt_hci_cmd_read_clock_offset {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LMP_HANDLE             0x0420
+struct bt_hci_cmd_read_lmp_handle {
+       uint16_t  handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_lmp_handle {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  lmp_handle;
+       uint32_t reserved;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SETUP_SYNC_CONN             0x0428
+struct bt_hci_cmd_setup_sync_conn {
+       uint16_t handle;
+       uint32_t tx_bandwidth;
+       uint32_t rx_bandwidth;
+       uint16_t max_latency;
+       uint16_t voice_setting;
+       uint8_t  retrans_effort;
+       uint16_t pkt_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ACCEPT_SYNC_CONN            0x0429
+struct bt_hci_cmd_accept_sync_conn {
+       uint8_t  bdaddr[6];
+       uint32_t tx_bandwidth;
+       uint32_t rx_bandwidth;
+       uint16_t max_latency;
+       uint16_t voice_setting;
+       uint8_t  retrans_effort;
+       uint16_t pkt_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REJECT_SYNC_CONN            0x042a
+struct bt_hci_cmd_reject_sync_conn {
+       uint8_t  bdaddr[6];
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_IO_CAPABILITY_REQUEST_REPLY         0x042b
+struct bt_hci_cmd_io_capability_request_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  capability;
+       uint8_t  oob_data;
+       uint8_t  authentication;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_USER_CONFIRM_REQUEST_REPLY          0x042c
+struct bt_hci_cmd_user_confirm_request_reply {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_USER_CONFIRM_REQUEST_NEG_REPLY      0x042d
+struct bt_hci_cmd_user_confirm_request_neg_reply {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_USER_PASSKEY_REQUEST_REPLY          0x042e
+struct bt_hci_cmd_user_passkey_request_reply {
+       uint8_t  bdaddr[6];
+       uint32_t passkey;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_USER_PASSKEY_REQUEST_NEG_REPLY      0x042f
+struct bt_hci_cmd_user_passkey_request_neg_reply {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REMOTE_OOB_DATA_REQUEST_REPLY       0x0430
+struct bt_hci_cmd_remote_oob_data_request_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  hash[16];
+       uint8_t  randomizer[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REMOTE_OOB_DATA_REQUEST_NEG_REPLY   0x0433
+struct bt_hci_cmd_remote_oob_data_request_neg_reply {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_IO_CAPABILITY_REQUEST_NEG_REPLY     0x0434
+struct bt_hci_cmd_io_capability_request_neg_reply {
+       uint8_t  bdaddr[6];
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CREATE_PHY_LINK             0x0435
+struct bt_hci_cmd_create_phy_link {
+       uint8_t  phy_handle;
+       uint8_t  key_len;
+       uint8_t  key_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ACCEPT_PHY_LINK             0x0436
+struct bt_hci_cmd_accept_phy_link {
+       uint8_t  phy_handle;
+       uint8_t  key_len;
+       uint8_t  key_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_DISCONN_PHY_LINK            0x0437
+struct bt_hci_cmd_disconn_phy_link {
+       uint8_t  phy_handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CREATE_LOGIC_LINK           0x0438
+struct bt_hci_cmd_create_logic_link {
+       uint8_t  phy_handle;
+       uint8_t  tx_flow_spec[16];
+       uint8_t  rx_flow_spec[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ACCEPT_LOGIC_LINK           0x0439
+struct bt_hci_cmd_accept_logic_link {
+       uint8_t  phy_handle;
+       uint8_t  tx_flow_spec[16];
+       uint8_t  rx_flow_spec[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_DISCONN_LOGIC_LINK          0x043a
+struct bt_hci_cmd_disconn_logic_link {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LOGIC_LINK_CANCEL           0x043b
+struct bt_hci_cmd_logic_link_cancel {
+       uint8_t  phy_handle;
+       uint8_t  flow_spec;
+} __attribute__ ((packed));
+struct bt_hci_rsp_logic_link_cancel {
+       uint8_t  status;
+       uint8_t  phy_handle;
+       uint8_t  flow_spec;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_FLOW_SPEC_MODIFY            0x043c
+struct bt_hci_cmd_flow_spec_modify {
+       uint16_t handle;
+       uint8_t  tx_flow_spec[16];
+       uint8_t  rx_flow_spec[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_HOLD_MODE                   0x0801
+struct bt_hci_cmd_hold_mode {
+       uint16_t handle;
+       uint16_t max_interval;
+       uint16_t min_interval;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SNIFF_MODE                  0x0803
+struct bt_hci_cmd_sniff_mode {
+       uint16_t handle;
+       uint16_t max_interval;
+       uint16_t min_interval;
+       uint16_t attempt;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_EXIT_SNIFF_MODE             0x0804
+struct bt_hci_cmd_exit_sniff_mode {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_PARK_STATE                  0x0805
+struct bt_hci_cmd_park_state {
+       uint16_t handle;
+       uint16_t max_interval;
+       uint16_t min_interval;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_EXIT_PARK_STATE             0x0806
+struct bt_hci_cmd_exit_park_state {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_QOS_SETUP                   0x0807
+struct bt_hci_cmd_qos_setup {
+       uint16_t handle;
+       uint8_t  flags;
+       uint8_t  service_type;
+       uint32_t token_rate;
+       uint32_t peak_bandwidth;
+       uint32_t latency;
+       uint32_t delay_variation;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ROLE_DISCOVERY              0x0809
+struct bt_hci_cmd_role_discovery {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_role_discovery {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  role;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SWITCH_ROLE                 0x080b
+struct bt_hci_cmd_switch_role {
+       uint8_t  bdaddr[6];
+       uint8_t  role;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LINK_POLICY            0x080c
+struct bt_hci_cmd_read_link_policy {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_link_policy {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t policy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_LINK_POLICY           0x080d
+struct bt_hci_cmd_write_link_policy {
+       uint16_t handle;
+       uint16_t policy;
+} __attribute__ ((packed));
+struct bt_hci_rsp_write_link_policy {
+       uint8_t  status;
+       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;
@@ -135,6 +502,30 @@ struct bt_hci_cmd_write_default_link_policy {
        uint16_t policy;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_FLOW_SPEC                   0x0810
+struct bt_hci_cmd_flow_spec {
+       uint16_t handle;
+       uint8_t  flags;
+       uint8_t  direction;
+       uint8_t  service_type;
+       uint32_t token_rate;
+       uint32_t token_bucket_size;
+       uint32_t peak_bandwidth;
+       uint32_t access_latency;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SNIFF_SUBRATING             0x0811
+struct bt_hci_cmd_sniff_subrating {
+       uint16_t handle;
+       uint16_t max_latency;
+       uint16_t min_remote_timeout;
+       uint16_t min_local_timeout;
+} __attribute__ ((packed));
+struct bt_hci_rsp_sniff_subrating {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_SET_EVENT_MASK              0x0c01
 struct bt_hci_cmd_set_event_mask {
        uint8_t  mask[8];
@@ -149,6 +540,28 @@ struct bt_hci_cmd_set_event_filter {
        uint8_t  cond[0];
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_FLUSH                       0x0c08
+struct bt_hci_cmd_flush {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_flush {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_PIN_TYPE               0x0c09
+struct bt_hci_rsp_read_pin_type {
+       uint8_t  status;
+       uint8_t  pin_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_PIN_TYPE              0x0c0a
+struct bt_hci_cmd_write_pin_type {
+       uint8_t  pin_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_CREATE_NEW_UNIT_KEY         0x0c0b
+
 #define BT_HCI_CMD_READ_STORED_LINK_KEY                0x0c0d
 struct bt_hci_cmd_read_stored_link_key {
        uint8_t  bdaddr[6];
@@ -223,6 +636,32 @@ struct bt_hci_cmd_write_scan_enable {
        uint8_t  enable;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_PAGE_SCAN_ACTIVITY     0x0c1b
+struct bt_hci_rsp_read_page_scan_activity {
+       uint8_t  status;
+       uint16_t interval;
+       uint16_t window;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_PAGE_SCAN_ACTIVITY    0x0c1c
+struct bt_hci_cmd_write_page_scan_activity {
+       uint16_t interval;
+       uint16_t window;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_INQUIRY_SCAN_ACTIVITY  0x0c1d
+struct bt_hci_rsp_read_inquiry_scan_activity {
+       uint8_t  status;
+       uint16_t interval;
+       uint16_t window;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_INQUIRY_SCAN_ACTIVITY 0x0c1e
+struct bt_hci_cmd_write_inquiry_scan_activity {
+       uint16_t interval;
+       uint16_t window;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_AUTH_ENABLE            0x0c1f
 struct bt_hci_rsp_read_auth_enable {
        uint8_t  status;
@@ -234,6 +673,17 @@ struct bt_hci_cmd_write_auth_enable {
        uint8_t  enable;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_ENCRYPT_MODE           0x0c21
+struct bt_hci_rsp_read_encrypt_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_ENCRYPT_MODE          0x0c22
+struct bt_hci_cmd_write_encrypt_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_CLASS_OF_DEV           0x0c23
 struct bt_hci_rsp_read_class_of_dev {
        uint8_t  status;
@@ -256,56 +706,208 @@ 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;
+#define BT_HCI_CMD_HOST_BUFFER_SIZE            0x0c33
+struct bt_hci_cmd_host_buffer_size {
+       uint16_t acl_mtu;
+       uint8_t  sco_mtu;
+       uint16_t acl_max_pkt;
+       uint16_t sco_max_pkt;
 } __attribute__ ((packed));
 
-#define BT_HCI_CMD_WRITE_INQUIRY_MODE          0x0c45
-struct bt_hci_cmd_write_inquiry_mode {
-       uint8_t  mode;
+#define BT_HCI_CMD_READ_LINK_SUPV_TIMEOUT      0x0c36
+struct bt_hci_cmd_read_link_supv_timeout {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_link_supv_timeout {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t timeout;
 } __attribute__ ((packed));
 
-#define BT_HCI_CMD_READ_AFH_ASSESS_MODE                0x0c48
-struct bt_hci_rsp_read_afh_assess_mode {
+#define BT_HCI_CMD_WRITE_LINK_SUPV_TIMEOUT     0x0c37
+struct bt_hci_cmd_write_link_supv_timeout {
+       uint16_t handle;
+       uint16_t timeout;
+} __attribute__ ((packed));
+struct bt_hci_rsp_write_link_supv_timeout {
        uint8_t  status;
-       uint8_t  mode;
+       uint16_t handle;
 } __attribute__ ((packed));
 
-#define BT_HCI_CMD_WRITE_AFH_ASSESS_MODE       0x0c49
-struct bt_hci_cmd_write_afh_assess_mode {
-       uint8_t  mode;
+#define BT_HCI_CMD_READ_NUM_SUPPORTED_IAC      0x0c38
+struct bt_hci_rsp_read_num_supported_iac {
+       uint8_t  status;
+       uint8_t  num_iac;
 } __attribute__ ((packed));
 
-#define BT_HCI_CMD_READ_EXT_INQUIRY_RSP                0x0c51
-struct bt_hci_rsp_read_ext_inquiry_rsp {
+#define BT_HCI_CMD_READ_CURRENT_IAC_LAP                0x0c39
+struct bt_hci_rsp_read_current_iac_lap {
        uint8_t  status;
-       uint8_t  fec;
-       uint8_t  data[240];
+       uint8_t  num_iac;
+       uint8_t  iac_lap[0];
 } __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];
+#define BT_HCI_CMD_WRITE_CURRENT_IAC_LAP       0x0c3a
+struct bt_hci_cmd_write_current_iac_lap {
+       uint8_t  num_iac;
+       uint8_t  iac_lap[0];
 } __attribute__ ((packed));
 
-#define BT_HCI_CMD_READ_SIMPLE_PAIRING_MODE    0x0c55
-struct bt_hci_rsp_read_simple_pairing_mode {
+#define BT_HCI_CMD_READ_PAGE_SCAN_PERIOD_MODE  0x0c3b
+struct bt_hci_rsp_read_page_scan_period_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 {
+#define BT_HCI_CMD_WRITE_PAGE_SCAN_PERIOD_MODE 0x0c3c
+struct bt_hci_cmd_write_page_scan_period_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 {
+#define BT_HCI_CMD_READ_PAGE_SCAN_MODE         0x0c3d
+struct bt_hci_rsp_read_page_scan_mode {
        uint8_t  status;
-       int8_t   level;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_PAGE_SCAN_MODE                0x0c3e
+struct bt_hci_cmd_write_page_scan_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SET_AFH_HOST_CLASSIFICATION 0x0c3f
+struct bt_hci_cmd_set_afh_host_classification {
+       uint8_t  map[10];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_INQUIRY_SCAN_TYPE      0x0c42
+struct bt_hci_rsp_read_inquiry_scan_type {
+       uint8_t status;
+       uint8_t type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_INQUIRY_SCAN_TYPE     0x0c43
+struct bt_hci_cmd_write_inquiry_scan_type {
+       uint8_t type;
+} __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_PAGE_SCAN_TYPE         0x0c46
+struct bt_hci_rsp_read_page_scan_type {
+       uint8_t status;
+       uint8_t type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_PAGE_SCAN_TYPE                0x0c47
+struct bt_hci_cmd_write_page_scan_type {
+       uint8_t type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_AFH_ASSESSMENT_MODE    0x0c48
+struct bt_hci_rsp_read_afh_assessment_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_AFH_ASSESSMENT_MODE   0x0c49
+struct bt_hci_cmd_write_afh_assessment_mode {
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_EXT_INQUIRY_RESPONSE   0x0c51
+struct bt_hci_rsp_read_ext_inquiry_response {
+       uint8_t  status;
+       uint8_t  fec;
+       uint8_t  data[240];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE  0x0c52
+struct bt_hci_cmd_write_ext_inquiry_response {
+       uint8_t  fec;
+       uint8_t  data[240];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_REFRESH_ENCRYPT_KEY         0x0c53
+struct bt_hci_cmd_refresh_encrypt_key {
+       uint16_t handle;
+} __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_LOCAL_OOB_DATA         0x0c57
+struct bt_hci_rsp_read_local_oob_data {
+       uint8_t  status;
+       uint8_t  hash[16];
+       uint8_t  randomizer[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_INQUIRY_RESP_TX_POWER  0x0c58
+struct bt_hci_rsp_read_inquiry_resp_tx_power {
+       uint8_t  status;
+       int8_t   level;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_INQUIRY_TX_POWER      0x0c59
+struct bt_hci_cmd_write_inquiry_tx_power {
+       int8_t   level;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ENHANCED_FLUSH              0x0c5f
+struct bt_hci_cmd_enhanced_flush {
+       uint16_t handle;
+       uint8_t  type;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_SET_EVENT_MASK_PAGE2                0x0c63
+struct bt_hci_cmd_set_event_mask_page2 {
+       uint8_t  mask[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCATION_DATA          0x0c64
+struct bt_hci_rsp_read_location_data {
+       uint8_t  status;
+       uint8_t  domain_aware;
+       uint8_t  domain[2];
+       uint8_t  domain_options;
+       uint8_t  options;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_LOCATION_DATA         0x0c65
+struct bt_hci_cmd_write_location_data {
+       uint8_t  domain_aware;
+       uint8_t  domain[2];
+       uint8_t  domain_options;
+       uint8_t  options;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_FLOW_CONTROL_MODE      0x0c66
+struct bt_hci_rsp_read_flow_control_mode {
+       uint8_t  status;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_FLOW_CONTROL_MODE     0x0c67
+struct bt_hci_cmd_write_flow_control_mode {
+       uint8_t  mode;
 } __attribute__ ((packed));
 
 #define BT_HCI_CMD_READ_LE_HOST_SUPPORTED      0x0c6c
@@ -321,6 +923,14 @@ struct bt_hci_cmd_write_le_host_supported {
        uint8_t  simultaneous;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_SYNC_TRAIN_PARAMS      0x0c77
+struct bt_hci_rsp_read_sync_train_params {
+       uint8_t  status;
+       uint16_t interval;
+       uint32_t timeout;
+       uint8_t  service_data;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_READ_LOCAL_VERSION          0x1001
 struct bt_hci_rsp_read_local_version {
        uint8_t  status;
@@ -383,6 +993,120 @@ struct bt_hci_rsp_read_data_block_size {
        uint16_t num_blocks;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_READ_FAILED_CONTACT_COUNTER 0x1401
+struct bt_hci_cmd_read_failed_contact_counter {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_failed_contact_counter {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t counter;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_RESET_FAILED_CONTACT_COUNTER        0x1402
+struct bt_hci_cmd_reset_failed_contact_counter {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_reset_failed_contact_counter {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LINK_QUALITY           0x1403
+struct bt_hci_cmd_read_link_quality {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_link_quality {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  link_quality;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_RSSI                   0x1405
+struct bt_hci_cmd_read_rssi {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_rssi {
+       uint8_t  status;
+       uint16_t handle;
+       int8_t   rssi;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_AFH_CHANNEL_MAP                0x1406
+struct bt_hci_cmd_read_afh_channel_map {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_afh_channel_map {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  mode;
+       uint8_t  map[10];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_CLOCK                  0x1407
+struct bt_hci_cmd_read_clock {
+       uint16_t handle;
+       uint8_t  type;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_clock {
+       uint8_t  status;
+       uint16_t handle;
+       uint32_t clock;
+       uint16_t accuracy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_ENCRYPT_KEY_SIZE       0x1408
+struct bt_hci_cmd_read_encrypt_key_size {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_encrypt_key_size {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  key_size;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_AMP_INFO         0x1409
+struct bt_hci_rsp_read_local_amp_info {
+       uint8_t  status;
+       uint8_t  amp_status;
+       uint32_t total_bw;
+       uint32_t max_bw;
+       uint32_t min_latency;
+       uint32_t max_pdu;
+       uint8_t  amp_type;
+       uint16_t pal_cap;
+       uint16_t max_assoc_len;
+       uint32_t max_flush_to;
+       uint32_t be_flush_to;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_READ_LOCAL_AMP_ASSOC                0x140a
+struct bt_hci_cmd_read_local_amp_assoc {
+       uint8_t  phy_handle;
+       uint16_t len_so_far;
+       uint16_t max_assoc_len;
+} __attribute__ ((packed));
+struct bt_hci_rsp_read_local_amp_assoc {
+       uint8_t  status;
+       uint8_t  phy_handle;
+       uint16_t remain_assoc_len;
+       uint8_t  assoc_fragment[248];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_WRITE_REMOTE_AMP_ASSOC      0x140b
+struct bt_hci_cmd_write_remote_amp_assoc {
+       uint8_t  phy_handle;
+       uint16_t len_so_far;
+       uint16_t remain_assoc_len;
+       uint8_t  assoc_fragment[248];
+} __attribute__ ((packed));
+struct bt_hci_rsp_write_remote_amp_assoc {
+       uint8_t  status;
+       uint8_t  phy_handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_ENABLE_DUT_MODE             0x1803
+
 #define BT_HCI_CMD_LE_SET_EVENT_MASK           0x2001
 struct bt_hci_cmd_le_set_event_mask {
        uint8_t  mask[8];
@@ -401,6 +1125,46 @@ struct bt_hci_rsp_le_read_local_features {
        uint8_t  features[8];
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_LE_SET_RANDOM_ADDRESS       0x2005
+struct bt_hci_cmd_le_set_random_address {
+       uint8_t  addr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_ADV_PARAMETERS       0x2006
+struct bt_hci_cmd_le_set_adv_parameters {
+       uint16_t min_interval;
+       uint16_t max_interval;
+       uint8_t  type;
+       uint8_t  own_addr_type;
+       uint8_t  direct_addr_type;
+       uint8_t  direct_addr[6];
+       uint8_t  channel_map;
+       uint8_t  filter_policy;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_ADV_TX_POWER                0x2007
+struct bt_hci_rsp_le_read_adv_tx_power {
+       uint8_t  status;
+       int8_t   level;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_ADV_DATA             0x2008
+struct bt_hci_cmd_le_set_adv_data {
+       uint8_t  len;
+       uint8_t  data[31];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_SCAN_RSP_DATA                0x2009
+struct bt_hci_cmd_le_set_scan_rsp_data {
+       uint8_t  len;
+       uint8_t  data[31];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_ADV_ENABLE           0x200a
+struct bt_hci_cmd_le_set_adv_enable {
+       uint8_t  enable;
+} __attribute__ ((packed));
+
 #define BT_HCI_CMD_LE_SET_SCAN_PARAMETERS      0x200b
 struct bt_hci_cmd_le_set_scan_parameters {
        uint8_t  type;
@@ -416,12 +1180,142 @@ struct bt_hci_cmd_le_set_scan_enable {
        uint8_t  filter_dup;
 } __attribute__ ((packed));
 
+#define BT_HCI_CMD_LE_CREATE_CONN              0x200d
+struct bt_hci_cmd_le_create_conn {
+       uint16_t scan_interval;
+       uint16_t scan_window;
+       uint8_t  filter_policy;
+       uint8_t  peer_addr_type;
+       uint8_t  peer_addr[6];
+       uint8_t  own_addr_type;
+       uint16_t min_interval;
+       uint16_t max_interval;
+       uint16_t latency;
+       uint16_t supv_timeout;
+       uint16_t min_length;
+       uint16_t max_length;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_CREATE_CONN_CANCEL       0x200e
+
+#define BT_HCI_CMD_LE_READ_WHITE_LIST_SIZE     0x200f
+struct bt_hci_rsp_le_read_white_list_size {
+       uint8_t  status;
+       uint8_t  size;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_CLEAR_WHITE_LIST         0x2010
+
+#define BT_HCI_CMD_LE_ADD_TO_WHITE_LIST                0x2011
+struct bt_hci_cmd_le_add_to_white_list {
+       uint8_t  addr_type;
+       uint8_t  addr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_REMOVE_FROM_WHITE_LIST   0x2012
+struct bt_hci_cmd_le_remove_from_white_list {
+       uint8_t  addr_type;
+       uint8_t  addr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_CONN_UPDATE              0x2013
+struct bt_hci_cmd_le_conn_update {
+       uint16_t handle;
+       uint16_t min_interval;
+       uint16_t max_interval;
+       uint16_t latency;
+       uint16_t supv_timeout;
+       uint16_t min_length;
+       uint16_t max_length;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_SET_HOST_CLASSIFICATION  0x2014
+struct bt_hci_cmd_le_set_host_classification {
+       uint8_t  map[5];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_CHANNEL_MAP         0x2015
+struct bt_hci_cmd_le_read_channel_map {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_le_read_channel_map {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  map[5];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_READ_REMOTE_FEATURES     0x2016
+struct bt_hci_cmd_le_read_remote_features {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_ENCRYPT                  0x2017
+struct bt_hci_cmd_le_encrypt {
+       uint8_t  key[16];
+       uint8_t  plaintext[16];
+} __attribute__ ((packed));
+struct bt_hci_rsp_le_encrypt {
+       uint8_t  status;
+       uint8_t  data[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_RAND                     0x2018
+struct bt_hci_rsp_le_rand {
+       uint8_t  status;
+       uint8_t  number[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_START_ENCRYPT            0x2019
+struct bt_hci_cmd_le_start_encrypt {
+       uint16_t handle;
+       uint8_t  number[8];
+       uint16_t diversifier;
+       uint8_t  ltk[16];
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_LTK_REQ_REPLY            0x201a
+struct bt_hci_cmd_le_ltk_req_reply {
+       uint16_t handle;
+       uint8_t  ltk[16];
+} __attribute__ ((packed));
+struct bt_hci_rsp_le_ltk_req_reply {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_LTK_REQ_NEG_REPLY                0x201b
+struct bt_hci_cmd_le_ltk_req_neg_reply {
+       uint16_t handle;
+} __attribute__ ((packed));
+struct bt_hci_rsp_le_ltk_req_neg_reply {
+       uint8_t  status;
+       uint16_t handle;
+} __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_CMD_LE_RECEIVER_TEST            0x201d
+struct bt_hci_cmd_le_receiver_test {
+       uint8_t  frequency;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_TRANSMITTER_TEST         0x201e
+struct bt_hci_cmd_le_transmitter_test {
+       uint8_t  frequency;
+       uint8_t  data_len;
+       uint8_t  payload;
+} __attribute__ ((packed));
+
+#define BT_HCI_CMD_LE_TEST_END                 0x201f
+struct bt_hci_rsp_le_test_end {
+       uint8_t  status;
+       uint16_t num_packets;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_INQUIRY_COMPLETE            0x01
 struct bt_hci_evt_inquiry_complete {
        uint8_t  status;
@@ -435,7 +1329,7 @@ struct bt_hci_evt_inquiry_result {
        uint8_t  pscan_period_mode;
        uint8_t  pscan_mode;
        uint8_t  dev_class[3];
-       uint8_t  clock_offset;
+       uint16_t clock_offset;
 } __attribute__ ((packed));
 
 #define BT_HCI_EVT_CONN_COMPLETE               0x03
@@ -461,13 +1355,39 @@ struct bt_hci_evt_disconnect_complete {
        uint8_t  reason;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_AUTH_COMPLETE               0x06
+struct bt_hci_evt_auth_complete {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_REMOTE_NAME_REQUEST_COMPLETE        0x07
-struct bt_hci_evt_remote_name_req_complete {
+struct bt_hci_evt_remote_name_request_complete {
        uint8_t  status;
        uint8_t  bdaddr[6];
        uint8_t  name[248];
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_ENCRYPT_CHANGE              0x08
+struct bt_hci_evt_encrypt_change {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  encr_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CHANGE_CONN_LINK_KEY_COMPLETE 0x09
+struct bt_hci_evt_change_conn_link_key_complete {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_MASTER_LINK_KEY_COMPLETE    0x0a
+struct bt_hci_evt_master_link_key_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  key_flag;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_REMOTE_FEATURES_COMPLETE    0x0b
 struct bt_hci_evt_remote_features_complete {
        uint8_t  status;
@@ -484,6 +1404,18 @@ struct bt_hci_evt_remote_version_complete {
        uint16_t lmp_subver;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_QOS_SETUP_COMPLETE          0x0d
+struct bt_hci_evt_qos_setup_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  flags;
+       uint8_t  service_type;
+       uint32_t token_rate;
+       uint32_t peak_bandwidth;
+       uint32_t latency;
+       uint32_t delay_variation;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_CMD_COMPLETE                        0x0e
 struct bt_hci_evt_cmd_complete {
        uint8_t  ncmd;
@@ -497,6 +1429,23 @@ struct bt_hci_evt_cmd_status {
        uint16_t opcode;
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_HARDWARE_ERROR              0x10
+struct bt_hci_evt_hardware_error {
+       uint8_t  code;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_FLUSH_OCCURRED              0x11
+struct bt_hci_evt_flush_occurred {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_ROLE_CHANGE                 0x12
+struct bt_hci_evt_role_change {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+       uint8_t  role;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_NUM_COMPLETED_PACKETS       0x13
 struct bt_hci_evt_num_completed_packets {
        uint8_t  num_handles;
@@ -504,15 +1453,92 @@ struct bt_hci_evt_num_completed_packets {
        uint16_t count;
 } __attribute__ ((packed));
 
-#define BT_HCI_EVT_CONN_PKT_TYPE_CHANGED       0x1d
-struct bt_hci_evt_conn_pkt_type_changed {
+#define BT_HCI_EVT_MODE_CHANGE                 0x14
+struct bt_hci_evt_mode_change {
        uint8_t  status;
        uint16_t handle;
-       uint16_t pkt_type;
+       uint8_t  mode;
+       uint16_t interval;
 } __attribute__ ((packed));
 
-#define BT_HCI_EVT_INQUIRY_RESULT_WITH_RSSI    0x22
-struct bt_hci_evt_inquiry_result_with_rssi {
+#define BT_HCI_EVT_RETURN_LINK_KEYS            0x15
+
+#define BT_HCI_EVT_PIN_CODE_REQUEST            0x16
+struct bt_hci_evt_pin_code_request {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LINK_KEY_REQUEST            0x17
+struct bt_hci_evt_link_key_request {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LINK_KEY_NOTIFY             0x18
+struct bt_hci_evt_link_key_notify {
+       uint8_t  bdaddr[6];
+       uint8_t  link_key[16];
+       uint8_t  key_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LOOPBACK_COMMAND            0x19
+
+#define BT_HCI_EVT_DATA_BUFFER_OVERFLOW                0x1a
+struct bt_hci_evt_data_buffer_overflow {
+       uint8_t  link_type;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_MAX_SLOTS_CHANGE            0x1b
+struct bt_hci_evt_max_slots_change {
+       uint16_t handle;
+       uint8_t  max_slots;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CLOCK_OFFSET_COMPLETE       0x1c
+struct bt_hci_evt_clock_offset_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t clock_offset;
+} __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_QOS_VIOLATION               0x1e
+struct bt_hci_evt_qos_violation {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_PSCAN_MODE_CHANGE           0x1f
+struct bt_hci_evt_pscan_mode_change {
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_PSCAN_REP_MODE_CHANGE       0x20
+struct bt_hci_evt_pscan_rep_mode_change {
+       uint8_t  bdaddr[6];
+       uint8_t  pscan_rep_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_FLOW_SPEC_COMPLETE          0x21
+struct bt_hci_evt_flow_spec_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  flags;
+       uint8_t  direction;
+       uint8_t  service_type;
+       uint32_t token_rate;
+       uint32_t token_bucket_size;
+       uint32_t peak_bandwidth;
+       uint32_t access_latency;
+} __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;
@@ -531,6 +1557,39 @@ struct bt_hci_evt_remote_ext_features_complete {
        uint8_t  features[8];
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_SYNC_CONN_COMPLETE          0x2c
+struct bt_hci_evt_sync_conn_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  bdaddr[6];
+       uint8_t  link_type;
+       uint8_t  tx_interval;
+       uint8_t  retrans_window;
+       uint16_t rx_pkt_len;
+       uint16_t tx_pkt_len;
+       uint8_t  air_mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_SYNC_CONN_CHANGED           0x2d
+struct bt_hci_evt_sync_conn_changed {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  tx_interval;
+       uint8_t  retrans_window;
+       uint16_t rx_pkt_len;
+       uint16_t tx_pkt_len;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_SNIFF_SUBRATING             0x2e
+struct bt_hci_evt_sniff_subrating {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t max_tx_latency;
+       uint16_t max_rx_latency;
+       uint16_t min_remote_timeout;
+       uint16_t min_local_timeout;
+} __attribute__ ((packed));
+
 #define BT_HCI_EVT_EXT_INQUIRY_RESULT          0x2f
 struct bt_hci_evt_ext_inquiry_result {
        uint8_t  num_resp;
@@ -543,9 +1602,548 @@ struct bt_hci_evt_ext_inquiry_result {
        uint8_t  data[240];
 } __attribute__ ((packed));
 
+#define BT_HCI_EVT_ENCRYPT_KEY_REFRESH_COMPLETE        0x30
+struct bt_hci_evt_encrypt_key_refresh_complete {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_IO_CAPABILITY_REQUEST       0x31
+struct bt_hci_evt_io_capability_request {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_IO_CAPABILITY_RESPONSE      0x32
+struct bt_hci_evt_io_capability_response {
+       uint8_t  bdaddr[6];
+       uint8_t  capability;
+       uint8_t  oob_data;
+       uint8_t  authentication;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_USER_CONFIRM_REQUEST                0x33
+struct bt_hci_evt_user_confirm_request {
+       uint8_t  bdaddr[6];
+       uint32_t passkey;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_USER_PASSKEY_REQUEST                0x34
+struct bt_hci_evt_user_passkey_request {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_OOB_DATA_REQUEST     0x35
+struct bt_hci_evt_remote_oob_data_request {
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_SIMPLE_PAIRING_COMPLETE     0x36
+struct bt_hci_evt_simple_pairing_complete {
+       uint8_t  status;
+       uint8_t  bdaddr[6];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LINK_SUPV_TIMEOUT_CHANGED   0x38
+struct bt_hci_evt_link_supv_timeout_changed {
+       uint16_t handle;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_ENHANCED_FLUSH_COMPLETE     0x39
+struct bt_hci_evt_enhanced_flush_complete {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_USER_PASSKEY_NOTIFY         0x3b
+struct bt_hci_evt_user_passkey_notify {
+       uint8_t  bdaddr[6];
+       uint32_t passkey;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_KEYPRESS_NOTIFY             0x3c
+struct bt_hci_evt_keypress_notify {
+       uint8_t  bdaddr[6];
+       uint8_t  type;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_REMOTE_HOST_FEATURES_NOTIFY 0x3d
+struct bt_hci_evt_remote_host_features_notify {
+       uint8_t  bdaddr[6];
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_META_EVENT               0x3e
+
+#define BT_HCI_EVT_PHY_LINK_COMPLETE           0x40
+struct bt_hci_evt_phy_link_complete {
+       uint8_t  status;
+       uint8_t  phy_handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_CHANNEL_SELECTED            0x41
+struct bt_hci_evt_channel_selected {
+       uint8_t  phy_handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_DISCONN_PHY_LINK_COMPLETE   0x42
+struct bt_hci_evt_disconn_phy_link_complete {
+       uint8_t  status;
+       uint8_t  phy_handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_PHY_LINK_LOSS_EARLY_WARNING 0x43
+struct bt_hci_evt_phy_link_loss_early_warning {
+       uint8_t  phy_handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_PHY_LINK_RECOVERY           0x44
+struct bt_hci_evt_phy_link_recovery {
+       uint8_t  phy_handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LOGIC_LINK_COMPLETE         0x45
+struct bt_hci_evt_logic_link_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  phy_handle;
+       uint8_t  flow_spec;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_DISCONN_LOGIC_LINK_COMPLETE 0x46
+struct bt_hci_evt_disconn_logic_link_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_FLOW_SPEC_MODIFY_COMPLETE   0x47
+struct bt_hci_evt_flow_spec_modify_complete {
+       uint8_t  status;
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_NUM_COMPLETED_DATA_BLOCKS   0x48
+struct bt_hci_evt_num_completed_data_blocks {
+       uint16_t total_num_blocks;
+       uint8_t  num_handles;
+       uint16_t handle;
+       uint16_t num_packets;
+       uint16_t num_blocks;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_SHORT_RANGE_MODE_CHANGE     0x4c
+struct bt_hci_evt_short_range_mode_change {
+       uint8_t  status;
+       uint8_t  phy_handle;
+       uint8_t  mode;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_AMP_STATUS_CHANGE           0x4d
+struct bt_hci_evt_amp_status_change {
+       uint8_t  status;
+       uint8_t  amp_status;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_CONN_COMPLETE            0x01
+struct bt_hci_evt_le_conn_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  role;
+       uint8_t  peer_addr_type;
+       uint8_t  peer_addr[6];
+       uint16_t interval;
+       uint16_t latency;
+       uint16_t supv_timeout;
+       uint8_t  clock_accuracy;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_ADV_REPORT               0x02
+struct bt_hci_evt_le_adv_report {
+       uint8_t  num_reports;
+       uint8_t  event_type;
+       uint8_t  addr_type;
+       uint8_t  addr[6];
+       uint8_t  data_len;
+       uint8_t  data[0];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_CONN_UPDATE_COMPLETE     0x03
+struct bt_hci_evt_le_conn_update_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint16_t interval;
+       uint16_t latency;
+       uint16_t supv_timeout;
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_REMOTE_FEATURES_COMPLETE 0x04
+struct bt_hci_evt_le_remote_features_complete {
+       uint8_t  status;
+       uint16_t handle;
+       uint8_t  features[8];
+} __attribute__ ((packed));
+
+#define BT_HCI_EVT_LE_LONG_TERM_KEY_REQUEST    0x05
+struct bt_hci_evt_le_long_term_key_request {
+       uint16_t handle;
+       uint8_t  number[8];
+       uint16_t diversifier;
+} __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_MEM_CAPACITY_EXCEEDED       0x07
+#define BT_HCI_ERR_COMMAND_DISALLOWED          0x0c
+#define BT_HCI_ERR_UNSUPPORTED_FEATURE         0x11
 #define BT_HCI_ERR_INVALID_PARAMETERS          0x12
+#define BT_HCI_ERR_UNSPECIFIED_ERROR           0x1f
+#define BT_HCI_ERR_CONN_FAILED_TO_ESTABLISH    0x3e
+
+struct bt_l2cap_hdr {
+       uint16_t len;
+       uint16_t cid;
+} __attribute__ ((packed));
+
+struct bt_l2cap_hdr_sig {
+       uint8_t  code;
+       uint8_t  ident;
+       uint16_t len;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CMD_REJECT                0x01
+struct bt_l2cap_pdu_cmd_reject {
+       uint16_t reason;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONN_REQ          0x02
+struct bt_l2cap_pdu_conn_req {
+       uint16_t psm;
+       uint16_t scid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONN_RSP          0x03
+struct bt_l2cap_pdu_conn_rsp {
+       uint16_t dcid;
+       uint16_t scid;
+       uint16_t result;
+       uint16_t status;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONFIG_REQ                0x04
+struct bt_l2cap_pdu_config_req {
+       uint16_t dcid;
+       uint16_t flags;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONFIG_RSP                0x05
+struct bt_l2cap_pdu_config_rsp {
+       uint16_t scid;
+       uint16_t flags;
+       uint16_t result;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_DISCONN_REQ       0x06
+struct bt_l2cap_pdu_disconn_req {
+       uint16_t dcid;
+       uint16_t scid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_DISCONN_RSP       0x07
+struct bt_l2cap_pdu_disconn_rsp {
+       uint16_t dcid;
+       uint16_t scid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_ECHO_REQ          0x08
+
+#define BT_L2CAP_PDU_ECHO_RSP          0x09
+
+#define BT_L2CAP_PDU_INFO_REQ          0x0a
+struct bt_l2cap_pdu_info_req {
+       uint16_t type;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_INFO_RSP          0x0b
+struct bt_l2cap_pdu_info_rsp {
+       uint16_t type;
+       uint16_t result;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CREATE_CHAN_REQ   0x0c
+struct bt_l2cap_pdu_create_chan_req {
+       uint16_t psm;
+       uint16_t scid;
+       uint8_t  ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CREATE_CHAN_RSP   0x0d
+struct bt_l2cap_pdu_create_chan_rsp {
+       uint16_t dcid;
+       uint16_t scid;
+       uint16_t result;
+       uint16_t status;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_MOVE_CHAN_REQ     0x0e
+struct bt_l2cap_pdu_move_chan_req {
+       uint16_t icid;
+       uint8_t  ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_MOVE_CHAN_RSP     0x0f
+struct bt_l2cap_pdu_move_chan_rsp {
+       uint16_t icid;
+       uint16_t result;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_MOVE_CHAN_CFM     0x10
+struct bt_l2cap_pdu_move_chan_cfm {
+       uint16_t icid;
+       uint16_t result;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_MOVE_CHAN_CFM_RSP 0x11
+struct bt_l2cap_pdu_move_chan_cfm_rsp {
+       uint16_t icid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONN_PARAM_REQ    0x12
+struct bt_l2cap_pdu_conn_param_req {
+       uint16_t min_interval;
+       uint16_t max_interval;
+       uint16_t latency;
+       uint16_t timeout;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_PDU_CONN_PARAM_RSP    0x13
+struct bt_l2cap_pdu_conn_param_rsp {
+       uint16_t result;
+} __attribute__ ((packed));
+
+struct bt_l2cap_hdr_connless {
+       uint16_t psm;
+} __attribute__ ((packed));
+
+struct bt_l2cap_hdr_amp {
+       uint8_t  code;
+       uint8_t  ident;
+       uint16_t len;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_CMD_REJECT                0x01
+struct bt_l2cap_amp_cmd_reject {
+       uint16_t reason;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_DISCOVER_REQ      0x02
+struct bt_l2cap_amp_discover_req {
+       uint16_t size;
+       uint16_t features;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_DISCOVER_RSP      0x03
+struct bt_l2cap_amp_discover_rsp {
+       uint16_t size;
+       uint16_t features;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_CHANGE_NOTIFY     0x04
+
+#define BT_L2CAP_AMP_CHANGE_RESPONSE   0x05
+
+#define BT_L2CAP_AMP_GET_INFO_REQ      0x06
+struct bt_l2cap_amp_get_info_req {
+       uint8_t  ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_GET_INFO_RSP      0x07
+struct bt_l2cap_amp_get_info_rsp {
+       uint8_t  ctrlid;
+       uint8_t  status;
+       uint32_t total_bw;
+       uint32_t max_bw;
+       uint32_t min_latency;
+       uint16_t pal_cap;
+       uint16_t max_assoc_len;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_GET_ASSOC_REQ     0x08
+struct bt_l2cap_amp_get_assoc_req {
+       uint8_t  ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_GET_ASSOC_RSP     0x09
+struct bt_l2cap_amp_get_assoc_rsp {
+       uint8_t  ctrlid;
+       uint8_t  status;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_CREATE_PHY_LINK_REQ       0x0a
+struct bt_l2cap_amp_create_phy_link_req {
+       uint8_t  local_ctrlid;
+       uint8_t  remote_ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_CREATE_PHY_LINK_RSP       0x0b
+struct bt_l2cap_amp_create_phy_link_rsp {
+       uint8_t  local_ctrlid;
+       uint8_t  remote_ctrlid;
+       uint8_t  status;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_DISCONN_PHY_LINK_REQ      0x0c
+struct bt_l2cap_amp_disconn_phy_link_req {
+       uint8_t  local_ctrlid;
+       uint8_t  remote_ctrlid;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_AMP_DISCONN_PHY_LINK_RSP      0x0d
+struct bt_l2cap_amp_disconn_phy_link_rsp {
+       uint8_t  local_ctrlid;
+       uint8_t  remote_ctrlid;
+       uint8_t  status;
+} __attribute__ ((packed));
+
+struct bt_l2cap_hdr_att {
+       uint8_t  code;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_ERROR_RESPONSE            0x01
+struct bt_l2cap_att_error_response {
+       uint8_t  request;
+       uint16_t handle;
+       uint8_t  error;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_EXCHANGE_MTU_REQ          0x02
+struct bt_l2cap_att_exchange_mtu_req {
+       uint16_t mtu;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_EXCHANGE_MTU_RSP          0x03
+struct bt_l2cap_att_exchange_mtu_rsp {
+       uint16_t mtu;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_READ_TYPE_REQ             0x08
+struct bt_l2cap_att_read_type_req {
+       uint16_t start_handle;
+       uint16_t end_handle;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_READ_TYPE_RSP             0x09
+struct bt_l2cap_att_read_type_rsp {
+       uint8_t  length;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_READ_REQ                  0x0a
+struct bt_l2cap_att_read_req {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_READ_RSP                  0x0b
+
+#define BT_L2CAP_ATT_READ_GROUP_TYPE_REQ       0x10
+struct bt_l2cap_att_read_group_type_req {
+       uint16_t start_handle;
+       uint16_t end_handle;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_READ_GROUP_TYPE_RSP       0x11
+struct bt_l2cap_att_read_group_type_rsp {
+       uint8_t  length;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_HANDLE_VALUE_NOTIFY       0x1b
+struct bt_l2cap_att_handle_value_notify {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_HANDLE_VALUE_IND          0x1d
+struct bt_l2cap_att_handle_value_ind {
+       uint16_t handle;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_ATT_HANDLE_VALUE_CONF         0x1e
+
+struct bt_l2cap_hdr_smp {
+       uint8_t  code;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_REQUEST   0x01
+struct bt_l2cap_smp_pairing_request {
+       uint8_t  io_capa;
+       uint8_t  oob_data;
+       uint8_t  auth_req;
+       uint8_t  max_key_size;
+       uint8_t  init_key_dist;
+       uint8_t  resp_key_dist;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_RESPONSE  0x02
+struct bt_l2cap_smp_pairing_response {
+       uint8_t  io_capa;
+       uint8_t  oob_data;
+       uint8_t  auth_req;
+       uint8_t  max_key_size;
+       uint8_t  init_key_dist;
+       uint8_t  resp_key_dist;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_CONFIRM   0x03
+struct bt_l2cap_smp_pairing_confirm {
+       uint8_t  value[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_RANDOM    0x04
+struct bt_l2cap_smp_pairing_random {
+       uint8_t  value[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_PAIRING_FAILED    0x05
+struct bt_l2cap_smp_pairing_failed {
+       uint8_t  reason;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_ENCRYPT_INFO      0x06
+struct bt_l2cap_smp_encrypt_info {
+       uint8_t  ltk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_MASTER_IDENT      0x07
+struct bt_l2cap_smp_master_ident {
+       uint16_t ediv;
+       uint64_t rand;
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_IDENT_INFO                0x08
+struct bt_l2cap_smp_ident_info {
+       uint8_t  irk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_IDENT_ADDR_INFO   0x09
+struct bt_l2cap_smp_ident_addr_info {
+       uint8_t  addr_type;
+       uint8_t  addr[6];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_SIGNING_INFO      0x0a
+struct bt_l2cap_smp_signing_info {
+       uint8_t  csrk[16];
+} __attribute__ ((packed));
+
+#define BT_L2CAP_SMP_SECURITY_REQUEST  0x0b
+struct bt_l2cap_smp_security_request {
+       uint8_t  auth_req;
+} __attribute__ ((packed));
+
+struct bt_sdp_hdr {
+       uint8_t  pdu;
+       uint16_t tid;
+       uint16_t plen;
+} __attribute__ ((packed));
index 09c5e25..b92fb74 100644 (file)
 #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);
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
 
-       h = ntohl(n >> 32);
-       h |= tmp << 32;
-
-       return h;
-}
-
-#define hton64(x)     ntoh64(x)
+#include "btsnoop.h"
 
 struct btsnoop_hdr {
        uint8_t         id[8];          /* Identification Pattern */
@@ -71,48 +61,44 @@ 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 uint32_t btsnoop_type = 0;
 
 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)
+void btsnoop_create(const char *path, uint32_t type)
 {
        struct btsnoop_hdr hdr;
-       struct btsnoop_pkt pkt;
-       uint64_t ts;
        ssize_t written;
 
-       if (!tv)
+       if (btsnoop_fd >= 0)
                return;
 
+       btsnoop_fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+                               S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
        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);
+       btsnoop_type = type;
 
-               written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
-               if (written < 0)
-                       return;
+       memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+       hdr.version = htonl(btsnoop_version);
+       hdr.type = htonl(btsnoop_type);
 
-               btsnoop_index = index;
+       written = write(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (written < 0) {
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return;
        }
+}
 
-       if (index != btsnoop_index)
-               return;
+void btsnoop_write(struct timeval *tv, uint32_t flags,
+                                       const void *data, uint16_t size)
+{
+       struct btsnoop_pkt pkt;
+       uint64_t ts;
+       ssize_t written;
 
        ts = (tv->tv_sec - 946684800ll) * 1000000ll + tv->tv_usec;
 
@@ -133,6 +119,298 @@ void btsnoop_write(struct timeval *tv, uint16_t index, uint32_t flags,
        }
 }
 
+static uint32_t get_flags_from_opcode(uint16_t opcode)
+{
+       switch (opcode) {
+       case BTSNOOP_OPCODE_NEW_INDEX:
+       case BTSNOOP_OPCODE_DEL_INDEX:
+               break;
+       case BTSNOOP_OPCODE_COMMAND_PKT:
+               return 0x02;
+       case BTSNOOP_OPCODE_EVENT_PKT:
+               return 0x03;
+       case BTSNOOP_OPCODE_ACL_TX_PKT:
+               return 0x00;
+       case BTSNOOP_OPCODE_ACL_RX_PKT:
+               return 0x01;
+       case BTSNOOP_OPCODE_SCO_TX_PKT:
+       case BTSNOOP_OPCODE_SCO_RX_PKT:
+               break;
+       }
+
+       return 0xff;
+}
+
+void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size)
+{
+       uint32_t flags;
+
+       if (!tv)
+               return;
+
+       if (btsnoop_fd < 0)
+               return;
+
+       switch (btsnoop_type) {
+       case BTSNOOP_TYPE_HCI:
+               if (btsnoop_index == 0xffff)
+                       btsnoop_index = index;
+
+               if (index != btsnoop_index)
+                       return;
+
+               flags = get_flags_from_opcode(opcode);
+               if (flags == 0xff)
+                       return;
+               break;
+
+       case BTSNOOP_TYPE_EXTENDED_HCI:
+               flags = (index << 16) | opcode;
+               break;
+
+       default:
+               return;
+       }
+
+       btsnoop_write(tv, flags, data, size);
+}
+
+void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
+                                       const void *data, uint16_t size)
+{
+       uint32_t flags;
+
+       if (!tv)
+               return;
+
+       if (btsnoop_fd < 0)
+               return;
+
+       switch (btsnoop_type) {
+       case BTSNOOP_TYPE_EXTENDED_PHY:
+               flags = (1 << 16) | frequency;
+               break;
+
+       default:
+               return;
+       }
+
+       btsnoop_write(tv, flags, data, size);
+}
+
+int btsnoop_open(const char *path, uint32_t *type)
+{
+       struct btsnoop_hdr hdr;
+       ssize_t len;
+
+       if (btsnoop_fd >= 0) {
+               fprintf(stderr, "Too many open files\n");
+               return -1;
+       }
+
+       btsnoop_fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (btsnoop_fd < 0) {
+               perror("Failed to open file");
+               return -1;
+       }
+
+       len = read(btsnoop_fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (len < 0 || len != BTSNOOP_HDR_SIZE) {
+               perror("Failed to read header");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
+               fprintf(stderr, "Invalid btsnoop header\n");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       if (ntohl(hdr.version) != btsnoop_version) {
+               fprintf(stderr, "Invalid btsnoop version\n");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       btsnoop_type = ntohl(hdr.type);
+
+       if (type)
+               *type = btsnoop_type;
+
+       return 0;
+}
+
+static uint16_t get_opcode_from_flags(uint8_t type, uint32_t flags)
+{
+       switch (type) {
+       case HCI_COMMAND_PKT:
+               return BTSNOOP_OPCODE_COMMAND_PKT;
+       case HCI_ACLDATA_PKT:
+               if (flags & 0x01)
+                       return BTSNOOP_OPCODE_ACL_RX_PKT;
+               else
+                       return BTSNOOP_OPCODE_ACL_TX_PKT;
+       case HCI_SCODATA_PKT:
+               if (flags & 0x01)
+                       return BTSNOOP_OPCODE_SCO_RX_PKT;
+               else
+                       return BTSNOOP_OPCODE_SCO_TX_PKT;
+       case HCI_EVENT_PKT:
+               return BTSNOOP_OPCODE_EVENT_PKT;
+       case 0xff:
+               if (flags & 0x02) {
+                       if (flags & 0x01)
+                               return BTSNOOP_OPCODE_EVENT_PKT;
+                       else
+                               return BTSNOOP_OPCODE_COMMAND_PKT;
+               } else {
+                       if (flags & 0x01)
+                               return BTSNOOP_OPCODE_ACL_RX_PKT;
+                       else
+                               return BTSNOOP_OPCODE_ACL_TX_PKT;
+               }
+               break;
+       }
+
+       return 0xff;
+}
+
+int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
+                                               void *data, uint16_t *size)
+{
+       struct btsnoop_pkt pkt;
+       uint32_t toread, flags;
+       uint64_t ts;
+       uint8_t pkt_type;
+       ssize_t len;
+
+       if (btsnoop_fd < 0)
+               return -1;
+
+       len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (len == 0)
+               return -1;
+
+       if (len < 0 || len != BTSNOOP_PKT_SIZE) {
+               perror("Failed to read packet");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       toread = ntohl(pkt.size);
+       flags = ntohl(pkt.flags);
+
+       ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
+       tv->tv_sec = (ts / 1000000ll) + 946684800ll;
+       tv->tv_usec = ts % 1000000ll;
+
+       switch (btsnoop_type) {
+       case BTSNOOP_TYPE_HCI:
+               *index = 0;
+               *opcode = get_opcode_from_flags(0xff, flags);
+               break;
+
+       case BTSNOOP_TYPE_UART:
+               len = read(btsnoop_fd, &pkt_type, 1);
+               if (len < 0) {
+                       perror("Failed to read packet type");
+                       close(btsnoop_fd);
+                       btsnoop_fd = -1;
+                       return -1;
+               }
+               toread--;
+
+               *index = 0;
+               *opcode = get_opcode_from_flags(pkt_type, flags);
+               break;
+
+       case BTSNOOP_TYPE_EXTENDED_HCI:
+               *index = flags >> 16;
+               *opcode = flags & 0xffff;
+               break;
+
+       default:
+               fprintf(stderr, "Unknown packet type\n");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       len = read(btsnoop_fd, data, toread);
+       if (len < 0) {
+               perror("Failed to read data");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       *size = toread;
+
+       return 0;
+}
+
+int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
+                                               void *data, uint16_t *size)
+{
+       struct btsnoop_pkt pkt;
+       uint32_t toread, flags;
+       uint64_t ts;
+       ssize_t len;
+
+       if (btsnoop_fd < 0)
+               return -1;
+
+       len = read(btsnoop_fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (len == 0)
+               return -1;
+
+       if (len < 0 || len != BTSNOOP_PKT_SIZE) {
+               perror("Failed to read packet");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       toread = ntohl(pkt.size);
+       flags = ntohl(pkt.flags);
+
+       ts = ntoh64(pkt.ts) - 0x00E03AB44A676000ll;
+       tv->tv_sec = (ts / 1000000ll) + 946684800ll;
+       tv->tv_usec = ts % 1000000ll;
+
+       switch (btsnoop_type) {
+       case BTSNOOP_TYPE_EXTENDED_PHY:
+               if ((flags >> 16) != 1)
+                       break;
+               *frequency = flags & 0xffff;
+               break;
+
+       default:
+               fprintf(stderr, "Unknown packet type\n");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       len = read(btsnoop_fd, data, toread);
+       if (len < 0) {
+               perror("Failed to read data");
+               close(btsnoop_fd);
+               btsnoop_fd = -1;
+               return -1;
+       }
+
+       *size = toread;
+
+       return 0;
+}
+
 void btsnoop_close(void)
 {
        if (btsnoop_fd < 0)
index 9472d1a..cdefb8c 100644 (file)
  *
  */
 
+#include <stdint.h>
 #include <sys/time.h>
 
-void btsnoop_open(const char *path);
-void btsnoop_write(struct timeval *tv, uint16_t index, uint32_t flags,
+#define BTSNOOP_TYPE_HCI               1001
+#define BTSNOOP_TYPE_UART              1002
+#define BTSNOOP_TYPE_BCSP              1003
+#define BTSNOOP_TYPE_3WIRE             1004
+
+#define BTSNOOP_TYPE_EXTENDED_HCI      2001
+#define BTSNOOP_TYPE_EXTENDED_PHY      2002
+
+#define BTSNOOP_OPCODE_NEW_INDEX       0
+#define BTSNOOP_OPCODE_DEL_INDEX       1
+#define BTSNOOP_OPCODE_COMMAND_PKT     2
+#define BTSNOOP_OPCODE_EVENT_PKT       3
+#define BTSNOOP_OPCODE_ACL_TX_PKT      4
+#define BTSNOOP_OPCODE_ACL_RX_PKT      5
+#define BTSNOOP_OPCODE_SCO_TX_PKT      6
+#define BTSNOOP_OPCODE_SCO_RX_PKT      7
+
+void btsnoop_create(const char *path, uint32_t type);
+void btsnoop_write(struct timeval *tv, uint32_t flags,
+                                       const void *data, uint16_t size);
+void btsnoop_write_hci(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size);
+void btsnoop_write_phy(struct timeval *tv, uint16_t frequency,
                                        const void *data, uint16_t size);
+int btsnoop_open(const char *path, uint32_t *type);
+int btsnoop_read_hci(struct timeval *tv, uint16_t *index, uint16_t *opcode,
+                                               void *data, uint16_t *size);
+int btsnoop_read_phy(struct timeval *tv, uint16_t *frequency,
+                                               void *data, uint16_t *size);
 void btsnoop_close(void);
index 159ba9d..4edefde 100644 (file)
 #endif
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
 #include <sys/time.h>
+#include <sys/socket.h>
+#include <sys/un.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/mgmt.h>
+#include "lib/bluetooth.h"
+#include "lib/hci.h"
+#include "lib/mgmt.h"
 
 #include "mainloop.h"
+#include "display.h"
 #include "packet.h"
+#include "btsnoop.h"
+#include "hcidump.h"
 #include "control.h"
 
+static bool hcidump_fallback = false;
+
+#define MAX_PACKET_SIZE                (1486 + 4)
+
 struct control_data {
        uint16_t channel;
        int fd;
+       unsigned char buf[MAX_PACKET_SIZE];
+       uint16_t offset;
 };
 
 static void free_data(void *user_data)
@@ -92,7 +104,8 @@ static void mgmt_controller_error(uint16_t len, const void *buf)
 
 static const char *settings_str[] = {
        "powered", "connectable", "fast-connectable", "discoverable",
-       "pairable", "link-security", "ssp", "br/edr", "hs", "le"
+       "pairable", "link-security", "ssp", "br/edr", "hs", "le",
+       "advertising",
 };
 
 static void mgmt_new_settings(uint16_t len, const void *buf)
@@ -210,7 +223,7 @@ static void mgmt_device_connected(uint16_t len, const void *buf)
                return;
        }
 
-       flags = btohs(ev->flags);
+       flags = btohl(ev->flags);
        ba2str(&ev->addr.bdaddr, str);
 
        printf("@ Device Connected: %s (%d) flags 0x%4.4x\n",
@@ -226,18 +239,29 @@ static void mgmt_device_disconnected(uint16_t len, const void *buf)
 {
        const struct mgmt_ev_device_disconnected *ev = buf;
        char str[18];
+       uint8_t reason;
+       uint16_t consumed_len;
 
-       if (len < sizeof(*ev)) {
+       if (len < sizeof(struct mgmt_addr_info)) {
                printf("* Malformed Device Disconnected control\n");
                return;
        }
 
+       if (len < sizeof(*ev)) {
+               reason = MGMT_DEV_DISCONN_UNKNOWN;
+               consumed_len = len;
+       } else {
+               reason = ev->reason;
+               consumed_len = sizeof(*ev);
+       }
+
        ba2str(&ev->addr.bdaddr, str);
 
-       printf("@ Device Disconnected: %s (%d)\n", str, ev->addr.type);
+       printf("@ Device Disconnected: %s (%d) reason %u\n", str, ev->addr.type,
+                                                                       reason);
 
-       buf += sizeof(*ev);
-       len -= sizeof(*ev);
+       buf += consumed_len;
+       len -= consumed_len;
 
        packet_hexdump(buf, len);
 }
@@ -357,7 +381,7 @@ static void mgmt_device_found(uint16_t len, const void *buf)
                return;
        }
 
-       flags = btohs(ev->flags);
+       flags = btohl(ev->flags);
        ba2str(&ev->addr.bdaddr, str);
 
        printf("@ Device Found: %s (%d) rssi %d flags 0x%4.4x\n",
@@ -446,6 +470,30 @@ static void mgmt_device_unpaired(uint16_t len, const void *buf)
        packet_hexdump(buf, len);
 }
 
+static void mgmt_passkey_notify(uint16_t len, const void *buf)
+{
+       const struct mgmt_ev_passkey_notify *ev = buf;
+       uint32_t passkey;
+       char str[18];
+
+       if (len < sizeof(*ev)) {
+               printf("* Malformed Passkey Notify control\n");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, str);
+
+       passkey = btohl(ev->passkey);
+
+       printf("@ Passkey Notify: %s (%d) passkey %06u entered %u\n",
+                               str, ev->addr.type, passkey, ev->entered);
+
+       buf += sizeof(*ev);
+       len -= sizeof(*ev);
+
+       packet_hexdump(buf, len);
+}
+
 void control_message(uint16_t opcode, const void *data, uint16_t size)
 {
        switch (opcode) {
@@ -509,6 +557,9 @@ void control_message(uint16_t opcode, const void *data, uint16_t size)
        case MGMT_EV_DEVICE_UNPAIRED:
                mgmt_device_unpaired(size, data);
                break;
+       case MGMT_EV_PASSKEY_NOTIFY:
+               mgmt_passkey_notify(size, data);
+               break;
        default:
                printf("* Unknown control (code %d len %d)\n", opcode, size);
                packet_hexdump(data, size);
@@ -519,21 +570,20 @@ void control_message(uint16_t opcode, const void *data, uint16_t size)
 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);
+               mainloop_remove_fd(data->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);
+       iov[1].iov_base = data->buf;
+       iov[1].iov_len = sizeof(data->buf);
 
        memset(&msg, 0, sizeof(msg));
        msg.msg_iov = iov;
@@ -544,10 +594,11 @@ static void data_callback(int fd, uint32_t events, void *user_data)
        while (1) {
                struct cmsghdr *cmsg;
                struct timeval *tv = NULL;
+               struct timeval ctv;
                uint16_t opcode, index, pktlen;
                ssize_t len;
 
-               len = recvmsg(fd, &msg, MSG_DONTWAIT);
+               len = recvmsg(data->fd, &msg, MSG_DONTWAIT);
                if (len < 0)
                        break;
 
@@ -559,8 +610,10 @@ static void data_callback(int fd, uint32_t events, void *user_data)
                        if (cmsg->cmsg_level != SOL_SOCKET)
                                continue;
 
-                       if (cmsg->cmsg_type == SCM_TIMESTAMP)
-                               tv = (struct timeval *) CMSG_DATA(cmsg);
+                       if (cmsg->cmsg_type == SCM_TIMESTAMP) {
+                               memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
+                               tv = &ctv;
+                       }
                }
 
                opcode = btohs(hdr.opcode);
@@ -569,10 +622,11 @@ static void data_callback(int fd, uint32_t events, void *user_data)
 
                switch (data->channel) {
                case HCI_CHANNEL_CONTROL:
-                       packet_control(tv, index, opcode, buf, pktlen);
+                       packet_control(tv, index, opcode, data->buf, pktlen);
                        break;
                case HCI_CHANNEL_MONITOR:
-                       packet_monitor(tv, index, opcode, buf, pktlen);
+                       packet_monitor(tv, index, opcode, data->buf, pktlen);
+                       btsnoop_write_hci(tv, index, opcode, data->buf, pktlen);
                        break;
                }
        }
@@ -583,7 +637,7 @@ static int open_socket(uint16_t channel)
        struct sockaddr_hci addr;
        int fd, opt = 1;
 
-       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (fd < 0) {
                perror("Failed to open channel");
                return -1;
@@ -597,6 +651,7 @@ static int open_socket(uint16_t channel)
        if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                if (errno == EINVAL) {
                        /* Fallback to hcidump support */
+                       hcidump_fallback = true;
                        close(fd);
                        return -1;
                }
@@ -636,10 +691,198 @@ static int open_channel(uint16_t channel)
        return 0;
 }
 
+static void client_callback(int fd, uint32_t events, void *user_data)
+{
+       struct control_data *data = user_data;
+       ssize_t len;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(data->fd);
+               return;
+       }
+
+       len = recv(data->fd, data->buf + data->offset,
+                       sizeof(data->buf) - data->offset, MSG_DONTWAIT);
+       if (len < 0)
+               return;
+
+       data->offset += len;
+
+       if (data->offset > MGMT_HDR_SIZE) {
+               struct mgmt_hdr *hdr = (struct mgmt_hdr *) data->buf;
+               uint16_t pktlen = btohs(hdr->len);
+
+               if (data->offset > pktlen + MGMT_HDR_SIZE) {
+                       uint16_t opcode = btohs(hdr->opcode);
+                       uint16_t index = btohs(hdr->index);
+
+                       packet_monitor(NULL, index, opcode,
+                                       data->buf + MGMT_HDR_SIZE, pktlen);
+
+                       data->offset -= pktlen + MGMT_HDR_SIZE;
+
+                       if (data->offset > 0)
+                               memmove(data->buf, data->buf +
+                                        MGMT_HDR_SIZE + pktlen, data->offset);
+               }
+       }
+}
+
+static void server_accept_callback(int fd, uint32_t events, void *user_data)
+{
+       struct control_data *data;
+       struct sockaddr_un addr;
+       socklen_t len;
+       int nfd;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       len = sizeof(addr);
+
+       nfd = accept(fd, (struct sockaddr *) &addr, &len);
+       if (nfd < 0) {
+               perror("Failed to accept client socket");
+               return;
+       }
+
+       printf("--- New monitor connection ---\n");
+
+       data = malloc(sizeof(*data));
+       if (!data) {
+               close(nfd);
+               return;
+       }
+
+       memset(data, 0, sizeof(*data));
+       data->channel = HCI_CHANNEL_MONITOR;
+       data->fd = nfd;
+
+        mainloop_add_fd(data->fd, EPOLLIN, client_callback, data, free_data);
+}
+
+static int server_fd = -1;
+
+void control_server(const char *path)
+{
+       struct sockaddr_un addr;
+       int fd;
+
+       if (server_fd >= 0)
+               return;
+
+       unlink(path);
+
+       fd = socket(PF_UNIX, SOCK_STREAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               perror("Failed to open server socket");
+               return;
+       }
+
+       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;
+       }
+
+       if (listen(fd, 5) < 0) {
+               perror("Failed to listen server socket");
+               close(fd);
+               return;
+       }
+
+       if (mainloop_add_fd(fd, EPOLLIN, server_accept_callback,
+                                               NULL, NULL) < 0) {
+               close(fd);
+               return;
+       }
+
+       server_fd = fd;
+}
+
+void control_writer(const char *path)
+{
+       btsnoop_create(path, BTSNOOP_TYPE_EXTENDED_HCI);
+}
+
+void control_reader(const char *path)
+{
+       unsigned char buf[MAX_PACKET_SIZE];
+       uint16_t pktlen;
+       uint32_t type;
+       struct timeval tv;
+
+       if (btsnoop_open(path, &type) < 0)
+               return;
+
+       switch (type) {
+       case BTSNOOP_TYPE_HCI:
+       case BTSNOOP_TYPE_UART:
+       case BTSNOOP_TYPE_EXTENDED_PHY:
+               packet_del_filter(PACKET_FILTER_SHOW_INDEX);
+               break;
+
+       case BTSNOOP_TYPE_EXTENDED_HCI:
+               packet_add_filter(PACKET_FILTER_SHOW_INDEX);
+               break;
+       }
+
+       open_pager();
+
+       switch (type) {
+       case BTSNOOP_TYPE_HCI:
+       case BTSNOOP_TYPE_UART:
+       case BTSNOOP_TYPE_EXTENDED_HCI:
+               while (1) {
+                       uint16_t index, opcode;
+
+                       if (btsnoop_read_hci(&tv, &index, &opcode,
+                                                       buf, &pktlen) < 0)
+                               break;
+
+                       packet_monitor(&tv, index, opcode, buf, pktlen);
+               }
+               break;
+
+       case BTSNOOP_TYPE_EXTENDED_PHY:
+               while (1) {
+                       uint16_t frequency;
+
+                       if (btsnoop_read_phy(&tv, &frequency,
+                                                       buf, &pktlen) < 0)
+                               break;
+
+                       packet_simulator(&tv, frequency, buf, pktlen);
+               }
+               break;
+       }
+
+       close_pager();
+
+       btsnoop_close();
+}
+
 int control_tracing(void)
 {
-       if (open_channel(HCI_CHANNEL_MONITOR) < 0)
-               return -1;
+       packet_add_filter(PACKET_FILTER_SHOW_INDEX);
+
+       if (server_fd >= 0)
+               return 0;
+
+       if (open_channel(HCI_CHANNEL_MONITOR) < 0) {
+               if (!hcidump_fallback)
+                       return -1;
+               if (hcidump_tracing() < 0)
+                       return -1;
+               return 0;
+       }
 
        open_channel(HCI_CHANNEL_CONTROL);
 
index 961f66c..8781bd0 100644 (file)
@@ -24,6 +24,9 @@
 
 #include <stdint.h>
 
+void control_writer(const char *path);
+void control_reader(const char *path);
+void control_server(const char *path);
 int control_tracing(void);
 
 void control_message(uint16_t opcode, const void *data, uint16_t size);
diff --git a/monitor/crc.c b/monitor/crc.c
new file mode 100644 (file)
index 0000000..9ea11fb
--- /dev/null
@@ -0,0 +1,84 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011-2012  Intel Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "crc.h"
+
+uint32_t crc24_bit_reverse(uint32_t value)
+{
+       uint32_t result = 0;
+       uint8_t i;
+
+       for (i = 0; i < 24; i++)
+               result |= ((value >> i) & 1) << (23 - i);
+
+       return result;
+}
+
+uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len)
+{
+       uint32_t state = preset;
+       uint8_t i;
+
+       for (i = 0; i < len; i++) {
+               uint8_t n, cur = data[i];
+
+               for (n = 0; n < 8; n++) {
+                       int next_bit = (state ^ cur) & 1;
+
+                       cur >>= 1;
+                       state >>= 1;
+                       if (next_bit) {
+                               state |= 1 << 23;
+                               state ^= 0x5a6000;
+                       }
+               }
+       }
+
+       return state;
+}
+
+uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len)
+{
+       uint32_t state = crc;
+       uint8_t i;
+
+       for (i = 0; i < len; i++) {
+               uint8_t n, cur = data[len - i - 1];
+
+               for (n = 0; n < 8; n++) {
+                       int top_bit = state >> 23;
+
+                       state = (state << 1) & 0xffffff;
+                       state |= top_bit ^ ((cur >> (7 - n)) & 1);
+                       if (top_bit)
+                               state ^= 0xb4c000;
+               }
+       }
+
+       return state;
+}
similarity index 59%
rename from sbc/sbc_primitives_neon.h
rename to monitor/crc.h
index ea3da06..84f5d7f 100644 (file)
@@ -1,11 +1,9 @@
 /*
  *
- *  Bluetooth low-complexity, subband codec (SBC) library
+ *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2008-2010  Nokia Corporation
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
  *
  *
  *  This library is free software; you can redistribute it and/or
  *
  */
 
-#ifndef __SBC_PRIMITIVES_NEON_H
-#define __SBC_PRIMITIVES_NEON_H
+#include <stdint.h>
 
-#include "sbc_primitives.h"
+uint32_t crc24_bit_reverse(uint32_t value);
 
-#if defined(__GNUC__) && defined(__ARM_NEON__) && \
-               !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
-
-#define SBC_BUILD_WITH_NEON_SUPPORT
-
-void sbc_init_primitives_neon(struct sbc_encoder_state *encoder_state);
-
-#endif
-
-#endif
+uint32_t crc24_calculate(uint32_t preset, const uint8_t *data, uint8_t len);
+uint32_t crc24_reverse(uint32_t crc, const uint8_t *data, uint8_t len);
diff --git a/monitor/display.c b/monitor/display.c
new file mode 100644 (file)
index 0000000..b8dce1f
--- /dev/null
@@ -0,0 +1,171 @@
+/*
+ *
+ *  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 <signal.h>
+#include <sys/wait.h>
+#include <sys/prctl.h>
+#include <sys/ioctl.h>
+#include <termios.h>
+
+#include "display.h"
+
+static pid_t pager_pid = 0;
+
+bool use_color(void)
+{
+       static int cached_use_color = -1;
+
+       if (__builtin_expect(!!(cached_use_color < 0), 0))
+               cached_use_color = isatty(STDOUT_FILENO) > 0 || pager_pid > 0;
+
+       return cached_use_color;
+}
+
+int num_columns(void)
+{
+       static int cached_num_columns = -1;
+
+       if (__builtin_expect(!!(cached_num_columns < 0), 0)) {
+               struct winsize ws;
+
+               if (ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws) < 0)
+                       return -1;
+
+               if (ws.ws_col > 0)
+                       cached_num_columns = ws.ws_col;
+       }
+
+       return cached_num_columns;
+}
+
+static void close_pipe(int p[])
+{
+       if (p[0] >= 0)
+               close(p[0]);
+       if (p[1] >= 0)
+               close(p[1]);
+}
+
+static void wait_for_terminate(pid_t pid)
+{
+       siginfo_t dummy;
+
+       for (;;) {
+               memset(&dummy, 0, sizeof(dummy));
+
+               if (waitid(P_PID, pid, &dummy, WEXITED) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       return;
+               }
+
+               return;
+       }
+}
+
+void open_pager(void)
+{
+       const char *pager;
+       pid_t parent_pid;
+       int fd[2];
+
+       if (pager_pid > 0)
+               return;
+
+       pager = getenv("PAGER");
+       if (pager) {
+               if (!*pager || strcmp(pager, "cat") == 0)
+                       return;
+       }
+
+       if (!(isatty(STDOUT_FILENO) > 0))
+               return;
+
+       num_columns();
+
+       if (pipe(fd) < 0) {
+               perror("Failed to create pager pipe");
+               return;
+       }
+
+       parent_pid = getpid();
+
+       pager_pid = fork();
+       if (pager_pid < 0) {
+               perror("Failed to fork pager");
+               close_pipe(fd);
+               return;
+       }
+
+       if (pager_pid == 0) {
+               dup2(fd[0], STDIN_FILENO);
+               close_pipe(fd);
+
+               setenv("LESS", "FRSX", 0);
+
+               if (prctl(PR_SET_PDEATHSIG, SIGTERM) < 0)
+                       _exit(EXIT_FAILURE);
+
+               if (getppid() != parent_pid)
+                       _exit(EXIT_SUCCESS);
+
+               if (pager) {
+                       execlp(pager, pager, NULL);
+                       execl("/bin/sh", "sh", "-c", pager, NULL);
+               }
+
+               execlp("pager", "pager", NULL);
+               execlp("less", "less", NULL);
+               execlp("more", "more", NULL);
+
+               _exit(EXIT_FAILURE);
+       }
+
+       if (dup2(fd[1], STDOUT_FILENO) < 0) {
+               perror("Failed to duplicate pager pipe");
+               return;
+       }
+
+       close_pipe(fd);
+}
+
+void close_pager(void)
+{
+       if (pager_pid <= 0)
+               return;
+
+       fclose(stdout);
+       kill(pager_pid, SIGCONT);
+       wait_for_terminate(pager_pid);
+       pager_pid = 0;
+}
diff --git a/monitor/display.h b/monitor/display.h
new file mode 100644 (file)
index 0000000..6139cc2
--- /dev/null
@@ -0,0 +1,60 @@
+/*
+ *
+ *  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>
+
+bool use_color(void);
+
+#define COLOR_OFF      "\x1B[0m"
+#define COLOR_BLACK    "\x1B[0;30m"
+#define COLOR_RED      "\x1B[0;31m"
+#define COLOR_GREEN    "\x1B[0;32m"
+#define COLOR_YELLOW   "\x1B[0;33m"
+#define COLOR_BLUE     "\x1B[0;34m"
+#define COLOR_MAGENTA  "\x1B[0;35m"
+#define COLOR_CYAN     "\x1B[0;36m"
+#define COLOR_WHITE    "\x1B[0;37m"
+#define COLOR_WHITE_BG "\x1B[0;47m"
+#define COLOR_HIGHLIGHT        "\x1B[1;39m"
+
+#define COLOR_ERROR    "\x1B[1;31m"
+
+#define print_indent(indent, color1, prefix, title, color2, fmt, args...) \
+do { \
+       printf("%*c%s%s%s%s" fmt "%s\n", (indent), ' ', \
+               use_color() ? (color1) : "", prefix, title, \
+               use_color() ? (color2) : "", ## args, \
+               use_color() ? COLOR_OFF : ""); \
+} while (0)
+
+#define print_text(color, fmt, args...) \
+               print_indent(8, COLOR_OFF, "", "", color, fmt, ## args)
+
+#define print_field(fmt, args...) \
+               print_indent(8, COLOR_OFF, "", "", COLOR_OFF, fmt, ## args)
+
+int num_columns(void);
+
+void open_pager(void);
+void close_pager(void);
index 373d2f5..9881bb3 100644 (file)
@@ -62,7 +62,7 @@ static int open_hci_dev(uint16_t index)
        struct hci_filter flt;
        int fd, opt = 1;
 
-       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (fd < 0) {
                perror("Failed to open channel");
                return -1;
@@ -108,7 +108,7 @@ static int open_hci_dev(uint16_t index)
 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 buf[HCI_MAX_FRAME_SIZE * 2];
        unsigned char control[64];
        struct msghdr msg;
        struct iovec iov;
@@ -130,7 +130,8 @@ static void device_callback(int fd, uint32_t events, void *user_data)
        while (1) {
                struct cmsghdr *cmsg;
                struct timeval *tv = NULL;
-               int *dir = NULL;
+               struct timeval ctv;
+               int dir = -1;
                ssize_t len;
 
                len = recvmsg(fd, &msg, MSG_DONTWAIT);
@@ -144,15 +145,16 @@ static void device_callback(int fd, uint32_t events, void *user_data)
 
                        switch (cmsg->cmsg_type) {
                        case HCI_DATA_DIR:
-                               dir = (int *) CMSG_DATA(cmsg);
+                               memcpy(&dir, CMSG_DATA(cmsg), sizeof(dir));
                                break;
                        case HCI_CMSG_TSTAMP:
-                               tv = (struct timeval *) CMSG_DATA(cmsg);
+                               memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
+                               tv = &ctv;
                                break;
                        }
                }
 
-               if (!dir || len < 1)
+               if (dir < 0 || len < 1)
                        continue;
 
                switch (buf[0]) {
@@ -163,11 +165,11 @@ static void device_callback(int fd, uint32_t events, void *user_data)
                        packet_hci_event(tv, data->index, buf + 1, len - 1);
                        break;
                case HCI_ACLDATA_PKT:
-                       packet_hci_acldata(tv, data->index, !!(*dir),
+                       packet_hci_acldata(tv, data->index, !!dir,
                                                        buf + 1, len - 1);
                        break;
                case HCI_SCODATA_PKT:
-                       packet_hci_scodata(tv, data->index, !!(*dir),
+                       packet_hci_scodata(tv, data->index, !!dir,
                                                        buf + 1, len - 1);
                        break;
                }
@@ -263,7 +265,7 @@ static int open_stack_internal(void)
        struct hci_filter flt;
        int fd, opt = 1;
 
-       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
        if (fd < 0) {
                perror("Failed to open channel");
                return -1;
@@ -314,6 +316,7 @@ static void stack_internal_callback(int fd, uint32_t events, void *user_data)
        evt_stack_internal *si;
        evt_si_device *sd;
        struct timeval *tv = NULL;
+       struct timeval ctv;
        uint8_t type = 0xff, bus = 0xff;
        char str[18], name[8] = "";
        bdaddr_t bdaddr;
@@ -345,7 +348,8 @@ static void stack_internal_callback(int fd, uint32_t events, void *user_data)
 
                switch (cmsg->cmsg_type) {
                case HCI_CMSG_TSTAMP:
-                       tv = (struct timeval *) CMSG_DATA(cmsg);
+                       memcpy(&ctv, CMSG_DATA(cmsg), sizeof(ctv));
+                       tv = &ctv;
                        break;
                }
        }
diff --git a/monitor/l2cap.c b/monitor/l2cap.c
new file mode 100644 (file)
index 0000000..ad6e64b
--- /dev/null
@@ -0,0 +1,2690 @@
+/*
+ *
+ *  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 <inttypes.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "uuid.h"
+#include "sdp.h"
+
+#define MAX_CHAN 64
+
+struct chan_data {
+       uint16_t index;
+       uint16_t handle;
+       uint16_t scid;
+       uint16_t dcid;
+       uint16_t psm;
+       uint8_t  ctrlid;
+       uint8_t  mode;
+};
+
+static struct chan_data chan_list[MAX_CHAN];
+
+static void assign_scid(const struct l2cap_frame *frame,
+                               uint16_t scid, uint16_t psm, uint8_t ctrlid)
+{
+       int i, n = -1;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (n < 0 && chan_list[i].handle == 0x0000)
+                       n = i;
+
+               if (chan_list[i].index != frame->index)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].dcid == scid) {
+                               n = i;
+                               break;
+                       }
+               } else {
+                       if (chan_list[i].scid == scid) {
+                               n = i;
+                               break;
+                       }
+               }
+       }
+
+       if (n < 0)
+               return;
+
+       memset(&chan_list[n], 0, sizeof(chan_list[n]));
+       chan_list[n].index = frame->index;
+       chan_list[n].handle = frame->handle;
+
+       if (frame->in)
+               chan_list[n].dcid = scid;
+       else
+               chan_list[n].scid = scid;
+
+       chan_list[n].psm = psm;
+       chan_list[n].ctrlid = ctrlid;
+       chan_list[n].mode = 0;
+}
+
+static void release_scid(const struct l2cap_frame *frame, uint16_t scid)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == scid) {
+                               chan_list[i].handle = 0;
+                               break;
+                       }
+               } else {
+                       if (chan_list[i].dcid == scid) {
+                               chan_list[i].handle = 0;
+                               break;
+                       }
+               }
+       }
+}
+
+static void assign_dcid(const struct l2cap_frame *frame,
+                                       uint16_t dcid, uint16_t scid)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == scid) {
+                               chan_list[i].dcid = dcid;
+                               break;
+                       }
+               } else {
+                       if (chan_list[i].dcid == scid) {
+                               chan_list[i].scid = dcid;
+                               break;
+                       }
+               }
+       }
+}
+
+static void assign_mode(const struct l2cap_frame *frame,
+                                       uint8_t mode, uint16_t dcid)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == dcid) {
+                               chan_list[i].mode = mode;
+                               break;
+                       }
+               } else {
+                       if (chan_list[i].dcid == dcid) {
+                               chan_list[i].mode = mode;
+                               break;
+                       }
+               }
+       }
+}
+
+static uint16_t get_psm(const struct l2cap_frame *frame)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index &&
+                                       chan_list[i].ctrlid == 0)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle &&
+                                       chan_list[i].ctrlid != frame->index)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == frame->cid)
+                               return chan_list[i].psm;
+               } else {
+                       if (chan_list[i].dcid == frame->cid)
+                               return chan_list[i].psm;
+               }
+       }
+
+       return 0;
+}
+
+static uint8_t get_mode(const struct l2cap_frame *frame)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index &&
+                                       chan_list[i].ctrlid == 0)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle &&
+                                       chan_list[i].ctrlid != frame->index)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == frame->cid)
+                               return chan_list[i].mode;
+               } else {
+                       if (chan_list[i].dcid == frame->cid)
+                               return chan_list[i].mode;
+               }
+       }
+
+       return 0;
+}
+
+static uint16_t get_chan(const struct l2cap_frame *frame)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHAN; i++) {
+               if (chan_list[i].index != frame->index &&
+                                       chan_list[i].ctrlid == 0)
+                       continue;
+
+               if (chan_list[i].handle != frame->handle &&
+                                       chan_list[i].ctrlid != frame->index)
+                       continue;
+
+               if (frame->in) {
+                       if (chan_list[i].scid == frame->cid)
+                               return i;
+               } else {
+                       if (chan_list[i].dcid == frame->cid)
+                               return i;
+               }
+       }
+
+       return 0;
+}
+
+#define MAX_INDEX 16
+
+struct index_data {
+       void *frag_buf;
+       uint16_t frag_pos;
+       uint16_t frag_len;
+       uint16_t frag_cid;
+};
+
+static struct index_data index_list[MAX_INDEX];
+
+static void clear_fragment_buffer(uint16_t index)
+{
+       free(index_list[index].frag_buf);
+       index_list[index].frag_buf = NULL;
+       index_list[index].frag_pos = 0;
+       index_list[index].frag_len = 0;
+}
+
+static void print_psm(uint16_t psm)
+{
+       print_field("PSM: %d (0x%4.4x)", btohs(psm), btohs(psm));
+}
+
+static void print_cid(const char *type, uint16_t cid)
+{
+       print_field("%s CID: %d", type, btohs(cid));
+}
+
+static void print_reject_reason(uint16_t reason)
+{
+       const char *str;
+
+       switch (btohs(reason)) {
+       case 0x0000:
+               str = "Command not understood";
+               break;
+       case 0x0001:
+               str = "Signaling MTU exceeded";
+               break;
+       case 0x0002:
+               str = "Invalid CID in request";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Reason: %s (0x%4.4x)", str, btohs(reason));
+}
+
+static void print_conn_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Connection successful";
+               break;
+       case 0x0001:
+               str = "Connection pending";
+               break;
+       case 0x0002:
+               str = "Connection refused - PSM not supported";
+               break;
+       case 0x0003:
+               str = "Connection refused - security block";
+               break;
+       case 0x0004:
+               str = "Connection refused - no resources available";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static void print_conn_status(uint16_t status)
+{
+        const char *str;
+
+       switch (btohs(status)) {
+       case 0x0000:
+               str = "No further information available";
+               break;
+       case 0x0001:
+               str = "Authentication pending";
+               break;
+       case 0x0002:
+               str = "Authorization pending";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Status: %s (0x%4.4x)", str, btohs(status));
+}
+
+static void print_config_flags(uint16_t flags)
+{
+       const char *str;
+
+       if (btohs(flags) & 0x0001)
+               str = " (continuation)";
+       else
+               str = "";
+
+       print_field("Flags: 0x%4.4x%s", btohs(flags), str);
+}
+
+static void print_config_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Success";
+               break;
+       case 0x0001:
+               str = "Failure - unacceptable parameters";
+               break;
+       case 0x0002:
+               str = "Failure - rejected";
+               break;
+       case 0x0003:
+               str = "Failure - unknown options";
+               break;
+       case 0x0004:
+               str = "Pending";
+               break;
+       case 0x0005:
+               str = "Failure - flow spec rejected";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static struct {
+       uint8_t type;
+       uint8_t len;
+       const char *str;
+} options_table[] = {
+       { 0x01,  2, "Maximum Transmission Unit"         },
+       { 0x02,  2, "Flush Timeout"                     },
+       { 0x03, 22, "Quality of Service"                },
+       { 0x04,  9, "Retransmission and Flow Control"   },
+       { 0x05,  1, "Frame Check Sequence"              },
+       { 0x06, 16, "Extended Flow Specification"       },
+       { 0x07,  2, "Extended Window Size"              },
+        { }
+};
+
+static void print_config_options(const struct l2cap_frame *frame,
+                               uint8_t offset, uint16_t dcid, bool response)
+{
+       const uint8_t *data = frame->data + offset;
+       uint16_t size = frame->size - offset;
+       uint16_t consumed = 0;
+
+       while (consumed < size - 2) {
+               const char *str = "Unknown";
+               uint8_t type = data[consumed];
+               uint8_t len = data[consumed + 1];
+               uint8_t expect_len = 0;
+               int i;
+
+               for (i = 0; options_table[i].str; i++) {
+                       if (options_table[i].type == type) {
+                               str = options_table[i].str;
+                               expect_len = options_table[i].len;
+                               break;
+                       }
+               }
+
+               print_field("Option: %s (0x%2.2x)", str, type);
+
+               if (expect_len == 0) {
+                       consumed += 2;
+                       break;
+               }
+
+               if (len != expect_len) {
+                       print_text(COLOR_ERROR, "wrong option size (%d != %d)",
+                                                       len, expect_len);
+                       consumed += 2;
+                       break;
+               }
+
+               switch (type) {
+               case 0x01:
+                       print_field("  MTU: %d",
+                                       bt_get_le16(data + consumed + 2));
+                       break;
+               case 0x02:
+                       print_field("  Flush timeout: %d",
+                                       bt_get_le16(data + consumed + 2));
+                       break;
+               case 0x03:
+                       switch (data[consumed + 3]) {
+                       case 0x00:
+                               str = "No Traffic";
+                               break;
+                       case 0x01:
+                               str = "Best Effort";
+                               break;
+                       case 0x02:
+                               str = "Guaranteed";
+                               break;
+                       default:
+                               str = "Reserved";
+                               break;
+                       }
+                       print_field("  Flags: 0x%2.2x", data[consumed + 2]);
+                       print_field("  Service type: %s (0x%2.2x)",
+                                               str, data[consumed + 3]);
+                       print_field("  Token rate: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 4));
+                       print_field("  Token bucket size: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 8));
+                       print_field("  Peak bandwidth: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 12));
+                       print_field("  Latency: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 16));
+                       print_field("  Delay variation: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 20));
+                        break;
+               case 0x04:
+                       if (response)
+                               assign_mode(frame, data[consumed + 2], dcid);
+
+                       switch (data[consumed + 2]) {
+                       case 0x00:
+                               str = "Basic";
+                               break;
+                       case 0x01:
+                               str = "Retransmission";
+                               break;
+                       case 0x02:
+                               str = "Flow control";
+                               break;
+                       case 0x03:
+                               str = "Enhanced retransmission";
+                               break;
+                       case 0x04:
+                               str = "Streaming";
+                               break;
+                       default:
+                               str = "Reserved";
+                               break;
+                       }
+                       print_field("  Mode: %s (0x%2.2x)",
+                                               str, data[consumed + 2]);
+                       print_field("  TX window size: %d", data[consumed + 3]);
+                       print_field("  Max transmit: %d", data[consumed + 4]);
+                       print_field("  Retransmission timeout: %d",
+                                       bt_get_le16(data + consumed + 5));
+                       print_field("  Monitor timeout: %d",
+                                       bt_get_le16(data + consumed + 7));
+                       print_field("  Maximum PDU size: %d",
+                                       bt_get_le16(data + consumed + 9));
+                       break;
+               case 0x05:
+                       switch (data[consumed + 2]) {
+                       case 0x00:
+                               str = "No FCS";
+                               break;
+                       case 0x01:
+                               str = "16-bit FCS";
+                               break;
+                       default:
+                               str = "Reserved";
+                               break;
+                       }
+                       print_field("  FCS: %s (0x%2.2d)",
+                                               str, data[consumed + 2]);
+                       break;
+               case 0x06:
+                       switch (data[consumed + 3]) {
+                       case 0x00:
+                               str = "No traffic";
+                               break;
+                       case 0x01:
+                               str = "Best effort";
+                               break;
+                       case 0x02:
+                               str = "Guaranteed";
+                               break;
+                       default:
+                               str = "Reserved";
+                               break;
+                       }
+                       print_field("  Identifier: 0x%2.2x",
+                                               data[consumed + 2]);
+                       print_field("  Service type: %s (0x%2.2x)",
+                                               str, data[consumed + 3]);
+                       print_field("  Maximum SDU size: 0x%4.4x",
+                                       bt_get_le16(data + consumed + 4));
+                       print_field("  SDU inter-arrival time: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 6));
+                       print_field("  Access latency: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 10));
+                       print_field("  Flush timeout: 0x%8.8x",
+                                       bt_get_le32(data + consumed + 14));
+                       break;
+               case 0x07:
+                       print_field("  Max window size: %d",
+                                       bt_get_le16(data + consumed + 2));
+                       break;
+               default:
+                       packet_hexdump(data + consumed + 2, len);
+                       break;
+               }
+
+               consumed += len + 2;
+       }
+
+       if (consumed < size)
+               packet_hexdump(data + consumed, size - consumed);
+}
+
+static void print_info_type(uint16_t type)
+{
+       const char *str;
+
+       switch (btohs(type)) {
+       case 0x0001:
+               str = "Connectionless MTU";
+               break;
+       case 0x0002:
+               str = "Extended features supported";
+               break;
+       case 0x0003:
+               str = "Fixed channels supported";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%4.4x)", str, btohs(type));
+}
+
+static void print_info_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Success";
+               break;
+       case 0x0001:
+               str = "Not supported";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static struct {
+       uint8_t bit;
+       const char *str;
+} features_table[] = {
+       {  0, "Flow control mode"                       },
+       {  1, "Retransmission mode"                     },
+       {  2, "Bi-directional QoS"                      },
+       {  3, "Enhanced Retransmission Mode"            },
+       {  4, "Streaming Mode"                          },
+       {  5, "FCS Option"                              },
+       {  6, "Extended Flow Specification for BR/EDR"  },
+       {  7, "Fixed Channels"                          },
+       {  8, "Extended Window Size"                    },
+       {  9, "Unicast Connectionless Data Reception"   },
+       { 31, "Reserved for feature mask extension"     },
+       { }
+};
+
+static void print_features(uint32_t features)
+{
+       uint32_t mask = features;
+       int i;
+
+       print_field("Features: 0x%8.8x", features);
+
+       for (i = 0; features_table[i].str; i++) {
+               if (features & (1 << features_table[i].bit)) {
+                       print_field("  %s", features_table[i].str);
+                       mask &= ~(1 << features_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_field("  Unknown features (0x%8.8x)", mask);
+}
+
+static struct {
+       uint16_t cid;
+       const char *str;
+} channels_table[] = {
+       { 0x0000, "Null identifier"             },
+       { 0x0001, "L2CAP Signaling (BR/EDR)"    },
+       { 0x0002, "Connectionless reception"    },
+       { 0x0003, "AMP Manager Protocol"        },
+       { 0x0004, "Attribute Protocol"          },
+       { 0x0005, "L2CAP Signaling (LE)"        },
+       { 0x0006, "Security Manager"            },
+       { 0x003f, "AMP Test Manager"            },
+       { }
+};
+
+static void print_channels(uint64_t channels)
+{
+       uint64_t mask = channels;
+       int i;
+
+       print_field("Channels: 0x%16.16" PRIx64, channels);
+
+       for (i = 0; channels_table[i].str; i++) {
+               if (channels & (1 << channels_table[i].cid)) {
+                       print_field("  %s", channels_table[i].str);
+                       mask &= ~(1 << channels_table[i].cid);
+               }
+       }
+
+       if (mask)
+               print_field("  Unknown channels (0x%8.8" PRIx64 ")", mask);
+}
+
+static void print_move_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Move success";
+               break;
+       case 0x0001:
+               str = "Move pending";
+               break;
+       case 0x0002:
+               str = "Move refused - Controller ID not supported";
+               break;
+       case 0x0003:
+               str = "Move refused - new Controller ID is same";
+               break;
+       case 0x0004:
+               str = "Move refused - Configuration not supported";
+               break;
+       case 0x0005:
+               str = "Move refused - Move Channel collision";
+               break;
+       case 0x0006:
+               str = "Move refused - Channel not allowed to be moved";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static void print_move_cfm_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Move success - both sides succeed";
+               break;
+       case 0x0001:
+               str = "Move failure - one or both sides refuse";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static void print_conn_param_result(uint16_t result)
+{
+       const char *str;
+
+       switch (btohs(result)) {
+       case 0x0000:
+               str = "Connection Parameters accepted";
+               break;
+       case 0x0001:
+               str = "Connection Parameters rejected";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Result: %s (0x%4.4x)", str, btohs(result));
+}
+
+static void sig_cmd_reject(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_cmd_reject *pdu = frame->data;
+       const void *data = frame->data;
+       uint16_t size = frame->size;
+       uint16_t scid, dcid;
+
+       print_reject_reason(pdu->reason);
+
+       data += sizeof(*pdu);
+       size -= sizeof(*pdu);
+
+       switch (btohs(pdu->reason)) {
+       case 0x0000:
+               if (size != 0) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               break;
+       case 0x0001:
+               if (size != 2) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               print_field("MTU: %d", bt_get_le16(data));
+               break;
+       case 0x0002:
+               if (size != 4) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               dcid = bt_get_le16(data);
+               scid = bt_get_le16(data + 2);
+               print_cid("Destination", htobs(dcid));
+               print_cid("Source", htobs(scid));
+               break;
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void sig_conn_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_conn_req *pdu = frame->data;
+
+       print_psm(pdu->psm);
+       print_cid("Source", pdu->scid);
+
+       assign_scid(frame, btohs(pdu->scid), btohs(pdu->psm), 0);
+}
+
+static void sig_conn_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_conn_rsp *pdu = frame->data;
+
+       print_cid("Destination", pdu->dcid);
+       print_cid("Source", pdu->scid);
+       print_conn_result(pdu->result);
+       print_conn_status(pdu->status);
+
+       assign_dcid(frame, btohs(pdu->dcid), btohs(pdu->scid));
+}
+
+static void sig_config_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_config_req *pdu = frame->data;
+
+       print_cid("Destination", pdu->dcid);
+       print_config_flags(pdu->flags);
+       print_config_options(frame, 4, btohs(pdu->dcid), false);
+}
+
+static void sig_config_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_config_rsp *pdu = frame->data;
+
+       print_cid("Source", pdu->scid);
+       print_config_flags(pdu->flags);
+       print_config_result(pdu->result);
+       print_config_options(frame, 6, btohs(pdu->scid), true);
+}
+
+static void sig_disconn_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_disconn_req *pdu = frame->data;
+
+       print_cid("Destination", pdu->dcid);
+       print_cid("Source", pdu->scid);
+}
+
+static void sig_disconn_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_disconn_rsp *pdu = frame->data;
+
+       print_cid("Destination", pdu->dcid);
+       print_cid("Source", pdu->scid);
+
+       release_scid(frame, btohs(pdu->scid));
+}
+
+static void sig_echo_req(const struct l2cap_frame *frame)
+{
+       packet_hexdump(frame->data, frame->size);
+}
+
+static void sig_echo_rsp(const struct l2cap_frame *frame)
+{
+       packet_hexdump(frame->data, frame->size);
+}
+
+static void sig_info_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_info_req *pdu = frame->data;
+
+       print_info_type(pdu->type);
+}
+
+static void sig_info_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_info_rsp *pdu = frame->data;
+       const void *data = frame->data;
+       uint16_t size = frame->size;
+
+       print_info_type(pdu->type);
+       print_info_result(pdu->result);
+
+       data += sizeof(*pdu);
+       size -= sizeof(*pdu);
+
+       if (btohs(pdu->result) != 0x0000) {
+               if (size > 0) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+               }
+               return;
+       }
+
+       switch (btohs(pdu->type)) {
+       case 0x0001:
+               if (size != 2) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               print_field("MTU: %d", bt_get_le16(data));
+               break;
+       case 0x0002:
+               if (size != 4) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               print_features(bt_get_le32(data));
+               break;
+       case 0x0003:
+               if (size != 8) {
+                       print_text(COLOR_ERROR, "invalid data size");
+                       packet_hexdump(data, size);
+                       break;
+               }
+               print_channels(bt_get_le64(data));
+               break;
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void sig_create_chan_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_create_chan_req *pdu = frame->data;
+
+       print_psm(pdu->psm);
+       print_cid("Source", pdu->scid);
+       print_field("Controller ID: %d", pdu->ctrlid);
+
+       assign_scid(frame, btohs(pdu->scid), btohs(pdu->psm), pdu->ctrlid);
+}
+
+static void sig_create_chan_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_create_chan_rsp *pdu = frame->data;
+
+       print_cid("Destination", pdu->dcid);
+       print_cid("Source", pdu->scid);
+       print_conn_result(pdu->result);
+       print_conn_status(pdu->status);
+
+       assign_dcid(frame, btohs(pdu->dcid), btohs(pdu->scid));
+}
+
+static void sig_move_chan_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_move_chan_req *pdu = frame->data;
+
+       print_cid("Initiator", pdu->icid);
+       print_field("Controller ID: %d", pdu->ctrlid);
+}
+
+static void sig_move_chan_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_move_chan_rsp *pdu = frame->data;
+
+       print_cid("Initiator", pdu->icid);
+       print_move_result(pdu->result);
+}
+
+static void sig_move_chan_cfm(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_move_chan_cfm *pdu = frame->data;
+
+       print_cid("Initiator", pdu->icid);
+       print_move_cfm_result(pdu->result);
+}
+
+static void sig_move_chan_cfm_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_move_chan_cfm_rsp *pdu = frame->data;
+
+       print_cid("Initiator", pdu->icid);
+}
+
+static void sig_conn_param_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_conn_param_req *pdu = frame->data;
+
+       print_field("Min interval: %d", btohs(pdu->min_interval));
+       print_field("Max interval: %d", btohs(pdu->max_interval));
+       print_field("Slave latency: %d", btohs(pdu->latency));
+       print_field("Timeout multiplier: %d", btohs(pdu->timeout));
+}
+
+static void sig_conn_param_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_pdu_conn_param_rsp *pdu = frame->data;
+
+       print_conn_param_result(pdu->result);
+}
+
+struct sig_opcode_data {
+       uint8_t opcode;
+       const char *str;
+       void (*func) (const struct l2cap_frame *frame);
+       uint16_t size;
+       bool fixed;
+};
+
+static const struct sig_opcode_data bredr_sig_opcode_table[] = {
+       { 0x01, "Command Reject",
+                       sig_cmd_reject, 2, false },
+       { 0x02, "Connection Request",
+                       sig_conn_req, 4, true },
+       { 0x03, "Connection Response",
+                       sig_conn_rsp, 8, true },
+       { 0x04, "Configure Request",
+                       sig_config_req, 4, false },
+       { 0x05, "Configure Response",
+                       sig_config_rsp, 6, false },
+       { 0x06, "Disconnection Request",
+                       sig_disconn_req, 4, true },
+       { 0x07, "Disconnection Response",
+                       sig_disconn_rsp, 4, true },
+       { 0x08, "Echo Request",
+                       sig_echo_req, 0, false },
+       { 0x09, "Echo Response",
+                       sig_echo_rsp, 0, false },
+       { 0x0a, "Information Request",
+                       sig_info_req, 2, true },
+       { 0x0b, "Information Response",
+                       sig_info_rsp, 4, false },
+       { 0x0c, "Create Channel Request",
+                       sig_create_chan_req, 5, true },
+       { 0x0d, "Create Channel Response",
+                       sig_create_chan_rsp, 8, true },
+       { 0x0e, "Move Channel Request",
+                       sig_move_chan_req, 3, true },
+       { 0x0f, "Move Channel Response",
+                       sig_move_chan_rsp, 4, true },
+       { 0x10, "Move Channel Confirmation",
+                       sig_move_chan_cfm, 4, true },
+       { 0x11, "Move Channel Confirmation Response",
+                       sig_move_chan_cfm_rsp, 2, true },
+       { },
+};
+
+static const struct sig_opcode_data le_sig_opcode_table[] = {
+       { 0x01, "Command Reject",
+                       sig_cmd_reject, 2, false },
+       { 0x12, "Connection Parameter Update Request",
+                       sig_conn_param_req, 8, true },
+       { 0x13, "Connection Parameter Update Response",
+                       sig_conn_param_rsp, 2, true },
+       { },
+};
+
+static void bredr_sig_packet(uint16_t index, bool in, uint16_t handle,
+                               uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+
+       while (size > 0) {
+               const struct bt_l2cap_hdr_sig *hdr = data;
+               const struct sig_opcode_data *opcode_data = NULL;
+               const char *opcode_color, *opcode_str;
+               uint16_t len;
+               int i;
+
+               if (size < 4) {
+                       print_text(COLOR_ERROR, "malformed signal packet");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               len = btohs(hdr->len);
+
+               data += 4;
+               size -= 4;
+
+               if (size < len) {
+                       print_text(COLOR_ERROR, "invalid signal packet size");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               for (i = 0; bredr_sig_opcode_table[i].str; i++) {
+                       if (bredr_sig_opcode_table[i].opcode == hdr->code) {
+                               opcode_data = &bredr_sig_opcode_table[i];
+                               break;
+                       }
+               }
+
+               if (opcode_data) {
+                       if (opcode_data->func) {
+                               if (in)
+                                       opcode_color = COLOR_MAGENTA;
+                               else
+                                       opcode_color = COLOR_BLUE;
+                       } else
+                               opcode_color = COLOR_WHITE_BG;
+                       opcode_str = opcode_data->str;
+               } else {
+                       opcode_color = COLOR_WHITE_BG;
+                       opcode_str = "Unknown";
+               }
+
+               print_indent(6, opcode_color, "L2CAP: ", opcode_str,
+                                       COLOR_OFF,
+                                       " (0x%2.2x) ident %d len %d",
+                                       hdr->code, hdr->ident, len);
+
+               if (!opcode_data || !opcode_data->func) {
+                       packet_hexdump(data, len);
+                       data += len;
+                       size -= len;
+                       return;
+               }
+
+               if (opcode_data->fixed) {
+                       if (len != opcode_data->size) {
+                               print_text(COLOR_ERROR, "invalid size");
+                               packet_hexdump(data, len);
+                               data += len;
+                               size -= len;
+                               continue;
+                       }
+               } else {
+                       if (len < opcode_data->size) {
+                               print_text(COLOR_ERROR, "too short packet");
+                               packet_hexdump(data, size);
+                               data += len;
+                               size -= len;
+                               continue;
+                       }
+               }
+
+               l2cap_frame_init(&frame, index, in, handle, cid, data, len);
+               opcode_data->func(&frame);
+
+               data += len;
+               size -= len;
+       }
+
+       packet_hexdump(data, size);
+}
+
+static void le_sig_packet(uint16_t index, bool in, uint16_t handle,
+                               uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       const struct bt_l2cap_hdr_sig *hdr = data;
+       const struct sig_opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       uint16_t len;
+       int i;
+
+       if (size < 4) {
+               print_text(COLOR_ERROR, "malformed signal packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       len = btohs(hdr->len);
+
+       data += 4;
+       size -= 4;
+
+       if (size != len) {
+               print_text(COLOR_ERROR, "invalid signal packet size");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       for (i = 0; le_sig_opcode_table[i].str; i++) {
+               if (le_sig_opcode_table[i].opcode == hdr->code) {
+                       opcode_data = &le_sig_opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->func) {
+                       if (in)
+                               opcode_color = COLOR_MAGENTA;
+                       else
+                               opcode_color = COLOR_BLUE;
+               } else
+                       opcode_color = COLOR_WHITE_BG;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_WHITE_BG;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "LE L2CAP: ", opcode_str, COLOR_OFF,
+                                       " (0x%2.2x) ident %d len %d",
+                                       hdr->code, hdr->ident, len);
+
+       if (!opcode_data || !opcode_data->func) {
+               packet_hexdump(data, len);
+               return;
+       }
+
+       if (opcode_data->fixed) {
+               if (len != opcode_data->size) {
+                       print_text(COLOR_ERROR, "invalid size");
+                       packet_hexdump(data, len);
+                       return;
+               }
+       } else {
+               if (len < opcode_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data, size);
+                       return;
+               }
+       }
+
+       l2cap_frame_init(&frame, index, in, handle, cid, data, len);
+       opcode_data->func(&frame);
+}
+
+static void connless_packet(uint16_t index, bool in, uint16_t handle,
+                               uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       const struct bt_l2cap_hdr_connless *hdr = data;
+       uint16_t psm;
+
+       if (size < 2) {
+               print_text(COLOR_ERROR, "malformed connectionless packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       psm = btohs(hdr->psm);
+
+       data += 2;
+       size -= 2;
+
+       print_indent(6, COLOR_CYAN, "L2CAP: Connectionless", "", COLOR_OFF,
+                                               " len %d [PSM %d]", size, psm);
+
+       switch (psm) {
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+
+       l2cap_frame_init(&frame, index, in, handle, cid, data, size);
+}
+
+static void print_controller_list(const uint8_t *data, uint16_t size)
+{
+       while (size > 2) {
+               const char *str;
+
+               print_field("Controller ID: %d", data[0]);
+
+               switch (data[1]) {
+               case 0x00:
+                       str = "Primary BR/EDR Controller";
+                       break;
+               case 0x01:
+                       str = "802.11 AMP Controller";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("  Type: %s (0x%2.2x)", str, data[1]);
+
+               switch (data[2]) {
+               case 0x00:
+                       str = "Present";
+                       break;
+               case 0x01:
+                       str = "Bluetooth only";
+                       break;
+               case 0x02:
+                       str = "No capacity";
+                       break;
+               case 0x03:
+                       str = "Low capacity";
+                       break;
+               case 0x04:
+                       str = "Medium capacity";
+                       break;
+               case 0x05:
+                       str = "High capacity";
+                       break;
+               case 0x06:
+                       str = "Full capacity";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("  Status: %s (0x%2.2x)", str, data[2]);
+
+               data += 3;
+               size -= 3;
+       }
+
+       packet_hexdump(data, size);
+}
+
+static void amp_cmd_reject(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_cmd_reject *pdu = frame->data;
+
+       print_field("Reason: 0x%4.4x", btohs(pdu->reason));
+}
+
+static void amp_discover_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_discover_req *pdu = frame->data;
+
+       print_field("MTU/MPS size: %d", btohs(pdu->size));
+       print_field("Extended feature mask: 0x%4.4x", btohs(pdu->features));
+}
+
+static void amp_discover_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_discover_rsp *pdu = frame->data;
+
+       print_field("MTU/MPS size: %d", btohs(pdu->size));
+       print_field("Extended feature mask: 0x%4.4x", btohs(pdu->features));
+
+       print_controller_list(frame->data + 4, frame->size - 4);
+}
+
+static void amp_change_notify(const struct l2cap_frame *frame)
+{
+       print_controller_list(frame->data, frame->size);
+}
+
+static void amp_change_response(const struct l2cap_frame *frame)
+{
+}
+
+static void amp_get_info_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_get_info_req *pdu = frame->data;
+
+       print_field("Controller ID: %d", pdu->ctrlid);
+}
+
+static void amp_get_info_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_get_info_rsp *pdu = frame->data;
+       const char *str;
+
+       print_field("Controller ID: %d", pdu->ctrlid);
+
+       switch (pdu->status) {
+       case 0x00:
+               str = "Success";
+               break;
+       case 0x01:
+               str = "Invalid Controller ID";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Status: %s (0x%2.2x)", str, pdu->status);
+
+       print_field("Total bandwidth: %d kbps", btohl(pdu->total_bw));
+       print_field("Max guaranteed bandwidth: %d kbps", btohl(pdu->max_bw));
+       print_field("Min latency: %d", btohl(pdu->min_latency));
+
+       print_field("PAL capabilities: 0x%4.4x", btohs(pdu->pal_cap));
+       print_field("Max ASSOC length: %d", btohs(pdu->max_assoc_len));
+}
+
+static void amp_get_assoc_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_get_assoc_req *pdu = frame->data;
+
+       print_field("Controller ID: %d", pdu->ctrlid);
+}
+
+static void amp_get_assoc_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_get_assoc_rsp *pdu = frame->data;
+       const char *str;
+
+       print_field("Controller ID: %d", pdu->ctrlid);
+
+       switch (pdu->status) {
+       case 0x00:
+               str = "Success";
+               break;
+       case 0x01:
+               str = "Invalid Controller ID";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Status: %s (0x%2.2x)", str, pdu->status);
+
+       packet_hexdump(frame->data + 2, frame->size - 2);
+}
+
+static void amp_create_phy_link_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_create_phy_link_req *pdu = frame->data;
+
+       print_field("Local controller ID: %d", pdu->local_ctrlid);
+       print_field("Remote controller ID: %d", pdu->remote_ctrlid);
+
+       packet_hexdump(frame->data + 2, frame->size - 2);
+}
+
+static void amp_create_phy_link_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_create_phy_link_rsp *pdu = frame->data;
+       const char *str;
+
+       print_field("Local controller ID: %d", pdu->local_ctrlid);
+       print_field("Remote controller ID: %d", pdu->remote_ctrlid);
+
+       switch (pdu->status) {
+       case 0x00:
+               str = "Success";
+               break;
+       case 0x01:
+               str = "Invalid Controller ID";
+               break;
+       case 0x02:
+               str = "Failed - Unable to start link creation";
+               break;
+       case 0x03:
+               str = "Failed - Collision occurred";
+               break;
+       case 0x04:
+               str = "Failed - Disconnected link packet received";
+               break;
+       case 0x05:
+               str = "Failed - Link already exists";
+               break;
+       case 0x06:
+               str = "Failed - Security violation";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Status: %s (0x%2.2x)", str, pdu->status);
+}
+
+static void amp_disconn_phy_link_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_disconn_phy_link_req *pdu = frame->data;
+
+       print_field("Local controller ID: %d", pdu->local_ctrlid);
+       print_field("Remote controller ID: %d", pdu->remote_ctrlid);
+}
+
+static void amp_disconn_phy_link_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_amp_disconn_phy_link_rsp *pdu = frame->data;
+       const char *str;
+
+       print_field("Local controller ID: %d", pdu->local_ctrlid);
+       print_field("Remote controller ID: %d", pdu->remote_ctrlid);
+
+       switch (pdu->status) {
+       case 0x00:
+               str = "Success";
+               break;
+       case 0x01:
+               str = "Invalid Controller ID";
+               break;
+       case 0x02:
+               str = "Failed - No link exists";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Status: %s (0x%2.2x)", str, pdu->status);
+}
+
+struct amp_opcode_data {
+       uint8_t opcode;
+       const char *str;
+       void (*func) (const struct l2cap_frame *frame);
+       uint16_t size;
+       bool fixed;
+};
+
+static const struct amp_opcode_data amp_opcode_table[] = {
+       { 0x01, "Command Reject",
+                       amp_cmd_reject, 2, false },
+       { 0x02, "Discover Request",
+                       amp_discover_req, 4, true },
+       { 0x03, "Discover Response",
+                       amp_discover_rsp, 7, false },
+       { 0x04, "Change Notify",
+                       amp_change_notify, 3, false },
+       { 0x05, "Change Response",
+                       amp_change_response, 0, true },
+       { 0x06, "Get Info Request",
+                       amp_get_info_req, 1, true },
+       { 0x07, "Get Info Response",
+                       amp_get_info_rsp, 18, true },
+       { 0x08, "Get Assoc Request",
+                       amp_get_assoc_req, 1, true },
+       { 0x09, "Get Assoc Response",
+                       amp_get_assoc_rsp, 2, false },
+       { 0x0a, "Create Physical Link Request",
+                       amp_create_phy_link_req, 2, false },
+       { 0x0b, "Create Physical Link Response",
+                       amp_create_phy_link_rsp, 3, true },
+       { 0x0c, "Disconnect Physical Link Request",
+                       amp_disconn_phy_link_req, 2, true },
+       { 0x0d, "Disconnect Physical Link Response",
+                       amp_disconn_phy_link_rsp, 3, true },
+       { },
+};
+
+static void amp_packet(uint16_t index, bool in, uint16_t handle,
+                       uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       uint16_t control, fcs, len;
+       uint8_t opcode, ident;
+       const struct amp_opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       if (size < 4) {
+               print_text(COLOR_ERROR, "malformed info frame packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       control = bt_get_le16(data);
+       fcs = bt_get_le16(data + size - 2);
+
+       print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
+                               " %d dlen %d control 0x%4.4x fcs 0x%4.4x",
+                                               3, size, control, fcs);
+
+       if (control & 0x01)
+               return;
+
+       if (size < 8) {
+               print_text(COLOR_ERROR, "malformed manager packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       opcode = *((const uint8_t *) (data + 2));
+       ident = *((const uint8_t *) (data + 3));
+       len = bt_get_le16(data + 4);
+
+       if (len != size - 8) {
+               print_text(COLOR_ERROR, "invalid manager packet size");
+               packet_hexdump(data +  2, size - 4);
+               return;
+       }
+
+       for (i = 0; amp_opcode_table[i].str; i++) {
+               if (amp_opcode_table[i].opcode == opcode) {
+                       opcode_data = &amp_opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->func) {
+                       if (in)
+                               opcode_color = COLOR_MAGENTA;
+                       else
+                               opcode_color = COLOR_BLUE;
+               } else
+                       opcode_color = COLOR_WHITE_BG;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_WHITE_BG;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "AMP: ", opcode_str, COLOR_OFF,
+                       " (0x%2.2x) ident %d len %d", opcode, ident, len);
+
+       if (!opcode_data || !opcode_data->func) {
+               packet_hexdump(data + 6, size - 8);
+               return;
+       }
+
+       if (opcode_data->fixed) {
+               if (len != opcode_data->size) {
+                       print_text(COLOR_ERROR, "invalid size");
+                       packet_hexdump(data + 6, size - 8);
+                       return;
+               }
+       } else {
+               if (len < opcode_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 6, size - 8);
+                       return;
+               }
+       }
+
+       l2cap_frame_init(&frame, index, in, handle, cid, data + 6, len);
+       opcode_data->func(&frame);
+}
+
+static void print_hex_field(const char *label, const uint8_t *data,
+                                                               uint8_t len)
+{
+       char str[len * 2 + 1];
+       uint8_t i;
+
+       str[0] = '\0';
+
+       for (i = 0; i < len; i++)
+               sprintf(str + (i * 2), "%2.2x", data[i]);
+
+       print_field("%s: %s", label, str);
+}
+
+static void print_uuid(const char *label, const void *data, uint16_t size)
+{
+       const char *str;
+
+       switch (size) {
+       case 2:
+               str = uuid16_to_str(bt_get_le16(data));
+               print_field("%s: %s (0x%4.4x)", label, str, bt_get_le16(data));
+               break;
+       case 4:
+               str = uuid32_to_str(bt_get_le32(data));
+               print_field("%s: %s (0x%8.8x)", label, str, bt_get_le32(data));
+               break;
+       case 16:
+               str = uuid128_to_str(data);
+               print_field("%s: %s (%8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x)",
+                               label, str,
+                               bt_get_le32(data + 12), bt_get_le16(data + 10),
+                               bt_get_le16(data + 8), bt_get_le16(data + 6),
+                               bt_get_le32(data + 2), bt_get_le16(data + 0));
+               break;
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void print_handle_range(const char *label, const void *data)
+{
+       print_field("%s: 0x%4.4x-0x%4.4x", label,
+                               bt_get_le16(data), bt_get_le16(data + 2));
+}
+
+static void print_data_list(const char *label, uint8_t length,
+                                       const void *data, uint16_t size)
+{
+       uint8_t count;
+
+       if (length == 0)
+               return;
+
+       count = size / length;
+
+       print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");
+
+       while (size >= length) {
+               print_field("Handle: 0x%4.4x", bt_get_le16(data));
+               print_hex_field("Value", data + 2, length - 2);
+
+               data += length;
+               size -= length;
+       }
+
+       packet_hexdump(data, size);
+}
+
+static void print_attribute_info(uint16_t type, const void *data, uint16_t len)
+{
+       const char *str = uuid16_to_str(type);
+
+       print_field("%s: %s (0x%4.4x)", "Attribute type", str, type);
+
+       switch (type) {
+       case 0x2800:    /* Primary Service */
+       case 0x2801:    /* Secondary Service */
+               print_uuid("  UUID", data, len);
+               break;
+       case 0x2802:    /* Include */
+               if (len < 4) {
+                       print_hex_field("  Value", data, len);
+                       break;
+               }
+               print_handle_range("  Handle range", data);
+               print_uuid("  UUID", data + 4, len - 4);
+               break;
+       case 0x2803:    /* Characteristic */
+               if (len < 3) {
+                       print_hex_field("  Value", data, len);
+                       break;
+               }
+               print_field("  Properties: 0x%2.2x", *((uint8_t *) data));
+               print_field("  Handle: 0x%2.2x", bt_get_le16(data + 1));
+               print_uuid("  UUID", data + 3, len - 3);
+               break;
+       default:
+               print_hex_field("Value", data, len);
+               break;
+       }
+}
+
+static const char *att_opcode_to_str(uint8_t opcode);
+
+static void att_error_response(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_error_response *pdu = frame->data;
+       const char *str;
+
+       switch (pdu->error) {
+       case 0x01:
+               str = "Invalid Handle";
+               break;
+       case 0x02:
+               str = "Read Not Permitted";
+               break;
+       case 0x03:
+               str = "Write Not Permitted";
+               break;
+       case 0x04:
+               str = "Invalid PDU";
+               break;
+       case 0x05:
+               str = "Insufficient Authentication";
+               break;
+       case 0x06:
+               str = "Request Not Supported";
+               break;
+       case 0x07:
+               str = "Invalid Offset";
+               break;
+       case 0x08:
+               str = "Insufficient Authorization";
+               break;
+       case 0x09:
+               str = "Prepare Queue Full";
+               break;
+       case 0x0a:
+               str = "Attribute Not Found";
+               break;
+       case 0x0b:
+               str = "Attribute Not Long";
+               break;
+       case 0x0c:
+               str = "Insufficient Encryption Key Size";
+               break;
+       case 0x0d:
+               str = "Invalid Attribute Value Length";
+               break;
+       case 0x0e:
+               str = "Unlikely Error";
+               break;
+       case 0x0f:
+               str = "Insufficient Encryption";
+               break;
+       case 0x10:
+               str = "Unsupported Group Type";
+               break;
+       case 0x11:
+               str = "Insufficient Resources";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("%s (0x%2.2x)", att_opcode_to_str(pdu->request),
+                                                       pdu->request);
+       print_field("Handle: 0x%4.4x", btohs(pdu->handle));
+       print_field("Error: %s (0x%2.2x)", str, pdu->error);
+}
+
+static void att_exchange_mtu_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_exchange_mtu_req *pdu = frame->data;
+
+       print_field("Client RX MTU: %d", btohs(pdu->mtu));
+}
+
+static void att_exchange_mtu_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_exchange_mtu_rsp *pdu = frame->data;
+
+       print_field("Server RX MTU: %d", btohs(pdu->mtu));
+}
+
+static void att_find_info_req(const struct l2cap_frame *frame)
+{
+       print_handle_range("Handle range", frame->data);
+}
+
+static const char *att_format_str(uint8_t format)
+{
+       switch (format) {
+       case 0x01:
+               return "UUID-16";
+       case 0x02:
+               return "UUID-128";
+       default:
+               return "unknown";
+       }
+}
+
+static uint16_t print_info_data_16(const uint16_t *data, uint16_t len)
+{
+       while (len >= 4) {
+               print_field("Handle: 0x%4.4x", bt_get_le16(data));
+               print_uuid("UUID", data + 2, 2);
+               data += 4;
+               len -= 4;
+       }
+
+       return len;
+}
+
+static uint16_t print_info_data_128(const uint16_t *data, uint16_t len)
+{
+       while (len >= 18) {
+               print_field("Handle: 0x%4.4x", bt_get_le16(data));
+               print_uuid("UUID", data + 2, 16);
+               data += 18;
+               len -= 18;
+       }
+
+       return len;
+}
+
+static void att_find_info_rsp(const struct l2cap_frame *frame)
+{
+       const uint8_t *format = frame->data;
+       uint16_t len;
+
+       print_field("Format: %s (0x%2.2x)", att_format_str(*format), *format);
+
+       if (*format == 0x01)
+               len = print_info_data_16(frame->data + 1, frame->size - 1);
+       else if (*format == 0x02)
+               len = print_info_data_128(frame->data + 1, frame->size - 1);
+       else
+               len = frame->size - 1;
+
+       packet_hexdump(frame->data + (frame->size - len), len);
+}
+
+static void att_find_by_type_val_req(const struct l2cap_frame *frame)
+{
+       uint16_t type;
+
+       print_handle_range("Handle range", frame->data);
+
+       type = bt_get_le16(frame->data + 4);
+       print_attribute_info(type, frame->data + 6, frame->size - 6);
+}
+
+static void att_find_by_type_val_rsp(const struct l2cap_frame *frame)
+{
+       const uint8_t *ptr = frame->data;
+       uint16_t len = frame->size;
+
+       while (len >= 4) {
+               print_handle_range("Handle range", ptr);
+               ptr += 4;
+               len -= 4;
+       }
+
+       packet_hexdump(ptr, len);
+}
+
+static void att_read_type_req(const struct l2cap_frame *frame)
+{
+       print_handle_range("Handle range", frame->data);
+       print_uuid("Attribute type", frame->data + 4, frame->size - 4);
+}
+
+static void att_read_type_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;
+
+       print_field("Attribute data length: %d", pdu->length);
+       print_data_list("Attribute data list", pdu->length,
+                                       frame->data + 1, frame->size - 1);
+}
+
+static void att_read_req(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_read_req *pdu = frame->data;
+
+       print_field("Handle: 0x%4.4x", btohs(pdu->handle));
+}
+
+static void att_read_rsp(const struct l2cap_frame *frame)
+{
+       print_hex_field("Value", frame->data, frame->size);
+}
+
+static void att_read_blob_req(const struct l2cap_frame *frame)
+{
+       print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));
+       print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));
+}
+
+static void att_read_blob_rsp(const struct l2cap_frame *frame)
+{
+       packet_hexdump(frame->data, frame->size);
+}
+
+static void att_read_multiple_req(const struct l2cap_frame *frame)
+{
+       int i, count;
+
+       count = frame->size / 2;
+
+       for (i = 0; i < count; i++)
+               print_field("Handle: 0x%4.4x",
+                                       bt_get_le16(frame->data + (i * 2)));
+}
+
+static void att_read_group_type_req(const struct l2cap_frame *frame)
+{
+       print_handle_range("Handle range", frame->data);
+       print_uuid("Attribute group type", frame->data + 4, frame->size - 4);
+}
+
+static void att_read_group_type_rsp(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_read_group_type_rsp *pdu = frame->data;
+
+       print_field("Attribute data length: %d", pdu->length);
+       print_data_list("Attribute data list", pdu->length,
+                                       frame->data + 1, frame->size - 1);
+}
+
+static void att_write_req(const struct l2cap_frame *frame)
+{
+       print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));
+       print_hex_field("  Data", frame->data + 2, frame->size - 2);
+}
+
+static void att_write_rsp(const struct l2cap_frame *frame)
+{
+}
+
+static void att_prepare_write_req(const struct l2cap_frame *frame)
+{
+       print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));
+       print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));
+       print_hex_field("  Data", frame->data + 4, frame->size - 4);
+}
+
+static void att_prepare_write_rsp(const struct l2cap_frame *frame)
+{
+       print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));
+       print_field("Offset: 0x%4.4x", bt_get_le16(frame->data + 2));
+       print_hex_field("  Data", frame->data + 4, frame->size - 4);
+}
+
+static void att_execute_write_req(const struct l2cap_frame *frame)
+{
+       uint8_t flags = *(uint8_t *) frame->data;
+       const char *flags_str;
+
+       switch (flags) {
+       case 0x00:
+               flags_str = "Cancel all prepared writes";
+               break;
+       case 0x01:
+               flags_str = "Immediately write all pending values";
+               break;
+       default:
+               flags_str = "Unknown";
+               break;
+       }
+
+       print_field("Flags: %s (0x%02x)", flags_str, flags);
+}
+
+static void att_handle_value_notify(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_handle_value_notify *pdu = frame->data;
+
+       print_field("Handle: 0x%4.4x", btohs(pdu->handle));
+       print_hex_field("  Data", frame->data + 2, frame->size - 2);
+}
+
+static void att_handle_value_ind(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_att_handle_value_ind *pdu = frame->data;
+
+       print_field("Handle: 0x%4.4x", btohs(pdu->handle));
+       print_hex_field("  Data", frame->data + 2, frame->size - 2);
+}
+
+static void att_handle_value_conf(const struct l2cap_frame *frame)
+{
+}
+
+static void att_write_command(const struct l2cap_frame *frame)
+{
+       print_field("Handle: 0x%4.4x", bt_get_le16(frame->data));
+       print_hex_field("  Data", frame->data + 2, frame->size - 2);
+}
+
+struct att_opcode_data {
+       uint8_t opcode;
+       const char *str;
+       void (*func) (const struct l2cap_frame *frame);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct att_opcode_data att_opcode_table[] = {
+       { 0x01, "Error Response",
+                       att_error_response, 4, true },
+       { 0x02, "Exchange MTU Request",
+                       att_exchange_mtu_req, 2, true },
+       { 0x03, "Exchange MTU Response",
+                       att_exchange_mtu_rsp, 2, true },
+       { 0x04, "Find Information Request",
+                       att_find_info_req, 4, true },
+       { 0x05, "Find Information Response",
+                       att_find_info_rsp, 5, false },
+       { 0x06, "Find By Type Value Request",
+                       att_find_by_type_val_req, 6, false },
+       { 0x07, "Find By Type Value Response",
+                       att_find_by_type_val_rsp, 4, false },
+       { 0x08, "Read By Type Request",
+                       att_read_type_req, 6, false },
+       { 0x09, "Read By Type Response",
+                       att_read_type_rsp, 3, false },
+       { 0x0a, "Read Request",
+                       att_read_req, 2, true },
+       { 0x0b, "Read Response",
+                       att_read_rsp, 0, false },
+       { 0x0c, "Read Blob Request",
+                       att_read_blob_req, 4, true },
+       { 0x0d, "Read Blob Response",
+                       att_read_blob_rsp, 0, false },
+       { 0x0e, "Read Multiple Request",
+                       att_read_multiple_req, 4, false },
+       { 0x0f, "Read Multiple Response"        },
+       { 0x10, "Read By Group Type Request",
+                       att_read_group_type_req, 6, false },
+       { 0x11, "Read By Group Type Response",
+                       att_read_group_type_rsp, 4, false },
+       { 0x12, "Write Request" ,
+                       att_write_req, 2, false },
+       { 0x13, "Write Response",
+                       att_write_rsp, 0, true  },
+       { 0x16, "Prepare Write Request",
+                       att_prepare_write_req, 4, false },
+       { 0x17, "Prepare Write Response",
+                       att_prepare_write_rsp, 4, false },
+       { 0x18, "Execute Write Request",
+                       att_execute_write_req, 1, true },
+       { 0x19, "Execute Write Response"        },
+       { 0x1b, "Handle Value Notification",
+                       att_handle_value_notify, 2, false },
+       { 0x1d, "Handle Value Indication",
+                       att_handle_value_ind, 2, false },
+       { 0x1e, "Handle Value Confirmation",
+                       att_handle_value_conf, 0, true },
+       { 0x52, "Write Command",
+                       att_write_command, 2, false },
+       { 0xd2, "Signed Write Command"          },
+       { }
+};
+
+static const char *att_opcode_to_str(uint8_t opcode)
+{
+       int i;
+
+       for (i = 0; att_opcode_table[i].str; i++) {
+               if (att_opcode_table[i].opcode == opcode)
+                       return att_opcode_table[i].str;
+       }
+
+       return "Unknown";
+}
+
+static void att_packet(uint16_t index, bool in, uint16_t handle,
+                       uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       uint8_t opcode = *((const uint8_t *) data);
+       const struct att_opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       if (size < 1) {
+               print_text(COLOR_ERROR, "malformed attribute packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       for (i = 0; att_opcode_table[i].str; i++) {
+               if (att_opcode_table[i].opcode == opcode) {
+                       opcode_data = &att_opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->func) {
+                       if (in)
+                               opcode_color = COLOR_MAGENTA;
+                       else
+                               opcode_color = COLOR_BLUE;
+               } else
+                       opcode_color = COLOR_WHITE_BG;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_WHITE_BG;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "ATT: ", opcode_str, COLOR_OFF,
+                               " (0x%2.2x) len %d", opcode, size - 1);
+
+       if (!opcode_data || !opcode_data->func) {
+               packet_hexdump(data + 1, size - 1);
+               return;
+       }
+
+       if (opcode_data->fixed) {
+               if (size - 1 != opcode_data->size) {
+                       print_text(COLOR_ERROR, "invalid size");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       } else {
+               if (size - 1 < opcode_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       }
+
+       l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);
+       opcode_data->func(&frame);
+}
+
+static void print_addr(const uint8_t *addr, uint8_t addr_type)
+{
+       const char *str;
+
+       switch (addr_type) {
+       case 0x00:
+               print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+                                               addr[5], addr[4], addr[3],
+                                               addr[2], addr[1], addr[0]);
+               break;
+       case 0x01:
+               switch ((addr[5] & 0xc0) >> 6) {
+               case 0x00:
+                       str = "Non-Resolvable";
+                       break;
+               case 0x01:
+                       str = "Resolvable";
+                       break;
+               case 0x03:
+                       str = "Static";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"
+                                       " (%s)", addr[5], addr[4], addr[3],
+                                       addr[2], addr[1], addr[0], str);
+               break;
+       default:
+               print_field("Address: %2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X",
+                                               addr[5], addr[4], addr[3],
+                                               addr[2], addr[1], addr[0]);
+               break;
+       }
+}
+
+static void print_addr_type(uint8_t addr_type)
+{
+       const char *str;
+
+       switch (addr_type) {
+       case 0x00:
+               str = "Public";
+               break;
+       case 0x01:
+               str = "Random";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Address type: %s (0x%2.2x)", str, addr_type);
+}
+
+static void print_smp_io_capa(uint8_t io_capa)
+{
+       const char *str;
+
+       switch (io_capa) {
+       case 0x00:
+               str = "DisplayOnly";
+               break;
+       case 0x01:
+               str = "DisplayYesNo";
+               break;
+       case 0x02:
+               str = "KeyboardOnly";
+               break;
+       case 0x03:
+               str = "NoInputNoOutput";
+               break;
+       case 0x04:
+               str = "KeyboardDisplay";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("IO capability: %s (0x%2.2x)", str, io_capa);
+}
+
+static void print_smp_oob_data(uint8_t oob_data)
+{
+       const char *str;
+
+       switch (oob_data) {
+       case 0x00:
+               str = "Authentication data not present";
+               break;
+       case 0x01:
+               str = "Authentication data from remote device present";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("OOB data: %s (0x%2.2x)", str, oob_data);
+}
+
+static void print_smp_auth_req(uint8_t auth_req)
+{
+       const char *str;
+
+       switch (auth_req & 0x03) {
+       case 0x00:
+               str = "No bonding";
+               break;
+       case 0x01:
+               str = "Bonding";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Authentication requirement: %s - %s (0x%2.2x)",
+                       str, (auth_req & 0x04) ? "MITM" : "No MITM", auth_req);
+}
+
+static void smp_pairing_request(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_pairing_request *pdu = frame->data;
+
+       print_smp_io_capa(pdu->io_capa);
+       print_smp_oob_data(pdu->oob_data);
+       print_smp_auth_req(pdu->auth_req);
+
+       print_field("Max encryption key size: %d", pdu->max_key_size);
+       print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);
+       print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);
+}
+
+static void smp_pairing_response(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_pairing_response *pdu = frame->data;
+
+       print_smp_io_capa(pdu->io_capa);
+       print_smp_oob_data(pdu->oob_data);
+       print_smp_auth_req(pdu->auth_req);
+
+       print_field("Max encryption key size: %d", pdu->max_key_size);
+       print_field("Initiator key distribution: 0x%2.2x", pdu->init_key_dist);
+       print_field("Responder key distribution: 0x%2.2x", pdu->resp_key_dist);
+}
+
+static void smp_pairing_confirm(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_pairing_confirm *pdu = frame->data;
+
+       print_hex_field("Confim value", pdu->value, 16);
+}
+
+static void smp_pairing_random(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_pairing_random *pdu = frame->data;
+
+       print_hex_field("Random value", pdu->value, 16);
+}
+
+static void smp_pairing_failed(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_pairing_failed *pdu = frame->data;
+       const char *str;
+
+       switch (pdu->reason) {
+       case 0x01:
+               str = "Passkey entry failed";
+               break;
+       case 0x02:
+               str = "OOB not available";
+               break;
+       case 0x03:
+               str = "Authentication requirements";
+               break;
+       case 0x04:
+               str = "Confirm value failed";
+               break;
+       case 0x05:
+               str = "Pairing not supported";
+               break;
+       case 0x06:
+               str = "Encryption key size";
+               break;
+       case 0x07:
+               str = "Command not supported";
+               break;
+       case 0x08:
+               str = "Unspecified reason";
+               break;
+       case 0x09:
+               str = "Repeated attempts";
+               break;
+       case 0x0a:
+               str = "Invalid parameters";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Reason: %s (0x%2.2x)", str, pdu->reason);
+}
+
+static void smp_encrypt_info(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_encrypt_info *pdu = frame->data;
+
+       print_hex_field("Long term key", pdu->ltk, 16);
+}
+
+static void smp_master_ident(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_master_ident *pdu = frame->data;
+
+       print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));
+       print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));
+}
+
+static void smp_ident_info(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_ident_info *pdu = frame->data;
+
+       print_hex_field("Identity resolving key", pdu->irk, 16);
+}
+
+static void smp_ident_addr_info(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_ident_addr_info *pdu = frame->data;
+
+       print_addr_type(pdu->addr_type);
+       print_addr(pdu->addr, pdu->addr_type);
+}
+
+static void smp_signing_info(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_signing_info *pdu = frame->data;
+
+       print_hex_field("Signature key", pdu->csrk, 16);
+}
+
+static void smp_security_request(const struct l2cap_frame *frame)
+{
+       const struct bt_l2cap_smp_security_request *pdu = frame->data;
+
+       print_smp_auth_req(pdu->auth_req);
+}
+
+struct smp_opcode_data {
+       uint8_t opcode;
+       const char *str;
+       void (*func) (const struct l2cap_frame *frame);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct smp_opcode_data smp_opcode_table[] = {
+       { 0x01, "Pairing Request",
+                       smp_pairing_request, 6, true },
+       { 0x02, "Pairing Response",
+                       smp_pairing_response, 6, true },
+       { 0x03, "Pairing Confirm",
+                       smp_pairing_confirm, 16, true },
+       { 0x04, "Pairing Random",
+                       smp_pairing_random, 16, true },
+       { 0x05, "Pairing Failed",
+                       smp_pairing_failed, 1, true },
+       { 0x06, "Encryption Information",
+                       smp_encrypt_info, 16, true },
+       { 0x07, "Master Identification",
+                       smp_master_ident, 10, true },
+       { 0x08, "Identity Information",
+                       smp_ident_info, 16, true },
+       { 0x09, "Identity Address Information",
+                       smp_ident_addr_info, 7, true },
+       { 0x0a, "Signing Information",
+                       smp_signing_info, 16, true },
+       { 0x0b, "Security Request",
+                       smp_security_request, 1, true },
+       { }
+};
+
+static void smp_packet(uint16_t index, bool in, uint16_t handle,
+                       uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       uint8_t opcode = *((const uint8_t *) data);
+       const struct smp_opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       if (size < 1) {
+               print_text(COLOR_ERROR, "malformed attribute packet");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       for (i = 0; smp_opcode_table[i].str; i++) {
+               if (smp_opcode_table[i].opcode == opcode) {
+                       opcode_data = &smp_opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->func) {
+                       if (in)
+                               opcode_color = COLOR_MAGENTA;
+                       else
+                               opcode_color = COLOR_BLUE;
+               } else
+                       opcode_color = COLOR_WHITE_BG;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_WHITE_BG;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "SMP: ", opcode_str, COLOR_OFF,
+                               " (0x%2.2x) len %d", opcode, size - 1);
+
+       if (!opcode_data || !opcode_data->func) {
+               packet_hexdump(data + 1, size - 1);
+               return;
+       }
+
+       if (opcode_data->fixed) {
+               if (size - 1 != opcode_data->size) {
+                       print_text(COLOR_ERROR, "invalid size");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       } else {
+               if (size - 1 < opcode_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       }
+
+       l2cap_frame_init(&frame, index, in, handle, cid, data + 1, size - 1);
+       opcode_data->func(&frame);
+}
+
+static void l2cap_frame(uint16_t index, bool in, uint16_t handle,
+                       uint16_t cid, const void *data, uint16_t size)
+{
+       struct l2cap_frame frame;
+       uint16_t psm, chan;
+       uint8_t mode;
+
+       switch (cid) {
+       case 0x0001:
+               bredr_sig_packet(index, in, handle, cid, data, size);
+               break;
+       case 0x0002:
+               connless_packet(index, in, handle, cid, data, size);
+               break;
+       case 0x0003:
+               amp_packet(index, in, handle, cid, data, size);
+               break;
+       case 0x0004:
+               att_packet(index, in, handle, cid, data, size);
+               break;
+       case 0x0005:
+               le_sig_packet(index, in, handle, cid, data, size);
+               break;
+       case 0x0006:
+               smp_packet(index, in, handle, cid, data, size);
+               break;
+       default:
+               l2cap_frame_init(&frame, index, in, handle, cid, data, size);
+               psm = get_psm(&frame);
+               mode = get_mode(&frame);
+               chan = get_chan(&frame);
+
+               print_indent(6, COLOR_CYAN, "Channel:", "", COLOR_OFF,
+                               " %d len %d [PSM %d mode %d] {chan %d}",
+                                               cid, size, psm, mode, chan);
+
+               switch (psm) {
+               case 0x0001:
+                       sdp_packet(&frame, chan);
+                       break;
+               case 0x001f:
+                       att_packet(index, in, handle, cid, data, size);
+                       break;
+               default:
+                       packet_hexdump(data, size);
+                       break;
+               }
+               break;
+       }
+}
+
+void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,
+                                       const void *data, uint16_t size)
+{
+       const struct bt_l2cap_hdr *hdr = data;
+       uint16_t len, cid;
+
+       if (index > MAX_INDEX - 1) {
+               print_text(COLOR_ERROR, "controller index too large");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       switch (flags) {
+       case 0x00:      /* start of a non-automatically-flushable PDU */
+       case 0x02:      /* start of an automatically-flushable PDU */
+               if (index_list[index].frag_len) {
+                       print_text(COLOR_ERROR, "unexpected start frame");
+                       packet_hexdump(data, size);
+                       clear_fragment_buffer(index);
+                       return;
+               }
+
+               if (size < sizeof(*hdr)) {
+                       print_text(COLOR_ERROR, "frame too short");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               len = btohs(hdr->len);
+               cid = btohs(hdr->cid);
+
+               data += sizeof(*hdr);
+               size -= sizeof(*hdr);
+
+               if (len == size) {
+                       /* complete frame */
+                       l2cap_frame(index, in, handle, cid, data, len);
+                       return;
+               }
+
+               if (size > len) {
+                       print_text(COLOR_ERROR, "frame too long");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               index_list[index].frag_buf = malloc(len);
+               if (!index_list[index].frag_buf) {
+                       print_text(COLOR_ERROR, "failed buffer allocation");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               memcpy(index_list[index].frag_buf, data, size);
+               index_list[index].frag_pos = size;
+               index_list[index].frag_len = len - size;
+               index_list[index].frag_cid = cid;
+               break;
+
+       case 0x01:      /* continuing fragment */
+               if (!index_list[index].frag_len) {
+                       print_text(COLOR_ERROR, "unexpected continuation");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               if (size > index_list[index].frag_len) {
+                       print_text(COLOR_ERROR, "fragment too long");
+                       packet_hexdump(data, size);
+                       clear_fragment_buffer(index);
+                       return;
+               }
+
+               memcpy(index_list[index].frag_buf +
+                               index_list[index].frag_pos, data, size);
+               index_list[index].frag_pos += size;
+               index_list[index].frag_len -= size;
+
+               if (!index_list[index].frag_len) {
+                       /* complete frame */
+                       l2cap_frame(index, in, handle,
+                                       index_list[index].frag_cid,
+                                       index_list[index].frag_buf,
+                                       index_list[index].frag_pos);
+                       clear_fragment_buffer(index);
+                       return;
+               }
+               break;
+
+       case 0x03:      /* complete automatically-flushable PDU */
+               if (index_list[index].frag_len) {
+                       print_text(COLOR_ERROR, "unexpected complete frame");
+                       packet_hexdump(data, size);
+                       clear_fragment_buffer(index);
+                       return;
+               }
+
+               if (size < sizeof(*hdr)) {
+                       print_text(COLOR_ERROR, "frame too short");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               len = btohs(hdr->len);
+               cid = btohs(hdr->cid);
+
+               data += sizeof(*hdr);
+               size -= sizeof(*hdr);
+
+               if (len != size) {
+                       print_text(COLOR_ERROR, "wrong frame size");
+                       packet_hexdump(data, size);
+                       return;
+               }
+
+               /* complete frame */
+               l2cap_frame(index, in, handle, cid, data, len);
+               break;
+
+       default:
+               print_text(COLOR_ERROR, "invalid packet flags (0x%2.2x)",
+                                                               flags);
+               packet_hexdump(data, size);
+               return;
+       }
+}
diff --git a/monitor/l2cap.h b/monitor/l2cap.h
new file mode 100644 (file)
index 0000000..30bcb6a
--- /dev/null
@@ -0,0 +1,61 @@
+/*
+ *
+ *  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>
+#include <stdbool.h>
+
+struct l2cap_frame {
+       uint16_t index;
+       bool in;
+       uint16_t handle;
+       uint16_t cid;
+       const void *data;
+       uint16_t size;
+};
+
+static inline void l2cap_frame_init(struct l2cap_frame *frame,
+                               uint16_t index, bool in, uint16_t handle,
+                               uint16_t cid, const void *data, uint16_t size)
+{
+       frame->index  = index;
+       frame->in     = in;
+       frame->handle = handle;
+       frame->cid    = cid;
+       frame->data   = data;
+       frame->size   = size;
+}
+
+static inline void l2cap_frame_pull(struct l2cap_frame *frame,
+                               const struct l2cap_frame *source, uint16_t len)
+{
+       frame->index   = source->index;
+       frame->in      = source->in;
+       frame->handle  = source->handle;
+       frame->cid     = source->cid;
+       frame->data    = source->data + len;
+       frame->size    = source->size - len;
+}
+
+void l2cap_packet(uint16_t index, bool in, uint16_t handle, uint8_t flags,
+                                       const void *data, uint16_t size);
diff --git a/monitor/ll.c b/monitor/ll.c
new file mode 100644 (file)
index 0000000..e8b7a7a
--- /dev/null
@@ -0,0 +1,549 @@
+/*
+ *
+ *  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 <inttypes.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "display.h"
+#include "packet.h"
+#include "crc.h"
+#include "bt.h"
+#include "ll.h"
+
+#define COLOR_OPCODE           COLOR_MAGENTA
+#define COLOR_OPCODE_UNKNOWN   COLOR_WHITE_BG
+
+#define MAX_CHANNEL 16
+
+struct channel_data {
+       uint32_t access_addr;
+       uint32_t crc_init;
+};
+
+static struct channel_data channel_list[MAX_CHANNEL];
+
+static void set_crc_init(uint32_t access_addr, uint32_t crc_init)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHANNEL; i++) {
+               if (channel_list[i].access_addr == 0x00000000 ||
+                               channel_list[i].access_addr == access_addr) {
+                       channel_list[i].access_addr = access_addr;
+                       channel_list[i].crc_init = crc_init;
+                       break;
+               }
+       }
+}
+
+static uint32_t get_crc_init(uint32_t access_addr)
+{
+       int i;
+
+       for (i = 0; i < MAX_CHANNEL; i++) {
+               if (channel_list[i].access_addr == access_addr)
+                       return channel_list[i].crc_init;
+       }
+
+       return 0x00000000;
+}
+
+static void advertising_packet(const void *data, uint8_t size)
+{
+       const uint8_t *ptr = data;
+       uint8_t pdu_type, length, win_size, hop, sca;
+       bool tx_add, rx_add;
+       uint32_t access_addr, crc_init;
+       uint16_t win_offset, interval, latency, timeout;
+       const char *str;
+
+       if (size < 2) {
+               print_text(COLOR_ERROR, "packet too short");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       pdu_type = ptr[0] & 0x0f;
+       tx_add = !!(ptr[0] & 0x40);
+       rx_add = !!(ptr[0] & 0x80);
+       length = ptr[1] & 0x3f;
+
+       switch (pdu_type) {
+       case 0x00:
+               str = "ADV_IND";
+               break;
+       case 0x01:
+               str = "ADV_DIRECT_IND";
+               break;
+       case 0x02:
+               str = "ADV_NONCONN_IND";
+               break;
+       case 0x03:
+               str = "SCAN_REQ";
+               break;
+       case 0x04:
+               str = "SCAN_RSP";
+               break;
+       case 0x05:
+               str = "CONNECT_REQ";
+               break;
+       case 0x06:
+               str = "ADV_SCAN_IND";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, pdu_type);
+       print_field("TxAdd: %u", tx_add);
+       print_field("RxAdd: %u", rx_add);
+       print_field("Length: %u", length);
+
+       if (length != size - 2) {
+               print_text(COLOR_ERROR, "packet size mismatch");
+               packet_hexdump(data + 2, size - 2);
+               return;
+       }
+
+       switch (pdu_type) {
+       case 0x00:      /* ADV_IND */
+       case 0x02:      /* AVD_NONCONN_IND */
+       case 0x06:      /* ADV_SCAN_IND */
+       case 0x04:      /* SCAN_RSP */
+               if (length < 6) {
+                       print_text(COLOR_ERROR, "payload too short");
+                       packet_hexdump(data + 2, length);
+                       return;
+               }
+
+               packet_print_addr("Advertiser address", data + 2, tx_add);
+               packet_print_ad(data + 8, length - 6);
+               break;
+
+       case 0x01:      /* ADV_DIRECT_IND */
+               if (length < 12) {
+                       print_text(COLOR_ERROR, "payload too short");
+                       packet_hexdump(data + 2, length);
+                       return;
+               }
+
+               packet_print_addr("Advertiser address", data + 2, tx_add);
+               packet_print_addr("Inititator address", data + 8, rx_add);
+               break;
+
+       case 0x03:      /* SCAN_REQ */
+               if (length < 12) {
+                       print_text(COLOR_ERROR, "payload too short");
+                       packet_hexdump(data + 2, length);
+                       return;
+               }
+
+               packet_print_addr("Scanner address", data + 2, tx_add);
+               packet_print_addr("Advertiser address", data + 8, rx_add);
+               break;
+
+       case 0x05:      /* CONNECT_REQ */
+               if (length < 34) {
+                       print_text(COLOR_ERROR, "payload too short");
+                       packet_hexdump(data + 2, length);
+                       return;
+               }
+
+               packet_print_addr("Inititator address", data + 2, tx_add);
+               packet_print_addr("Advertiser address", data + 8, rx_add);
+
+               access_addr = ptr[14] | ptr[15] << 8 |
+                                       ptr[16] << 16 | ptr[17] << 24;
+               crc_init = ptr[18] | ptr[19] << 8 | ptr[20] << 16;
+
+               print_field("Access address: 0x%8.8x", access_addr);
+               print_field("CRC init: 0x%6.6x", crc_init);
+
+               set_crc_init(access_addr, crc24_bit_reverse(crc_init));
+
+               win_size = ptr[21];
+               win_offset = ptr[22] | ptr[23] << 8;
+               interval = ptr[24] | ptr[25] << 8;
+               latency = ptr[26] | ptr[27] << 8;
+               timeout = ptr[28] | ptr[29] << 8;
+
+               print_field("Transmit window size: %u", win_size);
+               print_field("Transmit window offset: %u", win_offset);
+               print_field("Connection interval: %u", interval);
+               print_field("Connection slave latency: %u", latency);
+               print_field("Connection supervision timeout: %u", timeout);
+
+               packet_print_channel_map_ll(ptr + 30);
+
+               hop = ptr[35] & 0x1f;
+               sca = (ptr[35] & 0xe0) >> 5;
+
+               switch (sca) {
+               case 0:
+                       str = "251 ppm to 500 ppm";
+                       break;
+               case 1:
+                       str = "151 ppm to 250 ppm";
+                       break;
+               case 2:
+                       str = "101 ppm to 150ppm";
+                       break;
+               case 3:
+                       str = "76 ppm to 100 ppm";
+                       break;
+               case 4:
+                       str = "51 ppm to 75 ppm";
+                       break;
+               case 5:
+                       str = "31 ppm to 50 ppm";
+                       break;
+               case 6:
+                       str = "21 ppm to 30 ppm";
+                       break;
+               case 7:
+                       str = "0 ppm to 20 ppm";
+                       break;
+               default:
+                       str = "Invalid";
+                       break;
+               }
+
+               print_field("Hop increment: %u", hop);
+               print_field("Sleep clock accuracy: %s (%u)", str, sca);
+               break;
+
+       default:
+               packet_hexdump(data + 2, length);
+               break;
+       }
+}
+
+static void data_packet(const void *data, uint8_t size)
+{
+       const uint8_t *ptr = data;
+       uint8_t llid, length;
+       bool nesn, sn, md;
+       const char *str;
+
+       if (size < 2) {
+               print_text(COLOR_ERROR, "packet too short");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       llid = ptr[0] & 0x03;
+       nesn = !!(ptr[0] & 0x04);
+       sn = !!(ptr[0] & 0x08);
+       md = !!(ptr[0] & 0x10);
+       length = ptr[1] & 0x1f;
+
+       switch (llid) {
+       case 0x01:
+               if (length > 0)
+                       str = "Continuation fragement of L2CAP message";
+               else
+                       str = "Empty message";
+               break;
+       case 0x02:
+               str = "Start of L2CAP message";
+               break;
+       case 0x03:
+               str = "Control";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("LLID: %s (0x%2.2x)", str, llid);
+       print_field("Next expected sequence number: %u", nesn);
+       print_field("Sequence number: %u", sn);
+       print_field("More data: %u", md);
+       print_field("Length: %u", length);
+
+       switch (llid) {
+       case 0x03:
+               llcp_packet(data + 2, size - 2);
+               break;
+
+       default:
+               packet_hexdump(data + 2, size - 2);
+               break;
+       }
+}
+
+void ll_packet(uint16_t frequency, const void *data, uint8_t size)
+{
+       const struct bt_ll_hdr *hdr = data;
+       uint8_t channel = (frequency - 2402) / 2;
+       uint32_t access_addr;
+       char access_str[12];
+       const char *channel_label, *channel_color;
+       const uint8_t *pdu_data;
+       uint8_t pdu_len;
+       uint32_t pdu_crc, crc, crc_init;
+
+       if (size < sizeof(*hdr)) {
+               print_text(COLOR_ERROR, "packet missing header");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       if (size < sizeof(*hdr) + 3) {
+               print_text(COLOR_ERROR, "packet missing checksum");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       if (hdr->preamble != 0xaa && hdr->preamble != 0x55) {
+               print_text(COLOR_ERROR, "invalid preamble");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       access_addr = btohl(hdr->access_addr);
+
+       pdu_data = data + sizeof(*hdr);
+       pdu_len = size - sizeof(*hdr) - 3;
+
+       pdu_crc = pdu_data[pdu_len + 0] | (pdu_data[pdu_len + 1] << 8) |
+                                               (pdu_data[pdu_len + 2] << 16);
+
+       if (access_addr == 0x8e89bed6) {
+               channel_label = "Advertising channel: ";
+               channel_color = COLOR_MAGENTA;
+       } else {
+               channel_label = "Data channel: ";
+               channel_color = COLOR_CYAN;
+       }
+
+       sprintf(access_str, "0x%8.8x", access_addr);
+
+       print_indent(6, channel_color, channel_label, access_str, COLOR_OFF,
+               " (channel %d) len %d crc 0x%6.6x", channel, pdu_len, pdu_crc);
+
+       if (access_addr == 0x8e89bed6)
+               crc_init = 0xaaaaaa;
+       else
+               crc_init = get_crc_init(access_addr);
+
+       if (crc_init) {
+               crc = crc24_calculate(crc_init, pdu_data, pdu_len);
+
+               if (crc != pdu_crc) {
+                       print_text(COLOR_ERROR, "invalid checksum");
+                       packet_hexdump(pdu_data, pdu_len);
+                       return;
+               }
+       } else
+               print_text(COLOR_ERROR, "unknown access address");
+
+       if (access_addr == 0x8e89bed6)
+               advertising_packet(pdu_data, pdu_len);
+       else
+               data_packet(pdu_data, pdu_len);
+}
+
+static void null_pdu(const void *data, uint8_t size)
+{
+}
+
+static void conn_update_req(const void *data, uint8_t size)
+{
+       const struct bt_ll_conn_update_req *pdu = data;
+
+       print_field("Transmit window size: %u", pdu->win_size);
+       print_field("Transmit window offset: %u", btohs(pdu->win_offset));
+       print_field("Connection interval: %u", btohs(pdu->interval));
+       print_field("Connection slave latency: %u", btohs(pdu->latency));
+       print_field("Connection supervision timeout: %u", btohs(pdu->timeout));;
+       print_field("Connection instant: %u", btohs(pdu->instant));
+}
+
+static void channel_map_req(const void *data, uint8_t size)
+{
+       const struct bt_ll_channel_map_req *pdu = data;
+
+       packet_print_channel_map_ll(pdu->map);
+       print_field("Connection instant: %u", btohs(pdu->instant));
+}
+
+static void terminate_ind(const void *data, uint8_t size)
+{
+       const struct bt_ll_terminate_ind *pdu = data;
+
+       print_field("Error code: 0x%2.2x", pdu->error);
+}
+
+static void enc_req(const void *data, uint8_t size)
+{
+       const struct bt_ll_enc_req *pdu = data;
+
+       print_field("Rand: 0x%16.16" PRIx64, btohll(pdu->rand));
+       print_field("EDIV: 0x%4.4x", btohs(pdu->ediv));
+       print_field("SKD (master): 0x%16.16" PRIx64, btohll(pdu->skd));
+       print_field("IV (master): 0x%8.8x", btohl(pdu->iv));
+}
+
+static void enc_rsp(const void *data, uint8_t size)
+{
+       const struct bt_ll_enc_rsp *pdu = data;
+
+       print_field("SKD (slave): 0x%16.16" PRIx64, btohll(pdu->skd));
+       print_field("IV (slave): 0x%8.8x", btohl(pdu->iv));
+}
+
+static const char *opcode_to_string(uint8_t opcode);
+
+static void unknown_rsp(const void *data, uint8_t size)
+{
+       const struct bt_ll_unknown_rsp *pdu = data;
+
+       print_field("Unknown type: %s (0x%2.2x)",
+                               opcode_to_string(pdu->type), pdu->type);
+}
+
+static void feature_req(const void *data, uint8_t size)
+{
+       const struct bt_ll_feature_req *pdu = data;
+
+       packet_print_features_ll(pdu->features);
+}
+
+static void feature_rsp(const void *data, uint8_t size)
+{
+       const struct bt_ll_feature_rsp *pdu = data;
+
+       packet_print_features_ll(pdu->features);
+}
+
+static void version_ind(const void *data, uint8_t size)
+{
+       const struct bt_ll_version_ind *pdu = data;
+
+       packet_print_version("Version", pdu->version,
+                               "Subversion", btohs(pdu->subversion));
+       packet_print_company("Company", btohs(pdu->company));
+}
+
+static void reject_ind(const void *data, uint8_t size)
+{
+       const struct bt_ll_reject_ind *pdu = data;
+
+       print_field("Error code: 0x%2.2x", pdu->error);
+}
+
+struct llcp_data {
+       uint8_t opcode;
+       const char *str;
+       void (*func) (const void *data, uint8_t size);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct llcp_data llcp_table[] = {
+       { 0x00, "LL_CONNECTION_UPDATE_REQ", conn_update_req, 11, true },
+       { 0x01, "LL_CHANNEL_MAP_REQ",       channel_map_req,  7, true },
+       { 0x02, "LL_TERMINATE_IND",         terminate_ind,    1, true },
+       { 0x03, "LL_ENC_REQ",               enc_req,         22, true },
+       { 0x04, "LL_ENC_RSP",               enc_rsp,         12, true },
+       { 0x05, "LL_START_ENC_REQ",         null_pdu,         0, true },
+       { 0x06, "LL_START_ENC_RSP",         null_pdu,         0, true },
+       { 0x07, "LL_UNKNOWN_RSP",           unknown_rsp,      1, true },
+       { 0x08, "LL_FEATURE_REQ",           feature_req,      8, true },
+       { 0x09, "LL_FEATURE_RSP",           feature_rsp,      8, true },
+       { 0x0a, "LL_PAUSE_ENC_REQ",         null_pdu,         0, true },
+       { 0x0b, "LL_PAUSE_ENC_RSP",         null_pdu,         0, true },
+       { 0x0c, "LL_VERSION_IND",           version_ind,      5, true },
+       { 0x0d, "LL_REJECT_IND",            reject_ind,       1, true },
+       { }
+};
+
+static const char *opcode_to_string(uint8_t opcode)
+{
+       int i;
+
+       for (i = 0; llcp_table[i].str; i++) {
+               if (llcp_table[i].opcode == opcode)
+                       return llcp_table[i].str;
+       }
+
+       return "Unknown";
+}
+
+void llcp_packet(const void *data, uint8_t size)
+{
+       uint8_t opcode = ((const uint8_t *) data)[0];
+       const struct llcp_data *llcp_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       for (i = 0; llcp_table[i].str; i++) {
+               if (llcp_table[i].opcode == opcode) {
+                       llcp_data = &llcp_table[i];
+                       break;
+               }
+       }
+
+       if (llcp_data) {
+               if (llcp_data->func)
+                       opcode_color = COLOR_OPCODE;
+               else
+                       opcode_color = COLOR_OPCODE_UNKNOWN;
+               opcode_str = llcp_data->str;
+       } else {
+               opcode_color = COLOR_OPCODE_UNKNOWN;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
+                                               " (0x%2.2x)", opcode);
+
+       if (!llcp_data || !llcp_data->func) {
+               packet_hexdump(data + 1, size - 1);
+               return;
+       }
+
+       if (llcp_data->fixed) {
+               if (size - 1 != llcp_data->size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       } else {
+               if (size - 1 < llcp_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       }
+
+       llcp_data->func(data + 1, size - 1);
+}
diff --git a/monitor/ll.h b/monitor/ll.h
new file mode 100644 (file)
index 0000000..17d934b
--- /dev/null
@@ -0,0 +1,28 @@
+/*
+ *
+ *  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>
+
+void ll_packet(uint16_t frequency, const void *data, uint8_t size);
+void llcp_packet(const void *data, uint8_t size);
diff --git a/monitor/lmp.c b/monitor/lmp.c
new file mode 100644 (file)
index 0000000..e6db107
--- /dev/null
@@ -0,0 +1,215 @@
+/*
+ *
+ *  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 "display.h"
+#include "packet.h"
+#include "lmp.h"
+
+#define COLOR_OPCODE           COLOR_MAGENTA
+#define COLOR_OPCODE_UNKNOWN   COLOR_WHITE_BG
+
+#define ESC4(x) ((127 << 8) | (x))
+
+struct lmp_data {
+       uint16_t opcode;
+       const char *str;
+       void (*func) (const void *data, uint8_t size);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct lmp_data lmp_table[] = {
+       {  1, "LMP_name_req" },
+       {  2, "LMP_name_res" },
+       {  3, "LMP_accepted" },
+       {  4, "LMP_not_accepted" },
+       {  5, "LMP_clkoffset_req" },
+       {  6, "LMP_clkoffset_res" },
+       {  7, "LMP_detach" },
+       {  8, "LMP_in_rand" },
+       {  9, "LMP_comb_key" },
+       { 10, "LMP_unit_key" },
+       { 11, "LMP_au_rand" },
+       { 12, "LMP_sres" },
+       { 13, "LMP_temp_rand" },
+       { 14, "LMP_temp_key" },
+       { 15, "LMP_encryption_mode_req" },
+       { 16, "LMP_encryption_key_size_req" },
+       { 17, "LMP_start_encryption_req" },
+       { 18, "LMP_stop_encryption_req" },
+       { 19, "LMP_switch_req" },
+       { 20, "LMP_hold" },
+       { 21, "LMP_hold_req" },
+       { 22, "LMP_sniff" },
+       { 23, "LMP_sniff_req" },
+       { 24, "LMP_unsniff_req" },
+       { 25, "LMP_park_req" },
+       { 26, "LMP_park" },
+       { 27, "LMP_set_broadcast_scan_window" },
+       { 28, "LMP_modify_beacon" },
+       { 29, "LMP_unpark_BD_ADDR_req" },
+       { 30, "LMP_unpark_PM_ADDR_req" },
+       { 31, "LMP_incr_power_req" },
+       { 32, "LMP_decr_power_req" },
+       { 33, "LMP_max_power" },
+       { 34, "LMP_min_power" },
+       { 35, "LMP_auto_rate" },
+       { 36, "LMP_preferred_rate" },
+       { 37, "LMP_version_req" },
+       { 38, "LMP_version_res" },
+       { 39, "LMP_features_req" },
+       { 40, "LMP_features_res" },
+       { 41, "LMP_quality_of_service" },
+       { 42, "LMP_quality_of_service_req" },
+       { 43, "LMP_SCO_link_req" },
+       { 44, "LMP_remove_SCO_link_req" },
+       { 45, "LMP_max_slot" },
+       { 46, "LMP_max_slot_req" },
+       { 47, "LMP_timing_accuracy_req" },
+       { 48, "LMP_timing_accuracy_res" },
+       { 49, "LMP_setup_complete" },
+       { 50, "LMP_use_semi_permanent_key" },
+       { 51, "LMP_host_connection_req" },
+       { 52, "LMP_slot_offset" },
+       { 53, "LMP_page_mode_req" },
+       { 54, "LMP_Page_scan_mode_req" },
+       { 55, "LMP_supervision_timeout" },
+       { 56, "LMP_test_activate" },
+       { 57, "LMP_test_control" },
+       { 58, "LMP_encryption_key_size_mask_req" },
+       { 59, "LMP_encryption_key_size_mask_res" },
+       { 60, "LMP_set_AFH" },
+       { 61, "LMP_encapsulated_header" },
+       { 62, "LMP_encapsulated_payload" },
+       { 63, "LMP_simple_pairing_confirm" },
+       { 64, "LMP_simple_pairing_number" },
+       { 65, "LMP_DHkey_check" },
+       { 66, "LMP_pause_encryption_aes_req" },
+       { ESC4(1),  "LMP_accepted_ext" },
+       { ESC4(2),  "LMP_not_accepted_ext" },
+       { ESC4(3),  "LMP_features_req_ext" },
+       { ESC4(4),  "LMP_features_res_ext" },
+       { ESC4(5),  "LMP_clk_adj" },
+       { ESC4(6),  "LMP_clk_adj_ack" },
+       { ESC4(7),  "LMP_clk_adj_req" },
+       { ESC4(11), "LMP_packet_type_table" },
+       { ESC4(12), "LMP_eSCO_link_req" },
+       { ESC4(13), "LMP_remove_eSCO_link_req" },
+       { ESC4(16), "LMP_channel_classification_req" },
+       { ESC4(17), "LMP_channel_classification" },
+       { ESC4(21), "LMP_sniff_subrating_req" },
+       { ESC4(22), "LMP_sniff_subrating_res" },
+       { ESC4(23), "LMP_pause_encryption_req" },
+       { ESC4(24), "LMP_resume_encryption_req" },
+       { ESC4(25), "LMP_IO_capability_req" },
+       { ESC4(26), "LMP_IO_capability_res" },
+       { ESC4(27), "LMP_numeric_comparision_failed" },
+       { ESC4(28), "LMP_passkey_failed" },
+       { ESC4(29), "LMP_oob_failed" },
+       { ESC4(30), "LMP_keypress_notification" },
+       { ESC4(31), "LMP_power_control_req" },
+       { ESC4(32), "LMP_power_control_res" },
+       { ESC4(33), "LMP_ping_req" },
+       { ESC4(34), "LMP_ping_res" },
+       { }
+};
+
+
+void lmp_packet(const void *data, uint8_t size)
+{
+       const struct lmp_data *lmp_data = NULL;
+       const char *opcode_color, *opcode_str;
+       uint16_t opcode;
+       uint8_t tid, off;
+       int i;
+
+       tid = ((const uint8_t *) data)[0] & 0x01;
+       opcode = (((const uint8_t *) data)[0] & 0xfe) >> 1;
+
+       switch (opcode) {
+       case 127:
+               opcode = ESC4(((const uint8_t *) data)[1]);
+               off = 2;
+               break;
+       case 126:
+       case 125:
+       case 124:
+               return;
+       default:
+               off = 1;
+               break;
+       }
+
+       for (i = 0; lmp_table[i].str; i++) {
+               if (lmp_table[i].opcode == opcode) {
+                       lmp_data = &lmp_table[i];
+                       break;
+               }
+       }
+
+       if (lmp_data) {
+               if (lmp_data->func)
+                       opcode_color = COLOR_OPCODE;
+               else
+                       opcode_color = COLOR_OPCODE_UNKNOWN;
+               opcode_str = lmp_data->str;
+       } else {
+               opcode_color = COLOR_OPCODE_UNKNOWN;
+               opcode_str = "Unknown";
+       }
+
+       if (opcode & 0xff00)
+               print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
+                       " (%d/%d) TID %d", opcode >> 8, opcode & 0xff, tid);
+       else
+               print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
+                                       " (%d) TID %d", opcode, tid);
+
+       if (!lmp_data || !lmp_data->func) {
+               packet_hexdump(data + off, size - off);
+               return;
+       }
+
+       if (lmp_data->fixed) {
+               if (size - 1 != lmp_data->size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data + off, size - off);
+                       return;
+               }
+       } else {
+               if (size - 1 < lmp_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + off, size - off);
+                       return;
+               }
+       }
+
+       lmp_data->func(data + off, size - off);
+}
similarity index 88%
rename from serial/manager.h
rename to monitor/lmp.h
index c8b96e8..b2beda4 100644 (file)
@@ -2,6 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
@@ -21,5 +22,6 @@
  *
  */
 
-int serial_manager_init(DBusConnection *conn);
-void serial_manager_exit(void);
+#include <stdint.h>
+
+void lmp_packet(const void *data, uint8_t size);
index 90e32c5..e72b240 100644 (file)
 #endif
 
 #include <stdio.h>
+#include <ctype.h>
 #include <stdlib.h>
+#include <string.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)
 {
@@ -52,34 +52,79 @@ static void usage(void)
                "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");
+               "\t-r, --read <file>      Read traces in btsnoop format\n"
+               "\t-w, --write <file>     Save traces in btsnoop format\n"
+               "\t-s, --server <socket>  Start monitor server socket\n"
+               "\t-i, --index <num>      Show only specified controller\n"
+               "\t-t, --time             Show time instead of time offset\n"
+               "\t-T, --date             Show time and date information\n"
+               "\t-S, --sco              Dump SCO traffic\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'    },
+       { "read",    required_argument, NULL, 'r' },
+       { "write",   required_argument, NULL, 'w' },
+       { "server",  required_argument, NULL, 's' },
+       { "index",   required_argument, NULL, 'i' },
+       { "time",    no_argument,       NULL, 't' },
+       { "date",    no_argument,       NULL, 'T' },
+       { "sco",     no_argument,       NULL, 'S' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
        { }
 };
 
 int main(int argc, char *argv[])
 {
        unsigned long filter_mask = 0;
+       const char *str, *reader_path = NULL, *writer_path = NULL;
        sigset_t mask;
 
        mainloop_init();
 
+       filter_mask |= PACKET_FILTER_SHOW_TIME_OFFSET;
+
        for (;;) {
                int opt;
 
-               opt = getopt_long(argc, argv, "bvh", main_options, NULL);
+               opt = getopt_long(argc, argv, "r:w:s:i:tTSvh",
+                                               main_options, NULL);
                if (opt < 0)
                        break;
 
                switch (opt) {
-               case 'b':
-                       btsnoop_open(optarg);
+               case 'r':
+                       reader_path = optarg;
+                       break;
+               case 'w':
+                       writer_path = optarg;
+                       break;
+               case 's':
+                       control_server(optarg);
+                       break;
+               case 'i':
+                       if (strlen(optarg) > 3 && !strncmp(optarg, "hci", 3))
+                               str = optarg + 3;
+                       else
+                               str = optarg;
+                       if (!isdigit(*str)) {
+                               usage();
+                               return EXIT_FAILURE;
+                       }
+                       packet_select_index(atoi(str));
+                       break;
+               case 't':
+                       filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
+                       filter_mask |= PACKET_FILTER_SHOW_TIME;
+                       break;
+               case 'T':
+                       filter_mask &= ~PACKET_FILTER_SHOW_TIME_OFFSET;
+                       filter_mask |= PACKET_FILTER_SHOW_TIME;
+                       filter_mask |= PACKET_FILTER_SHOW_DATE;
+                       break;
+               case 'S':
+                       filter_mask |= PACKET_FILTER_SHOW_SCO_DATA;
                        break;
                case 'v':
                        printf("%s\n", VERSION);
@@ -92,24 +137,31 @@ int main(int argc, char *argv[])
                }
        }
 
+       if (argc - optind > 0) {
+               fprintf(stderr, "Invalid command line parameters\n");
+               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;
+       printf("Bluetooth monitor ver %s\n", VERSION);
 
        packet_set_filter(filter_mask);
 
-       printf("Bluetooth monitor ver %s\n", VERSION);
-
-       if (control_tracing() < 0) {
-               if (hcidump_tracing() < 0)
-                       return EXIT_FAILURE;
+       if (reader_path) {
+               control_reader(reader_path);
+               return EXIT_SUCCESS;
        }
 
+       if (writer_path)
+               control_writer(writer_path);
+
+       if (control_tracing() < 0)
+               return EXIT_FAILURE;
+
        return mainloop_run();
 }
index 0f14ea6..55c9f0f 100644 (file)
@@ -33,6 +33,7 @@
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>
+#include <inttypes.h>
 #include <time.h>
 #include <sys/time.h>
 
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
 
+#include "display.h"
+#include "bt.h"
+#include "ll.h"
+#include "uuid.h"
+#include "l2cap.h"
 #include "control.h"
 #include "btsnoop.h"
+#include "vendor.h"
 #include "packet.h"
 
+#define COLOR_INDEX_LABEL              COLOR_WHITE
+#define COLOR_TIMESTAMP                        COLOR_YELLOW
+
+#define COLOR_NEW_INDEX                        COLOR_GREEN
+#define COLOR_DEL_INDEX                        COLOR_RED
+
+#define COLOR_HCI_COMMAND              COLOR_BLUE
+#define COLOR_HCI_COMMAND_UNKNOWN      COLOR_WHITE_BG
+
+#define COLOR_HCI_EVENT                        COLOR_MAGENTA
+#define COLOR_HCI_EVENT_UNKNOWN                COLOR_WHITE_BG
+
+#define COLOR_HCI_ACLDATA              COLOR_CYAN
+#define COLOR_HCI_SCODATA              COLOR_YELLOW
+
+#define COLOR_UNKNOWN_FEATURE_BIT      COLOR_WHITE_BG
+#define COLOR_UNKNOWN_EVENT_MASK       COLOR_WHITE_BG
+#define COLOR_UNKNOWN_LE_STATES                COLOR_WHITE_BG
+#define COLOR_UNKNOWN_SERVICE_CLASS    COLOR_WHITE_BG
+
+#define COLOR_PHY_PACKET               COLOR_BLUE
+
+static time_t time_offset = ((time_t) -1);
 static unsigned long filter_mask = 0;
+static bool index_filter = false;
+static uint16_t index_number = 0;
+static uint16_t index_current = 0;
+
+#define MAX_CONN 16
+
+struct conn_data {
+       uint16_t handle;
+       uint8_t  type;
+};
+
+static struct conn_data conn_list[MAX_CONN];
+
+static void assign_handle(uint16_t handle, uint8_t type)
+{
+       int i;
+
+       for (i = 0; i < MAX_CONN; i++) {
+               if (conn_list[i].handle == 0x0000) {
+                       conn_list[i].handle = handle;
+                       conn_list[i].type = type;
+                       break;
+               }
+       }
+}
+
+static void release_handle(uint16_t handle)
+{
+       int i;
+
+       for (i = 0; i < MAX_CONN; i++) {
+               if (conn_list[i].handle == handle) {
+                       conn_list[i].handle = 0x0000;
+                       conn_list[i].type = 0x00;
+                       break;
+               }
+       }
+}
+
+static uint8_t get_type(uint16_t handle)
+{
+       int i;
+
+       for (i = 0; i < MAX_CONN; i++) {
+               if (conn_list[i].handle == handle)
+                       return conn_list[i].type;
+       }
+
+       return 0xff;
+}
+
+void packet_set_filter(unsigned long filter)
+{
+       filter_mask = filter;
+}
+
+void packet_add_filter(unsigned long filter)
+{
+       if (index_filter)
+               filter &= ~PACKET_FILTER_SHOW_INDEX;
+
+       filter_mask |= filter;
+}
+
+void packet_del_filter(unsigned long filter)
+{
+       filter_mask &= ~filter;
+}
+
+void packet_select_index(uint16_t index)
+{
+       filter_mask &= ~PACKET_FILTER_SHOW_INDEX;
+
+       index_filter = true;
+       index_number = index;
+}
+
+#define print_space(x) printf("%*c", (x), ' ');
+
+static void print_packet(struct timeval *tv, uint16_t index, char ident,
+                                       const char *color, const char *label,
+                                       const char *text, const char *extra)
+{
+       int col = num_columns();
+       char line[256], ts_str[64];
+       int n, ts_len = 0, ts_pos = 0, len = 0, pos = 0;
+
+       if (filter_mask & PACKET_FILTER_SHOW_INDEX) {
+               if (use_color()) {
+                       n = sprintf(ts_str + ts_pos, "%s", COLOR_INDEX_LABEL);
+                       if (n > 0)
+                               ts_pos += n;
+               }
+
+               n = sprintf(ts_str + ts_pos, " [hci%d]", index);
+               if (n > 0) {
+                       ts_pos += n;
+                       ts_len += n;
+               }
+       }
+
+       if (tv) {
+               time_t t = tv->tv_sec;
+               struct tm tm;
+
+               localtime_r(&t, &tm);
+
+               if (use_color()) {
+                       n = sprintf(ts_str + ts_pos, "%s", COLOR_TIMESTAMP);
+                       if (n > 0)
+                               ts_pos += n;
+               }
+
+               if (filter_mask & PACKET_FILTER_SHOW_DATE) {
+                       n = sprintf(ts_str + ts_pos, " %04d-%02d-%02d",
+                               tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday);
+                       if (n > 0) {
+                               ts_pos += n;
+                               ts_len += n;
+                       }
+               }
+
+               if (filter_mask & PACKET_FILTER_SHOW_TIME) {
+                       n = sprintf(ts_str + ts_pos, " %02d:%02d:%02d.%06lu",
+                               tm.tm_hour, tm.tm_min, tm.tm_sec, tv->tv_usec);
+                       if (n > 0) {
+                               ts_pos += n;
+                               ts_len += n;
+                       }
+               }
+
+               if (filter_mask & PACKET_FILTER_SHOW_TIME_OFFSET) {
+                       n = sprintf(ts_str + ts_pos, " %lu.%06lu",
+                                       tv->tv_sec - time_offset, tv->tv_usec);
+                       if (n > 0) {
+                               ts_pos += n;
+                               ts_len += n;
+                       }
+               }
+       }
+
+       if (use_color()) {
+               n = sprintf(ts_str + ts_pos, "%s", COLOR_OFF);
+               if (n > 0)
+                       ts_pos += n;
+       }
+
+       if (use_color()) {
+               n = sprintf(line + pos, "%s", color);
+               if (n > 0)
+                       pos += n;
+       }
+
+       n = sprintf(line + pos, "%c %s", ident, label);
+       if (n > 0) {
+               pos += n;
+               len += n;
+       }
+
+       if (text) {
+               int extra_len = extra ? strlen(extra) : 0;
+               int max_len = col - len - extra_len - ts_len - 3;
+
+               n = snprintf(line + pos, max_len + 1, ": %s", text);
+               if (n > max_len) {
+                       line[pos + max_len - 1] = '.';
+                       line[pos + max_len - 2] = '.';
+                       if (line[pos + max_len - 3] == ' ')
+                               line[pos + max_len - 3] = '.';
+
+                       n = max_len;
+               }
+
+               if (n > 0) {
+                       pos += n;
+                       len += n;
+               }
+       }
+
+       if (use_color()) {
+               n = sprintf(line + pos, "%s", COLOR_OFF);
+               if (n > 0)
+                       pos += n;
+       }
+
+       if (extra) {
+               n = sprintf(line + pos, " %s", extra);
+               if (n > 0) {
+                       pos += n;
+                       len += n;
+               }
+       }
+
+       if (ts_len > 0) {
+               printf("%s", line);
+               if (len < col)
+                       print_space(col - len - ts_len - 1);
+               printf("%s%s\n", use_color() ? COLOR_TIMESTAMP : "", ts_str);
+       } else
+               printf("%s\n", line);
+}
+
+static const struct {
+       uint8_t error;
+       const char *str;
+} error2str_table[] = {
+       { 0x00, "Success"                                               },
+       { 0x01, "Unknown HCI Command"                                   },
+       { 0x02, "Unknown Connection Identifier"                         },
+       { 0x03, "Hardware Failure"                                      },
+       { 0x04, "Page Timeout"                                          },
+       { 0x05, "Authentication Failure"                                },
+       { 0x06, "PIN or Key Missing"                                    },
+       { 0x07, "Memory Capacity Exceeded"                              },
+       { 0x08, "Connection Timeout"                                    },
+       { 0x09, "Connection Limit Exceeded"                             },
+       { 0x0a, "Synchronous Connection Limit to a Device Exceeded"     },
+       { 0x0b, "ACL Connection Already Exists"                         },
+       { 0x0c, "Command Disallowed"                                    },
+       { 0x0d, "Connection Rejected due to Limited Resources"          },
+       { 0x0e, "Connection Rejected due to Security Reasons"           },
+       { 0x0f, "Connection Rejected due to Unacceptable BD_ADDR"       },
+       { 0x10, "Connection Accept Timeout Exceeded"                    },
+       { 0x11, "Unsupported Feature or Parameter Value"                },
+       { 0x12, "Invalid HCI Command Parameters"                        },
+       { 0x13, "Remote User Terminated Connection"                     },
+       { 0x14, "Remote Device Terminated due to Low Resources"         },
+       { 0x15, "Remote Device Terminated due to Power Off"             },
+       { 0x16, "Connection Terminated By Local Host"                   },
+       { 0x17, "Repeated Attempts"                                     },
+       { 0x18, "Pairing Not Allowed"                                   },
+       { 0x19, "Unknown LMP PDU"                                       },
+       { 0x1a, "Unsupported Remote Feature / Unsupported LMP Feature"  },
+       { 0x1b, "SCO Offset Rejected"                                   },
+       { 0x1c, "SCO Interval Rejected"                                 },
+       { 0x1d, "SCO Air Mode Rejected"                                 },
+       { 0x1e, "Invalid LMP Parameters"                                },
+       { 0x1f, "Unspecified Error"                                     },
+       { 0x20, "Unsupported LMP Parameter Value"                       },
+       { 0x21, "Role Change Not Allowed"                               },
+       { 0x22, "LMP Response Timeout / LL Response Timeout"            },
+       { 0x23, "LMP Error Transaction Collision"                       },
+       { 0x24, "LMP PDU Not Allowed"                                   },
+       { 0x25, "Encryption Mode Not Acceptable"                        },
+       { 0x26, "Link Key cannot be Changed"                            },
+       { 0x27, "Requested QoS Not Supported"                           },
+       { 0x28, "Instant Passed"                                        },
+       { 0x29, "Pairing With Unit Key Not Supported"                   },
+       { 0x2a, "Different Transaction Collision"                       },
+       { 0x2b, "Reserved"                                              },
+       { 0x2c, "QoS Unacceptable Parameter"                            },
+       { 0x2d, "QoS Rejected"                                          },
+       { 0x2e, "Channel Classification Not Supported"                  },
+       { 0x2f, "Insufficient Security"                                 },
+       { 0x30, "Parameter Out Of Manadatory Range"                     },
+       { 0x31, "Reserved"                                              },
+       { 0x32, "Role Switch Pending"                                   },
+       { 0x33, "Reserved"                                              },
+       { 0x34, "Reserved Slot Violation"                               },
+       { 0x35, "Role Switch Failed"                                    },
+       { 0x36, "Extended Inquiry Response Too Large"                   },
+       { 0x37, "Secure Simple Pairing Not Supported By Host"           },
+       { 0x38, "Host Busy - Pairing"                                   },
+       { 0x39, "Connection Rejected due to No Suitable Channel Found"  },
+       { 0x3a, "Controller Busy"                                       },
+       { 0x3b, "Unacceptable Connection Interval"                      },
+       { 0x3c, "Directed Advertising Timeout"                          },
+       { 0x3d, "Connection Terminated due to MIC Failure"              },
+       { 0x3e, "Connection Failed to be Established"                   },
+       { 0x3f, "MAC Connection Failed"                                 },
+       { }
+};
+
+static void print_error(const char *label, uint8_t error)
+{
+       const char *str = "Unknown";
+       const char *color_on, *color_off;
+       int i;
+
+       for (i = 0; error2str_table[i].str; i++) {
+               if (error2str_table[i].error == error) {
+                       str = error2str_table[i].str;
+                       break;
+               }
+       }
+
+       if (use_color()) {
+               if (error)
+                       color_on = COLOR_RED;
+               else
+                       color_on = COLOR_GREEN;
+               color_off = COLOR_OFF;
+       } else {
+               color_on = "";
+               color_off = "";
+       }
+
+       print_field("%s: %s%s%s (0x%2.2x)", label,
+                               color_on, str, color_off, error);
+}
+
+static void print_status(uint8_t status)
+{
+       print_error("Status", status);
+}
+
+static void print_reason(uint8_t reason)
+{
+       print_error("Reason", reason);
+}
+
+static void print_bdaddr(const uint8_t *bdaddr)
+{
+       print_field("Address: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"
+                                       " (OUI %2.2X-%2.2X-%2.2X)",
+                                       bdaddr[5], bdaddr[4], bdaddr[3],
+                                       bdaddr[2], bdaddr[1], bdaddr[0],
+                                       bdaddr[5], bdaddr[4], bdaddr[3]);
+}
+
+static void print_addr(const char *label, const uint8_t *addr,
+                                               uint8_t addr_type)
+{
+       const char *str;
+
+       switch (addr_type) {
+       case 0x00:
+               print_field("%s: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X"
+                               " (OUI %2.2X-%2.2X-%2.2X)", label,
+                                       addr[5], addr[4], addr[3],
+                                       addr[2], addr[1], addr[0],
+                                       addr[5], addr[4], addr[3]);
+               break;
+       case 0x01:
+               switch ((addr[5] & 0xc0) >> 6) {
+               case 0x00:
+                       str = "Non-Resolvable";
+                       break;
+               case 0x01:
+                       str = "Resolvable";
+                       break;
+               case 0x03:
+                       str = "Static";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("%s: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X (%s)",
+                                       label, addr[5], addr[4], addr[3],
+                                       addr[2], addr[1], addr[0], str);
+               break;
+       default:
+               print_field("%s: %2.2X-%2.2X-%2.2X-%2.2X-%2.2X-%2.2X",
+                                       label, addr[5], addr[4], addr[3],
+                                       addr[2], addr[1], addr[0]);
+               break;
+       }
+}
+
+static void print_addr_type(const char *label, uint8_t addr_type)
+{
+       const char *str;
+
+       switch (addr_type) {
+       case 0x00:
+               str = "Public";
+               break;
+       case 0x01:
+               str = "Random";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("%s: %s (0x%2.2x)", label, str, addr_type);
+}
+
+static void print_handle(uint16_t handle)
+{
+       print_field("Handle: %d", btohs(handle));
+}
+
+static void print_phy_handle(uint8_t phy_handle)
+{
+       print_field("Physical handle: %d", phy_handle);
+}
+
+static void print_pkt_type(uint16_t pkt_type)
+{
+       print_field("Packet type: 0x%4.4x", btohs(pkt_type));
+}
+
+static void print_iac(const uint8_t *lap)
+{
+       const char *str = "";
+
+       if (lap[2] == 0x9e && lap[1] == 0x8b) {
+               switch (lap[0]) {
+               case 0x33:
+                       str = " (General Inquiry)";
+                       break;
+               case 0x00:
+                       str = " (Limited Inquiry)";
+                       break;
+               }
+       }
+
+       print_field("Access code: 0x%2.2x%2.2x%2.2x%s",
+                                               lap[2], lap[1], lap[0], str);
+}
+
+static void print_auth_enable(uint8_t enable)
+{
+       const char *str;
+
+       switch (enable) {
+       case 0x00:
+               str = "Authentication not required";
+               break;
+       case 0x01:
+               str = "Authentication required for all connections";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Enable: %s (0x%2.2x)", str, enable);
+}
+
+static void print_encrypt_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Encryption not required";
+               break;
+       case 0x01:
+               str = "Encryption required for all connections";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} svc_class_table[] = {
+       { 0, "Positioning (Location identification)"            },
+       { 1, "Networking (LAN, Ad hoc)"                         },
+       { 2, "Rendering (Printing, Speaker)"                    },
+       { 3, "Capturing (Scanner, Microphone)"                  },
+       { 4, "Object Transfer (v-Inbox, v-Folder)"              },
+       { 5, "Audio (Speaker, Microphone, Headset)"             },
+       { 6, "Telephony (Cordless telephony, Modem, Headset)"   },
+       { 7, "Information (WEB-server, WAP-server)"             },
+       { }
+};
+
+static const struct {
+       uint8_t val;
+       const char *str;
+} major_class_computer_table[] = {
+       { 0x00, "Uncategorized, code for device not assigned"   },
+       { 0x01, "Desktop workstation"                           },
+       { 0x02, "Server-class computer"                         },
+       { 0x03, "Laptop"                                        },
+       { 0x04, "Handheld PC/PDA (clam shell)"                  },
+       { 0x05, "Palm sized PC/PDA"                             },
+       { 0x06, "Wearable computer (Watch sized)"               },
+       { 0x07, "Tablet"                                        },
+       { }
+};
+
+static const char *major_class_computer(uint8_t minor)
+{
+       int i;
+
+       for (i = 0; major_class_computer_table[i].str; i++) {
+               if (major_class_computer_table[i].val == minor)
+                       return major_class_computer_table[i].str;
+       }
+
+       return NULL;
+}
+
+static const struct {
+       uint8_t val;
+       const char *str;
+} major_class_phone_table[] = {
+       { 0x00, "Uncategorized, code for device not assigned"   },
+       { 0x01, "Cellular"                                      },
+       { 0x02, "Cordless"                                      },
+       { 0x03, "Smart phone"                                   },
+       { 0x04, "Wired modem or voice gateway"                  },
+       { 0x05, "Common ISDN Access"                            },
+       { }
+};
+
+static const char *major_class_phone(uint8_t minor)
+{
+       int i;
+
+       for (i = 0; major_class_phone_table[i].str; i++) {
+               if (major_class_phone_table[i].val == minor)
+                       return major_class_phone_table[i].str;
+       }
+
+       return NULL;
+}
+
+static const struct {
+       uint8_t val;
+       const char *str;
+} major_class_av_table[] = {
+       { 0x00, "Uncategorized, code for device not assigned"   },
+       { 0x01, "earable Headset Device"                        },
+       { 0x02, "Hands-free Device"                             },
+       { 0x04, "Microphone"                                    },
+       { 0x05, "Loudspeaker"                                   },
+       { 0x06, "Headphones"                                    },
+       { 0x07, "Portable Audio"                                },
+       { 0x08, "Car audio"                                     },
+       { 0x09, "Set-top box"                                   },
+       { 0x0a, "HiFi Audio Device"                             },
+       { 0x0b, "VCR"                                           },
+       { 0x0c, "Video Camera"                                  },
+       { 0x0d, "Camcorder"                                     },
+       { 0x0e, "Video Monitor"                                 },
+       { 0x0f, "Video Display and Loudspeaker"                 },
+       { 0x10, "Video Conferencing"                            },
+       { 0x12, "Gaming/Toy"                                    },
+       { }
+};
+
+static const char *major_class_av(uint8_t minor)
+{
+       int i;
+
+       for (i = 0; major_class_av_table[i].str; i++) {
+               if (major_class_av_table[i].val == minor)
+                       return major_class_av_table[i].str;
+       }
+
+       return NULL;
+}
+
+static const struct {
+       uint8_t val;
+       const char *str;
+} major_class_wearable_table[] = {
+       { 0x01, "Wrist Watch"   },
+       { 0x02, "Pager"         },
+       { 0x03, "Jacket"        },
+       { 0x04, "Helmet"        },
+       { 0x05, "Glasses"       },
+       { }
+};
+
+static const char *major_class_wearable(uint8_t minor)
+{
+       int i;
+
+       for (i = 0; major_class_wearable_table[i].str; i++) {
+               if (major_class_wearable_table[i].val == minor)
+                       return major_class_wearable_table[i].str;
+       }
+
+       return NULL;
+}
+
+static const struct {
+       uint8_t val;
+       const char *str;
+       const char *(*func)(uint8_t minor);
+} major_class_table[] = {
+       { 0x00, "Miscellaneous"                                         },
+       { 0x01, "Computer (desktop, notebook, PDA, organizers)",
+                                               major_class_computer    },
+       { 0x02, "Phone (cellular, cordless, payphone, modem)",
+                                               major_class_phone       },
+       { 0x03, "LAN /Network Access point"                             },
+       { 0x04, "Audio/Video (headset, speaker, stereo, video, vcr)",
+                                               major_class_av          },
+       { 0x05, "Peripheral (mouse, joystick, keyboards)"               },
+       { 0x06, "Imaging (printing, scanner, camera, display)"          },
+       { 0x07, "Wearable",                     major_class_wearable    },
+       { 0x08, "Toy"                                                   },
+       { 0x09, "Health"                                                },
+       { 0x1f, "Uncategorized, specific device code not specified"     },
+       { }
+};
+
+static void print_dev_class(const uint8_t *dev_class)
+{
+       uint8_t mask, major_cls, minor_cls;
+       const char *major_str = NULL;
+       const char *minor_str = NULL;
+       int i;
+
+       print_field("Class: 0x%2.2x%2.2x%2.2x",
+                       dev_class[2], dev_class[1], dev_class[0]);
+
+       if ((dev_class[0] & 0x03) != 0x00) {
+               print_field("  Format type: 0x%2.2x", dev_class[0] & 0x03);
+               print_text(COLOR_ERROR, "  invalid format type");
+               return;
+       }
+
+       major_cls = dev_class[1] & 0x1f;
+       minor_cls = (dev_class[0] & 0xfc) >> 2;
+
+       for (i = 0; major_class_table[i].str; i++) {
+               if (major_class_table[i].val == major_cls) {
+                       major_str = major_class_table[i].str;
+
+                       if (!major_class_table[i].func)
+                               break;
+
+                       minor_str = major_class_table[i].func(minor_cls);
+                       break;
+               }
+       }
+
+       if (major_str) {
+               print_field("  Major class: %s", major_str);
+               if (minor_str)
+                       print_field("  Minor class: %s", minor_str);
+               else
+                       print_field("  Minor class: 0x%2.2x", minor_cls);
+       } else {
+               print_field("  Major class: 0x%2.2x", major_cls);
+               print_field("  Minor class: 0x%2.2x", minor_cls);
+       }
+
+       if (dev_class[1] & 0x20)
+               print_field("  Limited Discoverable Mode");
+
+       if ((dev_class[1] & 0xc0) != 0x00) {
+               print_text(COLOR_ERROR, "  invalid service class");
+               return;
+       }
+
+       mask = dev_class[2];
+
+       for (i = 0; svc_class_table[i].str; i++) {
+               if (dev_class[2] & (1 << svc_class_table[i].bit)) {
+                       print_field("  %s", svc_class_table[i].str);
+                       mask &= ~(1 << svc_class_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_SERVICE_CLASS,
+                               "  Unknown service class (0x%2.2x)", mask);
+}
+
+static void print_voice_setting(uint16_t setting)
+{
+       print_field("Setting: 0x%4.4x", btohs(setting));
+}
+
+static void print_retransmission_effort(uint8_t effort)
+{
+       const char *str;
+
+       switch (effort) {
+       case 0x00:
+               str = "No retransmissions";
+               break;
+       case 0x01:
+               str = "Optimize for power consumption";
+               break;
+       case 0x02:
+               str = "Optimize for link quality";
+               break;
+       case 0xff:
+               str = "Don't care";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Retransmission effort: %s (0x%2.2x)", str, effort);
+}
+
+static void print_scan_enable(uint8_t scan_enable)
+{
+       const char *str;
+
+       switch (scan_enable) {
+       case 0x00:
+               str = "No Scans";
+               break;
+       case 0x01:
+               str = "Inquiry Scan";
+               break;
+       case 0x02:
+               str = "Page Scan";
+               break;
+       case 0x03:
+               str = "Inquiry Scan + Page Scan";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Scan enable: %s (0x%2.2x)", str, scan_enable);
+}
+
+static void print_link_policy(uint16_t link_policy)
+{
+       print_field("Link policy: 0x%4.4x", btohs(link_policy));
+}
+
+static void print_air_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "u-law log";
+               break;
+       case 0x01:
+               str = "A-law log";
+               break;
+       case 0x02:
+               str = "CVSD";
+               break;
+       case 0x03:
+               str = "Transparent";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Air mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_inquiry_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Standard Inquiry Result";
+               break;
+       case 0x01:
+               str = "Inquiry Result with RSSI";
+               break;
+       case 0x02:
+               str = "Inquiry Result with RSSI or Extended Inquiry Result";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_inquiry_scan_type(uint8_t type)
+{
+       const char *str;
+
+       switch (type) {
+       case 0x00:
+               str = "Standard Scan";
+               break;
+       case 0x01:
+               str = "Interlaced Scan";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, type);
+}
+
+static void print_pscan_type(uint8_t type)
+{
+       const char *str;
+
+       switch (type) {
+       case 0x00:
+               str = "Standard Scan";
+               break;
+       case 0x01:
+               str = "Interlaced Scan";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, type);
+}
+
+static void print_afh_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_simple_pairing_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_pscan_rep_mode(uint8_t pscan_rep_mode)
+{
+       const char *str;
+
+       switch (pscan_rep_mode) {
+       case 0x00:
+               str = "R0";
+               break;
+       case 0x01:
+               str = "R1";
+               break;
+       case 0x02:
+               str = "R2";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Page scan repetition mode: %s (0x%2.2x)",
+                                               str, pscan_rep_mode);
+}
+
+static void print_pscan_period_mode(uint8_t pscan_period_mode)
+{
+       const char *str;
+
+       switch (pscan_period_mode) {
+       case 0x00:
+               str = "P0";
+               break;
+       case 0x01:
+               str = "P1";
+               break;
+       case 0x02:
+               str = "P2";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Page period mode: %s (0x%2.2x)", str, pscan_period_mode);
+}
+
+static void print_pscan_mode(uint8_t pscan_mode)
+{
+       const char *str;
+
+       switch (pscan_mode) {
+       case 0x00:
+               str = "Mandatory";
+               break;
+       case 0x01:
+               str = "Optional I";
+               break;
+       case 0x02:
+               str = "Optional II";
+               break;
+       case 0x03:
+               str = "Optional III";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Page scan mode: %s (0x%2.2x)", str, pscan_mode);
+}
+
+static void print_clock_offset(uint16_t clock_offset)
+{
+       print_field("Clock offset: 0x%4.4x", btohs(clock_offset));
+}
+
+static void print_clock(uint32_t clock)
+{
+       print_field("Clock: 0x%8.8x", btohl(clock));
+}
+
+static void print_clock_accuracy(uint16_t accuracy)
+{
+       if (btohs(accuracy) == 0xffff)
+               print_field("Accuracy: Unknown (0x%4.4x)", btohs(accuracy));
+       else
+               print_field("Accuracy: %.4f msec (0x%4.4x)",
+                               btohs(accuracy) * 0.3125, btohs(accuracy));
+}
+
+static void print_link_type(uint8_t link_type)
+{
+       const char *str;
+
+       switch (link_type) {
+       case 0x00:
+               str = "SCO";
+               break;
+       case 0x01:
+               str = "ACL";
+               break;
+       case 0x02:
+               str = "eSCO";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Link type: %s (0x%2.2x)", str, link_type);
+}
+
+static void print_encr_mode(uint8_t encr_mode)
+{
+       const char *str;
+
+       switch (encr_mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Encryption: %s (0x%2.2x)", str, encr_mode);
+}
+
+static void print_encr_mode_change(uint8_t encr_mode, uint16_t handle)
+{
+       const char *str;
+       uint8_t conn_type;
+
+       conn_type = get_type(btohs(handle));
+
+       switch (encr_mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               switch (conn_type) {
+               case 0x00:
+                       str = "Enabled with E0";
+                       break;
+               case 0x01:
+                       str = "Enabled with AES-CCM";
+                       break;
+               default:
+                       str = "Enabled";
+                       break;
+               }
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Encryption: %s (0x%2.2x)", str, encr_mode);
+}
+
+static void print_pin_type(uint8_t pin_type)
+{
+       const char *str;
+
+       switch (pin_type) {
+       case 0x00:
+               str = "Variable";
+               break;
+       case 0x01:
+               str = "Fixed";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("PIN type: %s (0x%2.2x)", str, pin_type);
+}
+
+static void print_key_flag(uint8_t key_flag)
+{
+       const char *str;
+
+       switch (key_flag) {
+       case 0x00:
+               str = "Semi-permanent";
+               break;
+       case 0x01:
+               str = "Temporary";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Key flag: %s (0x%2.2x)", str, key_flag);
+}
+
+static void print_key_len(uint8_t key_len)
+{
+       const char *str;
+
+       switch (key_len) {
+       case 32:
+               str = "802.11 PAL";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Key length: %s (%d)", str, key_len);
+}
+
+static void print_key_type(uint8_t key_type)
+{
+       const char *str;
+
+       switch (key_type) {
+       case 0x00:
+               str = "Combination key";
+               break;
+       case 0x01:
+               str = "Local Unit key";
+               break;
+       case 0x02:
+               str = "Remote Unit key";
+               break;
+       case 0x03:
+               str = "Debug Combination key";
+               break;
+       case 0x04:
+               str = "Unauthenticated Combination key";
+               break;
+       case 0x05:
+               str = "Authenticated Combination key";
+               break;
+       case 0x06:
+               str = "Changed Combination key";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Key type: %s (0x%2.2x)", str, key_type);
+}
+
+static void print_key_size(uint8_t key_size)
+{
+       print_field("Key size: %d", key_size);
+}
+
+static void print_hex_field(const char *label, const uint8_t *data,
+                                                               uint8_t len)
+{
+       char str[len * 2 + 1];
+       uint8_t i;
+
+       str[0] = '\0';
+
+       for (i = 0; i < len; i++)
+               sprintf(str + (i * 2), "%2.2x", data[i]);
+
+       print_field("%s: %s", label, str);
+}
+
+static void print_key(const char *label, const uint8_t *link_key)
+{
+       print_hex_field(label, link_key, 16);
+}
+
+static void print_link_key(const uint8_t *link_key)
+{
+       print_key("Link key", link_key);
+}
+
+static void print_pin_code(const uint8_t *pin_code, uint8_t pin_len)
+{
+       char str[pin_len + 1];
+       uint8_t i;
+
+       for (i = 0; i < pin_len; i++)
+               sprintf(str + i, "%c", (const char) pin_code[i]);
+
+       print_field("PIN code: %s", str);
+}
+
+static void print_hash(const char *label, const uint8_t *hash)
+{
+       print_key("Hash C from %s", hash);
+}
+
+static void print_randomizer(const char *label, const uint8_t *randomizer)
+{
+       print_key("Randomizer R with %s", randomizer);
+}
+
+static void print_passkey(uint32_t passkey)
+{
+       print_field("Passkey: %06d", btohl(passkey));
+}
+
+static void print_io_capability(uint8_t capability)
+{
+       const char *str;
+
+       switch (capability) {
+       case 0x00:
+               str = "DisplayOnly";
+               break;
+       case 0x01:
+               str = "DisplayYesNo";
+               break;
+       case 0x02:
+               str = "KeyboardOnly";
+               break;
+       case 0x03:
+               str = "NoInputNoOutput";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("IO capability: %s (0x%2.2x)", str, capability);
+}
+
+static void print_oob_data(uint8_t oob_data)
+{
+       const char *str;
+
+       switch (oob_data) {
+       case 0x00:
+               str = "Authentication data not present";
+               break;
+       case 0x01:
+               str = "Authentication data present";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("OOB data: %s (0x%2.2x)", str, oob_data);
+}
+
+static void print_authentication(uint8_t authentication)
+{
+       const char *str;
+
+       switch (authentication) {
+       case 0x00:
+               str = "No Bonding - MITM not required";
+               break;
+       case 0x01:
+               str = "No Bonding - MITM required";
+               break;
+       case 0x02:
+               str = "Dedicated Bonding - MITM not required";
+               break;
+       case 0x03:
+               str = "Dedicated Bonding - MITM required";
+               break;
+       case 0x04:
+               str = "General Bonding - MITM not required";
+               break;
+       case 0x05:
+               str = "General Bonding - MITM required";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Authentication: %s (0x%2.2x)", str, authentication);
+}
+
+static void print_location_domain_aware(uint8_t aware)
+{
+       const char *str;
+
+       switch (aware) {
+       case 0x00:
+               str = "Regulatory domain unknown";
+               break;
+       case 0x01:
+               str = "Regulatory domain known";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Domain aware: %s (0x%2.2x)", str, aware);
+}
+
+static void print_location_domain(const uint8_t *domain)
+{
+       print_field("Domain: %c%c (0x%2.2x%2.2x)",
+               (char) domain[0], (char) domain[1], domain[0], domain[1]);
+}
+
+static void print_location_domain_options(uint8_t options)
+{
+       print_field("Domain options: %c (0x%2.2x)", (char) options, options);
+}
+
+static void print_location_options(uint8_t options)
+{
+       print_field("Options: 0x%2.2x", options);
+}
+
+static void print_flow_control_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Packet based";
+               break;
+       case 0x01:
+               str = "Data block based";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Flow control mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_flow_direction(uint8_t direction)
+{
+       const char *str;
+
+       switch (direction) {
+       case 0x00:
+               str = "Outgoing";
+               break;
+       case 0x01:
+               str = "Incoming";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Flow direction: %s (0x%2.2x)", str, direction);
+}
+
+static void print_service_type(uint8_t service_type)
+{
+       const char *str;
+
+       switch (service_type) {
+       case 0x00:
+               str = "No Traffic";
+               break;
+       case 0x01:
+               str = "Best Effort";
+               break;
+       case 0x02:
+               str = "Guaranteed";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Service type: %s (0x%2.2x)", str, service_type);
+}
+
+static void print_flow_spec(const char *label, const uint8_t *data)
+{
+       const char *str;
+
+       switch (data[1]) {
+       case 0x00:
+               str = "No traffic";
+               break;
+       case 0x01:
+               str = "Best effort";
+               break;
+       case 0x02:
+               str = "Guaranteed";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("%s flow spec: 0x%2.2x", label, data[0]);
+       print_field("  Service type: %s (0x%2.2x)", str, data[1]);
+       print_field("  Maximum SDU size: 0x%4.4x", bt_get_le16(data + 2));
+       print_field("  SDU inter-arrival time: 0x%8.8x", bt_get_le32(data + 4));
+       print_field("  Access latency: 0x%8.8x", bt_get_le32(data + 8));
+       print_field("  Flush timeout: 0x%8.8x", bt_get_le32(data + 12));
+}
+
+static void print_short_range_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Short range mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_amp_status(uint8_t amp_status)
+{
+       const char *str;
+
+       switch (amp_status) {
+       case 0x00:
+               str = "Present";
+               break;
+       case 0x01:
+               str = "Bluetooth only";
+               break;
+       case 0x02:
+               str = "No capacity";
+               break;
+       case 0x03:
+               str = "Low capacity";
+               break;
+       case 0x04:
+               str = "Medium capacity";
+               break;
+       case 0x05:
+               str = "High capacity";
+               break;
+       case 0x06:
+               str = "Full capacity";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("AMP status: %s (0x%2.2x)", str, amp_status);
+}
+
+static void print_num_resp(uint8_t num_resp)
+{
+       print_field("Num responses: %d", num_resp);
+}
+
+static void print_num_reports(uint8_t num_reports)
+{
+       print_field("Num reports: %d", num_reports);
+}
+
+static void print_rssi(int8_t rssi)
+{
+       if ((uint8_t) rssi == 0x99 || rssi == 127)
+               print_field("RSSI: invalid (0x%2.2x)", (uint8_t) rssi);
+       else
+               print_field("RSSI: %d dBm (0x%2.2x)", rssi, (uint8_t) rssi);
+}
+
+static void print_slot_625(const char *label, uint16_t value)
+{
+        print_field("%s: %.3f msec (0x%4.4x)", label,
+                                       btohs(value) * 0.625, btohs(value));
+}
+
+static void print_slot_125(const char *label, uint16_t value)
+{
+       print_field("%s: %.2f msec (0x%4.4x)", label,
+                                       btohs(value) * 1.25, btohs(value));
+}
+
+static void print_timeout(uint16_t timeout)
+{
+       print_slot_625("Timeout", timeout);
+}
+
+static void print_interval(uint16_t interval)
+{
+       print_slot_625("Interval", interval);
+}
+
+static void print_window(uint16_t window)
+{
+       print_slot_625("Window", window);
+}
+
+static void print_role(uint8_t role)
+{
+       const char *str;
+
+       switch (role) {
+       case 0x00:
+               str = "Master";
+               break;
+       case 0x01:
+               str = "Slave";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Role: %s (0x%2.2x)", str, role);
+}
+
+static void print_mode(uint8_t mode)
+{
+       const char *str;
+
+       switch (mode) {
+       case 0x00:
+               str = "Active";
+               break;
+       case 0x01:
+               str = "Hold";
+               break;
+       case 0x02:
+               str = "Sniff";
+               break;
+       case 0x03:
+               str = "Park";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Mode: %s (0x%2.2x)", str, mode);
+}
+
+static void print_name(const uint8_t *name)
+{
+       char str[249];
+
+       memcpy(str, name, 248);
+       str[248] = '\0';
+
+       print_field("Name: %s", str);
+}
+
+static void print_channel_map(const uint8_t *map)
+{
+       char str[21];
+       int i;
+
+       for (i = 0; i < 10; i++)
+               sprintf(str + (i * 2), "%2.2x", map[i]);
+
+       print_field("Channel map: 0x%s", str);
+}
+
+void packet_print_version(const char *label, uint8_t version,
+                               const char *sublabel, uint16_t subversion)
+{
+       const char *str;
+
+       switch (version) {
+       case 0x00:
+               str = "Bluetooth 1.0b";
+               break;
+       case 0x01:
+               str = "Bluetooth 1.1";
+               break;
+       case 0x02:
+               str = "Bluetooth 1.2";
+               break;
+       case 0x03:
+               str = "Bluetooth 2.0";
+               break;
+       case 0x04:
+               str = "Bluetooth 2.1";
+               break;
+       case 0x05:
+               str = "Bluetooth 3.0";
+               break;
+       case 0x06:
+               str = "Bluetooth 4.0";
+               break;
+       case 0x07:
+               str = "Bluetooth 4.1";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("%s: %s (0x%2.2x) - %s %d (0x%4.4x)", label, str, version,
+                                       sublabel, subversion, subversion);
+}
+
+static void print_hci_version(uint8_t version, uint16_t revision)
+{
+       packet_print_version("HCI version", version,
+                               "Revision", btohs(revision));
+}
+
+static void print_lmp_version(uint8_t version, uint16_t subversion)
+{
+       packet_print_version("LMP version", version,
+                               "Subversion", btohs(subversion));
+}
+
+static void print_pal_version(uint8_t version, uint16_t subversion)
+{
+       const char *str;
+
+       switch (version) {
+       case 0x01:
+               str = "Bluetooth 3.0";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("PAL version: %s (0x%2.2x) - Subversion %d (0x%4.4x)",
+                       str, version, btohs(subversion), btohs(subversion));
+}
+
+void packet_print_company(const char *label, uint16_t company)
+{
+       print_field("%s: %s (%d)", label, bt_compidtostr(company), company);
+}
+
+static void print_manufacturer(uint16_t manufacturer)
+{
+       packet_print_company("Manufacturer", btohs(manufacturer));
+}
+
+static const char *get_supported_command(int bit);
+
+static void print_commands(const uint8_t *commands)
+{
+       unsigned int count = 0;
+       int i, n;
+
+       for (i = 0; i < 64; i++) {
+               for (n = 0; n < 8; n++) {
+                       if (commands[i] & (1 << n))
+                               count++;
+               }
+       }
+
+       print_field("Commands: %u entr%s", count, count == 1 ? "y" : "ies");
+
+       for (i = 0; i < 64; i++) {
+               for (n = 0; n < 8; n++) {
+                       const char *cmd;
+
+                       if (!(commands[i] & (1 << n)))
+                               continue;
+
+                       cmd = get_supported_command((i * 8) + n);
+                       print_field("  %s (Octet %d - Bit %d)", cmd, i, n);
+               }
+       }
+}
+
+struct features_data {
+       uint8_t bit;
+       const char *str;
+};
+
+static const struct features_data features_page0[] = {
+       {  0, "3 slot packets"                          },
+       {  1, "5 slot packets"                          },
+       {  2, "Encryption"                              },
+       {  3, "Slot offset"                             },
+       {  4, "Timing accuracy"                         },
+       {  5, "Role switch"                             },
+       {  6, "Hold mode"                               },
+       {  7, "Sniff mode"                              },
+       {  8, "Park state"                              },
+       {  9, "Power control requests"                  },
+       { 10, "Channel quality driven data rate (CQDDR)"},
+       { 11, "SCO link"                                },
+       { 12, "HV2 packets"                             },
+       { 13, "HV3 packets"                             },
+       { 14, "u-law log synchronous data"              },
+       { 15, "A-law log synchronous data"              },
+       { 16, "CVSD synchronous data"                   },
+       { 17, "Paging parameter negotiation"            },
+       { 18, "Power control"                           },
+       { 19, "Transparent synchronous data"            },
+       { 20, "Flow control lag (least significant bit)"},
+       { 21, "Flow control lag (middle bit)"           },
+       { 22, "Flow control lag (most significant bit)" },
+       { 23, "Broadcast Encryption"                    },
+       { 25, "Enhanced Data Rate ACL 2 Mbps mode"      },
+       { 26, "Enhanced Data Rate ACL 3 Mbps mode"      },
+       { 27, "Enhanced inquiry scan"                   },
+       { 28, "Interlaced inquiry scan"                 },
+       { 29, "Interlaced page scan"                    },
+       { 30, "RSSI with inquiry results"               },
+       { 31, "Extended SCO link (EV3 packets)"         },
+       { 32, "EV4 packets"                             },
+       { 33, "EV5 packets"                             },
+       { 35, "AFH capable slave"                       },
+       { 36, "AFH classification slave"                },
+       { 37, "BR/EDR Not Supported"                    },
+       { 38, "LE Supported (Controller)"               },
+       { 39, "3-slot Enhanced Data Rate ACL packets"   },
+       { 40, "5-slot Enhanced Data Rate ACL packets"   },
+       { 41, "Sniff subrating"                         },
+       { 42, "Pause encryption"                        },
+       { 43, "AFH capable master"                      },
+       { 44, "AFH classification master"               },
+       { 45, "Enhanced Data Rate eSCO 2 Mbps mode"     },
+       { 46, "Enhanced Data Rate eSCO 3 Mbps mode"     },
+       { 47, "3-slot Enhanced Data Rate eSCO packets"  },
+       { 48, "Extended Inquiry Response"               },
+       { 49, "Simultaneous LE and BR/EDR (Controller)" },
+       { 51, "Secure Simple Pairing"                   },
+       { 52, "Encapsulated PDU"                        },
+       { 53, "Erroneous Data Reporting"                },
+       { 54, "Non-flushable Packet Boundary Flag"      },
+       { 56, "Link Supervision Timeout Changed Event"  },
+       { 57, "Inquiry TX Power Level"                  },
+       { 58, "Enhanced Power Control"                  },
+       { 63, "Extended features"                       },
+       { }
+};
+
+static const struct features_data features_page1[] = {
+       {  0, "Secure Simple Pairing (Host Support)"    },
+       {  1, "LE Supported (Host)"                     },
+       {  2, "Simultaneous LE and BR/EDR (Host)"       },
+       { }
+};
+
+static const struct features_data features_page2[] = {
+       {  0, "Connectionless Slave Broadcast - Master" },
+       {  1, "Connectionless Slave Broadcast - Slave"  },
+       {  2, "Synchronization Train"                   },
+       {  3, "Synchronization Scan"                    },
+       {  4, "Inquiry Response Notification Event"     },
+       { }
+};
+
+static const struct features_data features_le[] = {
+       {  0, "LE Encryption"                           },
+       { }
+};
+
+static void print_features(uint8_t page, const uint8_t *features_array,
+                                                               uint8_t type)
+{
+       const struct features_data *features_table = NULL;
+       uint64_t mask, features = 0;
+       char str[41];
+       int i;
+
+       for (i = 0; i < 8; i++) {
+               sprintf(str + (i * 5), " 0x%2.2x", features_array[i]);
+               features |= ((uint64_t) features_array[i]) << (i * 8);
+       }
+
+       print_field("Features:%s", str);
+
+       switch (type) {
+       case 0x00:
+               switch (page) {
+               case 0:
+                       features_table = features_page0;
+                       break;
+               case 1:
+                       features_table = features_page1;
+                       break;
+               case 2:
+                       features_table = features_page2;
+                       break;
+               }
+               break;
+       case 0x01:
+               switch (page) {
+               case 0:
+                       features_table = features_le;
+                       break;
+               }
+               break;
+       }
+
+       if (!features_table)
+               return;
+
+       mask = features;
+
+       for (i = 0; features_table[i].str; i++) {
+               if (features & (((uint64_t) 1) << features_table[i].bit)) {
+                       print_field("  %s", features_table[i].str);
+                       mask &= ~(((uint64_t) 1) << features_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_FEATURE_BIT, "  Unknown features "
+                                               "(0x%16.16" PRIx64 ")", mask);
+}
+
+void packet_print_features_ll(const uint8_t *features)
+{
+       print_features(0, features, 0x01);
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} le_states_table[] = {
+       {  0, "Non-connectable Advertising State"                       },
+       {  1, "Scannable Advertising State"                             },
+       {  2, "Connectable Advertising State"                           },
+       {  3, "Directed Advertising State"                              },
+       {  4, "Passive Scanning State"                                  },
+       {  5, "Active Scanning State"                                   },
+       {  6, "Initiating State and Connection State in Master Role"    },
+       {  7, "Connection State in Slave Role"                          },
+       {  8, "Non-connectable Advertising State and "
+                               "Passive Scanning State combination"    },
+       {  9, "Scannable Advertising State and "
+                               "Passive Scanning State combination"    },
+       { 10, "Connectable Advertising State and "
+                               "Passive Scanning State combination"    },
+       { 11, "Directed Advertising State and "
+                               "Passive Scanning State combination"    },
+       { 12, "Non-connectable Advertising State and "
+                               "Active Scanning State combination"     },
+       { 13, "Scannable Advertising State and "
+                               "Active Scanning State combination"     },
+       { 14, "Connectable Advertising State and "
+                               "Active Scanning State combination"     },
+       { 15, "Directed Advertising State and "
+                               "Active Scanning State combination"     },
+       { 16, "Non-connectable Advertising State and "
+                               "Initiating State combination"          },
+       { 17, "Scannable Advertising State and "
+                               "Initiating State combination"          },
+       { 18, "Non-connectable Advertising State and "
+                               "Mater Role combination"                },
+       { 19, "Scannable Advertising State and "
+                               "Master Role combination"               },
+       { 20, "Non-connectable Advertising State and "
+                               "Slave Role combination"                },
+       { 21, "Scannable Advertising State and "
+                               "Slave Role combination"                },
+       { 22, "Passive Scanning State and Initiating State combination" },
+       { 23, "Active Scanning State and Initiating State combination"  },
+       { 24, "Passive Scanning State and Master Role combination"      },
+       { 25, "Active Scanning State and Master Role combination"       },
+       { 26, "Passive Scanning State and Slave Role combination"       },
+       { 27, "Active Scanning State and Slave Role combination"        },
+       { 28, "Initiating State and Master Role combination"            },
+       { }
+};
+
+static void print_le_states(const uint8_t *states_array)
+{
+       uint64_t mask, states = 0;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               states |= ((uint64_t) states_array[i]) << (i * 8);
+
+       print_field("States: 0x%16.16" PRIx64, states);
+
+       mask = states;
+
+       for (i = 0; le_states_table[i].str; i++) {
+               if (states & (((uint64_t) 1) << le_states_table[i].bit)) {
+                       print_field("  %s", le_states_table[i].str);
+                       mask &= ~(((uint64_t) 1) << le_states_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_LE_STATES, "  Unknown states "
+                                               "(0x%16.16" PRIx64 ")", mask);
+}
+
+static void print_le_channel_map(const uint8_t *map)
+{
+       char str[11];
+       int i;
+
+       for (i = 0; i < 5; i++)
+               sprintf(str + (i * 2), "%2.2x", map[i]);
+
+       print_field("Channel map: 0x%s", str);
+}
+
+void packet_print_channel_map_ll(const uint8_t *map)
+{
+       print_le_channel_map(map);
+}
+
+static void print_random_number(const uint8_t *number)
+{
+       print_hex_field("Random number", number, 8);
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} events_table[] = {
+       {  0, "Inquiry Complete"                                        },
+       {  1, "Inquiry Result"                                          },
+       {  2, "Connection Complete"                                     },
+       {  3, "Connection Request"                                      },
+       {  4, "Disconnection Complete"                                  },
+       {  5, "Authentication Complete"                                 },
+       {  6, "Remote Name Request Complete"                            },
+       {  7, "Encryption Change"                                       },
+       {  8, "Change Connection Link Key Complete"                     },
+       {  9, "Master Link Key Complete"                                },
+       { 10, "Read Remote Supported Features Complete"                 },
+       { 11, "Read Remote Version Information Complete"                },
+       { 12, "QoS Setup Complete"                                      },
+       { 13, "Command Complete"                                        },
+       { 14, "Command Status"                                          },
+       { 15, "Hardware Error"                                          },
+       { 16, "Flush Occurred"                                          },
+       { 17, "Role Change"                                             },
+       { 18, "Number of Completed Packets"                             },
+       { 19, "Mode Change"                                             },
+       { 20, "Return Link Keys"                                        },
+       { 21, "PIN Code Request"                                        },
+       { 22, "Link Key Request"                                        },
+       { 23, "Link Key Notification"                                   },
+       { 24, "Loopback Command"                                        },
+       { 25, "Data Buffer Overflow"                                    },
+       { 26, "Max Slots Change"                                        },
+       { 27, "Read Clock Offset Complete"                              },
+       { 28, "Connection Packet Type Changed"                          },
+       { 29, "QoS Violation"                                           },
+       { 30, "Page Scan Mode Change"                                   },
+       { 31, "Page Scan Repetition Mode Change"                        },
+       { 32, "Flow Specification Complete"                             },
+       { 33, "Inquiry Result with RSSI"                                },
+       { 34, "Read Remote Extended Features Complete"                  },
+       { 43, "Synchronous Connection Complete"                         },
+       { 44, "Synchronous Connection Changed"                          },
+       { 45, "Sniff Subrating"                                         },
+       { 46, "Extended Inquiry Result"                                 },
+       { 47, "Encryption Key Refresh Complete"                         },
+       { 48, "IO Capability Request"                                   },
+       { 49, "IO Capability Request Reply"                             },
+       { 50, "User Confirmation Request"                               },
+       { 51, "User Passkey Request"                                    },
+       { 52, "Remote OOB Data Request"                                 },
+       { 53, "Simple Pairing Complete"                                 },
+       { 55, "Link Supervision Timeout Changed"                        },
+       { 56, "Enhanced Flush Complete"                                 },
+       { 58, "User Passkey Notification"                               },
+       { 59, "Keypress Notification"                                   },
+       { 60, "Remote Host Supported Features Notification"             },
+       { 61, "LE Meta"                                                 },
+       { }
+};
+
+static void print_event_mask(const uint8_t *events_array)
+{
+       uint64_t mask, events = 0;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               events |= ((uint64_t) events_array[i]) << (i * 8);
+
+       print_field("Mask: 0x%16.16" PRIx64, events);
+
+       mask = events;
+
+       for (i = 0; events_table[i].str; i++) {
+               if (events & (((uint64_t) 1) << events_table[i].bit)) {
+                       print_field("  %s", events_table[i].str);
+                       mask &= ~(((uint64_t) 1) << events_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_EVENT_MASK, "  Unknown mask "
+                                               "(0x%16.16" PRIx64 ")", mask);
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} events_page2_table[] = {
+       {  0, "Physical Link Complete"                                  },
+       {  1, "Channel Selected"                                        },
+       {  2, "Disconnection Physical Link Complete"                    },
+       {  3, "Physical Link Loss Early Warning"                        },
+       {  4, "Physical Link Recovery"                                  },
+       {  5, "Logical Link Complete"                                   },
+       {  6, "Disconnection Logical Link Complete"                     },
+       {  7, "Flow Specification Modify Complete"                      },
+       {  8, "Number of Completed Data Blocks"                         },
+       {  9, "AMP Start Test"                                          },
+       { 10, "AMP Test End"                                            },
+       { 11, "AMP Receiver Report"                                     },
+       { 12, "Short Range Mode Change Complete"                        },
+       { 13, "AMP Status Change"                                       },
+       { 14, "Triggered Clock Capture"                                 },
+       { 15, "Synchronization Train Complete"                          },
+       { 16, "Synchronization Train Received"                          },
+       { 17, "Connectionless Slave Broadcast Receive"                  },
+       { 18, "Connectionless Slave Broadcast Timeout"                  },
+       { 19, "Truncated Page Complete"                                 },
+       { 20, "Slave Page Response Timeout"                             },
+       { 21, "Connectionless Slave Broadcast Channel Map Change"       },
+       { 22, "Inquiry Response Notification"                           },
+       { }
+};
+
+static void print_event_mask_page2(const uint8_t *events_array)
+{
+       uint64_t mask, events = 0;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               events |= ((uint64_t) events_array[i]) << (i * 8);
+
+       print_field("Mask: 0x%16.16" PRIx64, events);
+
+       mask = events;
+
+       for (i = 0; events_page2_table[i].str; i++) {
+               if (events & (((uint64_t) 1) << events_page2_table[i].bit)) {
+                       print_field("  %s", events_page2_table[i].str);
+                       mask &= ~(((uint64_t) 1) << events_page2_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_EVENT_MASK, "  Unknown mask "
+                                               "(0x%16.16" PRIx64 ")", mask);
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} events_le_table[] = {
+       {  0, "LE Connection Complete"          },
+       {  1, "LE Advertising Report"           },
+       {  2, "LE Connection Update Complete"   },
+       {  3, "LE Read Remote Used Features"    },
+       {  4, "LE Long Term Key Request"        },
+       { }
+};
+
+static void print_event_mask_le(const uint8_t *events_array)
+{
+       uint64_t mask, events = 0;
+       int i;
+
+       for (i = 0; i < 8; i++)
+               events |= ((uint64_t) events_array[i]) << (i * 8);
+
+       print_field("Mask: 0x%16.16" PRIx64, events);
+
+       mask = events;
+
+       for (i = 0; events_le_table[i].str; i++) {
+               if (events & (((uint64_t) 1) << events_le_table[i].bit)) {
+                       print_field("  %s", events_le_table[i].str);
+                       mask &= ~(((uint64_t) 1) << events_le_table[i].bit);
+               }
+       }
+
+       if (mask)
+               print_text(COLOR_UNKNOWN_EVENT_MASK, "  Unknown mask "
+                                               "(0x%16.16" PRIx64 ")", mask);
+}
+
+static void print_fec(uint8_t fec)
+{
+       const char *str;
+
+       switch (fec) {
+       case 0x00:
+               str = "Not required";
+               break;
+       case 0x01:
+               str = "Required";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("FEC: %s (0x%02x)", str, fec);
+}
+
+#define BT_EIR_FLAGS                   0x01
+#define BT_EIR_UUID16_SOME             0x02
+#define BT_EIR_UUID16_ALL              0x03
+#define BT_EIR_UUID32_SOME             0x04
+#define BT_EIR_UUID32_ALL              0x05
+#define BT_EIR_UUID128_SOME            0x06
+#define BT_EIR_UUID128_ALL             0x07
+#define BT_EIR_NAME_SHORT              0x08
+#define BT_EIR_NAME_COMPLETE           0x09
+#define BT_EIR_TX_POWER                        0x0a
+#define BT_EIR_CLASS_OF_DEV            0x0d
+#define BT_EIR_SSP_HASH_P192           0x0e
+#define BT_EIR_SSP_RANDOMIZER_P192     0x0f
+#define BT_EIR_DEVICE_ID               0x10
+#define BT_EIR_SMP_TK                  0x10
+#define BT_EIR_SMP_OOB_FLAGS           0x11
+#define BT_EIR_SLAVE_CONN_INTERVAL     0x12
+#define BT_EIR_SERVICE_UUID16          0x14
+#define BT_EIR_SERVICE_UUID128         0x15
+#define BT_EIR_SERVICE_DATA            0x16
+#define BT_EIR_PUBLIC_ADDRESS          0x17
+#define BT_EIR_RANDOM_ADDRESS          0x18
+#define BT_EIR_GAP_APPEARANCE          0x19
+#define BT_EIR_ADVERTISING_INTERVAL    0x1a
+#define BT_EIR_LE_DEVICE_ADDRESS       0x1b
+#define BT_EIR_LE_ROLE                 0x1c
+#define BT_EIR_SSP_HASH_P256           0x1d
+#define BT_EIR_SSP_RANDOMIZER_P256     0x1e
+#define BT_EIR_3D_INFO_DATA            0x3d
+#define BT_EIR_MANUFACTURER_DATA       0xff
+
+static void print_manufacturer_apple(const void *data, uint8_t data_len)
+{
+       uint8_t type = *((uint8_t *) data);
+       uint8_t len;
+       const uint8_t *uuid;
+       uint16_t minor, major;
+       int8_t tx_power;
+       char identifier[100];
+
+       if (data_len < 1)
+               return;
+
+       switch (type) {
+       case 0x01:
+               snprintf(identifier, sizeof(identifier) - 1, "%s",
+                                               (const char *) (data + 1));
+               print_field("  Identifier: %s", identifier);
+               break;
+       case 0x02:
+               len = *((uint8_t *) (data + 1));
+               if (len != 0x15) {
+                       print_hex_field("  Data", data, data_len);
+                       break;
+               }
+
+               uuid = data + 2;
+               print_field("  iBeacon: %8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x",
+                               bt_get_le32(&uuid[12]), bt_get_le16(&uuid[10]),
+                               bt_get_le16(&uuid[8]), bt_get_le16(&uuid[6]),
+                               bt_get_le32(&uuid[2]), bt_get_le16(&uuid[0]));
+
+               major = bt_get_le16(data + 18);
+               minor = bt_get_le16(data + 20);
+               print_field("  Version: %u.%u", major, minor);
+
+               tx_power = *(int8_t *) (data + 22);
+               print_field("  TX power: %d dB", tx_power);
+               break;
+       default:
+               print_hex_field("  Data", data, data_len);
+               break;
+       }
+}
+
+static void print_manufacturer_data(const void *data, uint8_t data_len)
+{
+       uint16_t company = bt_get_le16(data);
+
+       packet_print_company("Company", company);
+
+       switch (company) {
+       case 76:
+       case 19456:
+               print_manufacturer_apple(data + 2, data_len - 2);
+               break;
+       default:
+               print_hex_field("  Data", data + 2, data_len - 2);
+               break;
+       }
+}
+
+static void print_uuid16_list(const char *label, const void *data,
+                                                       uint8_t data_len)
+{
+       uint8_t count = data_len / sizeof(uint16_t);
+       unsigned int i;
+
+       print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");
+
+       for (i = 0; i < count; i++) {
+               uint16_t uuid = bt_get_le16(data + (i * 2));
+               print_field("  %s (0x%4.4x)", uuid16_to_str(uuid), uuid);
+       }
+}
+
+static void print_uuid32_list(const char *label, const void *data,
+                                                       uint8_t data_len)
+{
+       uint8_t count = data_len / sizeof(uint32_t);
+       unsigned int i;
+
+       print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");
+
+       for (i = 0; i < count; i++) {
+               uint32_t uuid = bt_get_le32(data + (i * 4));
+               print_field("  %s (0x%8.8x)", uuid32_to_str(uuid), uuid);
+       }
+}
+
+static void print_uuid128_list(const char *label, const void *data,
+                                                       uint8_t data_len)
+{
+       uint8_t count = data_len / 16;
+       unsigned int i;
+
+       print_field("%s: %u entr%s", label, count, count == 1 ? "y" : "ies");
+
+       for (i = 0; i < count; i++) {
+               const uint8_t *uuid = data + (i * 16);
+
+               print_field("  %8.8x-%4.4x-%4.4x-%4.4x-%8.8x%4.4x",
+                               bt_get_le32(&uuid[12]), bt_get_le16(&uuid[10]),
+                               bt_get_le16(&uuid[8]), bt_get_le16(&uuid[6]),
+                               bt_get_le32(&uuid[2]), bt_get_le16(&uuid[0]));
+       }
+}
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} eir_flags_table[] = {
+       { 0, "LE Limited Discoverable Mode"             },
+       { 1, "LE General Discoverable Mode"             },
+       { 2, "BR/EDR Not Supported"                     },
+       { 3, "Simultaneous LE and BR/EDR (Controller)"  },
+       { 4, "Simultaneous LE and BR/EDR (Host)"        },
+       { }
+};
+
+static const struct {
+       uint8_t bit;
+       const char *str;
+} eir_3d_table[] = {
+       { 0, "Association Notification"                                 },
+       { 1, "Battery Level Reporting"                                  },
+       { 2, "Send Battery Level Report on Start-up Synchronization"    },
+       { 7, "Factory Test Mode"                                        },
+       { }
+};
+
+static void print_eir(const uint8_t *eir, uint8_t eir_len, bool le)
+{
+       uint16_t len = 0;
+
+       if (eir_len == 0)
+               return;
+
+       while (len < eir_len - 1) {
+               uint8_t field_len = eir[0];
+               const uint8_t *data = &eir[2];
+               uint8_t data_len;
+               char name[239], label[100];
+               uint8_t flags, mask;
+               int i;
+
+               /* Check for the end of EIR */
+               if (field_len == 0)
+                       break;
+
+               len += field_len + 1;
+
+               /* Do not continue EIR Data parsing if got incorrect length */
+               if (len > eir_len) {
+                       len -= field_len + 1;
+                       break;
+               }
+
+               data_len = field_len - 1;
+
+               switch (eir[1]) {
+               case BT_EIR_FLAGS:
+                       flags = *data;
+                       mask = flags;
+
+                       print_field("Flags: 0x%2.2x", flags);
+
+                       for (i = 0; eir_flags_table[i].str; i++) {
+                               if (flags & (1 << eir_flags_table[i].bit)) {
+                                       print_field("  %s",
+                                                       eir_flags_table[i].str);
+                                       mask &= ~(1 << eir_flags_table[i].bit);
+                               }
+                       }
+
+                       if (mask)
+                               print_text(COLOR_UNKNOWN_SERVICE_CLASS,
+                                       "  Unknown flags (0x%2.2x)", mask);
+                       break;
+
+               case BT_EIR_UUID16_SOME:
+                       if (data_len < sizeof(uint16_t))
+                               break;
+                       print_uuid16_list("16-bit Service UUIDs (partial)",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_UUID16_ALL:
+                       if (data_len < sizeof(uint16_t))
+                               break;
+                       print_uuid16_list("16-bit Service UUIDs (complete)",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_UUID32_SOME:
+                       if (data_len < sizeof(uint32_t))
+                               break;
+                       print_uuid32_list("32-bit Service UUIDs (partial)",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_UUID32_ALL:
+                       if (data_len < sizeof(uint32_t))
+                               break;
+                       print_uuid32_list("32-bit Service UUIDs (complete)",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_UUID128_SOME:
+                       if (data_len < 16)
+                               break;
+                       print_uuid128_list("128-bit Service UUIDs (partial)",
+                                                               data, data_len);
+                       break;
+
+               case BT_EIR_UUID128_ALL:
+                       if (data_len < 16)
+                               break;
+                       print_uuid128_list("128-bit Service UUIDs (complete)",
+                                                               data, data_len);
+                       break;
+
+               case BT_EIR_NAME_SHORT:
+                       memset(name, 0, sizeof(name));
+                       memcpy(name, data, data_len);
+                       print_field("Name (short): %s", name);
+                       break;
+
+               case BT_EIR_NAME_COMPLETE:
+                       memset(name, 0, sizeof(name));
+                       memcpy(name, data, data_len);
+                       print_field("Name (complete): %s", name);
+                       break;
+
+               case BT_EIR_TX_POWER:
+                       if (data_len < 1)
+                               break;
+                       print_field("TX power: %d dBm", (int8_t) *data);
+                       break;
+
+               case BT_EIR_CLASS_OF_DEV:
+                       if (data_len < 3)
+                               break;
+                       print_dev_class(data);
+                       break;
+
+               case BT_EIR_SSP_HASH_P192:
+                       if (data_len < 16)
+                               break;
+                       print_hash("P-192", data);
+                       break;
+
+               case BT_EIR_SSP_RANDOMIZER_P192:
+                       if (data_len < 16)
+                               break;
+                       print_randomizer("P-192", data);
+                       break;
+
+               case BT_EIR_DEVICE_ID:
+                       /* SMP TK has the same value as Device ID */
+                       if (le)
+                               print_hex_field("SMP TK", data, data_len);
+                       else if (data_len >= 8)
+                               print_field("Device ID: "
+                                               "Source 0x%4.4x "
+                                               "Vendor 0x%4.4x "
+                                               "Product 0x%4.4x "
+                                               "Version 0x%4.4x",
+                                               bt_get_le16(&data[0]),
+                                               bt_get_le16(&data[2]),
+                                               bt_get_le16(&data[4]),
+                                               bt_get_le16(&data[6]));
+                       break;
+
+               case BT_EIR_SMP_OOB_FLAGS:
+                       print_field("SMP OOB Flags: 0x%2.2x", *data);
+                       break;
+
+               case BT_EIR_SLAVE_CONN_INTERVAL:
+                       if (data_len < 4)
+                               break;
+                       print_field("Slave Conn. Interval: 0x%4.4x - 0x%4.4x",
+                                                       bt_get_le16(&data[0]),
+                                                       bt_get_le16(&data[2]));
+                       break;
+
+               case BT_EIR_SERVICE_UUID16:
+                       if (data_len < sizeof(uint16_t))
+                               break;
+                       print_uuid16_list("16-bit Service UUIDs",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_SERVICE_UUID128:
+                       if (data_len < 16)
+                               break;
+                       print_uuid128_list("128-bit Service UUIDs",
+                                                       data, data_len);
+                       break;
+
+               case BT_EIR_SERVICE_DATA:
+                       if (data_len < 2)
+                               break;
+                       sprintf(label, "Service Data (UUID 0x%4.4x)",
+                                                       bt_get_le16(&data[0]));
+                       print_hex_field(label, &data[2], data_len - 2);
+                       break;
+
+               case BT_EIR_RANDOM_ADDRESS:
+                       if (data_len < 6)
+                               break;
+                       print_addr("Random Address", data, 0x01);
+                       break;
+
+               case BT_EIR_PUBLIC_ADDRESS:
+                       if (data_len < 6)
+                               break;
+                       print_addr("Public Address", data, 0x00);
+                       break;
+
+               case BT_EIR_GAP_APPEARANCE:
+                       if (data_len < 2)
+                               break;
+                       print_field("Appearance: 0x%4.4x", bt_get_le16(data));
+                       break;
+
+               case BT_EIR_SSP_HASH_P256:
+                       if (data_len < 16)
+                               break;
+                       print_hash("P-256", data);
+                       break;
+
+               case BT_EIR_SSP_RANDOMIZER_P256:
+                       if (data_len < 16)
+                               break;
+                       print_randomizer("P-256", data);
+                       break;
+
+               case BT_EIR_3D_INFO_DATA:
+                       print_hex_field("3D Information Data", data, data_len);
+                       if (data_len < 2)
+                               break;
+
+                       flags = *data;
+                       mask = flags;
+
+                       print_field("  Features: 0x%2.2x", flags);
+
+                       for (i = 0; eir_3d_table[i].str; i++) {
+                               if (flags & (1 << eir_3d_table[i].bit)) {
+                                       print_field("    %s",
+                                                       eir_3d_table[i].str);
+                                       mask &= ~(1 << eir_3d_table[i].bit);
+                               }
+                       }
+
+                       if (mask)
+                               print_text(COLOR_UNKNOWN_FEATURE_BIT,
+                                       "      Unknown features (0x%2.2x)", mask);
+
+                       print_field("  Path Loss Threshold: %d", data[1]);
+                       break;
+
+               case BT_EIR_MANUFACTURER_DATA:
+                       if (data_len < 2)
+                               break;
+                       print_manufacturer_data(data, data_len);
+                       break;
+
+               default:
+                       sprintf(label, "Unknown EIR field 0x%2.2x", eir[1]);
+                       print_hex_field(label, data, data_len);
+                       break;
+               }
+
+               eir += field_len + 1;
+       }
+
+       if (len < eir_len && eir[0] != 0)
+               packet_hexdump(eir, eir_len - len);
+}
+
+void packet_print_addr(const char *label, const void *data, bool random)
+{
+       print_addr(label ? : "Address", data, random ? 0x01 : 0x00);
+}
+
+void packet_print_ad(const void *data, uint8_t size)
+{
+       print_eir(data, size, true);
+}
+
+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';
+                       print_text(COLOR_WHITE, "%s", 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';
+               print_text(COLOR_WHITE, "%s", str);
+       }
+}
+
+void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
+                                       const void *data, uint16_t size)
+{
+       if (index_filter && index_number != index)
+               return;
+
+       control_message(opcode, data, size);
+}
+
+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
+
+struct index_data {
+       uint8_t  type;
+       bdaddr_t bdaddr;
+};
+
+static struct index_data 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], extra_str[24];
+
+       if (index_filter && index_number != index)
+               return;
+
+       index_current = index;
+
+       if (tv && time_offset == ((time_t) -1))
+               time_offset = tv->tv_sec;
+
+       switch (opcode) {
+       case BTSNOOP_OPCODE_NEW_INDEX:
+               ni = data;
+
+               if (index < MAX_INDEX) {
+                       index_list[index].type = ni->type;
+                       bacpy(&index_list[index].bdaddr, &ni->bdaddr);
+               }
+
+               ba2str(&ni->bdaddr, str);
+               packet_new_index(tv, index, str, ni->type, ni->bus, ni->name);
+               break;
+       case BTSNOOP_OPCODE_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 BTSNOOP_OPCODE_COMMAND_PKT:
+               packet_hci_command(tv, index, data, size);
+               break;
+       case BTSNOOP_OPCODE_EVENT_PKT:
+               packet_hci_event(tv, index, data, size);
+               break;
+       case BTSNOOP_OPCODE_ACL_TX_PKT:
+               packet_hci_acldata(tv, index, false, data, size);
+               break;
+       case BTSNOOP_OPCODE_ACL_RX_PKT:
+               packet_hci_acldata(tv, index, true, data, size);
+               break;
+       case BTSNOOP_OPCODE_SCO_TX_PKT:
+               packet_hci_scodata(tv, index, false, data, size);
+               break;
+       case BTSNOOP_OPCODE_SCO_RX_PKT:
+               packet_hci_scodata(tv, index, true, data, size);
+               break;
+       default:
+               sprintf(extra_str, "(code %d len %d)", opcode, size);
+               print_packet(tv, index, '*', COLOR_ERROR,
+                                       "Unknown packet", NULL, extra_str);
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+void packet_simulator(struct timeval *tv, uint16_t frequency,
+                                       const void *data, uint16_t size)
+{
+       char str[10];
+
+       if (tv && time_offset == ((time_t) -1))
+               time_offset = tv->tv_sec;
+
+       sprintf(str, "%u MHz", frequency);
+
+       print_packet(tv, 0, '*', COLOR_PHY_PACKET,
+                                       "Physical packet:", NULL, str);
+
+       ll_packet(frequency, data, size);
+}
+
+static void null_cmd(const void *data, uint8_t size)
+{
+}
+
+static void status_rsp(const void *data, uint8_t size)
+{
+       uint8_t status = *((const uint8_t *) data);
+
+       print_status(status);
+}
+
+static void status_bdaddr_rsp(const void *data, uint8_t size)
+{
+       uint8_t status = *((const uint8_t *) data);
+
+       print_status(status);
+       print_bdaddr(data + 1);
+}
+
+static void inquiry_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_inquiry *cmd = data;
+
+       print_iac(cmd->lap);
+       print_field("Length: %.2fs (0x%2.2x)",
+                               cmd->length * 1.28, cmd->length);
+       print_num_resp(cmd->num_resp);
+}
+
+static void periodic_inquiry_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_periodic_inquiry *cmd = data;
+
+       print_field("Max period: %.2fs (0x%2.2x)",
+                               cmd->max_period * 1.28, cmd->max_period);
+       print_field("Min period: %.2fs (0x%2.2x)",
+                               cmd->min_period * 1.28, cmd->min_period);
+       print_iac(cmd->lap);
+       print_field("Length: %.2fs (0x%2.2x)",
+                               cmd->length * 1.28, cmd->length);
+       print_num_resp(cmd->num_resp);
+}
+
+static void create_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_conn *cmd = data;
+       const char *str;
+
+       print_bdaddr(cmd->bdaddr);
+       print_pkt_type(cmd->pkt_type);
+       print_pscan_rep_mode(cmd->pscan_rep_mode);
+       print_pscan_mode(cmd->pscan_mode);
+       print_clock_offset(cmd->clock_offset);
+
+       switch (cmd->role_switch) {
+       case 0x00:
+               str = "Stay master";
+               break;
+       case 0x01:
+               str = "Allow slave";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Role switch: %s (0x%2.2x)", str, cmd->role_switch);
+}
+
+static void disconnect_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_disconnect *cmd = data;
+
+       print_handle(cmd->handle);
+       print_reason(cmd->reason);
+}
+
+static void add_sco_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_add_sco_conn *cmd = data;
+
+       print_handle(cmd->handle);
+       print_pkt_type(cmd->pkt_type);
+}
+
+static void create_conn_cancel_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_conn_cancel *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void accept_conn_request_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_accept_conn_request *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_role(cmd->role);
+}
+
+static void reject_conn_request_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_reject_conn_request *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_reason(cmd->reason);
+}
+
+static void link_key_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_link_key_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_link_key(cmd->link_key);
+}
+
+static void link_key_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_link_key_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void pin_code_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_pin_code_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_field("PIN length: %d", cmd->pin_len);
+       print_pin_code(cmd->pin_code, cmd->pin_len);
+}
+
+static void pin_code_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_pin_code_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void change_conn_pkt_type_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_change_conn_pkt_type *cmd = data;
+
+       print_handle(cmd->handle);
+       print_pkt_type(cmd->pkt_type);
+}
+
+static void auth_requested_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_auth_requested *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void set_conn_encrypt_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_conn_encrypt *cmd = data;
+
+       print_handle(cmd->handle);
+       print_encr_mode(cmd->encr_mode);
+}
+
+static void change_conn_link_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_change_conn_link_key *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void master_link_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_master_link_key *cmd = data;
+
+       print_key_flag(cmd->key_flag);
+}
+
+static void remote_name_request_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_remote_name_request *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_pscan_rep_mode(cmd->pscan_rep_mode);
+       print_pscan_mode(cmd->pscan_mode);
+       print_clock_offset(cmd->clock_offset);
+}
+
+static void remote_name_request_cancel_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_remote_name_request_cancel *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void read_remote_features_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_remote_features *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_remote_ext_features_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_remote_ext_features *cmd = data;
+
+       print_handle(cmd->handle);
+       print_field("Page: %d", cmd->page);
+}
+
+static void read_remote_version_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_remote_version *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_clock_offset_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_clock_offset *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_lmp_handle_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_lmp_handle *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_lmp_handle_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_lmp_handle *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_field("LMP handle: %d", rsp->lmp_handle);
+       print_field("Reserved: %d", btohl(rsp->reserved));
+}
+
+static void setup_sync_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_setup_sync_conn *cmd = data;
+
+       print_handle(cmd->handle);
+       print_field("Transmit bandwidth: %d", btohl(cmd->tx_bandwidth));
+       print_field("Receive bandwidth: %d", btohl(cmd->rx_bandwidth));
+       print_field("Max latency: %d", btohs(cmd->max_latency));
+       print_voice_setting(cmd->voice_setting);
+       print_retransmission_effort(cmd->retrans_effort);
+       print_pkt_type(cmd->pkt_type);
+}
+
+static void accept_sync_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_accept_sync_conn *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_field("Transmit bandwidth: %d", btohl(cmd->tx_bandwidth));
+       print_field("Receive bandwidth: %d", btohl(cmd->rx_bandwidth));
+       print_field("Max latency: %d", btohs(cmd->max_latency));
+       print_voice_setting(cmd->voice_setting);
+       print_retransmission_effort(cmd->retrans_effort);
+       print_pkt_type(cmd->pkt_type);
+}
+
+static void reject_sync_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_reject_sync_conn *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_reason(cmd->reason);
+}
+
+static void io_capability_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_io_capability_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_io_capability(cmd->capability);
+       print_oob_data(cmd->oob_data);
+       print_authentication(cmd->authentication);
+}
+
+static void user_confirm_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_user_confirm_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void user_confirm_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_user_confirm_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void user_passkey_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_user_passkey_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_passkey(cmd->passkey);
+}
+
+static void user_passkey_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_user_passkey_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void remote_oob_data_request_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_remote_oob_data_request_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_hash("P-192", cmd->hash);
+       print_randomizer("P-192", cmd->randomizer);
+}
+
+static void remote_oob_data_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_remote_oob_data_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+}
+
+static void io_capability_request_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_io_capability_request_neg_reply *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_reason(cmd->reason);
+}
+
+static void create_phy_link_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_phy_link *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_key_len(cmd->key_len);
+       print_key_type(cmd->key_type);
+
+       packet_hexdump(data + 3, size - 3);
+}
+
+static void accept_phy_link_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_accept_phy_link *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_key_len(cmd->key_len);
+       print_key_type(cmd->key_type);
+
+       packet_hexdump(data + 3, size - 3);
+}
+
+static void disconn_phy_link_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_disconn_phy_link *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_reason(cmd->reason);
+}
+
+static void create_logic_link_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_create_logic_link *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_flow_spec("TX", cmd->tx_flow_spec);
+       print_flow_spec("RX", cmd->rx_flow_spec);
+}
+
+static void accept_logic_link_cmd(const void *data, uint8_t size)
+{
+        const struct bt_hci_cmd_accept_logic_link *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_flow_spec("TX", cmd->tx_flow_spec);
+       print_flow_spec("RX", cmd->rx_flow_spec);
+}
+
+static void disconn_logic_link_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_disconn_logic_link *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void logic_link_cancel_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_logic_link_cancel *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_field("TX flow spec: 0x%2.2x", cmd->flow_spec);
+}
+
+static void logic_link_cancel_rsp(const void *data, uint8_t size)
+{
+        const struct bt_hci_rsp_logic_link_cancel *rsp = data;
+
+       print_status(rsp->status);
+       print_phy_handle(rsp->phy_handle);
+       print_field("TX flow spec: 0x%2.2x", rsp->flow_spec);
+}
+
+static void flow_spec_modify_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_flow_spec_modify *cmd = data;
+
+       print_handle(cmd->handle);
+       print_flow_spec("TX", cmd->tx_flow_spec);
+       print_flow_spec("RX", cmd->rx_flow_spec);
+}
+
+static void hold_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_hold_mode *cmd = data;
+
+       print_handle(cmd->handle);
+       print_slot_625("Hold max interval", cmd->max_interval);
+       print_slot_625("Hold min interval", cmd->min_interval);
+}
+
+static void sniff_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_sniff_mode *cmd = data;
+
+       print_handle(cmd->handle);
+       print_slot_625("Sniff max interval", cmd->max_interval);
+       print_slot_625("Sniff min interval", cmd->min_interval);
+       print_slot_125("Sniff attempt", cmd->attempt);
+       print_slot_125("Sniff timeout", cmd->timeout);
+}
+
+static void exit_sniff_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_exit_sniff_mode *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void park_state_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_park_state *cmd = data;
+
+       print_handle(cmd->handle);
+       print_slot_625("Beacon max interval", cmd->max_interval);
+       print_slot_625("Beacon min interval", cmd->min_interval);
+}
+
+static void exit_park_state_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_exit_park_state *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void qos_setup_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_qos_setup *cmd = data;
+
+       print_handle(cmd->handle);
+       print_field("Flags: 0x%2.2x", cmd->flags);
+
+       print_service_type(cmd->service_type);
+
+       print_field("Token rate: %d", btohl(cmd->token_rate));
+       print_field("Peak bandwidth: %d", btohl(cmd->peak_bandwidth));
+       print_field("Latency: %d", btohl(cmd->latency));
+       print_field("Delay variation: %d", btohl(cmd->delay_variation));
+}
+
+static void role_discovery_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_role_discovery *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void role_discovery_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_role_discovery *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_role(rsp->role);
+}
+
+static void switch_role_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_switch_role *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_role(cmd->role);
+}
+
+static void read_link_policy_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_link_policy *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_link_policy_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_link_policy *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_link_policy(rsp->policy);
+}
+
+static void write_link_policy_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_link_policy *cmd = data;
+
+       print_handle(cmd->handle);
+       print_link_policy(cmd->policy);
+}
+
+static void write_link_policy_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_write_link_policy *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void read_default_link_policy_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_default_link_policy *rsp = data;
+
+       print_status(rsp->status);
+       print_link_policy(rsp->policy);
+}
+
+static void write_default_link_policy_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_default_link_policy *cmd = data;
+
+       print_link_policy(cmd->policy);
+}
+
+static void flow_spec_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_flow_spec *cmd = data;
+
+       print_handle(cmd->handle);
+       print_field("Flags: 0x%2.2x", cmd->flags);
+
+       print_flow_direction(cmd->direction);
+       print_service_type(cmd->service_type);
+
+       print_field("Token rate: %d", btohl(cmd->token_rate));
+       print_field("Token bucket size: %d", btohl(cmd->token_bucket_size));
+       print_field("Peak bandwidth: %d", btohl(cmd->peak_bandwidth));
+       print_field("Access latency: %d", btohl(cmd->access_latency));
+}
+
+static void sniff_subrating_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_sniff_subrating *cmd = data;
+
+       print_handle(cmd->handle);
+       print_slot_625("Max latency", cmd->max_latency);
+       print_slot_625("Min remote timeout", cmd->min_remote_timeout);
+       print_slot_625("Min local timeout", cmd->min_local_timeout);
+}
+
+static void sniff_subrating_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_sniff_subrating *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void set_event_mask_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_event_mask *cmd = data;
+
+       print_event_mask(cmd->mask);
+}
+
+static void set_event_filter_cmd(const void *data, uint8_t size)
+{
+       uint8_t type = *((const uint8_t *) data);
+       uint8_t filter;
+       const char *str;
+
+       switch (type) {
+       case 0x00:
+               str = "Clear All Filters";
+               break;
+       case 0x01:
+               str = "Inquiry Result";
+               break;
+       case 0x02:
+               str = "Connection Setup";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, type);
+
+       switch (type) {
+       case 0x00:
+               if (size > 1) {
+                       print_text(COLOR_ERROR, "  invalid parameter size");
+                       packet_hexdump(data + 1, size - 1);
+               }
+               break;
+
+       case 0x01:
+               filter = *((const uint8_t *) (data + 1));
+
+               switch (filter) {
+               case 0x00:
+                       str = "Return responses from all devices";
+                       break;
+               case 0x01:
+                       str = "Device with specific Class of Device";
+                       break;
+               case 0x02:
+                       str = "Device with specific BD_ADDR";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("Filter: %s (0x%2.2x)", str, filter);
+               packet_hexdump(data + 2, size - 2);
+               break;
+
+       case 0x02:
+               filter = *((const uint8_t *) (data + 1));
+
+               switch (filter) {
+               case 0x00:
+                       str = "Allow connections all devices";
+                       break;
+               case 0x01:
+                       str = "Allow connections with specific Class of Device";
+                       break;
+               case 0x02:
+                       str = "Allow connections with specific BD_ADDR";
+                       break;
+               default:
+                       str = "Reserved";
+                       break;
+               }
+
+               print_field("Filter: %s (0x%2.2x)", str, filter);
+               packet_hexdump(data + 2, size - 2);
+               break;
+
+       default:
+               filter = *((const uint8_t *) (data + 1));
+
+               print_field("Filter: Reserved (0x%2.2x)", filter);
+               packet_hexdump(data + 2, size - 2);
+               break;
+       }
+}
+
+static void flush_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_flush *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void flush_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_flush *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void read_pin_type_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_pin_type *rsp = data;
+
+       print_status(rsp->status);
+       print_pin_type(rsp->pin_type);
+}
+
+static void write_pin_type_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_pin_type *cmd = data;
+
+       print_pin_type(cmd->pin_type);
+}
+
+static void read_stored_link_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_stored_link_key *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_field("Read all: 0x%2.2x", cmd->read_all);
+}
+
+static void read_stored_link_key_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_stored_link_key *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Max num keys: %d", btohs(rsp->max_num_keys));
+       print_field("Num keys: %d", btohs(rsp->num_keys));
+}
+
+static void write_stored_link_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_stored_link_key *cmd = data;
+
+       print_field("Num keys: %d", cmd->num_keys);
+
+       packet_hexdump(data + 1, size - 1);
+}
+
+static void write_stored_link_key_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_write_stored_link_key *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Num keys: %d", rsp->num_keys);
+}
+
+static void delete_stored_link_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_delete_stored_link_key *cmd = data;
+
+       print_bdaddr(cmd->bdaddr);
+       print_field("Delete all: 0x%2.2x", cmd->delete_all);
+}
+
+static void delete_stored_link_key_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_delete_stored_link_key *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Num keys: %d", btohs(rsp->num_keys));
+}
+
+static void write_local_name_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_local_name *cmd = data;
+
+       print_name(cmd->name);
+}
+
+static void read_local_name_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_name *rsp = data;
+
+       print_status(rsp->status);
+       print_name(rsp->name);
+}
+
+static void read_conn_accept_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_conn_accept_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_timeout(rsp->timeout);
+}
+
+static void write_conn_accept_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_conn_accept_timeout *cmd = data;
+
+       print_timeout(cmd->timeout);
+}
+
+static void read_page_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_page_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_timeout(rsp->timeout);
+}
+
+static void write_page_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_page_timeout *cmd = data;
+
+       print_timeout(cmd->timeout);
+}
+
+static void read_scan_enable_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_scan_enable *rsp = data;
+
+       print_status(rsp->status);
+       print_scan_enable(rsp->enable);
+}
+
+static void write_scan_enable_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_scan_enable *cmd = data;
+
+       print_scan_enable(cmd->enable);
+}
+
+static void read_page_scan_activity_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_page_scan_activity *rsp = data;
+
+       print_status(rsp->status);
+       print_interval(rsp->interval);
+       print_window(rsp->window);
+}
+
+static void write_page_scan_activity_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_page_scan_activity *cmd = data;
+
+       print_interval(cmd->interval);
+       print_window(cmd->window);
+}
+
+static void read_inquiry_scan_activity_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_inquiry_scan_activity *rsp = data;
+
+       print_status(rsp->status);
+       print_interval(rsp->interval);
+       print_window(rsp->window);
+}
+
+static void write_inquiry_scan_activity_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_inquiry_scan_activity *cmd = data;
+
+       print_interval(cmd->interval);
+       print_window(cmd->window);
+}
+
+static void read_auth_enable_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_auth_enable *rsp = data;
+
+       print_status(rsp->status);
+       print_auth_enable(rsp->enable);
+}
+
+static void write_auth_enable_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_auth_enable *cmd = data;
+
+       print_auth_enable(cmd->enable);
+}
+
+static void read_encrypt_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_encrypt_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_encrypt_mode(rsp->mode);
+}
+
+static void write_encrypt_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_encrypt_mode *cmd = data;
+
+       print_encrypt_mode(cmd->mode);
+}
+
+static void read_class_of_dev_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_class_of_dev *rsp = data;
+
+       print_status(rsp->status);
+       print_dev_class(rsp->dev_class);
+}
+
+static void write_class_of_dev_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_class_of_dev *cmd = data;
+
+       print_dev_class(cmd->dev_class);
+}
+
+static void read_voice_setting_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_voice_setting *rsp = data;
+
+       print_status(rsp->status);
+       print_voice_setting(rsp->setting);
+}
+
+static void write_voice_setting_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_voice_setting *cmd = data;
+
+       print_voice_setting(cmd->setting);
+}
+
+static void host_buffer_size_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_host_buffer_size *cmd = data;
+
+       print_field("ACL MTU: %-4d ACL max packet: %d",
+                               btohs(cmd->acl_mtu), btohs(cmd->acl_max_pkt));
+       print_field("SCO MTU: %-4d SCO max packet: %d",
+                               cmd->sco_mtu, btohs(cmd->sco_max_pkt));
+}
+
+static void read_link_supv_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_link_supv_timeout *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_link_supv_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_link_supv_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_timeout(rsp->timeout);
+}
+
+static void write_link_supv_timeout_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_link_supv_timeout *cmd = data;
+
+       print_handle(cmd->handle);
+       print_timeout(cmd->timeout);
+}
+
+static void write_link_supv_timeout_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_write_link_supv_timeout *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void read_num_supported_iac_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_num_supported_iac *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Number of IAC: %d", rsp->num_iac);
+}
+
+static void read_current_iac_lap_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_current_iac_lap *rsp = data;
+       uint8_t i;
+
+       print_status(rsp->status);
+       print_field("Number of IAC: %d", rsp->num_iac);
+
+       for (i = 0; i < rsp->num_iac; i++)
+               print_iac(rsp->iac_lap + (i * 3));
+}
+
+static void write_current_iac_lap_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_current_iac_lap *cmd = data;
+       uint8_t i;
+
+       print_field("Number of IAC: %d", cmd->num_iac);
+
+       for (i = 0; i < cmd->num_iac; i++)
+               print_iac(cmd->iac_lap + (i * 3));
+}
+
+static void read_page_scan_period_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_page_scan_period_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_pscan_period_mode(rsp->mode);
+}
+
+static void write_page_scan_period_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_page_scan_period_mode *cmd = data;
+
+       print_pscan_period_mode(cmd->mode);
+}
+
+static void read_page_scan_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_page_scan_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_pscan_mode(rsp->mode);
+}
+
+static void write_page_scan_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_page_scan_mode *cmd = data;
+
+       print_pscan_mode(cmd->mode);
+}
+
+static void set_afh_host_classification_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_afh_host_classification *cmd = data;
+
+       print_channel_map(cmd->map);
+}
+
+static void read_inquiry_scan_type_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_inquiry_scan_type *rsp = data;
+
+       print_status(rsp->status);
+       print_inquiry_scan_type(rsp->type);
+}
+
+static void write_inquiry_scan_type_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_inquiry_scan_type *cmd = data;
+
+       print_inquiry_scan_type(cmd->type);
+}
+
+static void read_inquiry_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_inquiry_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_inquiry_mode(rsp->mode);
+}
+
+static void write_inquiry_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_inquiry_mode *cmd = data;
+
+       print_inquiry_mode(cmd->mode);
+}
+
+static void read_page_scan_type_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_page_scan_type *rsp = data;
+
+       print_status(rsp->status);
+       print_pscan_type(rsp->type);
+}
+
+static void write_page_scan_type_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_page_scan_type *cmd = data;
+
+       print_pscan_type(cmd->type);
+}
+
+static void read_afh_assessment_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_afh_assessment_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_afh_mode(rsp->mode);
+}
+
+static void write_afh_assessment_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_afh_assessment_mode *cmd = data;
+
+       print_afh_mode(cmd->mode);
+}
+
+static void read_ext_inquiry_response_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_ext_inquiry_response *rsp = data;
+
+       print_status(rsp->status);
+       print_fec(rsp->fec);
+       print_eir(rsp->data, sizeof(rsp->data), false);
+}
+
+static void write_ext_inquiry_response_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_ext_inquiry_response *cmd = data;
+
+       print_fec(cmd->fec);
+       print_eir(cmd->data, sizeof(cmd->data), false);
+}
+
+static void refresh_encrypt_key_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_refresh_encrypt_key *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_simple_pairing_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_simple_pairing_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_simple_pairing_mode(rsp->mode);
+}
+
+static void write_simple_pairing_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_simple_pairing_mode *cmd = data;
+
+       print_simple_pairing_mode(cmd->mode);
+}
+
+static void read_local_oob_data_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_oob_data *rsp = data;
+
+       print_status(rsp->status);
+       print_hash("P-192", rsp->hash);
+       print_randomizer("P-192", rsp->randomizer);
+}
+
+static void read_inquiry_resp_tx_power_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_inquiry_resp_tx_power *rsp = data;
+
+       print_status(rsp->status);
+       print_field("TX power: %d dBm", rsp->level);
+}
+
+static void write_inquiry_tx_power_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_inquiry_tx_power *cmd = data;
+
+       print_field("TX power: %d dBm", cmd->level);
+}
+
+static void enhanced_flush_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_enhanced_flush *cmd = data;
+       const char *str;
+
+       print_handle(cmd->handle);
+
+       switch (cmd->type) {
+       case 0x00:
+               str = "Automatic flushable only";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, cmd->type);
+}
+
+static void set_event_mask_page2_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_set_event_mask_page2 *cmd = data;
+
+       print_event_mask_page2(cmd->mask);
+}
+
+static void read_location_data_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_location_data *rsp = data;
+
+       print_status(rsp->status);
+       print_location_domain_aware(rsp->domain_aware);
+       print_location_domain(rsp->domain);
+       print_location_domain_options(rsp->domain_options);
+       print_location_options(rsp->options);
+}
+
+static void write_location_data_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_location_data *cmd = data;
+
+       print_location_domain_aware(cmd->domain_aware);
+       print_location_domain(cmd->domain);
+       print_location_domain_options(cmd->domain_options);
+       print_location_options(cmd->options);
+}
+
+static void read_flow_control_mode_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_flow_control_mode *rsp = data;
+
+       print_status(rsp->status);
+       print_flow_control_mode(rsp->mode);
+}
+
+static void write_flow_control_mode_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_flow_control_mode *cmd = data;
+
+       print_flow_control_mode(cmd->mode);
+}
+
+static void read_le_host_supported_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_le_host_supported *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Supported: 0x%2.2x", rsp->supported);
+       print_field("Simultaneous: 0x%2.2x", rsp->simultaneous);
+}
+
+static void write_le_host_supported_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_le_host_supported *cmd = data;
+
+       print_field("Supported: 0x%2.2x", cmd->supported);
+       print_field("Simultaneous: 0x%2.2x", cmd->simultaneous);
+}
+
+static void read_sync_train_params_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_sync_train_params *rsp = data;
+
+       print_status(rsp->status);
+       print_interval(rsp->interval);
+       print_field("Timeout: %.3f msec (0x%8.8x)",
+                       btohl(rsp->timeout) * 0.625, btohl(rsp->timeout));
+       print_field("Service Data: 0x%2.2x", rsp->service_data);
+}
+
+static void read_local_version_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_version *rsp = data;
+
+       print_status(rsp->status);
+       print_hci_version(rsp->hci_ver, rsp->hci_rev);
+
+       switch (index_list[index_current].type) {
+       case HCI_BREDR:
+               print_lmp_version(rsp->lmp_ver, rsp->lmp_subver);
+               break;
+       case HCI_AMP:
+               print_pal_version(rsp->lmp_ver, rsp->lmp_subver);
+               break;
+       }
+
+       print_manufacturer(rsp->manufacturer);
+}
+
+static void read_local_commands_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_commands *rsp = data;
+
+       print_status(rsp->status);
+       print_commands(rsp->commands);
+}
+
+static void read_local_features_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_features *rsp = data;
+
+       print_status(rsp->status);
+       print_features(0, rsp->features, 0x00);
+}
+
+static void read_local_ext_features_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_local_ext_features *cmd = data;
+
+       print_field("Page: %d", cmd->page);
+}
+
+static void read_local_ext_features_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_ext_features *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Page: %d/%d", rsp->page, rsp->max_page);
+       print_features(rsp->page, rsp->features, 0x00);
+}
+
+static void read_buffer_size_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_buffer_size *rsp = data;
+
+       print_status(rsp->status);
+       print_field("ACL MTU: %-4d ACL max packet: %d",
+                               btohs(rsp->acl_mtu), btohs(rsp->acl_max_pkt));
+       print_field("SCO MTU: %-4d SCO max packet: %d",
+                               rsp->sco_mtu, btohs(rsp->sco_max_pkt));
+}
+
+static void read_country_code_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_country_code *rsp = data;
+       const char *str;
+
+       print_status(rsp->status);
+
+       switch (rsp->code) {
+       case 0x00:
+               str = "North America, Europe*, Japan";
+               break;
+       case 0x01:
+               str = "France";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Country code: %s (0x%2.2x)", str, rsp->code);
+}
+
+static void read_bd_addr_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_bd_addr *rsp = data;
+
+       print_status(rsp->status);
+       print_bdaddr(rsp->bdaddr);
+}
+
+static void read_data_block_size_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_data_block_size *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Max ACL length: %d", btohs(rsp->max_acl_len));
+       print_field("Block length: %d", btohs(rsp->block_len));
+       print_field("Num blocks: %d", btohs(rsp->num_blocks));
+}
+
+static void read_failed_contact_counter_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_failed_contact_counter *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_failed_contact_counter_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_failed_contact_counter *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_field("Counter: %u", htobs(rsp->counter));
+}
+
+static void reset_failed_contact_counter_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_reset_failed_contact_counter *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void reset_failed_contact_counter_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_reset_failed_contact_counter *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void read_link_quality_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_link_quality *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_link_quality_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_link_quality *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_field("Link quality: 0x%2.2x", rsp->link_quality);
+}
+
+static void read_rssi_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_rssi *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_rssi_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_rssi *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_rssi(rsp->rssi);
+}
+
+static void read_afh_channel_map_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_afh_channel_map *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_afh_channel_map_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_afh_channel_map *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_afh_mode(rsp->mode);
+       print_channel_map(rsp->map);
+}
+
+static void read_clock_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_clock *cmd = data;
+       const char *str;
+
+       print_handle(cmd->handle);
+
+       switch (cmd->type) {
+       case 0x00:
+               str = "Local clock";
+               break;
+       case 0x01:
+               str = "Piconet clock";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, cmd->type);
+}
+
+static void read_clock_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_clock *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_clock(rsp->clock);
+       print_clock_accuracy(rsp->accuracy);
+}
+
+static void read_encrypt_key_size_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_encrypt_key_size *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void read_encrypt_key_size_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_encrypt_key_size *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_key_size(rsp->key_size);
+}
+
+static void read_local_amp_info_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_amp_info *rsp = data;
+       const char *str;
+
+       print_status(rsp->status);
+       print_amp_status(rsp->amp_status);
+
+       print_field("Total bandwidth: %d kbps", btohl(rsp->total_bw));
+       print_field("Max guaranteed bandwidth: %d kbps", btohl(rsp->max_bw));
+       print_field("Min latency: %d", btohl(rsp->min_latency));
+       print_field("Max PDU size: %d", btohl(rsp->max_pdu));
+
+       switch (rsp->amp_type) {
+       case 0x00:
+               str = "Primary BR/EDR Controller";
+               break;
+       case 0x01:
+               str = "802.11 AMP Controller";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Controller type: %s (0x%2.2x)", str, rsp->amp_type);
+
+       print_field("PAL capabilities: 0x%4.4x", btohs(rsp->pal_cap));
+       print_field("Max ASSOC length: %d", btohs(rsp->max_assoc_len));
+       print_field("Max flush timeout: %d", btohl(rsp->max_flush_to));
+       print_field("Best effort flush timeout: %d", btohl(rsp->be_flush_to));
+}
+
+static void read_local_amp_assoc_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_read_local_amp_assoc *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_field("Length so far: %d", btohs(cmd->len_so_far));
+       print_field("Max ASSOC length: %d", btohs(cmd->max_assoc_len));
+}
+
+static void read_local_amp_assoc_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_read_local_amp_assoc *rsp = data;
+
+       print_status(rsp->status);
+       print_phy_handle(rsp->phy_handle);
+       print_field("Remaining ASSOC length: %d", btohs(rsp->remain_assoc_len));
+
+       packet_hexdump(data + 4, size - 4);
+}
+
+static void write_remote_amp_assoc_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_write_remote_amp_assoc *cmd = data;
+
+       print_phy_handle(cmd->phy_handle);
+       print_field("Length so far: %d", btohs(cmd->len_so_far));
+       print_field("Remaining ASSOC length: %d", btohs(cmd->remain_assoc_len));
+
+       packet_hexdump(data + 5, size - 5);
+}
+
+static void write_remote_amp_assoc_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_write_remote_amp_assoc *rsp = data;
+
+       print_status(rsp->status);
+       print_phy_handle(rsp->phy_handle);
+}
+
+static void le_set_event_mask_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_event_mask *cmd = data;
+
+       print_event_mask_le(cmd->mask);
+}
+
+static void le_read_buffer_size_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_buffer_size *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Data packet length: %d", btohs(rsp->le_mtu));
+       print_field("Num data packets: %d", rsp->le_max_pkt);
+}
+
+static void le_read_local_features_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_local_features *rsp = data;
+
+       print_status(rsp->status);
+       print_features(0, rsp->features, 0x01);
+}
+
+static void le_set_random_address_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_random_address *cmd = data;
+
+       print_addr("Address", cmd->addr, 0x01);
+}
+
+static void le_set_adv_parameters_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_adv_parameters *cmd = data;
+       const char *str;
+
+       print_slot_625("Min advertising interval", cmd->min_interval);
+       print_slot_625("Max advertising interval", cmd->max_interval);
+
+       switch (cmd->type) {
+       case 0x00:
+               str = "Connectable undirected - ADV_IND";
+               break;
+       case 0x01:
+               str = "Connectable directed - ADV_DIRECT_IND";
+               break;
+       case 0x02:
+               str = "Scannable undirected - ADV_SCAN_IND";
+               break;
+       case 0x03:
+               str = "Non connectable undirect - ADV_NONCONN_IND";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, cmd->type);
+
+       print_addr_type("Own address type", cmd->own_addr_type);
+       print_addr_type("Direct address type", cmd->direct_addr_type);
+       print_addr("Direct address", cmd->direct_addr, cmd->direct_addr_type);
+
+       switch (cmd->channel_map) {
+       case 0x01:
+               str = "37";
+               break;
+       case 0x02:
+               str = "38";
+               break;
+       case 0x03:
+               str = "37, 38";
+               break;
+       case 0x04:
+               str = "39";
+               break;
+       case 0x05:
+               str = "37, 39";
+               break;
+       case 0x06:
+               str = "38, 39";
+               break;
+       case 0x07:
+               str = "37, 38, 39";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Channel map: %s (0x%2.2x)", str, cmd->channel_map);
+
+       switch (cmd->filter_policy) {
+       case 0x00:
+               str = "Allow Scan Request from Any, "
+                       "Allow Connect Request from Any";
+               break;
+       case 0x01:
+               str = "Allow Scan Request from White List Only, "
+                       "Allow Connect Request from Any";
+               break;
+       case 0x02:
+               str = "Allow Scan Request from Any, "
+                       "Allow Connect Request from White List Only";
+               break;
+       case 0x03:
+               str = "Allow Scan Request from White List Only, "
+                       "Allow Connect Request from White List Only";
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Filter policy: %s (0x%2.2x)", str, cmd->filter_policy);
+}
+
+static void le_read_adv_tx_power_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_adv_tx_power *rsp = data;
+
+       print_status(rsp->status);
+       print_field("TX power: %d dBm", rsp->level);
+}
+
+static void le_set_adv_data_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_adv_data *cmd = data;
+
+       print_field("Length: %d", cmd->len);
+       print_eir(cmd->data, cmd->len, true);
+}
+
+static void le_set_scan_rsp_data_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_scan_rsp_data *cmd = data;
+
+       print_field("Length: %d", cmd->len);
+       print_eir(cmd->data, cmd->len, true);
+}
+
+static void le_set_adv_enable_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_adv_enable *cmd = data;
+       const char *str;
+
+       switch (cmd->enable) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Advertising: %s (0x%2.2x)", str, cmd->enable);
+}
+
+static void le_set_scan_parameters_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_scan_parameters *cmd = data;
+       const char *str;
+
+       switch (cmd->type) {
+       case 0x00:
+               str = "Passive";
+               break;
+       case 0x01:
+               str = "Active";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Type: %s (0x%2.2x)", str, cmd->type);
+
+       print_interval(cmd->interval);
+       print_window(cmd->window);
+       print_addr_type("Own address type", cmd->own_addr_type);
+
+       switch (cmd->filter_policy) {
+       case 0x00:
+               str = "Accept all advertisement";
+               break;
+       case 0x01:
+               str = "Ignore not in white list";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Filter policy: %s (0x%2.2x)", str, cmd->filter_policy);
+}
+
+static void le_set_scan_enable_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_scan_enable *cmd = data;
+       const char *str;
+
+       switch (cmd->enable) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Scanning: %s (0x%2.2x)", str, cmd->enable);
+
+       switch (cmd->filter_dup) {
+       case 0x00:
+               str = "Disabled";
+               break;
+       case 0x01:
+               str = "Enabled";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Filter duplicates: %s (0x%2.2x)", str, cmd->filter_dup);
+}
+
+static void le_create_conn_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_create_conn *cmd = data;
+       const char *str;
+
+       print_slot_625("Scan interval", cmd->scan_interval);
+       print_slot_625("Scan window", cmd->scan_window);
+
+       switch (cmd->filter_policy) {
+       case 0x00:
+               str = "White list is not used";
+               break;
+       case 0x01:
+               str = "White list is used";
+               break;
+       default:
+               str = "Reserved";
+               break;
+       }
+
+       print_field("Filter policy: %s (0x%2.2x)", str, cmd->filter_policy);
+
+       print_addr_type("Peer address type", cmd->peer_addr_type);
+       print_addr("Peer address", cmd->peer_addr, cmd->peer_addr_type);
+       print_addr_type("Own address type", cmd->own_addr_type);
+
+       print_slot_125("Min connection interval", cmd->min_interval);
+       print_slot_125("Max connection interval", cmd->max_interval);
+       print_field("Connection latency: 0x%4.4x", btohs(cmd->latency));
+       print_field("Supervision timeout: %d msec (0x%4.4x)",
+               btohs(cmd->supv_timeout) * 10, btohs(cmd->supv_timeout));
+       print_slot_625("Min connection length", cmd->min_length);
+       print_slot_625("Max connection length", cmd->max_length);
+}
+
+static void le_read_white_list_size_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_white_list_size *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Size: %u", rsp->size);
+}
+
+static void le_add_to_white_list_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_add_to_white_list *cmd = data;
+
+       print_addr_type("Address type", cmd->addr_type);
+       print_addr("Address", cmd->addr, cmd->addr_type);
+}
+
+static void le_remove_from_white_list_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_remove_from_white_list *cmd = data;
+
+       print_addr_type("Address type", cmd->addr_type);
+       print_addr("Address", cmd->addr, cmd->addr_type);
+}
+
+static void le_conn_update_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_conn_update *cmd = data;
+
+       print_handle(cmd->handle);
+       print_slot_125("Min connection interval", cmd->min_interval);
+       print_slot_125("Max connection interval", cmd->max_interval);
+       print_field("Connection latency: 0x%4.4x", btohs(cmd->latency));
+       print_field("Supervision timeout: %d msec (0x%4.4x)",
+               btohs(cmd->supv_timeout) * 10, btohs(cmd->supv_timeout));
+       print_slot_625("Min connection length", cmd->min_length);
+       print_slot_625("Max connection length", cmd->max_length);
+}
+
+static void le_set_host_classification_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_set_host_classification *cmd = data;
+
+       print_le_channel_map(cmd->map);
+}
+
+static void le_read_channel_map_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_read_channel_map *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void le_read_channel_map_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_channel_map *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+       print_le_channel_map(rsp->map);
+}
+
+static void le_read_remote_features_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_read_remote_features *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void le_encrypt_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_encrypt *cmd = data;
+
+       print_key("Key", cmd->key);
+       print_key("Plaintext data", cmd->plaintext);
+}
+
+static void le_encrypt_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_encrypt *rsp = data;
+
+       print_status(rsp->status);
+       print_key("Encrypted data", rsp->data);
+}
+
+static void le_rand_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_rand *rsp = data;
+
+       print_status(rsp->status);
+       print_random_number(rsp->number);
+}
+
+static void le_start_encrypt_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_start_encrypt *cmd = data;
+
+       print_handle(cmd->handle);
+       print_random_number(cmd->number);
+       print_field("Encryption diversifier: 0x%4.4x",
+                                       btohs(cmd->diversifier));
+       print_key("Long term key", cmd->ltk);
+}
+
+static void le_ltk_req_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_ltk_req_reply *cmd = data;
+
+       print_handle(cmd->handle);
+       print_key("Long term key", cmd->ltk);
+}
+
+static void le_ltk_req_reply_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_ltk_req_reply *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void le_ltk_req_neg_reply_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_ltk_req_neg_reply *cmd = data;
+
+       print_handle(cmd->handle);
+}
+
+static void le_ltk_req_neg_reply_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_ltk_req_neg_reply *rsp = data;
+
+       print_status(rsp->status);
+       print_handle(rsp->handle);
+}
+
+static void le_read_supported_states_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_read_supported_states *rsp = data;
+
+       print_status(rsp->status);
+       print_le_states(rsp->states);
+}
+
+static void le_receiver_test_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_receiver_test *cmd = data;
+
+       print_field("RX frequency: %d MHz (0x%2.2x)",
+                               (cmd->frequency * 2) + 2402, cmd->frequency);
+}
+
+static void le_transmitter_test_cmd(const void *data, uint8_t size)
+{
+       const struct bt_hci_cmd_le_transmitter_test *cmd = data;
+
+       print_field("TX frequency: %d MHz (0x%2.2x)",
+                               (cmd->frequency * 2) + 2402, cmd->frequency);
+       print_field("Test data length: %d bytes", cmd->data_len);
+       print_field("Packet payload: 0x%2.2x", cmd->payload);
+}
+
+static void le_test_end_rsp(const void *data, uint8_t size)
+{
+       const struct bt_hci_rsp_le_test_end *rsp = data;
+
+       print_status(rsp->status);
+       print_field("Number of packets: %d", btohs(rsp->num_packets));
+}
+
+struct opcode_data {
+       uint16_t opcode;
+       int bit;
+       const char *str;
+       void (*cmd_func) (const void *data, uint8_t size);
+       uint8_t cmd_size;
+       bool cmd_fixed;
+       void (*rsp_func) (const void *data, uint8_t size);
+       uint8_t rsp_size;
+       bool rsp_fixed;
+};
+
+static const struct opcode_data opcode_table[] = {
+       { 0x0000,  -1, "NOP" },
+
+       /* OGF 1 - Link Control */
+       { 0x0401,   0, "Inquiry",
+                               inquiry_cmd, 5, true },
+       { 0x0402,   1, "Inquiry Cancel",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x0403,   2, "Periodic Inquiry Mode",
+                               periodic_inquiry_cmd, 9, true,
+                               status_rsp, 1, true },
+       { 0x0404,   3, "Exit Periodic Inquiry Mode",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x0405,   4, "Create Connection",
+                               create_conn_cmd, 13, true },
+       { 0x0406,   5, "Disconnect",
+                               disconnect_cmd, 3, true },
+       { 0x0407,   6, "Add SCO Connection",
+                               add_sco_conn_cmd, 4, true },
+       { 0x0408,   7, "Create Connection Cancel",
+                               create_conn_cancel_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x0409,   8, "Accept Connection Request",
+                               accept_conn_request_cmd, 7, true },
+       { 0x040a,   9, "Reject Connection Request",
+                               reject_conn_request_cmd, 7, true },
+       { 0x040b,  10, "Link Key Request Reply",
+                               link_key_request_reply_cmd, 22, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x040c,  11, "Link Key Request Negative Reply",
+                               link_key_request_neg_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x040d,  12, "PIN Code Request Reply",
+                               pin_code_request_reply_cmd, 23, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x040e,  13, "PIN Code Request Negative Reply",
+                               pin_code_request_neg_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x040f,  14, "Change Connection Packet Type",
+                               change_conn_pkt_type_cmd, 4, true },
+       { 0x0411,  15, "Authentication Requested",
+                               auth_requested_cmd, 2, true },
+       { 0x0413,  16, "Set Connection Encryption",
+                               set_conn_encrypt_cmd, 3, true },
+       { 0x0415,  17, "Change Connection Link Key",
+                               change_conn_link_key_cmd, 2, true },
+       { 0x0417,  18, "Master Link Key",
+                               master_link_key_cmd, 1, true },
+       { 0x0419,  19, "Remote Name Request",
+                               remote_name_request_cmd, 10, true },
+       { 0x041a,  20, "Remote Name Request Cancel",
+                               remote_name_request_cancel_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x041b,  21, "Read Remote Supported Features",
+                               read_remote_features_cmd, 2, true },
+       { 0x041c,  22, "Read Remote Extended Features",
+                               read_remote_ext_features_cmd, 3, true },
+       { 0x041d,  23, "Read Remote Version Information",
+                               read_remote_version_cmd, 2, true },
+       { 0x041f,  24, "Read Clock Offset",
+                               read_clock_offset_cmd, 2, true },
+       { 0x0420,  25, "Read LMP Handle",
+                               read_lmp_handle_cmd, 2, true,
+                               read_lmp_handle_rsp, 8, true },
+       { 0x0428, 131, "Setup Synchronous Connection",
+                               setup_sync_conn_cmd, 17, true },
+       { 0x0429, 132, "Accept Synchronous Connection",
+                               accept_sync_conn_cmd, 21, true },
+       { 0x042a, 133, "Reject Synchronous Connection",
+                               reject_sync_conn_cmd, 7, true },
+       { 0x042b, 151, "IO Capability Request Reply",
+                               io_capability_request_reply_cmd, 9, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x042c, 152, "User Confirmation Request Reply",
+                               user_confirm_request_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x042d, 153, "User Confirmation Request Neg Reply",
+                               user_confirm_request_neg_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x042e, 154, "User Passkey Request Reply",
+                               user_passkey_request_reply_cmd, 10, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x042f, 155, "User Passkey Request Negative Reply",
+                               user_passkey_request_neg_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x0430, 156, "Remote OOB Data Request Reply",
+                               remote_oob_data_request_reply_cmd, 38, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x0433, 159, "Remote OOB Data Request Neg Reply",
+                               remote_oob_data_request_neg_reply_cmd, 6, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x0434, 163, "IO Capability Request Negative Reply",
+                               io_capability_request_neg_reply_cmd, 7, true,
+                               status_bdaddr_rsp, 7, true },
+       { 0x0435, 168, "Create Physical Link",
+                               create_phy_link_cmd, 3, false },
+       { 0x0436, 169, "Accept Physical Link",
+                               accept_phy_link_cmd, 3, false },
+       { 0x0437, 170, "Disconnect Physical Link",
+                               disconn_phy_link_cmd, 2, true },
+       { 0x0438, 171, "Create Logical Link",
+                               create_logic_link_cmd, 33, true },
+       { 0x0439, 172, "Accept Logical Link",
+                               accept_logic_link_cmd, 33, true },
+       { 0x043a, 173, "Disconnect Logical Link",
+                               disconn_logic_link_cmd, 2, true },
+       { 0x043b, 174, "Logical Link Cancel",
+                               logic_link_cancel_cmd, 2, true,
+                               logic_link_cancel_rsp, 3, true },
+       { 0x043c, 175, "Flow Specifcation Modify",
+                               flow_spec_modify_cmd, 34, true },
+       { 0x043d, 235, "Enhanced Setup Synchronous Connection" },
+       { 0x043e, 236, "Enhanced Accept Synchronous Connection" },
+       { 0x043f, 246, "Truncated Page" },
+       { 0x0440, 247, "Truncated Page Cancel" },
+       { 0x0441, 248, "Set Connectionless Slave Broadcast" },
+       { 0x0442, 249, "Set Connectionless Slave Broadcast Receive" },
+       { 0x0443, 250, "Start Synchronization Train" },
+       { 0x0444, 251, "Receive Synchronization Train" },
+
+       /* OGF 2 - Link Policy */
+       { 0x0801,  33, "Holde Mode",
+                               hold_mode_cmd, 6, true },
+       { 0x0803,  34, "Sniff Mode",
+                               sniff_mode_cmd, 10, true },
+       { 0x0804,  35, "Exit Sniff Mode",
+                               exit_sniff_mode_cmd, 2, true },
+       { 0x0805,  36, "Park State",
+                               park_state_cmd, 6, true },
+       { 0x0806,  37, "Exit Park State",
+                               exit_park_state_cmd, 2, true },
+       { 0x0807,  38, "QoS Setup",
+                               qos_setup_cmd, 20, true },
+       { 0x0809,  39, "Role Discovery",
+                               role_discovery_cmd, 2, true,
+                               role_discovery_rsp, 4, true },
+       { 0x080b,  40, "Switch Role",
+                               switch_role_cmd, 7, true },
+       { 0x080c,  41, "Read Link Policy Settings",
+                               read_link_policy_cmd, 2, true,
+                               read_link_policy_rsp, 5, true },
+       { 0x080d,  42, "Write Link Policy Settings",
+                               write_link_policy_cmd, 4, true,
+                               write_link_policy_rsp, 3, true },
+       { 0x080e,  43, "Read Default Link Policy Settings",
+                               null_cmd, 0, true,
+                               read_default_link_policy_rsp, 3, true },
+       { 0x080f,  44, "Write Default Link Policy Settings",
+                               write_default_link_policy_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0810,  45, "Flow Specification",
+                               flow_spec_cmd, 21, true },
+       { 0x0811, 140, "Sniff Subrating",
+                               sniff_subrating_cmd, 8, true,
+                               sniff_subrating_rsp, 3, true },
+
+       /* OGF 3 - Host Control */
+       { 0x0c01,  46, "Set Event Mask",
+                               set_event_mask_cmd, 8, true,
+                               status_rsp, 1, true },
+       { 0x0c03,  47, "Reset",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x0c05,  48, "Set Event Filter",
+                               set_event_filter_cmd, 1, false,
+                               status_rsp, 1, true },
+       { 0x0c08,  49, "Flush",
+                               flush_cmd, 2, true,
+                               flush_rsp, 3, true },
+       { 0x0c09,  50, "Read PIN Type",
+                               null_cmd, 0, true,
+                               read_pin_type_rsp, 2, true },
+       { 0x0c0a,  51, "Write PIN Type",
+                               write_pin_type_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c0b,  52, "Create New Unit Key",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x0c0d,  53, "Read Stored Link Key",
+                               read_stored_link_key_cmd, 7, true,
+                               read_stored_link_key_rsp, 5, true },
+       { 0x0c11,  54, "Write Stored Link Key",
+                               write_stored_link_key_cmd, 1, false,
+                               write_stored_link_key_rsp, 2, true },
+       { 0x0c12,  55, "Delete Stored Link Key",
+                               delete_stored_link_key_cmd, 7, true,
+                               delete_stored_link_key_rsp, 3, true },
+       { 0x0c13,  56, "Write Local Name",
+                               write_local_name_cmd, 248, true,
+                               status_rsp, 1, true },
+       { 0x0c14,  57, "Read Local Name",
+                               null_cmd, 0, true,
+                               read_local_name_rsp, 249, true },
+       { 0x0c15,  58, "Read Connection Accept Timeout",
+                               null_cmd, 0, true,
+                               read_conn_accept_timeout_rsp, 3, true },
+       { 0x0c16,  59, "Write Connection Accept Timeout",
+                               write_conn_accept_timeout_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0c17,  60, "Read Page Timeout",
+                               null_cmd, 0, true,
+                               read_page_timeout_rsp, 3, true },
+       { 0x0c18,  61, "Write Page Timeout",
+                               write_page_timeout_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0c19,  62, "Read Scan Enable",
+                               null_cmd, 0, true,
+                               read_scan_enable_rsp, 2, true },
+       { 0x0c1a,  63, "Write Scan Enable",
+                               write_scan_enable_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c1b,  64, "Read Page Scan Activity",
+                               null_cmd, 0, true,
+                               read_page_scan_activity_rsp, 5, true },
+       { 0x0c1c,  65, "Write Page Scan Activity",
+                               write_page_scan_activity_cmd, 4, true,
+                               status_rsp, 1, true },
+       { 0x0c1d,  66, "Read Inquiry Scan Activity",
+                               null_cmd, 0, true,
+                               read_inquiry_scan_activity_rsp, 5, true },
+       { 0x0c1e,  67, "Write Inquiry Scan Activity",
+                               write_inquiry_scan_activity_cmd, 4, true,
+                               status_rsp, 1, true },
+       { 0x0c1f,  68, "Read Authentication Enable",
+                               null_cmd, 0, true,
+                               read_auth_enable_rsp, 2, true },
+       { 0x0c20,  69, "Write Authentication Enable",
+                               write_auth_enable_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c21,  70, "Read Encryption Mode",
+                               null_cmd, 0, true,
+                               read_encrypt_mode_rsp, 2, true },
+       { 0x0c22,  71, "Write Encryption Mode",
+                               write_encrypt_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c23,  72, "Read Class of Device",
+                               null_cmd, 0, true,
+                               read_class_of_dev_rsp, 4, true },
+       { 0x0c24,  73, "Write Class of Device",
+                               write_class_of_dev_cmd, 3, true,
+                               status_rsp, 1, true },
+       { 0x0c25,  74, "Read Voice Setting",
+                               null_cmd, 0, true,
+                               read_voice_setting_rsp, 3, true },
+       { 0x0c26,  75, "Write Voice Setting",
+                               write_voice_setting_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0c27,  76, "Read Automatic Flush Timeout" },
+       { 0x0c28,  77, "Write Automatic Flush Timeout" },
+       { 0x0c29,  78, "Read Num Broadcast Retransmissions" },
+       { 0x0c2a,  79, "Write Num Broadcast Retransmissions" },
+       { 0x0c2b,  80, "Read Hold Mode Activity" },
+       { 0x0c2c,  81, "Write Hold Mode Activity" },
+       { 0x0c2d,  82, "Read Transmit Power Level" },
+       { 0x0c2e,  83, "Read Sync Flow Control Enable" },
+       { 0x0c2f,  84, "Write Sync Flow Control Enable" },
+       { 0x0c31,  85, "Set Host Controller To Host Flow" },
+       { 0x0c33,  86, "Host Buffer Size",
+                               host_buffer_size_cmd, 7, true,
+                               status_rsp, 1, true },
+       { 0x0c35,  87, "Host Number of Completed Packets" },
+       { 0x0c36,  88, "Read Link Supervision Timeout",
+                               read_link_supv_timeout_cmd, 2, true,
+                               read_link_supv_timeout_rsp, 5, true },
+       { 0x0c37,  89, "Write Link Supervision Timeout",
+                               write_link_supv_timeout_cmd, 4, true,
+                               write_link_supv_timeout_rsp, 3, true },
+       { 0x0c38,  90, "Read Number of Supported IAC",
+                               null_cmd, 0, true,
+                               read_num_supported_iac_rsp, 2, true },
+       { 0x0c39,  91, "Read Current IAC LAP",
+                               null_cmd, 0, true,
+                               read_current_iac_lap_rsp, 2, false },
+       { 0x0c3a,  92, "Write Current IAC LAP",
+                               write_current_iac_lap_cmd, 1, false,
+                               status_rsp, 1, true },
+       { 0x0c3b,  93, "Read Page Scan Period Mode",
+                               null_cmd, 0, true,
+                               read_page_scan_period_mode_rsp, 2, true },
+       { 0x0c3c,  94, "Write Page Scan Period Mode",
+                               write_page_scan_period_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c3d,  95, "Read Page Scan Mode",
+                               null_cmd, 0, true,
+                               read_page_scan_mode_rsp, 2, true },
+       { 0x0c3e,  96, "Write Page Scan Mode",
+                               write_page_scan_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c3f,  97, "Set AFH Host Channel Classification",
+                               set_afh_host_classification_cmd, 10, true,
+                               status_rsp, 1, true },
+       { 0x0c42, 100, "Read Inquiry Scan Type",
+                               null_cmd, 0, true,
+                               read_inquiry_scan_type_rsp, 2, true },
+       { 0x0c43, 101, "Write Inquiry Scan Type",
+                               write_inquiry_scan_type_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c44, 102, "Read Inquiry Mode",
+                               null_cmd, 0, true,
+                               read_inquiry_mode_rsp, 2, true },
+       { 0x0c45, 103, "Write Inquiry Mode",
+                               write_inquiry_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c46, 104, "Read Page Scan Type",
+                               null_cmd, 0, true,
+                               read_page_scan_type_rsp, 2, true },
+       { 0x0c47, 105, "Write Page Scan Type",
+                               write_page_scan_type_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c48, 106, "Read AFH Channel Assessment Mode",
+                               null_cmd, 0, true,
+                               read_afh_assessment_mode_rsp, 2, true },
+       { 0x0c49, 107, "Write AFH Channel Assessment Mode",
+                               write_afh_assessment_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c51, 136, "Read Extended Inquiry Response",
+                               null_cmd, 0, true,
+                               read_ext_inquiry_response_rsp, 242, true },
+       { 0x0c52, 137, "Write Extended Inquiry Response",
+                               write_ext_inquiry_response_cmd, 241, true,
+                               status_rsp, 1, true },
+       { 0x0c53, 138, "Refresh Encryption Key",
+                               refresh_encrypt_key_cmd, 2, true },
+       { 0x0c55, 141, "Read Simple Pairing Mode",
+                               null_cmd, 0, true,
+                               read_simple_pairing_mode_rsp, 2, true },
+       { 0x0c56, 142, "Write Simple Pairing Mode",
+                               write_simple_pairing_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c57, 143, "Read Local OOB Data",
+                               null_cmd, 0, true,
+                               read_local_oob_data_rsp, 33, true },
+       { 0x0c58, 144, "Read Inquiry Response TX Power Level",
+                               null_cmd, 0, true,
+                               read_inquiry_resp_tx_power_rsp, 2, true },
+       { 0x0c59, 145, "Write Inquiry Transmit Power Level",
+                               write_inquiry_tx_power_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c5a, 146, "Read Default Erroneous Reporting" },
+       { 0x0c5b, 147, "Write Default Erroneous Reporting" },
+       { 0x0c5f, 158, "Enhanced Flush",
+                               enhanced_flush_cmd, 3, true },
+       { 0x0c60, 162, "Send Keypress Notification" },
+       { 0x0c61, 176, "Read Logical Link Accept Timeout" },
+       { 0x0c62, 177, "Write Logical Link Accept Timeout" },
+       { 0x0c63, 178, "Set Event Mask Page 2",
+                               set_event_mask_page2_cmd, 8, true,
+                               status_rsp, 1, true },
+       { 0x0c64, 179, "Read Location Data",
+                               null_cmd, 0, true,
+                               read_location_data_rsp, 6, true },
+       { 0x0c65, 180, "Write Location Data",
+                               write_location_data_cmd, 5, true,
+                               status_rsp, 1, true },
+       { 0x0c66, 184, "Read Flow Control Mode",
+                               null_cmd, 0, true,
+                               read_flow_control_mode_rsp, 2, true },
+       { 0x0c67, 185, "Write Flow Control Mode",
+                               write_flow_control_mode_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x0c68, 192, "Read Enhanced Transmit Power Level" },
+       { 0x0c69, 194, "Read Best Effort Flush Timeout" },
+       { 0x0c6a, 195, "Write Best Effort Flush Timeout" },
+       { 0x0c6b, 196, "Short Range Mode" },
+       { 0x0c6c, 197, "Read LE Host Supported",
+                               null_cmd, 0, true,
+                               read_le_host_supported_rsp, 3, true },
+       { 0x0c6d, 198, "Write LE Host Supported",
+                               write_le_host_supported_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x0c6e, 238, "Set MWS Channel Parameters" },
+       { 0x0c6f, 239, "Set External Frame Configuration" },
+       { 0x0c70, 240, "Set MWS Signaling" },
+       { 0x0c71, 241, "Set MWS Transport Layer" },
+       { 0x0c72, 242, "Set MWS Scan Frequency Table" },
+       { 0x0c73, 244, "Set MWS Pattern Configuration" },
+       { 0x0c74, 252, "Set Reserved LT_ADDR" },
+       { 0x0c75, 253, "Delete Reserved LT_ADDR" },
+       { 0x0c76, 254, "Set Connectionless Slave Broadcast Data" },
+       { 0x0c77, 255, "Read Synchronization Train Parameters",
+                               null_cmd, 0, true,
+                               read_sync_train_params_rsp, 8, true },
+       { 0x0c78, 256, "Write Synchronization Train Parameters" },
+
+       /* OGF 4 - Information Parameter */
+       { 0x1001, 115, "Read Local Version Information",
+                               null_cmd, 0, true,
+                               read_local_version_rsp, 9, true },
+       { 0x1002, 116, "Read Local Supported Commands",
+                               null_cmd, 0, true,
+                               read_local_commands_rsp, 65, true },
+       { 0x1003, 117, "Read Local Supported Features",
+                               null_cmd, 0, true,
+                               read_local_features_rsp, 9, true },
+       { 0x1004, 118, "Read Local Extended Features",
+                               read_local_ext_features_cmd, 1, true,
+                               read_local_ext_features_rsp, 11, true },
+       { 0x1005, 119, "Read Buffer Size",
+                               null_cmd, 0, true,
+                               read_buffer_size_rsp, 8, true },
+       { 0x1007, 120, "Read Country Code",
+                               null_cmd, 0, true,
+                               read_country_code_rsp, 2, true },
+       { 0x1009, 121, "Read BD ADDR",
+                               null_cmd, 0, true,
+                               read_bd_addr_rsp, 7, true },
+       { 0x100a, 186, "Read Data Block Size",
+                               null_cmd, 0, true,
+                               read_data_block_size_rsp, 7, true },
+       { 0x100b, 237, "Read Local Supported Codecs" },
+
+       /* OGF 5 - Status Parameter */
+       { 0x1401, 122, "Read Failed Contact Counter",
+                               read_failed_contact_counter_cmd, 2, true,
+                               read_failed_contact_counter_rsp, 5, true },
+       { 0x1402, 123, "Reset Failed Contact Counter",
+                               reset_failed_contact_counter_cmd, 2, true,
+                               reset_failed_contact_counter_rsp, 3, true },
+       { 0x1403, 124, "Read Link Quality",
+                               read_link_quality_cmd, 2, true,
+                               read_link_quality_rsp, 4, true },
+       { 0x1405, 125, "Read RSSI",
+                               read_rssi_cmd, 2, true,
+                               read_rssi_rsp, 4, true },
+       { 0x1406, 126, "Read AFH Channel Map",
+                               read_afh_channel_map_cmd, 2, true,
+                               read_afh_channel_map_rsp, 14, true },
+       { 0x1407, 127, "Read Clock",
+                               read_clock_cmd, 3, true,
+                               read_clock_rsp, 9, true },
+       { 0x1408, 164, "Read Encryption Key Size",
+                               read_encrypt_key_size_cmd, 2, true,
+                               read_encrypt_key_size_rsp, 4, true },
+       { 0x1409, 181, "Read Local AMP Info",
+                               null_cmd, 0, true,
+                               read_local_amp_info_rsp, 31, true },
+       { 0x140a, 182, "Read Local AMP ASSOC",
+                               read_local_amp_assoc_cmd, 5, true,
+                               read_local_amp_assoc_rsp, 5, false },
+       { 0x140b, 183, "Write Remote AMP ASSOC",
+                               write_remote_amp_assoc_cmd, 6, false,
+                               write_remote_amp_assoc_rsp, 2, true },
+       { 0x140c, 243, "Get MWS Transport Layer Configuration" },
+       { 0x140d, 245, "Set Triggered Clock Capture" },
+
+       /* OGF 6 - Testing */
+       { 0x1801, 128, "Read Loopback Mode" },
+       { 0x1802, 129, "Write Loopback Mode" },
+       { 0x1803, 130, "Enable Device Under Test Mode",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x1804, 157, "Write Simple Pairing Debug Mode" },
+       { 0x1807, 189, "Enable AMP Receiver Reports" },
+       { 0x1808, 190, "AMP Test End" },
+       { 0x1809, 191, "AMP Test" },
+
+       /* OGF 8 - LE Control */
+       { 0x2001, 200, "LE Set Event Mask",
+                               le_set_event_mask_cmd, 8, true,
+                               status_rsp, 1, true },
+       { 0x2002, 201, "LE Read Buffer Size",
+                               null_cmd, 0, true,
+                               le_read_buffer_size_rsp, 4, true },
+       { 0x2003, 202, "LE Read Local Supported Features",
+                               null_cmd, 0, true,
+                               le_read_local_features_rsp, 9, true },
+       { 0x2005, 204, "LE Set Random Address",
+                               le_set_random_address_cmd, 6, true,
+                               status_rsp, 1, true },
+       { 0x2006, 205, "LE Set Advertising Parameters",
+                               le_set_adv_parameters_cmd, 15, true,
+                               status_rsp, 1, true },
+       { 0x2007, 206, "LE Read Advertising Channel TX Power",
+                               null_cmd, 0, true,
+                               le_read_adv_tx_power_rsp, 2, true },
+       { 0x2008, 207, "LE Set Advertising Data",
+                               le_set_adv_data_cmd, 32, true,
+                               status_rsp, 1, true },
+       { 0x2009, 208, "LE Set Scan Response Data",
+                               le_set_scan_rsp_data_cmd, 32, true,
+                               status_rsp, 1, true },
+       { 0x200a, 209, "LE Set Advertise Enable",
+                               le_set_adv_enable_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x200b, 210, "LE Set Scan Parameters",
+                               le_set_scan_parameters_cmd, 7, true,
+                               status_rsp, 1, true },
+       { 0x200c, 211, "LE Set Scan Enable",
+                               le_set_scan_enable_cmd, 2, true,
+                               status_rsp, 1, true },
+       { 0x200d, 212, "LE Create Connection",
+                               le_create_conn_cmd, 25, true },
+       { 0x200e, 213, "LE Create Connection Cancel",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x200f, 214, "LE Read White List Size",
+                               null_cmd, 0, true,
+                               le_read_white_list_size_rsp, 2, true },
+       { 0x2010, 215, "LE Clear White List",
+                               null_cmd, 0, true,
+                               status_rsp, 1, true },
+       { 0x2011, 216, "LE Add Device To White List",
+                               le_add_to_white_list_cmd, 7, true,
+                               status_rsp, 1, true },
+       { 0x2012, 217, "LE Remove Device From White List",
+                               le_remove_from_white_list_cmd, 7, true,
+                               status_rsp, 1, true },
+       { 0x2013, 218, "LE Connection Update",
+                               le_conn_update_cmd, 14, true },
+       { 0x2014, 219, "LE Set Host Channel Classification",
+                               le_set_host_classification_cmd, 5, true,
+                               status_rsp, 1, true },
+       { 0x2015, 220, "LE Read Channel Map",
+                               le_read_channel_map_cmd, 2, true,
+                               le_read_channel_map_rsp, 8, true },
+       { 0x2016, 221, "LE Read Remote Used Features",
+                               le_read_remote_features_cmd, 2, true },
+       { 0x2017, 222, "LE Encrypt",
+                               le_encrypt_cmd, 32, true,
+                               le_encrypt_rsp, 17, true },
+       { 0x2018, 223, "LE Rand",
+                               null_cmd, 0, true,
+                               le_rand_rsp, 9, true },
+       { 0x2019, 224, "LE Start Encryption",
+                               le_start_encrypt_cmd, 28, true },
+       { 0x201a, 225, "LE Long Term Key Request Reply",
+                               le_ltk_req_reply_cmd, 18, true,
+                               le_ltk_req_reply_rsp, 3, true },
+       { 0x201b, 226, "LE Long Term Key Request Neg Reply",
+                               le_ltk_req_neg_reply_cmd, 2, true,
+                               le_ltk_req_neg_reply_rsp, 3, true },
+       { 0x201c, 227, "LE Read Supported States",
+                               null_cmd, 0, true,
+                               le_read_supported_states_rsp, 9, true },
+       { 0x201d, 228, "LE Receiver Test",
+                               le_receiver_test_cmd, 1, true,
+                               status_rsp, 1, true },
+       { 0x201e, 229, "LE Transmitter Test",
+                               le_transmitter_test_cmd, 3, true,
+                               status_rsp, 1, true },
+       { 0x201f, 230, "LE Test End",
+                               null_cmd, 0, true,
+                               le_test_end_rsp, 3, true },
+       { }
+};
+
+static const char *get_supported_command(int bit)
+{
+       int i;
+
+       for (i = 0; opcode_table[i].str; i++) {
+               if (opcode_table[i].bit == bit)
+                       return opcode_table[i].str;
+       }
+
+       return NULL;
+}
+
+static void status_evt(const void *data, uint8_t size)
+{
+       uint8_t status = *((uint8_t *) data);
+
+       print_status(status);
+}
+
+static void inquiry_result_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_inquiry_result *evt = data;
+
+       print_num_resp(evt->num_resp);
+       print_bdaddr(evt->bdaddr);
+       print_pscan_rep_mode(evt->pscan_rep_mode);
+       print_pscan_period_mode(evt->pscan_period_mode);
+       print_pscan_mode(evt->pscan_mode);
+       print_dev_class(evt->dev_class);
+       print_clock_offset(evt->clock_offset);
+
+       if (size > sizeof(*evt))
+               packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
+}
+
+static void conn_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_conn_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_bdaddr(evt->bdaddr);
+       print_link_type(evt->link_type);
+       print_encr_mode(evt->encr_mode);
+
+       if (evt->status == 0x00)
+               assign_handle(btohs(evt->handle), 0x00);
+}
+
+static void conn_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_conn_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_dev_class(evt->dev_class);
+       print_link_type(evt->link_type);
+}
+
+static void disconnect_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_disconnect_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_reason(evt->reason);
+
+       if (evt->status == 0x00)
+               release_handle(btohs(evt->handle));
+}
+
+static void auth_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_auth_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+}
+
+static void remote_name_request_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_remote_name_request_complete *evt = data;
+
+       print_status(evt->status);
+       print_bdaddr(evt->bdaddr);
+       print_name(evt->name);
+}
+
+static void encrypt_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_encrypt_change *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_encr_mode_change(evt->encr_mode, evt->handle);
+}
+
+static void change_conn_link_key_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_change_conn_link_key_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+}
+
+static void master_link_key_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_master_link_key_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_key_flag(evt->key_flag);
+}
+
+static void remote_features_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_remote_features_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_features(0, evt->features, 0x00);
+}
+
+static void remote_version_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_remote_version_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_lmp_version(evt->lmp_ver, evt->lmp_subver);
+       print_manufacturer(evt->manufacturer);
+}
+
+static void qos_setup_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_qos_setup_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_field("Flags: 0x%2.2x", evt->flags);
+
+       print_service_type(evt->service_type);
+
+       print_field("Token rate: %d", btohl(evt->token_rate));
+       print_field("Peak bandwidth: %d", btohl(evt->peak_bandwidth));
+       print_field("Latency: %d", btohl(evt->latency));
+       print_field("Delay variation: %d", btohl(evt->delay_variation));
+}
+
+static void cmd_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_cmd_complete *evt = data;
+       uint16_t opcode = btohs(evt->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+       const struct opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       for (i = 0; opcode_table[i].str; i++) {
+               if (opcode_table[i].opcode == opcode) {
+                       opcode_data = &opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->rsp_func)
+                       opcode_color = COLOR_HCI_COMMAND;
+               else
+                       opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
+                       " (0x%2.2x|0x%4.4x) ncmd %d", ogf, ocf, evt->ncmd);
+
+       if (!opcode_data || !opcode_data->rsp_func) {
+               packet_hexdump(data + 3, size - 3);
+               return;
+       }
+
+       if (opcode_data->rsp_fixed) {
+               if (size - 3 != opcode_data->rsp_size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data + 3, size - 3);
+                       return;
+               }
+       } else {
+               if (size - 3 < opcode_data->rsp_size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 3, size - 3);
+                       return;
+               }
+       }
+
+       opcode_data->rsp_func(data + 3, size - 3);
+}
+
+static void cmd_status_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_cmd_status *evt = data;
+       uint16_t opcode = btohs(evt->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+       const struct opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       int i;
+
+       for (i = 0; opcode_table[i].str; i++) {
+               if (opcode_table[i].opcode == opcode) {
+                       opcode_data = &opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               opcode_color = COLOR_HCI_COMMAND;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+               opcode_str = "Unknown";
+       }
+
+       print_indent(6, opcode_color, "", opcode_str, COLOR_OFF,
+                       " (0x%2.2x|0x%4.4x) ncmd %d", ogf, ocf, evt->ncmd);
+
+       print_status(evt->status);
+}
+
+static void hardware_error_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_hardware_error *evt = data;
+
+       print_field("Code: 0x%2.2x", evt->code);
+}
+
+static void flush_occurred_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_flush_occurred *evt = data;
+
+       print_handle(evt->handle);
+}
+
+static void role_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_role_change *evt = data;
+
+       print_status(evt->status);
+       print_bdaddr(evt->bdaddr);
+       print_role(evt->role);
+}
+
+static void num_completed_packets_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_num_completed_packets *evt = data;
+
+       print_field("Num handles: %d", evt->num_handles);
+       print_handle(evt->handle);
+       print_field("Count: %d", btohs(evt->count));
+
+       if (size > sizeof(*evt))
+               packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
+}
+
+static void mode_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_mode_change *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_mode(evt->mode);
+       print_interval(evt->interval);
+}
+
+static void return_link_keys_evt(const void *data, uint8_t size)
+{
+       uint8_t num_keys = *((uint8_t *) data);
+
+       print_field("Num keys: %d", num_keys);
+
+       packet_hexdump(data + 1, size - 1);
+}
+
+static void pin_code_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_pin_code_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+}
+
+static void link_key_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_link_key_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+}
+
+static void link_key_notify_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_link_key_notify *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_link_key(evt->link_key);
+       print_key_type(evt->key_type);
+}
+
+static void loopback_command_evt(const void *data, uint8_t size)
+{
+       packet_hexdump(data, size);
+}
+
+static void data_buffer_overflow_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_data_buffer_overflow *evt = data;
+
+       print_link_type(evt->link_type);
+}
+
+static void max_slots_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_max_slots_change *evt = data;
+
+       print_handle(evt->handle);
+       print_field("Max slots: %d", evt->max_slots);
+}
+
+static void clock_offset_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_clock_offset_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_clock_offset(evt->clock_offset);
+}
+
+static void conn_pkt_type_changed_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_conn_pkt_type_changed *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_pkt_type(evt->pkt_type);
+}
+
+static void qos_violation_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_qos_violation *evt = data;
+
+       print_handle(evt->handle);
+}
+
+static void pscan_mode_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_pscan_mode_change *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_pscan_mode(evt->pscan_mode);
+}
+
+static void pscan_rep_mode_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_pscan_rep_mode_change *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_pscan_rep_mode(evt->pscan_rep_mode);
+}
+
+static void flow_spec_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_flow_spec_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_field("Flags: 0x%2.2x", evt->flags);
+
+       print_flow_direction(evt->direction);
+       print_service_type(evt->service_type);
+
+       print_field("Token rate: %d", btohl(evt->token_rate));
+       print_field("Token bucket size: %d", btohl(evt->token_bucket_size));
+       print_field("Peak bandwidth: %d", btohl(evt->peak_bandwidth));
+       print_field("Access latency: %d", btohl(evt->access_latency));
+}
+
+static void inquiry_result_with_rssi_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_inquiry_result_with_rssi *evt = data;
+
+       print_num_resp(evt->num_resp);
+       print_bdaddr(evt->bdaddr);
+       print_pscan_rep_mode(evt->pscan_rep_mode);
+       print_pscan_period_mode(evt->pscan_period_mode);
+       print_dev_class(evt->dev_class);
+       print_clock_offset(evt->clock_offset);
+       print_rssi(evt->rssi);
+
+       if (size > sizeof(*evt))
+               packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
+}
+
+static void remote_ext_features_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_remote_ext_features_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_field("Page: %d/%d", evt->page, evt->max_page);
+       print_features(evt->page, evt->features, 0x00);
+}
+
+static void sync_conn_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_sync_conn_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_bdaddr(evt->bdaddr);
+       print_link_type(evt->link_type);
+       print_field("Transmission interval: 0x%2.2x", evt->tx_interval);
+       print_field("Retransmission window: 0x%2.2x", evt->retrans_window);
+       print_field("RX packet length: %d", btohs(evt->rx_pkt_len));
+       print_field("TX packet length: %d", btohs(evt->tx_pkt_len));
+       print_air_mode(evt->air_mode);
+}
+
+static void sync_conn_changed_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_sync_conn_changed *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_field("Transmission interval: 0x%2.2x", evt->tx_interval);
+       print_field("Retransmission window: 0x%2.2x", evt->retrans_window);
+       print_field("RX packet length: %d", btohs(evt->rx_pkt_len));
+       print_field("TX packet length: %d", btohs(evt->tx_pkt_len));
+}
+
+static void sniff_subrating_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_sniff_subrating *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_slot_625("Max transmit latency", evt->max_tx_latency);
+       print_slot_625("Max receive latency", evt->max_rx_latency);
+       print_slot_625("Min remote timeout", evt->min_remote_timeout);
+       print_slot_625("Min local timeout", evt->min_local_timeout);
+}
+
+static void ext_inquiry_result_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_ext_inquiry_result *evt = data;
+
+       print_num_resp(evt->num_resp);
+       print_bdaddr(evt->bdaddr);
+       print_pscan_rep_mode(evt->pscan_rep_mode);
+       print_pscan_period_mode(evt->pscan_period_mode);
+       print_dev_class(evt->dev_class);
+       print_clock_offset(evt->clock_offset);
+       print_rssi(evt->rssi);
+       print_eir(evt->data, sizeof(evt->data), false);
+}
+
+static void encrypt_key_refresh_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_encrypt_key_refresh_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+}
+
+static void io_capability_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_io_capability_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+}
+
+static void io_capability_response_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_io_capability_response *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_io_capability(evt->capability);
+       print_oob_data(evt->oob_data);
+       print_authentication(evt->authentication);
+}
+
+static void user_confirm_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_user_confirm_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_passkey(evt->passkey);
+}
+
+static void user_passkey_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_user_passkey_request *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+}
+
+static void remote_oob_data_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_remote_oob_data_request *evt = data;
 
-void packet_set_filter(unsigned long filter)
+       print_bdaddr(evt->bdaddr);
+}
+
+static void simple_pairing_complete_evt(const void *data, uint8_t size)
 {
-       filter_mask = filter;
+       const struct bt_hci_evt_simple_pairing_complete *evt = data;
+
+       print_status(evt->status);
+       print_bdaddr(evt->bdaddr);
 }
 
-static void print_channel_header(struct timeval *tv, uint16_t index,
-                                                       uint16_t channel)
+static void link_supv_timeout_changed_evt(const void *data, uint8_t size)
 {
-       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;
-               }
-       }
+       const struct bt_hci_evt_link_supv_timeout_changed *evt = data;
 
-       if (tv) {
-               time_t t = tv->tv_sec;
-               struct tm tm;
+       print_handle(evt->handle);
+       print_timeout(evt->timeout);
+}
 
-               localtime_r(&t, &tm);
+static void enhanced_flush_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_enhanced_flush_complete *evt = data;
+
+       print_handle(evt->handle);
+}
+
+static void user_passkey_notify_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_user_passkey_notify *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_passkey(evt->passkey);
+}
+
+static void keypress_notify_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_keypress_notify *evt = data;
+       const char *str;
 
-               if (filter_mask & PACKET_FILTER_SHOW_DATE)
-                       printf("%04d-%02d-%02d ", tm.tm_year + 1900,
-                                               tm.tm_mon + 1, tm.tm_mday);
+       print_bdaddr(evt->bdaddr);
 
-               if (filter_mask & PACKET_FILTER_SHOW_TIME)
-                       printf("%02d:%02d:%02d.%06lu ", tm.tm_hour,
-                                       tm.tm_min, tm.tm_sec, tv->tv_usec);
+       switch (evt->type) {
+       case 0x00:
+               str = "Passkey entry started";
+               break;
+       case 0x01:
+               str = "Passkey digit entered";
+               break;
+       case 0x02:
+               str = "Passkey digit erased";
+               break;
+       case 0x03:
+               str = "Passkey clared";
+               break;
+       case 0x04:
+               str = "Passkey entry completed";
+               break;
+       default:
+               str = "Reserved";
+               break;
        }
+
+       print_field("Notification type: %s (0x%2.2x)", str, evt->type);
 }
 
-static void print_header(struct timeval *tv, uint16_t index)
+static void remote_host_features_notify_evt(const void *data, uint8_t size)
 {
-       print_channel_header(tv, index, HCI_CHANNEL_MONITOR);
+       const struct bt_hci_evt_remote_host_features_notify *evt = data;
+
+       print_bdaddr(evt->bdaddr);
+       print_features(1, evt->features, 0x00);
 }
 
-void packet_hexdump(const unsigned char *buf, uint16_t len)
+static void phy_link_complete_evt(const void *data, uint8_t size)
 {
-       static const char hexdigits[] = "0123456789abcdef";
-       char str[68];
-       uint16_t i;
+       const struct bt_hci_evt_phy_link_complete *evt = data;
 
-       if (!len)
-               return;
+       print_status(evt->status);
+       print_phy_handle(evt->phy_handle);
+}
 
-       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] : '.';
+static void channel_selected_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_channel_selected *evt = data;
 
-               if ((i + 1) % 16 == 0) {
-                       str[47] = ' ';
-                       str[48] = ' ';
-                       str[65] = '\0';
-                       printf("%-12c%s\n", ' ', str);
-                       str[0] = ' ';
-               }
-       }
+       print_phy_handle(evt->phy_handle);
+}
 
-       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 disconn_phy_link_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_disconn_phy_link_complete *evt = data;
+
+       print_status(evt->status);
+       print_phy_handle(evt->phy_handle);
+       print_reason(evt->reason);
+}
+
+static void phy_link_loss_early_warning_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_phy_link_loss_early_warning *evt = data;
+       const char *str;
+
+       print_phy_handle(evt->phy_handle);
+
+       switch (evt->reason) {
+       case 0x00:
+               str = "Unknown";
+               break;
+       case 0x01:
+               str = "Range related";
+               break;
+       case 0x02:
+               str = "Bandwidth related";
+               break;
+       case 0x03:
+               str = "Resolving conflict";
+               break;
+       case 0x04:
+               str = "Interference";
+               break;
+       default:
+               str = "Reserved";
+               break;
        }
+
+       print_field("Reason: %s (0x%2.2x)", str, evt->reason);
 }
 
-void packet_control(struct timeval *tv, uint16_t index, uint16_t opcode,
-                                       const void *data, uint16_t size)
+static void phy_link_recovery_evt(const void *data, uint8_t size)
 {
-       print_channel_header(tv, index, HCI_CHANNEL_CONTROL);
+       const struct bt_hci_evt_phy_link_recovery *evt = data;
 
-       control_message(opcode, data, size);
+       print_phy_handle(evt->phy_handle);
 }
 
-#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
+static void logic_link_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_logic_link_complete *evt = data;
 
-struct monitor_new_index {
-       uint8_t  type;
-       uint8_t  bus;
-       bdaddr_t bdaddr;
-       char     name[8];
-} __attribute__((packed));
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_phy_handle(evt->phy_handle);
+       print_field("TX flow spec: 0x%2.2x", evt->flow_spec);
+}
 
-#define MONITOR_NEW_INDEX_SIZE 16
+static void disconn_logic_link_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_disconn_logic_link_complete *evt = data;
 
-#define MONITOR_DEL_INDEX_SIZE 0
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_reason(evt->reason);
+}
 
-#define MAX_INDEX 16
+static void flow_spec_modify_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_flow_spec_modify_complete *evt = data;
 
-static struct monitor_new_index index_list[MAX_INDEX];
+       print_status(evt->status);
+       print_handle(evt->handle);
+}
 
-void packet_monitor(struct timeval *tv, uint16_t index, uint16_t opcode,
-                                       const void *data, uint16_t size)
+static void num_completed_data_blocks_evt(const void *data, uint8_t size)
 {
-       const struct monitor_new_index *ni;
-       char str[18];
+       const struct bt_hci_evt_num_completed_data_blocks *evt = data;
 
-       switch (opcode) {
-       case MONITOR_NEW_INDEX:
-               ni = data;
+       print_field("Total num data blocks: %d", btohs(evt->total_num_blocks));
+       print_field("Num handles: %d", evt->num_handles);
+       print_handle(evt->handle);
+       print_field("Num packets: %d", evt->num_packets);
+       print_field("Num blocks: %d", evt->num_blocks);
 
-               if (index < MAX_INDEX)
-                       memcpy(&index_list[index], ni, MONITOR_NEW_INDEX_SIZE);
+       if (size > sizeof(*evt))
+               packet_hexdump(data + sizeof(*evt), size - sizeof(*evt));
+}
 
-               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);
+static void short_range_mode_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_short_range_mode_change *evt = data;
 
-               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);
+       print_status(evt->status);
+       print_phy_handle(evt->phy_handle);
+       print_short_range_mode(evt->mode);
+}
+
+static void amp_status_change_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_amp_status_change *evt = data;
+
+       print_status(evt->status);
+       print_amp_status(evt->amp_status);
+}
+
+static void le_conn_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_le_conn_complete *evt = data;
+
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_role(evt->role);
+       print_addr_type("Peer address type", evt->peer_addr_type);
+       print_addr("Peer address", evt->peer_addr, evt->peer_addr_type);
+       print_slot_125("Connection interval", evt->interval);
+       print_slot_125("Connection latency", evt->latency);
+       print_field("Supervision timeout: %d msec (0x%4.4x)",
+               btohs(evt->supv_timeout) * 10, btohs(evt->supv_timeout));
+       print_field("Master clock accuracy: 0x%2.2x", evt->clock_accuracy);
+
+       if (evt->status == 0x00)
+               assign_handle(btohs(evt->handle), 0x01);
+}
+
+static void le_adv_report_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_le_adv_report *evt = data;
+       const char *str;
+       uint8_t evt_len;
+       int8_t *rssi;
+
+       print_num_reports(evt->num_reports);
+
+       switch (evt->event_type) {
+       case 0x00:
+               str = "Connectable undirected - ADV_IND";
                break;
-       case MONITOR_ACL_TX_PKT:
-               packet_hci_acldata(tv, index, false, data, size);
+       case 0x01:
+               str = "Connectable directed - ADV_DIRECT_IND";
                break;
-       case MONITOR_ACL_RX_PKT:
-               packet_hci_acldata(tv, index, true, data, size);
+       case 0x02:
+               str = "Scannable undirected - ADV_SCAN_IND";
                break;
-       case MONITOR_SCO_TX_PKT:
-               packet_hci_scodata(tv, index, false, data, size);
+       case 0x03:
+               str = "Non connectable undirected - ADV_NONCONN_IND";
                break;
-       case MONITOR_SCO_RX_PKT:
-               packet_hci_scodata(tv, index, true, data, size);
+       case 0x04:
+               str = "Scan response - SCAN_RSP";
                break;
        default:
-               print_header(tv, index);
-               printf("* Unknown packet (code %d len %d)\n", opcode, size);
-               packet_hexdump(data, size);
+               str = "Reserved";
                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"            },
+       print_field("Event type: %s (0x%2.2x)", str, evt->event_type);
+       print_addr_type("Address type", evt->addr_type);
+       print_addr("Address", evt->addr, evt->addr_type);
+       print_field("Data length: %d", evt->data_len);
+       print_eir(evt->data, evt->data_len, true);
 
-       /* 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"                     },
+       rssi = (int8_t *) (evt->data + evt->data_len);
+       print_rssi(*rssi);
 
-       /* 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"             },
+       evt_len = sizeof(*evt) + evt->data_len + 1;
 
-       /* 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"                },
+       if (size > evt_len)
+               packet_hexdump(data + evt_len, size - evt_len);
+}
 
-       /* 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"              },
+static void le_conn_update_complete_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_le_conn_update_complete *evt = data;
 
-       /* 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"                         },
-       { }
-};
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_slot_125("Connection interval", evt->interval);
+       print_slot_125("Connection latency", evt->latency);
+       print_field("Supervision timeout: %d msec (0x%4.4x)",
+               btohs(evt->supv_timeout) * 10, btohs(evt->supv_timeout));
+}
 
-static const char *opcode2str(uint16_t opcode)
+static void le_remote_features_complete_evt(const void *data, uint8_t size)
 {
-       int i;
+       const struct bt_hci_evt_le_remote_features_complete *evt = data;
 
-       for (i = 0; opcode2str_table[i].str; i++) {
-               if (opcode2str_table[i].opcode == opcode)
-                       return opcode2str_table[i].str;
-       }
+       print_status(evt->status);
+       print_handle(evt->handle);
+       print_features(0, evt->features, 0x01);
+}
+
+static void le_long_term_key_request_evt(const void *data, uint8_t size)
+{
+       const struct bt_hci_evt_le_long_term_key_request *evt = data;
 
-       return "Unknown";
+       print_handle(evt->handle);
+       print_random_number(evt->number);
+       print_field("Encryption diversifier: 0x%4.4x",
+                                       btohs(evt->diversifier));
 }
 
-static const struct {
-       uint8_t event;
+struct subevent_data {
+       uint8_t subevent;
        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"                                },
+       void (*func) (const void *data, uint8_t size);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct subevent_data subevent_table[] = {
+       { 0x01, "LE Connection Complete",
+                               le_conn_complete_evt, 18, true },
+       { 0x02, "LE Advertising Report",
+                               le_adv_report_evt, 1, false },
+       { 0x03, "LE Connection Update Complete",
+                               le_conn_update_complete_evt, 9, true },
+       { 0x04, "LE Read Remote Used Features",
+                               le_remote_features_complete_evt, 11, true },
+       { 0x05, "LE Long Term Key Request",
+                               le_long_term_key_request_evt, 12, true },
        { }
 };
 
-static const char *event2str(uint8_t event)
+static void le_meta_event_evt(const void *data, uint8_t size)
 {
+       uint8_t subevent = *((const uint8_t *) data);
+       const struct subevent_data *subevent_data = NULL;
+       const char *subevent_color, *subevent_str;
        int i;
 
-       for (i = 0; event2str_table[i].str; i++) {
-               if (event2str_table[i].event == event)
-                       return event2str_table[i].str;
+       for (i = 0; subevent_table[i].str; i++) {
+               if (subevent_table[i].subevent == subevent) {
+                       subevent_data = &subevent_table[i];
+                       break;
+               }
+       }
+
+       if (subevent_data) {
+               if (subevent_data->func)
+                       subevent_color = COLOR_HCI_EVENT;
+               else
+                       subevent_color = COLOR_HCI_EVENT_UNKNOWN;
+               subevent_str = subevent_data->str;
+       } else {
+               subevent_color = COLOR_HCI_EVENT_UNKNOWN;
+               subevent_str = "Unknown";
+       }
+
+       print_indent(6, subevent_color, "", subevent_str, COLOR_OFF,
+                                               " (0x%2.2x)", subevent);
+
+       if (!subevent_data || !subevent_data->func) {
+               packet_hexdump(data + 1, size - 1);
+               return;
+       }
+
+       if (subevent_data->fixed) {
+               if (size - 1 != subevent_data->size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
+       } else {
+               if (size - 1 < subevent_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data + 1, size - 1);
+                       return;
+               }
        }
 
-       return "Unknown";
+       subevent_data->func(data + 1, size - 1);
+}
+
+static void vendor_evt(const void *data, uint8_t size)
+{
+       vendor_event(0xffff, data, size);
 }
 
+struct event_data {
+       uint8_t event;
+       const char *str;
+       void (*func) (const void *data, uint8_t size);
+       uint8_t size;
+       bool fixed;
+};
+
+static const struct event_data event_table[] = {
+       { 0x01, "Inquiry Complete",
+                               status_evt, 1, true },
+       { 0x02, "Inquiry Result",
+                               inquiry_result_evt, 1, false },
+       { 0x03, "Connect Complete",
+                               conn_complete_evt, 11, true },
+       { 0x04, "Connect Request",
+                               conn_request_evt, 10, true },
+       { 0x05, "Disconnect Complete",
+                               disconnect_complete_evt, 4, true },
+       { 0x06, "Auth Complete",
+                               auth_complete_evt, 3, true },
+       { 0x07, "Remote Name Req Complete",
+                               remote_name_request_complete_evt, 255, true },
+       { 0x08, "Encryption Change",
+                               encrypt_change_evt, 4, true },
+       { 0x09, "Change Connection Link Key Complete",
+                               change_conn_link_key_complete_evt, 3, true },
+       { 0x0a, "Master Link Key Complete",
+                               master_link_key_complete_evt, 4, true },
+       { 0x0b, "Read Remote Supported Features",
+                               remote_features_complete_evt, 11, true },
+       { 0x0c, "Read Remote Version Complete",
+                               remote_version_complete_evt, 8, true },
+       { 0x0d, "QoS Setup Complete",
+                               qos_setup_complete_evt, 21, true },
+       { 0x0e, "Command Complete",
+                               cmd_complete_evt, 3, false },
+       { 0x0f, "Command Status",
+                               cmd_status_evt, 4, true },
+       { 0x10, "Hardware Error",
+                               hardware_error_evt, 1, true },
+       { 0x11, "Flush Occurred",
+                               flush_occurred_evt, 2, true },
+       { 0x12, "Role Change",
+                               role_change_evt, 8, true },
+       { 0x13, "Number of Completed Packets",
+                               num_completed_packets_evt, 1, false },
+       { 0x14, "Mode Change",
+                               mode_change_evt, 6, true },
+       { 0x15, "Return Link Keys",
+                               return_link_keys_evt, 1, false },
+       { 0x16, "PIN Code Request",
+                               pin_code_request_evt, 6, true },
+       { 0x17, "Link Key Request",
+                               link_key_request_evt, 6, true },
+       { 0x18, "Link Key Notification",
+                               link_key_notify_evt, 23, true },
+       { 0x19, "Loopback Command",
+                               loopback_command_evt, 3, false },
+       { 0x1a, "Data Buffer Overflow",
+                               data_buffer_overflow_evt, 1, true },
+       { 0x1b, "Max Slots Change",
+                               max_slots_change_evt, 3, true },
+       { 0x1c, "Read Clock Offset Complete",
+                               clock_offset_complete_evt, 5, true },
+       { 0x1d, "Connection Packet Type Changed",
+                               conn_pkt_type_changed_evt, 5, true },
+       { 0x1e, "QoS Violation",
+                               qos_violation_evt, 2, true },
+       { 0x1f, "Page Scan Mode Change",
+                               pscan_mode_change_evt, 7, true },
+       { 0x20, "Page Scan Repetition Mode Change",
+                               pscan_rep_mode_change_evt, 7, true },
+       { 0x21, "Flow Specification Complete",
+                               flow_spec_complete_evt, 22, true },
+       { 0x22, "Inquiry Result with RSSI",
+                               inquiry_result_with_rssi_evt, 1, false },
+       { 0x23, "Read Remote Extended Features",
+                               remote_ext_features_complete_evt, 13, true },
+       { 0x2c, "Synchronous Connect Complete",
+                               sync_conn_complete_evt, 17, true },
+       { 0x2d, "Synchronous Connect Changed",
+                               sync_conn_changed_evt, 9, true },
+       { 0x2e, "Sniff Subrating",
+                               sniff_subrating_evt, 11, true },
+       { 0x2f, "Extended Inquiry Result",
+                               ext_inquiry_result_evt, 1, false },
+       { 0x30, "Encryption Key Refresh Complete",
+                               encrypt_key_refresh_complete_evt, 3, true },
+       { 0x31, "IO Capability Request",
+                               io_capability_request_evt, 6, true },
+       { 0x32, "IO Capability Response",
+                               io_capability_response_evt, 9, true },
+       { 0x33, "User Confirmation Request",
+                               user_confirm_request_evt, 10, true },
+       { 0x34, "User Passkey Request",
+                               user_passkey_request_evt, 6, true },
+       { 0x35, "Remote OOB Data Request",
+                               remote_oob_data_request_evt, 6, true },
+       { 0x36, "Simple Pairing Complete",
+                               simple_pairing_complete_evt, 7, true },
+       { 0x38, "Link Supervision Timeout Changed",
+                               link_supv_timeout_changed_evt, 4, true },
+       { 0x39, "Enhanced Flush Complete",
+                               enhanced_flush_complete_evt, 2, true },
+       { 0x3b, "User Passkey Notification",
+                               user_passkey_notify_evt, 10, true },
+       { 0x3c, "Keypress Notification",
+                               keypress_notify_evt, 7, true },
+       { 0x3d, "Remote Host Supported Features",
+                               remote_host_features_notify_evt, 14, true },
+       { 0x3e, "LE Meta Event",
+                               le_meta_event_evt, 1, false },
+       { 0x40, "Physical Link Complete",
+                               phy_link_complete_evt, 2, true },
+       { 0x41, "Channel Selected",
+                               channel_selected_evt, 1, true },
+       { 0x42, "Disconnect Physical Link Complete",
+                               disconn_phy_link_complete_evt, 3, true },
+       { 0x43, "Physical Link Loss Early Warning",
+                               phy_link_loss_early_warning_evt, 2, true },
+       { 0x44, "Physical Link Recovery",
+                               phy_link_recovery_evt, 1, true },
+       { 0x45, "Logical Link Complete",
+                               logic_link_complete_evt, 5, true },
+       { 0x46, "Disconnect Logical Link Complete",
+                               disconn_logic_link_complete_evt, 4, true },
+       { 0x47, "Flow Specification Modify Complete",
+                               flow_spec_modify_complete_evt, 3, true },
+       { 0x48, "Number of Completed Data Blocks",
+                               num_completed_data_blocks_evt, 3, false },
+       { 0x49, "AMP Start Test" },
+       { 0x4a, "AMP Test End" },
+       { 0x4b, "AMP Receiver Report" },
+       { 0x4c, "Short Range Mode Change Complete",
+                               short_range_mode_change_evt, 3, true },
+       { 0x4d, "AMP Status Change",
+                               amp_status_change_evt, 2, true },
+       { 0xfe, "Testing" },
+       { 0xff, "Vendor", vendor_evt, 0, false },
+       { }
+};
+
 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);
+       char details[48];
 
-       printf("= New Index: %s (%s,%s,%s)\n", label,
-                               hci_typetostr(type), hci_bustostr(bus), name);
+       sprintf(details, "(%s,%s,%s)", hci_typetostr(type),
+                                       hci_bustostr(bus), name);
+
+       print_packet(tv, index, '=', COLOR_NEW_INDEX, "New Index",
+                                                       label, details);
 }
 
 void packet_del_index(struct timeval *tv, uint16_t index, const char *label)
 {
-       print_header(tv, index);
-
-       printf("= Delete Index: %s\n", label);
+       print_packet(tv, index, '=', COLOR_DEL_INDEX, "Delete Index",
+                                                       label, NULL);
 }
 
 void packet_hci_command(struct timeval *tv, uint16_t index,
@@ -570,73 +6264,173 @@ void packet_hci_command(struct timeval *tv, uint16_t index,
        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);
+       const struct opcode_data *opcode_data = NULL;
+       const char *opcode_color, *opcode_str;
+       char extra_str[25];
+       int i;
 
        if (size < HCI_COMMAND_HDR_SIZE) {
-               printf("* Malformed HCI Command packet\n");
+               sprintf(extra_str, "(len %d)", size);
+               print_packet(tv, index, '*', COLOR_ERROR,
+                       "Malformed HCI Command packet", NULL, extra_str);
+               packet_hexdump(data, size);
                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);
+       for (i = 0; opcode_table[i].str; i++) {
+               if (opcode_table[i].opcode == opcode) {
+                       opcode_data = &opcode_table[i];
+                       break;
+               }
+       }
+
+       if (opcode_data) {
+               if (opcode_data->cmd_func)
+                       opcode_color = COLOR_HCI_COMMAND;
+               else
+                       opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+               opcode_str = opcode_data->str;
+       } else {
+               opcode_color = COLOR_HCI_COMMAND_UNKNOWN;
+               opcode_str = "Unknown";
+       }
+
+       sprintf(extra_str, "(0x%2.2x|0x%4.4x) plen %d", ogf, ocf, hdr->plen);
+
+       print_packet(tv, index, '<', opcode_color, "HCI Command",
+                                                       opcode_str, extra_str);
+
+       if (!opcode_data || !opcode_data->cmd_func) {
+               packet_hexdump(data, size);
+               return;
+       }
+
+       if (opcode_data->cmd_fixed) {
+               if (hdr->plen != opcode_data->cmd_size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data, size);
+                       return;
+               }
+       } else {
+               if (hdr->plen < opcode_data->cmd_size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data, size);
+                       return;
+               }
+       }
+
+       opcode_data->cmd_func(data, hdr->plen);
 }
 
 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);
+       const struct event_data *event_data = NULL;
+       const char *event_color, *event_str;
+       char extra_str[25];
+       int i;
 
        if (size < HCI_EVENT_HDR_SIZE) {
-               printf("* Malformed HCI Event packet\n");
+               sprintf(extra_str, "(len %d)", size);
+               print_packet(tv, index, '*', COLOR_ERROR,
+                       "Malformed HCI Event packet", NULL, extra_str);
+               packet_hexdump(data, size);
                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);
+       for (i = 0; event_table[i].str; i++) {
+               if (event_table[i].event == hdr->evt) {
+                       event_data = &event_table[i];
+                       break;
+               }
+       }
+
+       if (event_data) {
+               if (event_data->func)
+                       event_color = COLOR_HCI_EVENT;
+               else
+                       event_color = COLOR_HCI_EVENT_UNKNOWN;
+               event_str = event_data->str;
+       } else {
+               event_color = COLOR_HCI_EVENT_UNKNOWN;
+               event_str = "Unknown";
+       }
+
+       sprintf(extra_str, "(0x%2.2x) plen %d", hdr->evt, hdr->plen);
+
+       print_packet(tv, index, '>', event_color, "HCI Event",
+                                                        event_str, extra_str);
+
+       if (!event_data || !event_data->func) {
+               packet_hexdump(data, size);
+               return;
+       }
+
+       if (event_data->fixed) {
+               if (hdr->plen != event_data->size) {
+                       print_text(COLOR_ERROR, "invalid packet size");
+                       packet_hexdump(data, size);
+                       return;
+               }
+       } else {
+               if (hdr->plen < event_data->size) {
+                       print_text(COLOR_ERROR, "too short packet");
+                       packet_hexdump(data, size);
+                       return;
+               }
+       }
+
+       event_data->func(data, hdr->plen);
 }
 
 void packet_hci_acldata(struct timeval *tv, uint16_t index, bool in,
                                        const void *data, uint16_t size)
 {
-       const hci_acl_hdr *hdr = data;
+       const struct bt_hci_acl_hdr *hdr = data;
        uint16_t handle = btohs(hdr->handle);
        uint16_t dlen = btohs(hdr->dlen);
        uint8_t flags = acl_flags(handle);
+       char handle_str[16], extra_str[32];
 
-       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");
+       if (size < sizeof(*hdr)) {
+               if (in)
+                       print_packet(tv, index, '*', COLOR_ERROR,
+                               "Malformed ACL Data RX packet", NULL, NULL);
+               else
+                       print_packet(tv, index, '*', COLOR_ERROR,
+                               "Malformed ACL Data TX packet", NULL, NULL);
+               packet_hexdump(data, size);
                return;
        }
 
-       printf("%c ACL Data: handle %d flags 0x%2.2x dlen %d\n",
-                       in ? '>' : '<', acl_handle(handle), flags, dlen);
+       data += sizeof(*hdr);
+       size -= sizeof(*hdr);
 
-       data += HCI_ACL_HDR_SIZE;
-       size -= HCI_ACL_HDR_SIZE;
+       sprintf(handle_str, "Handle %d", acl_handle(handle));
+       sprintf(extra_str, "flags 0x%2.2x dlen %d", flags, dlen);
+
+       print_packet(tv, index, in ? '>' : '<', COLOR_HCI_ACLDATA,
+                               in ? "ACL Data RX" : "ACL Data TX",
+                                               handle_str, extra_str);
+
+       if (size != dlen) {
+               print_text(COLOR_ERROR, "invalid packet size (%d != %d)",
+                                                               size, dlen);
+               packet_hexdump(data, size);
+               return;
+       }
 
        if (filter_mask & PACKET_FILTER_SHOW_ACL_DATA)
                packet_hexdump(data, size);
+
+       l2cap_packet(index, in, acl_handle(handle), flags, data, size);
 }
 
 void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
@@ -645,20 +6439,36 @@ void packet_hci_scodata(struct timeval *tv, uint16_t index, bool in,
        const hci_sco_hdr *hdr = data;
        uint16_t handle = btohs(hdr->handle);
        uint8_t flags = acl_flags(handle);
-
-       print_header(tv, index);
+       char handle_str[16], extra_str[32];
 
        if (size < HCI_SCO_HDR_SIZE) {
-               printf("* Malformed SCO Data %s packet\n", in ? "RX" : "TX");
+               if (in)
+                       print_packet(tv, index, '*', COLOR_ERROR,
+                               "Malformed SCO Data RX packet", NULL, NULL);
+               else
+                       print_packet(tv, index, '*', COLOR_ERROR,
+                               "Malformed SCO Data TX packet", NULL, NULL);
+               packet_hexdump(data, size);
                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;
 
+       sprintf(handle_str, "Handle %d", acl_handle(handle));
+       sprintf(extra_str, "flags 0x%2.2x dlen %d", flags, hdr->dlen);
+
+       print_packet(tv, index, in ? '>' : '<', COLOR_HCI_SCODATA,
+                               in ? "SCO Data RX" : "SCO Data TX",
+                                               handle_str, extra_str);
+
+       if (size != hdr->dlen) {
+               print_text(COLOR_ERROR, "invalid packet size (%d != %d)",
+                                                       size, hdr->dlen);
+               packet_hexdump(data, size);
+               return;
+       }
+
        if (filter_mask & PACKET_FILTER_SHOW_SCO_DATA)
                packet_hexdump(data, size);
 }
index 90fc7ec..07c1ec3 100644 (file)
  *
  */
 
+#include <stdint.h>
 #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)
+#define PACKET_FILTER_SHOW_TIME_OFFSET (1 << 3)
+#define PACKET_FILTER_SHOW_ACL_DATA    (1 << 4)
+#define PACKET_FILTER_SHOW_SCO_DATA    (1 << 5)
 
 void packet_set_filter(unsigned long filter);
+void packet_add_filter(unsigned long filter);
+void packet_del_filter(unsigned long filter);
+
+void packet_select_index(uint16_t index);
 
 void packet_hexdump(const unsigned char *buf, uint16_t len);
+void packet_print_version(const char *label, uint8_t version,
+                               const char *sublabel, uint16_t subversion);
+void packet_print_company(const char *label, uint16_t company);
+void packet_print_addr(const char *label, const void *data, bool random);
+void packet_print_ad(const void *data, uint8_t size);
+void packet_print_features_ll(const uint8_t *features);
+void packet_print_channel_map_ll(const uint8_t *map);
 
 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_simulator(struct timeval *tv, uint16_t frequency,
+                                       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);
diff --git a/monitor/sdp.c b/monitor/sdp.c
new file mode 100644 (file)
index 0000000..4eb398b
--- /dev/null
@@ -0,0 +1,748 @@
+/*
+ *
+ *  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 <string.h>
+#include <inttypes.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "bt.h"
+#include "packet.h"
+#include "display.h"
+#include "l2cap.h"
+#include "uuid.h"
+#include "sdp.h"
+
+#define MAX_TID 16
+
+struct tid_data {
+       bool inuse;
+       uint16_t tid;
+       uint16_t channel;
+       uint8_t cont[17];
+};
+
+static struct tid_data tid_list[MAX_TID];
+
+static struct tid_data *get_tid(uint16_t tid, uint16_t channel)
+{
+       int i, n = -1;
+
+       for (i = 0; i < MAX_TID; i++) {
+               if (!tid_list[i].inuse) {
+                       if (n < 0)
+                               n = i;
+                       continue;
+               }
+
+               if (tid_list[i].tid == tid && tid_list[i].channel == channel)
+                       return &tid_list[i];
+       }
+
+       if (n < 0)
+               return NULL;
+
+       tid_list[n].inuse = true;
+       tid_list[n].tid = tid;
+       tid_list[n].channel = channel;
+
+       return &tid_list[n];
+}
+
+static void clear_tid(struct tid_data *tid)
+{
+       if (tid)
+               tid->inuse = false;
+}
+
+static void print_uint(uint8_t indent, const uint8_t *data, uint32_t size)
+{
+       switch (size) {
+       case 1:
+               print_field("%*c0x%2.2x", indent, ' ', data[0]);
+               break;
+       case 2:
+               print_field("%*c0x%4.4x", indent, ' ', bt_get_be16(data));
+               break;
+       case 4:
+               print_field("%*c0x%8.8x", indent, ' ', bt_get_be32(data));
+               break;
+       case 8:
+               print_field("%*c0x%16.16" PRIx64, indent, ' ',
+                                                       bt_get_be64(data));
+               break;
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void print_sint(uint8_t indent, const uint8_t *data, uint32_t size)
+{
+       packet_hexdump(data, size);
+}
+
+static void print_uuid(uint8_t indent, const uint8_t *data, uint32_t size)
+{
+       switch (size) {
+       case 2:
+               print_field("%*c%s (0x%4.4x)", indent, ' ',
+                       uuid16_to_str(bt_get_be16(data)), bt_get_be16(data));
+               break;
+       case 4:
+               print_field("%*c%s (0x%8.8x)", indent, ' ',
+                       uuid32_to_str(bt_get_be32(data)), bt_get_be32(data));
+               break;
+       case 16:
+               /* BASE_UUID = 00000000-0000-1000-8000-00805F9B34FB */
+               print_field("%*c%8.8x-%4.4x-%4.4x-%4.4x-%4.4x%8.4x",
+                               indent, ' ',
+                               bt_get_be32(data), bt_get_be16(data + 4),
+                               bt_get_be16(data + 6), bt_get_be16(data + 8),
+                               bt_get_be16(data + 10), bt_get_be32(data + 12));
+               if (bt_get_be16(data + 4) == 0x0000 &&
+                               bt_get_be16(data + 6) == 0x1000 &&
+                               bt_get_be16(data + 8) == 0x8000 &&
+                               bt_get_be16(data + 10) == 0x0080 &&
+                               bt_get_be32(data + 12) == 0x5F9B34FB)
+                       print_field("%*c%s", indent, ' ',
+                               uuid32_to_str(bt_get_be32(data)));
+               break;
+       default:
+               packet_hexdump(data, size);
+               break;
+       }
+}
+
+static void print_string(uint8_t indent, const uint8_t *data, uint32_t size)
+{
+       char *str = alloca(size + 1);
+
+       str[size] = '\0';
+       strncpy(str, (const char *) data, size);
+
+       print_field("%*c%s [len %d]", indent, ' ', str, size);
+}
+
+static void print_boolean(uint8_t indent, const uint8_t *data, uint32_t size)
+{
+       print_field("%*c%s", indent, ' ', data[0] ? "true" : "false");
+}
+
+#define SIZES(args...) ((uint8_t[]) { args, 0xff } )
+
+static struct {
+       uint8_t value;
+       uint8_t *sizes;
+       bool recurse;
+       const char *str;
+       void (*print) (uint8_t indent, const uint8_t *data, uint32_t size);
+} type_table[] = {
+       { 0, SIZES(0),             false, "Nil"                 },
+       { 1, SIZES(0, 1, 2, 3, 4), false, "Unsigned Integer",   print_uint },
+       { 2, SIZES(0, 1, 2, 3, 4), false, "Signed Integer",     print_sint },
+       { 3, SIZES(1, 2, 4),       false, "UUID",               print_uuid },
+       { 4, SIZES(5, 6, 7),       false, "String",             print_string },
+       { 5, SIZES(0),             false, "Boolean",            print_boolean },
+       { 6, SIZES(5, 6, 7),       true,  "Sequence"            },
+       { 7, SIZES(5, 6, 7),       true,  "Alternative"         },
+       { 8, SIZES(5, 6, 7),       false, "URL",                print_string },
+       { }
+};
+
+static struct {
+       uint8_t index;
+       uint8_t bits;
+       uint8_t size;
+       const char *str;
+} size_table[] = {
+       { 0,  0,  1, "1 byte"   },
+       { 1,  0,  2, "2 bytes"  },
+       { 2,  0,  4, "4 bytes"  },
+       { 3,  0,  8, "8 bytes"  },
+       { 4,  0, 16, "16 bytes" },
+       { 5,  8,  0, "8 bits"   },
+       { 6, 16,  0, "16 bits"  },
+       { 7, 32,  0, "32 bits"  },
+       { }
+};
+
+static bool valid_size(uint8_t size, uint8_t *sizes)
+{
+       int i;
+
+       for (i = 0; sizes[i] != 0xff; i++) {
+               if (sizes[i] == size)
+                       return true;
+       }
+
+       return false;
+}
+
+static uint8_t get_bits(const uint8_t *data, uint32_t size)
+{
+       int i;
+
+       for (i = 0; size_table[i].str; i++) {
+               if (size_table[i].index == (data[0] & 0x07))
+                       return size_table[i].bits;
+       }
+
+       return 0;
+}
+
+static uint32_t get_size(const uint8_t *data, uint32_t size)
+{
+       int i;
+
+       for (i = 0; size_table[i].str; i++) {
+               if (size_table[i].index == (data[0] & 0x07)) {
+                       switch (size_table[i].bits) {
+                       case 0:
+                               if ((data[0] & 0xf8) == 0)
+                                       return 0;
+                               else
+                                       return size_table[i].size;
+                       case 8:
+                               return data[1];
+                       case 16:
+                               return bt_get_be16(data + 1);
+                       case 32:
+                               return bt_get_be32(data + 1);
+                       default:
+                               return 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+
+static void decode_data_elements(uint32_t position, uint8_t indent,
+                               const uint8_t *data, uint32_t size,
+                               void (*print_func) (uint32_t, uint8_t, uint8_t,
+                                               const uint8_t *, uint32_t))
+
+{
+       uint32_t datalen, elemlen, extrabits;
+       int i;
+
+       if (!size)
+               return;
+
+       extrabits = get_bits(data, size);
+
+       if (size < 1 + (extrabits / 8)) {
+               print_text(COLOR_ERROR, "data element descriptor too short");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       datalen = get_size(data, size);
+
+       if (size < 1 + (extrabits / 8) + datalen) {
+               print_text(COLOR_ERROR, "data element size too short");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       elemlen = 1 + (extrabits / 8) + datalen;
+
+       for (i = 0; type_table[i].str; i++) {
+               uint8_t type = (data[0] & 0xf8) >> 3;
+
+               if (type_table[i].value != type)
+                       continue;
+
+               if (print_func) {
+                       print_func(position, indent, type,
+                                       data + 1 + (extrabits / 8), datalen);
+                       break;
+               }
+
+               print_field("%*c%s (%d) with %u byte%s [%u extra bits] len %u",
+                                       indent, ' ', type_table[i].str, type,
+                                       datalen, datalen == 1 ? "" : "s",
+                                       extrabits, elemlen);
+               if (!valid_size(data[0] & 0x07, type_table[i].sizes)) {
+                       print_text(COLOR_ERROR, "invalid data element size");
+                       packet_hexdump(data + 1 + (extrabits / 8), datalen);
+                       break;
+               }
+
+               if (type_table[i].recurse)
+                       decode_data_elements(0, indent + 2,
+                                       data + 1 + (extrabits / 8), datalen,
+                                                               print_func);
+               else if (type_table[i].print)
+                       type_table[i].print(indent + 2,
+                                       data + 1 + (extrabits / 8), datalen);
+               break;
+       }
+
+       data += elemlen;
+       size -= elemlen;
+
+       decode_data_elements(position + 1, indent, data, size, print_func);
+}
+
+static uint32_t get_bytes(const uint8_t *data, uint32_t size)
+{
+       switch (data[0] & 0x07) {
+       case 5:
+               return 2 + data[1];
+       case 6:
+               return 3 + bt_get_be16(data + 1);
+       case 7:
+               return 5 + bt_get_be32(data + 1);
+       }
+
+       return 0;
+}
+
+static struct {
+       uint16_t id;
+       const char *str;
+} attribute_table[] = {
+       { 0x0000, "Service Record Handle"               },
+       { 0x0001, "Service Class ID List"               },
+       { 0x0002, "Service Record State"                },
+       { 0x0003, "Service ID"                          },
+       { 0x0004, "Protocol Descriptor List"            },
+       { 0x0005, "Browse Group List"                   },
+       { 0x0006, "Language Base Attribute ID List"     },
+       { 0x0007, "Service Info Time To Live"           },
+       { 0x0008, "Service Availability"                },
+       { 0x0009, "Bluetooth Profile Descriptor List"   },
+       { 0x000a, "Documentation URL"                   },
+       { 0x000b, "Client Executable URL"               },
+       { 0x000c, "Icon URL"                            },
+       { 0x000d, "Additional Protocol Descriptor List" },
+       { }
+};
+
+static void print_attr(uint32_t position, uint8_t indent, uint8_t type,
+                                       const uint8_t *data, uint32_t size)
+{
+       int i;
+
+       if ((position % 2) == 0) {
+               uint16_t id = bt_get_be16(data);
+               const char *str = "Unknown";
+
+               for (i = 0; attribute_table[i].str; i++) {
+                       if (attribute_table[i].id == id)
+                               str = attribute_table[i].str;
+               }
+
+               print_field("%*cAttribute: %s (0x%4.4x) [len %d]",
+                                               indent, ' ', str, id, size);
+               return;
+       }
+
+       for (i = 0; type_table[i].str; i++) {
+               if (type_table[i].value != type)
+                       continue;
+
+               if (type_table[i].recurse)
+                       decode_data_elements(0, indent + 2, data, size, NULL);
+               else if (type_table[i].print)
+                       type_table[i].print(indent + 2, data, size);
+               break;
+       }
+}
+
+static void print_attr_list(uint32_t position, uint8_t indent, uint8_t type,
+                                       const uint8_t *data, uint32_t size)
+{
+       print_field("%*cAttribute list: [len %d] {position %d}",
+                                               indent, ' ', size, position);
+
+       decode_data_elements(0, indent + 2, data, size, print_attr);
+}
+
+static void print_attr_lists(uint32_t position, uint8_t indent, uint8_t type,
+                                       const uint8_t *data, uint32_t size)
+{
+       decode_data_elements(0, indent, data, size, print_attr_list);
+}
+
+static void print_continuation(const uint8_t *data, uint16_t size)
+{
+       if (data[0] != size - 1) {
+               print_text(COLOR_ERROR, "invalid continuation state");
+               packet_hexdump(data, size);
+               return;
+       }
+
+       print_field("Continuation state: %d", data[0]);
+       packet_hexdump(data + 1, size - 1);
+}
+
+static void store_continuation(struct tid_data *tid,
+                                       const uint8_t *data, uint16_t size)
+{
+       memcpy(tid->cont, data, size);
+       print_continuation(data, size);
+}
+
+#define MAX_CONT 8
+
+struct cont_data {
+       uint16_t channel;
+       uint8_t cont[17];
+       void *data;
+       uint32_t size;
+};
+
+static struct cont_data cont_list[MAX_CONT];
+
+static void handle_continuation(struct tid_data *tid, bool nested,
+                       uint16_t bytes, const uint8_t *data, uint16_t size)
+{
+       uint8_t *newdata;
+       int i, n = -1;
+
+       if (bytes + 1 > size) {
+               print_text(COLOR_ERROR, "missing continuation state");
+               return;
+       }
+
+       if (tid->cont[0] == 0x00 && data[bytes] == 0x00) {
+               decode_data_elements(0, 2, data, bytes,
+                               nested ? print_attr_lists : print_attr_list);
+
+               print_continuation(data + bytes, size - bytes);
+               return;
+       }
+
+       for (i = 0; i < MAX_CONT; i++) {
+               if (cont_list[i].cont[0] == 0x00) {
+                       if (n < 0)
+                               n = i;
+                       continue;
+               }
+
+               if (cont_list[i].channel != tid->channel)
+                       continue;
+
+               if (cont_list[i].cont[0] != tid->cont[0])
+                       continue;
+
+               if (!memcmp(cont_list[i].cont + 1,
+                                       tid->cont + 1, tid->cont[0])) {
+                       n = i;
+                       break;
+               }
+       }
+
+       print_continuation(data + bytes, size - bytes);
+
+       if (n < 0)
+               return;
+
+       newdata = realloc(cont_list[n].data, cont_list[n].size + bytes);
+       if (!newdata) {
+               print_text(COLOR_ERROR, "failed buffer allocation");
+               free(cont_list[n].data);
+               cont_list[n].data = NULL;
+               cont_list[n].size = 0;
+               return;
+       }
+
+       cont_list[n].channel = tid->channel;
+       cont_list[n].data = newdata;
+
+       if (bytes > 0) {
+               memcpy(cont_list[n].data + cont_list[n].size, data, bytes);
+               cont_list[n].size += bytes;
+       }
+
+       if (data[bytes] == 0x00) {
+               print_field("Combined attribute bytes: %d", cont_list[n].size);
+
+               decode_data_elements(0, 2, cont_list[n].data, cont_list[n].size,
+                               nested ? print_attr_lists : print_attr_list);
+
+               free(cont_list[n].data);
+               cont_list[n].data = NULL;
+               cont_list[n].size = 0;
+       } else
+               memcpy(cont_list[i].cont, data + bytes, data[bytes] + 1);
+}
+
+static uint16_t common_rsp(const struct l2cap_frame *frame,
+                                               struct tid_data *tid)
+{
+       uint16_t bytes;
+
+       if (frame->size < 2) {
+               print_text(COLOR_ERROR, "invalid size");
+               packet_hexdump(frame->data, frame->size);
+               return 0;
+       }
+
+       bytes = bt_get_be16(frame->data);
+       print_field("Attribute bytes: %d", bytes);
+
+       if (bytes > frame->size - 2) {
+               print_text(COLOR_ERROR, "invalid attribute size");
+               packet_hexdump(frame->data + 2, frame->size - 2);
+               return 0;
+       }
+
+       return bytes;
+}
+
+static void error_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
+{
+       uint16_t error;
+
+       clear_tid(tid);
+
+       if (frame->size < 2) {
+               print_text(COLOR_ERROR, "invalid size");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       error = bt_get_be16(frame->data);
+
+       print_field("Error code: 0x%2.2x", error);
+}
+
+static void service_req(const struct l2cap_frame *frame, struct tid_data *tid)
+{
+       uint32_t search_bytes;
+
+       search_bytes = get_bytes(frame->data, frame->size);
+       print_field("Search pattern: [len %d]", search_bytes);
+
+       if (search_bytes + 2 > frame->size) {
+               print_text(COLOR_ERROR, "invalid search list length");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       decode_data_elements(0, 2, frame->data, search_bytes, NULL);
+
+       print_field("Max record count: %d",
+                               bt_get_be16(frame->data + search_bytes));
+
+       print_continuation(frame->data + search_bytes + 2,
+                                       frame->size - search_bytes - 2);
+}
+
+static void service_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
+{
+       uint16_t count;
+       int i;
+
+       clear_tid(tid);
+
+       if (frame->size < 4) {
+               print_text(COLOR_ERROR, "invalid size");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       count = bt_get_be16(frame->data + 2);
+
+       print_field("Total record count: %d", bt_get_be16(frame->data));
+       print_field("Current record count: %d", count);
+
+       for (i = 0; i < count; i++)
+               print_field("Record handle: 0x%4.4x",
+                               bt_get_be32(frame->data + 4 + (i * 4)));
+
+       print_continuation(frame->data + 4 + (count * 4),
+                                       frame->size - 4 - (count * 4));
+}
+
+static void attr_req(const struct l2cap_frame *frame, struct tid_data *tid)
+{
+       uint32_t attr_bytes;
+
+       if (frame->size < 6) {
+               print_text(COLOR_ERROR, "invalid size");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       print_field("Record handle: 0x%4.4x", bt_get_be32(frame->data));
+       print_field("Max attribute bytes: %d", bt_get_be16(frame->data + 4));
+
+       attr_bytes = get_bytes(frame->data + 6, frame->size - 6);
+       print_field("Attribute list: [len %d]", attr_bytes);
+
+       if (attr_bytes + 6 > frame->size) {
+               print_text(COLOR_ERROR, "invalid attribute list length");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       decode_data_elements(0, 2, frame->data + 6, attr_bytes, NULL);
+
+       store_continuation(tid, frame->data + 6 + attr_bytes,
+                                       frame->size - 6 - attr_bytes);
+}
+
+static void attr_rsp(const struct l2cap_frame *frame, struct tid_data *tid)
+{
+       uint16_t bytes;
+
+       bytes = common_rsp(frame, tid);
+
+       handle_continuation(tid, false, bytes,
+                                       frame->data + 2, frame->size - 2);
+
+       clear_tid(tid);
+}
+
+static void search_attr_req(const struct l2cap_frame *frame,
+                                               struct tid_data *tid)
+{
+       uint32_t search_bytes, attr_bytes;
+
+       search_bytes = get_bytes(frame->data, frame->size);
+       print_field("Search pattern: [len %d]", search_bytes);
+
+       if (search_bytes + 2 > frame->size) {
+               print_text(COLOR_ERROR, "invalid search list length");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       decode_data_elements(0, 2, frame->data, search_bytes, NULL);
+
+       print_field("Max record count: %d",
+                               bt_get_be16(frame->data + search_bytes));
+
+       attr_bytes = get_bytes(frame->data + search_bytes + 2,
+                               frame->size - search_bytes - 2);
+       print_field("Attribute list: [len %d]", attr_bytes);
+
+       decode_data_elements(0, 2, frame->data + search_bytes + 2,
+                                               attr_bytes, NULL);
+
+       store_continuation(tid, frame->data + search_bytes + 2 + attr_bytes,
+                               frame->size - search_bytes - 2 - attr_bytes);
+}
+
+static void search_attr_rsp(const struct l2cap_frame *frame,
+                                               struct tid_data *tid)
+{
+       uint16_t bytes;
+
+       bytes = common_rsp(frame, tid);
+
+       handle_continuation(tid, true, bytes, frame->data + 2, frame->size - 2);
+
+       clear_tid(tid);
+}
+
+struct sdp_data {
+       uint8_t pdu;
+       const char *str;
+       void (*func) (const struct l2cap_frame *frame, struct tid_data *tid);
+};
+
+static const struct sdp_data sdp_table[] = {
+       { 0x01, "Error Response",                       error_rsp       },
+       { 0x02, "Service Search Request",               service_req     },
+       { 0x03, "Service Search Response",              service_rsp     },
+       { 0x04, "Service Attribute Request",            attr_req        },
+       { 0x05, "Service Attribute Response",           attr_rsp        },
+       { 0x06, "Service Search Attribute Request",     search_attr_req },
+       { 0x07, "Service Search Attribute Response",    search_attr_rsp },
+       { }
+};
+
+void sdp_packet(const struct l2cap_frame *frame, uint16_t channel)
+{
+       uint8_t pdu;
+       uint16_t tid, plen;
+       struct l2cap_frame sdp_frame;
+       struct tid_data *tid_info;
+       const struct sdp_data *sdp_data = NULL;
+       const char *pdu_color, *pdu_str;
+
+       int i;
+
+       if (frame->size < 5) {
+               print_text(COLOR_ERROR, "frame too short");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       pdu = *((uint8_t *) frame->data);
+       tid = bt_get_be16(frame->data + 1);
+       plen = bt_get_be16(frame->data + 3);
+
+       if (frame->size != plen + 5) {
+               print_text(COLOR_ERROR, "invalid frame size");
+               packet_hexdump(frame->data, frame->size);
+               return;
+       }
+
+       for (i = 0; sdp_table[i].str; i++) {
+               if (sdp_table[i].pdu == pdu) {
+                       sdp_data = &sdp_table[i];
+                       break;
+               }
+       }
+
+       if (sdp_data) {
+               if (sdp_data->func) {
+                       if (frame->in)
+                               pdu_color = COLOR_MAGENTA;
+                       else
+                               pdu_color = COLOR_BLUE;
+               } else
+                       pdu_color = COLOR_WHITE_BG;
+               pdu_str = sdp_data->str;
+       } else {
+               pdu_color = COLOR_WHITE_BG;
+               pdu_str = "Unknown";
+       }
+
+       print_indent(6, pdu_color, "SDP: ", pdu_str, COLOR_OFF,
+                               " (0x%2.2x) tid %d len %d", pdu, tid, plen);
+
+       if (!sdp_data || !sdp_data->func) {
+               packet_hexdump(frame->data + 5, frame->size - 5);
+               return;
+       }
+
+       tid_info = get_tid(tid, channel);
+
+       l2cap_frame_pull(&sdp_frame, frame, 5);
+       sdp_data->func(&sdp_frame, tid_info);
+}
similarity index 88%
rename from input/manager.h
rename to monitor/sdp.h
index 7b93c5b..c339772 100644 (file)
@@ -2,6 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
@@ -21,5 +22,4 @@
  *
  */
 
-int input_manager_init(DBusConnection *conn, GKeyFile *config);
-void input_manager_exit(void);
+void sdp_packet(const struct l2cap_frame *frame, uint16_t channel);
diff --git a/monitor/uuid.c b/monitor/uuid.c
new file mode 100644 (file)
index 0000000..3d39a47
--- /dev/null
@@ -0,0 +1,284 @@
+/*
+ *
+ *  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 <string.h>
+
+#include "uuid.h"
+
+static struct {
+       uint16_t uuid;
+       const char *str;
+} uuid16_table[] = {
+       { 0x0001, "SDP"                                         },
+       { 0x0003, "RFCOMM"                                      },
+       { 0x0005, "TCS-BIN"                                     },
+       { 0x0007, "ATT"                                         },
+       { 0x0008, "OBEX"                                        },
+       { 0x000f, "BNEP"                                        },
+       { 0x0010, "UPNP"                                        },
+       { 0x0011, "HIDP"                                        },
+       { 0x0012, "Hardcopy Control Channel"                    },
+       { 0x0014, "Hardcopy Data Channel"                       },
+       { 0x0016, "Hardcopy Notification"                       },
+       { 0x0017, "AVCTP"                                       },
+       { 0x0019, "AVDTP"                                       },
+       { 0x001b, "CMTP"                                        },
+       { 0x001e, "MCAP Control Channel"                        },
+       { 0x001f, "MCAP Data Channel"                           },
+       { 0x0100, "L2CAP"                                       },
+       { 0x1000, "Service Discovery Server Service Class"      },
+       { 0x1001, "Browse Group Descriptor Service Class"       },
+       { 0x1002, "Public Browse Root"                          },
+       { 0x1101, "Serial Port"                                 },
+       { 0x1102, "LAN Access Using PPP"                        },
+       { 0x1103, "Dialup Networking"                           },
+       { 0x1104, "IrMC Sync"                                   },
+       { 0x1105, "OBEX Object Push"                            },
+       { 0x1106, "OBEX File Transfer"                          },
+       { 0x1107, "IrMC Sync Command"                           },
+       { 0x1108, "Headset"                                     },
+       { 0x1109, "Cordless Telephony"                          },
+       { 0x110a, "Audio Source"                                },
+       { 0x110b, "Audio Sink"                                  },
+       { 0x110c, "A/V Remote Control Target"                   },
+       { 0x110d, "Advanced Audio Distribution"                 },
+       { 0x110e, "A/V Remote Control"                          },
+       { 0x110f, "A/V Remote Control Controller"               },
+       { 0x1110, "Intercom"                                    },
+       { 0x1111, "Fax"                                         },
+       { 0x1112, "Headset AG"                                  },
+       { 0x1113, "WAP"                                         },
+       { 0x1114, "WAP Client"                                  },
+       { 0x1115, "PANU"                                        },
+       { 0x1116, "NAP"                                         },
+       { 0x1117, "GN"                                          },
+       { 0x1118, "Direct Printing"                             },
+       { 0x1119, "Reference Printing"                          },
+       { 0x111a, "Basic Imaging Profile"                       },
+       { 0x111b, "Imaging Responder"                           },
+       { 0x111c, "Imaging Automatic Archive"                   },
+       { 0x111d, "Imaging Referenced Objects"                  },
+       { 0x111e, "Handsfree"                                   },
+       { 0x111f, "Handsfree Audio Gateway"                     },
+       { 0x1120, "Direct Printing Refrence Objects Service"    },
+       { 0x1121, "Reflected UI"                                },
+       { 0x1122, "Basic Printing"                              },
+       { 0x1123, "Printing Status"                             },
+       { 0x1124, "Human Interface Device Service"              },
+       { 0x1125, "Hardcopy Cable Replacement"                  },
+       { 0x1126, "HCR Print"                                   },
+       { 0x1127, "HCR Scan"                                    },
+       { 0x1128, "Common ISDN Access"                          },
+       { 0x112d, "SIM Access"                                  },
+       { 0x112e, "Phonebook Access Client"                     },
+       { 0x112f, "Phonebook Access Server"                     },
+       { 0x1130, "Phonebook Access"                            },
+       { 0x1131, "Headset HS"                                  },
+       { 0x1132, "Message Access Server"                       },
+       { 0x1133, "Message Notification Server"                 },
+       { 0x1134, "Message Access Profile"                      },
+       { 0x1135, "GNSS"                                        },
+       { 0x1136, "GNSS Server"                                 },
+       { 0x1200, "PnP Information"                             },
+       { 0x1201, "Generic Networking"                          },
+       { 0x1202, "Generic File Transfer"                       },
+       { 0x1203, "Generic Audio"                               },
+       { 0x1204, "Generic Telephony"                           },
+       { 0x1205, "UPNP Service"                                },
+       { 0x1206, "UPNP IP Service"                             },
+       { 0x1300, "UPNP IP PAN"                                 },
+       { 0x1301, "UPNP IP LAP"                                 },
+       { 0x1302, "UPNP IP L2CAP"                               },
+       { 0x1303, "Video Source"                                },
+       { 0x1304, "Video Sink"                                  },
+       { 0x1305, "Video Distribution"                          },
+       { 0x1400, "HDP"                                         },
+       { 0x1401, "HDP Source"                                  },
+       { 0x1402, "HDP Sink"                                    },
+       { 0x1800, "Generic Access Profile"                      },
+       { 0x1801, "Generic Attribute Profile"                   },
+       { 0x1802, "Immediate Alert"                             },
+       { 0x1803, "Link Loss"                                   },
+       { 0x1804, "Tx Power"                                    },
+       { 0x1805, "Current Time Service"                        },
+       { 0x1806, "Reference Time Update Service"               },
+       { 0x1807, "Next DST Change Service"                     },
+       { 0x1808, "Glucose"                                     },
+       { 0x1809, "Health Thermometer"                          },
+       { 0x180a, "Device Information"                          },
+       /* 0x180b and 0x180c undefined */
+       { 0x180d, "Heart Rate"                                  },
+       { 0x180e, "Phone Alert Status Service"                  },
+       { 0x180f, "Battery Service"                             },
+       { 0x1810, "Blood Pressure"                              },
+       { 0x1811, "Alert Notification Service"                  },
+       { 0x1812, "Human Interface Device"                      },
+       { 0x1813, "Scan Parameters"                             },
+       { 0x1814, "Running Speed and Cadence"                   },
+       /* 0x1815 undefined */
+       { 0x1816, "Cycling Speed and Cadence"                   },
+       { 0x2800, "Primary Service"                             },
+       { 0x2801, "Secondary Service"                           },
+       { 0x2802, "Include"                                     },
+       { 0x2803, "Characteristic"                              },
+       { 0x2900, "Characteristic Extended Properties"          },
+       { 0x2901, "Characteristic User Description"             },
+       { 0x2902, "Client Characteristic Configuration"         },
+       { 0x2903, "Server Characteristic Configuration"         },
+       { 0x2904, "Characteristic Format"                       },
+       { 0x2905, "Characteristic Aggregate Formate"            },
+       { 0x2906, "Valid Range"                                 },
+       { 0x2907, "External Report Reference"                   },
+       { 0x2908, "Report Reference"                            },
+       { 0x2a00, "Device Name"                                 },
+       { 0x2a01, "Appearance"                                  },
+       { 0x2a02, "Peripheral Privacy Flag"                     },
+       { 0x2a03, "Reconnection Address"                        },
+       { 0x2a04, "Peripheral Preferred Connection Parameters"  },
+       { 0x2a05, "Service Changed"                             },
+       { 0x2a06, "Alert Level"                                 },
+       { 0x2a07, "Tx Power Level"                              },
+       { 0x2a08, "Date Time"                                   },
+       { 0x2a09, "Day of Week"                                 },
+       { 0x2a0a, "Day Date Time"                               },
+       /* 0x2a0b undefined */
+       { 0x2a0c, "Exact Time 256"                              },
+       { 0x2a0d, "DST Offset"                                  },
+       { 0x2a0e, "Time Zone"                                   },
+       { 0x2a0f, "Local Time Information"                      },
+       /* 0x2a10 undefined */
+       { 0x2a11, "Time with DST"                               },
+       { 0x2a12, "Time Accuracy"                               },
+       { 0x2a13, "Time Source"                                 },
+       { 0x2a14, "Reference Time Information"                  },
+       /* 0x2a15 undefined */
+       { 0x2a16, "Time Update Control Point"                   },
+       { 0x2a17, "Time Update State"                           },
+       { 0x2a18, "Glucose Measurement"                         },
+       { 0x2a19, "Battery Level"                               },
+       /* 0x2a1a and 0x2a1b undefined */
+       { 0x2a1c, "Temperature Measurement"                     },
+       { 0x2a1d, "Temperature Type"                            },
+       { 0x2a1e, "Intermediate Temperature"                    },
+       /* 0x2a1f and 0x2a20 undefined */
+       { 0x2a21, "Measurement Interval"                        },
+       { 0x2a22, "Boot Keyboard Input Report"                  },
+       { 0x2a23, "System ID"                                   },
+       { 0x2a24, "Model Number String"                         },
+       { 0x2a25, "Serial Number String"                        },
+       { 0x2a26, "Firmware Revision String"                    },
+       { 0x2a27, "Hardware Revision String"                    },
+       { 0x2a28, "Software Revision String"                    },
+       { 0x2a29, "Manufacturer Name String"                    },
+       { 0x2a2a, "IEEE 11073-20601 Regulatory Cert. Data List" },
+       { 0x2a2b, "Current Time"                                },
+       /* 0x2a2c to 0x2a30 undefined */
+       { 0x2a31, "Scan Refresh"                                },
+       { 0x2a32, "Boot Keyboard Output Report"                 },
+       { 0x2a33, "Boot Mouse Input Report"                     },
+       { 0x2a34, "Glucose Measurement Context"                 },
+       { 0x2a35, "Blood Pressure Measurement"                  },
+       { 0x2a36, "Intermediate Cuff Pressure"                  },
+       { 0x2a37, "Heart Rate Measurement"                      },
+       { 0x2a38, "Body Sensor Location"                        },
+       { 0x2a39, "Heart Rate Control Point"                    },
+       /* 0x2a3a to 0x2a3e undefined */
+       { 0x2a3f, "Alert Status"                                },
+       { 0x2a40, "Ringer Control Point"                        },
+       { 0x2a41, "Ringer Setting"                              },
+       { 0x2a42, "Alert Category ID Bit Mask"                  },
+       { 0x2a43, "Alert Category ID"                           },
+       { 0x2a44, "Alert Notification Control Point"            },
+       { 0x2a45, "Unread Alert Status"                         },
+       { 0x2a46, "New Alert"                                   },
+       { 0x2a47, "Supported New Alert Category"                },
+       { 0x2a48, "Supported Unread Alert Category"             },
+       { 0x2a49, "Blood Pressure Feature"                      },
+       { 0x2a4a, "HID Information"                             },
+       { 0x2a4b, "Report Map"                                  },
+       { 0x2a4c, "HID Control Point"                           },
+       { 0x2a4d, "Report"                                      },
+       { 0x2a4e, "Protocol Mode"                               },
+       { 0x2a4f, "Scan Interval Window"                        },
+       { 0x2a50, "PnP ID"                                      },
+       { 0x2a51, "Glucose Feature"                             },
+       { 0x2a52, "Record Access Control Point"                 },
+       { 0x2a53, "RSC Measurement"                             },
+       { 0x2a54, "RSC Feature"                                 },
+       { 0x2a55, "SC Control Point"                            },
+       /* 0x2a56 to 0x2a5a undefined */
+       { 0x2a5b, "CSC Measurement"                             },
+       { 0x2a5c, "CSC Feature"                                 },
+       { 0x2a5d, "Sensor Location"                             },
+       { }
+};
+
+const char *uuid16_to_str(uint16_t uuid)
+{
+       int i;
+
+       for (i = 0; uuid16_table[i].str; i++) {
+               if (uuid16_table[i].uuid == uuid)
+                       return uuid16_table[i].str;
+       }
+
+       return "Unknown";
+}
+
+const char *uuid32_to_str(uint32_t uuid)
+{
+       if ((uuid & 0xffff0000) == 0x0000)
+               return uuid16_to_str(uuid & 0x0000ffff);
+
+       return "Unknown";
+}
+
+const char *uuid128_to_str(const unsigned char *uuid)
+{
+       return "Unknown";
+}
+
+const char *uuidstr_to_str(const char *uuid)
+{
+       uint32_t val;
+
+       if (!uuid)
+               return NULL;
+
+       if (strlen(uuid) != 36)
+               return NULL;
+
+       if (strncasecmp(uuid + 8, "-0000-1000-8000-00805f9b34fb", 28))
+               return "Vendor specific";
+
+       if (sscanf(uuid, "%08x-0000-1000-8000-00805f9b34fb", &val) != 1)
+               return NULL;
+
+       return uuid32_to_str(val);
+}
similarity index 77%
rename from serial/port.h
rename to monitor/uuid.h
index 74ac9f0..2a33c27 100644 (file)
@@ -2,6 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *
  */
 
-void port_release_all(void);
+#include <stdint.h>
 
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
-                 bdaddr_t *dst, const char *name, uint8_t channel);
+const char *uuid16_to_str(uint16_t uuid);
+const char *uuid32_to_str(uint32_t uuid);
+const char *uuid128_to_str(const unsigned char *uuid);
 
-int port_unregister(const char *path);
+const char *uuidstr_to_str(const char *uuid);
similarity index 78%
rename from audio/unix.h
rename to monitor/vendor.c
index 74ca16d..31d48ee 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *
  */
 
-void unix_device_removed(struct audio_device *dev);
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
 
-void unix_delay_report(struct audio_device *dev, uint8_t seid, uint16_t delay);
+#include "packet.h"
+#include "vendor.h"
 
-int unix_init(void);
-void unix_exit(void);
+void vendor_event(uint16_t manufacturer, const void *data, uint8_t size)
+{
+       packet_hexdump(data, size);
+}
similarity index 85%
rename from network/manager.h
rename to monitor/vendor.h
index 27bc13f..7dbd284 100644 (file)
@@ -2,6 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
+ *  Copyright (C) 2011-2012  Intel Corporation
  *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
@@ -21,5 +22,6 @@
  *
  */
 
-int network_manager_init(DBusConnection *conn);
-void network_manager_exit(void);
+#include <stdint.h>
+
+void vendor_event(uint16_t manufacturer, const void *data, uint8_t size);
diff --git a/network/connection.h b/network/connection.h
deleted file mode 100644 (file)
index 5ea4147..0000000
+++ /dev/null
@@ -1,28 +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
- *
- */
-
-int connection_init(DBusConnection *conn);
-void connection_exit(void);
-int connection_register(struct btd_device *device, const char *path,
-                       bdaddr_t *src, bdaddr_t *dst, uint16_t id);
-void connection_unregister(const char *path, uint16_t id);
diff --git a/network/manager.c b/network/manager.c
deleted file mode 100644 (file)
index 7fcd8f0..0000000
+++ /dev/null
@@ -1,223 +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 <bluetooth/bluetooth.h>
-#include <bluetooth/bnep.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "log.h"
-
-#include "adapter.h"
-#include "device.h"
-#include "manager.h"
-#include "common.h"
-#include "connection.h"
-#include "server.h"
-
-static DBusConnection *connection = NULL;
-
-static gboolean conf_security = TRUE;
-
-static void read_config(const char *file)
-{
-       GKeyFile *keyfile;
-       GError *err = NULL;
-
-       keyfile = g_key_file_new();
-
-       if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
-               g_clear_error(&err);
-               goto done;
-       }
-
-       conf_security = !g_key_file_get_boolean(keyfile, "General",
-                                               "DisableSecurity", &err);
-       if (err) {
-               DBG("%s: %s", file, err->message);
-               g_clear_error(&err);
-       }
-
-done:
-       g_key_file_free(keyfile);
-
-       DBG("Config options: Security=%s",
-                               conf_security ? "true" : "false");
-}
-
-static int network_probe(struct btd_device *device, GSList *uuids, uint16_t id)
-{
-       struct btd_adapter *adapter = device_get_adapter(device);
-       const gchar *path = device_get_path(device);
-       bdaddr_t src, dst;
-
-       DBG("path %s", path);
-
-       adapter_get_address(adapter, &src);
-       device_get_address(device, &dst, NULL);
-
-       return connection_register(device, path, &src, &dst, id);
-}
-
-static void network_remove(struct btd_device *device, uint16_t id)
-{
-       const gchar *path = device_get_path(device);
-
-       DBG("path %s", path);
-
-       connection_unregister(path, id);
-}
-
-static int panu_probe(struct btd_device *device, GSList *uuids)
-{
-       return network_probe(device, uuids, BNEP_SVC_PANU);
-}
-
-static void panu_remove(struct btd_device *device)
-{
-       network_remove(device, BNEP_SVC_PANU);
-}
-
-static int gn_probe(struct btd_device *device, GSList *uuids)
-{
-       return network_probe(device, uuids, BNEP_SVC_GN);
-}
-
-static void gn_remove(struct btd_device *device)
-{
-       network_remove(device, BNEP_SVC_GN);
-}
-
-static int nap_probe(struct btd_device *device, GSList *uuids)
-{
-       return network_probe(device, uuids, BNEP_SVC_NAP);
-}
-
-static void nap_remove(struct btd_device *device)
-{
-       network_remove(device, BNEP_SVC_NAP);
-}
-
-static int network_server_probe(struct btd_adapter *adapter)
-{
-       const gchar *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       return server_register(adapter);
-}
-
-static void network_server_remove(struct btd_adapter *adapter)
-{
-       const gchar *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       server_unregister(adapter);
-}
-
-static struct btd_device_driver network_panu_driver = {
-       .name   = "network-panu",
-       .uuids  = BTD_UUIDS(PANU_UUID),
-       .probe  = panu_probe,
-       .remove = panu_remove,
-};
-
-static struct btd_device_driver network_gn_driver = {
-       .name   = "network-gn",
-       .uuids  = BTD_UUIDS(GN_UUID),
-       .probe  = gn_probe,
-       .remove = gn_remove,
-};
-
-static struct btd_device_driver network_nap_driver = {
-       .name   = "network-nap",
-       .uuids  = BTD_UUIDS(NAP_UUID),
-       .probe  = nap_probe,
-       .remove = nap_remove,
-};
-
-static struct btd_adapter_driver network_server_driver = {
-       .name   = "network-server",
-       .probe  = network_server_probe,
-       .remove = network_server_remove,
-};
-
-int network_manager_init(DBusConnection *conn)
-{
-       read_config(CONFIGDIR "/network.conf");
-
-       if (bnep_init()) {
-               error("Can't init bnep module");
-               return -1;
-       }
-
-       /*
-        * 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.
-        */
-
-       if (server_init(conn, conf_security) < 0)
-               return -1;
-
-       /* Register network server if it doesn't exist */
-       btd_register_adapter_driver(&network_server_driver);
-
-       if (connection_init(conn) < 0)
-               return -1;
-
-       btd_register_device_driver(&network_panu_driver);
-       btd_register_device_driver(&network_gn_driver);
-       btd_register_device_driver(&network_nap_driver);
-
-       connection = dbus_connection_ref(conn);
-
-       return 0;
-}
-
-void network_manager_exit(void)
-{
-       server_exit();
-
-       btd_unregister_device_driver(&network_panu_driver);
-       btd_unregister_device_driver(&network_gn_driver);
-       btd_unregister_device_driver(&network_nap_driver);
-
-       connection_exit();
-
-       btd_unregister_adapter_driver(&network_server_driver);
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       bnep_cleanup();
-}
diff --git a/obexd/client/bluetooth.c b/obexd/client/bluetooth.c
new file mode 100644 (file)
index 0000000..75deea0
--- /dev/null
@@ -0,0 +1,513 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2012 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <inttypes.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+#include <btio/btio.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/rfcomm.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "log.h"
+#include "transport.h"
+#include "bluetooth.h"
+
+#define BT_RX_MTU 32767
+#define BT_TX_MTU 32767
+
+#define OBC_BT_ERROR obc_bt_error_quark()
+
+struct bluetooth_session {
+       guint id;
+       bdaddr_t src;
+       bdaddr_t dst;
+       uint16_t port;
+       sdp_session_t *sdp;
+       sdp_record_t *sdp_record;
+       GIOChannel *io;
+       char *service;
+       obc_transport_func func;
+       void *user_data;
+};
+
+static GSList *sessions = NULL;
+
+static GQuark obc_bt_error_quark(void)
+{
+       return g_quark_from_static_string("obc-bluetooth-error-quark");
+}
+
+static void session_destroy(struct bluetooth_session *session)
+{
+       DBG("%p", session);
+
+       if (g_slist_find(sessions, session) == NULL)
+               return;
+
+       sessions = g_slist_remove(sessions, session);
+
+       if (session->io != NULL) {
+               g_io_channel_shutdown(session->io, TRUE, NULL);
+               g_io_channel_unref(session->io);
+       }
+
+       if (session->sdp)
+               sdp_close(session->sdp);
+
+       if (session->sdp_record)
+               sdp_record_free(session->sdp_record);
+
+       g_free(session->service);
+       g_free(session);
+}
+
+static void transport_callback(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct bluetooth_session *session = user_data;
+
+       DBG("");
+
+       if (session->func)
+               session->func(io, err, session->user_data);
+
+       if (err != NULL)
+               session_destroy(session);
+}
+
+static GIOChannel *transport_connect(const bdaddr_t *src, const bdaddr_t *dst,
+                                       uint16_t port, BtIOConnect function,
+                                       gpointer user_data)
+{
+       GIOChannel *io;
+       GError *err = NULL;
+
+       DBG("port %u", port);
+
+       if (port > 31) {
+               io = bt_io_connect(function, user_data,
+                               NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_DEST_BDADDR, dst,
+                               BT_IO_OPT_PSM, port,
+                               BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                               BT_IO_OPT_OMTU, BT_TX_MTU,
+                               BT_IO_OPT_IMTU, BT_RX_MTU,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+       } else {
+               io = bt_io_connect(function, user_data,
+                               NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_DEST_BDADDR, dst,
+                               BT_IO_OPT_CHANNEL, port,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+       }
+
+       if (io != NULL)
+               return io;
+
+       error("%s", err->message);
+       g_error_free(err);
+       return NULL;
+}
+
+static void search_callback(uint8_t type, uint16_t status,
+                       uint8_t *rsp, size_t size, void *user_data)
+{
+       struct bluetooth_session *session = user_data;
+       unsigned int scanned, bytesleft = size;
+       int seqlen = 0;
+       uint8_t dataType;
+       uint16_t port = 0;
+       GError *gerr = NULL;
+
+       if (status || type != SDP_SVC_SEARCH_ATTR_RSP)
+               goto failed;
+
+       scanned = sdp_extract_seqtype(rsp, bytesleft, &dataType, &seqlen);
+       if (!scanned || !seqlen)
+               goto failed;
+
+       rsp += scanned;
+       bytesleft -= scanned;
+       do {
+               sdp_record_t *rec;
+               sdp_list_t *protos;
+               sdp_data_t *data;
+               int recsize, ch = -1;
+
+               recsize = 0;
+               rec = sdp_extract_pdu(rsp, bytesleft, &recsize);
+               if (!rec)
+                       break;
+
+               if (!recsize) {
+                       sdp_record_free(rec);
+                       break;
+               }
+
+               if (!sdp_get_access_protos(rec, &protos)) {
+                       ch = sdp_get_proto_port(protos, RFCOMM_UUID);
+                       sdp_list_foreach(protos,
+                                       (sdp_list_func_t) sdp_list_free, NULL);
+                       sdp_list_free(protos, NULL);
+                       protos = NULL;
+               }
+
+               data = sdp_data_get(rec, 0x0200);
+               /* PSM must be odd and lsb of upper byte must be 0 */
+               if (data != NULL && (data->val.uint16 & 0x0101) == 0x0001)
+                       ch = data->val.uint16;
+
+               /* Cache the sdp record associated with the service that we
+                * attempt to connect. This allows reading its application
+                * specific service attributes. */
+               if (ch > 0) {
+                       port = ch;
+                       session->sdp_record = rec;
+                       break;
+               }
+
+               sdp_record_free(rec);
+
+               scanned += recsize;
+               rsp += recsize;
+               bytesleft -= recsize;
+       } while (scanned < size && bytesleft > 0);
+
+       if (port == 0)
+               goto failed;
+
+       session->port = port;
+
+       g_io_channel_set_close_on_unref(session->io, FALSE);
+       g_io_channel_unref(session->io);
+
+       session->io = transport_connect(&session->src, &session->dst, port,
+                                               transport_callback, session);
+       if (session->io != NULL) {
+               sdp_close(session->sdp);
+               session->sdp = NULL;
+               return;
+       }
+
+failed:
+       if (session->io != NULL) {
+               g_io_channel_shutdown(session->io, TRUE, NULL);
+               g_io_channel_unref(session->io);
+               session->io = NULL;
+       }
+
+       g_set_error(&gerr, OBC_BT_ERROR, -EIO,
+                                       "Unable to find service record");
+       if (session->func)
+               session->func(session->io, gerr, session->user_data);
+
+       g_clear_error(&gerr);
+
+       session_destroy(session);
+}
+
+static gboolean process_callback(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct bluetooth_session *session = user_data;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+               return FALSE;
+
+       if (sdp_process(session->sdp) < 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static int bt_string2uuid(uuid_t *uuid, const char *string)
+{
+       uint32_t data0, data4;
+       uint16_t data1, data2, data3, data5;
+
+       if (sscanf(string, "%08x-%04hx-%04hx-%04hx-%08x%04hx",
+                               &data0, &data1, &data2, &data3, &data4, &data5) == 6) {
+               uint8_t val[16];
+
+               data0 = g_htonl(data0);
+               data1 = g_htons(data1);
+               data2 = g_htons(data2);
+               data3 = g_htons(data3);
+               data4 = g_htonl(data4);
+               data5 = g_htons(data5);
+
+               memcpy(&val[0], &data0, 4);
+               memcpy(&val[4], &data1, 2);
+               memcpy(&val[6], &data2, 2);
+               memcpy(&val[8], &data3, 2);
+               memcpy(&val[10], &data4, 4);
+               memcpy(&val[14], &data5, 2);
+
+               sdp_uuid128_create(uuid, val);
+
+               return 0;
+       }
+
+       return -EINVAL;
+}
+
+static gboolean service_callback(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct bluetooth_session *session = user_data;
+       sdp_list_t *search, *attrid;
+       uint32_t range = 0x0000ffff;
+       GError *gerr = NULL;
+       uuid_t uuid;
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & G_IO_ERR)
+               goto failed;
+
+       if (sdp_set_notify(session->sdp, search_callback, session) < 0)
+               goto failed;
+
+       if (bt_string2uuid(&uuid, session->service) < 0)
+               goto failed;
+
+       search = sdp_list_append(NULL, &uuid);
+       attrid = sdp_list_append(NULL, &range);
+
+       if (sdp_service_search_attr_async(session->sdp,
+                               search, SDP_ATTR_REQ_RANGE, attrid) < 0) {
+               sdp_list_free(attrid, NULL);
+               sdp_list_free(search, NULL);
+               goto failed;
+       }
+
+       sdp_list_free(attrid, NULL);
+       sdp_list_free(search, NULL);
+
+       g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                               process_callback, session);
+
+       return FALSE;
+
+failed:
+       g_io_channel_shutdown(session->io, TRUE, NULL);
+       g_io_channel_unref(session->io);
+       session->io = NULL;
+
+       g_set_error(&gerr, OBC_BT_ERROR, -EIO,
+                                       "Unable to find service record");
+       if (session->func)
+               session->func(session->io, gerr, session->user_data);
+       g_clear_error(&gerr);
+
+       session_destroy(session);
+       return FALSE;
+}
+
+static sdp_session_t *service_connect(const bdaddr_t *src, const bdaddr_t *dst,
+                                       GIOFunc function, gpointer user_data)
+{
+       struct bluetooth_session *session = user_data;
+       sdp_session_t *sdp;
+       GIOChannel *io;
+
+       DBG("");
+
+       sdp = sdp_connect(src, dst, SDP_NON_BLOCKING);
+       if (sdp == NULL)
+               return NULL;
+
+       io = g_io_channel_unix_new(sdp_get_socket(sdp));
+       if (io == NULL) {
+               sdp_close(sdp);
+               return NULL;
+       }
+
+       g_io_add_watch(io, G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                                       function, user_data);
+
+       session->io = io;
+
+       return sdp;
+}
+
+static int session_connect(struct bluetooth_session *session)
+{
+       int err;
+
+       DBG("session %p", session);
+
+       if (session->port > 0) {
+               session->io = transport_connect(&session->src, &session->dst,
+                                                       session->port,
+                                                       transport_callback,
+                                                       session);
+               err = (session->io == NULL) ? -EINVAL : 0;
+       } else {
+               session->sdp = service_connect(&session->src, &session->dst,
+                                               service_callback, session);
+               err = (session->sdp == NULL) ? -ENOMEM : 0;
+       }
+
+       return err;
+}
+
+static guint bluetooth_connect(const char *source, const char *destination,
+                               const char *service, uint16_t port,
+                               obc_transport_func func, void *user_data)
+{
+       struct bluetooth_session *session;
+       static guint id = 0;
+
+       DBG("src %s dest %s service %s port %u",
+                               source, destination, service, port);
+
+       if (destination == NULL)
+               return 0;
+
+       session = g_try_malloc0(sizeof(*session));
+       if (session == NULL)
+               return 0;
+
+       session->id = ++id;
+       session->func = func;
+       session->port = port;
+       session->user_data = user_data;
+
+       str2ba(destination, &session->dst);
+       str2ba(source, &session->src);
+
+       if (session_connect(session) < 0) {
+               g_free(session);
+               return 0;
+       }
+
+       session->service = g_strdup(service);
+       sessions = g_slist_prepend(sessions, session);
+
+       return session->id;
+}
+
+static void bluetooth_disconnect(guint id)
+{
+       GSList *l;
+
+       DBG("");
+
+       for (l = sessions; l; l = l->next) {
+               struct bluetooth_session *session = l->data;
+
+               if (session->id == id) {
+                       session_destroy(session);
+                       return;
+               }
+       }
+}
+
+static int bluetooth_getpacketopt(GIOChannel *io, int *tx_mtu, int *rx_mtu)
+{
+       int sk = g_io_channel_unix_get_fd(io);
+       int type;
+       int omtu = -1;
+       int imtu = -1;
+       socklen_t len = sizeof(int);
+
+       DBG("");
+
+       if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+               return -errno;
+
+       if (type != SOCK_SEQPACKET)
+               return -EINVAL;
+
+       if (!bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu,
+                                               BT_IO_OPT_IMTU, &imtu,
+                                               BT_IO_OPT_INVALID))
+               return -EINVAL;
+
+       if (tx_mtu)
+               *tx_mtu = omtu;
+
+       if (rx_mtu)
+               *rx_mtu = imtu;
+
+       return 0;
+}
+
+static const void *bluetooth_getattribute(guint id, int attribute_id)
+{
+       GSList *l;
+       sdp_data_t *data;
+
+       for (l = sessions; l; l = l->next) {
+               struct bluetooth_session *session = l->data;
+
+               if (session->id != id)
+                       continue;
+
+               if (session->sdp_record == NULL)
+                       break;
+
+               data = sdp_data_get(session->sdp_record, attribute_id);
+               if (!data)
+                       break;
+
+               return &data->val;
+       }
+       return NULL;
+}
+
+static struct obc_transport bluetooth = {
+       .name = "Bluetooth",
+       .connect = bluetooth_connect,
+       .getpacketopt = bluetooth_getpacketopt,
+       .disconnect = bluetooth_disconnect,
+       .getattribute = bluetooth_getattribute,
+};
+
+int bluetooth_init(void)
+{
+       DBG("");
+
+       return obc_transport_register(&bluetooth);
+}
+
+void bluetooth_exit(void)
+{
+       DBG("");
+
+       obc_transport_unregister(&bluetooth);
+}
diff --git a/obexd/client/bluetooth.h b/obexd/client/bluetooth.h
new file mode 100644 (file)
index 0000000..968e131
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int bluetooth_init(void);
+void bluetooth_exit(void);
diff --git a/obexd/client/dbus.c b/obexd/client/dbus.c
new file mode 100644 (file)
index 0000000..243af59
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+#include "dbus.h"
+
+static void append_variant(DBusMessageIter *iter,
+                               int type, void *value)
+{
+       char sig[2];
+       DBusMessageIter valueiter;
+
+       sig[0] = type;
+       sig[1] = 0;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                               sig, &valueiter);
+
+       dbus_message_iter_append_basic(&valueiter, type, value);
+
+       dbus_message_iter_close_container(iter, &valueiter);
+}
+
+void obex_dbus_dict_append(DBusMessageIter *dict,
+                       const char *key, int type, void *value)
+{
+       DBusMessageIter keyiter;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) value);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &keyiter);
+
+       dbus_message_iter_append_basic(&keyiter, DBUS_TYPE_STRING, &key);
+
+       append_variant(&keyiter, type, value);
+
+       dbus_message_iter_close_container(dict, &keyiter);
+}
+
+int obex_dbus_signal_property_changed(DBusConnection *conn,
+                                       const char *path,
+                                       const char *interface,
+                                       const char *name,
+                                       int type, void *value)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter;
+
+       signal = dbus_message_new_signal(path, interface, "PropertyChanged");
+       if (signal == NULL) {
+               error("Unable to allocate new %s.PropertyChanged signal",
+                               interface);
+               return -1;
+       }
+
+       dbus_message_iter_init_append(signal, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
+
+       append_variant(&iter, type, value);
+
+       return g_dbus_send_message(conn, signal);
+}
diff --git a/obexd/client/dbus.h b/obexd/client/dbus.h
new file mode 100644 (file)
index 0000000..6136bf5
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2008-2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 __OBEX_DBUS_H
+#define __OBEX_DBUS_H
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include <dbus/dbus.h>
+
+/* Essentially a{sv} */
+#define OBC_PROPERTIES_ARRAY_SIGNATURE DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING \
+                                       DBUS_TYPE_STRING_AS_STRING \
+                                       DBUS_TYPE_VARIANT_AS_STRING \
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+
+void obex_dbus_dict_append(DBusMessageIter *dict, const char *key, int type,
+                               void *value);
+
+int obex_dbus_signal_property_changed(DBusConnection *conn, const char *path,
+                                       const char *interface, const char *name,
+                                       int type, void *value);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __OBEX_DBUS_H */
diff --git a/obexd/client/driver.c b/obexd/client/driver.c
new file mode 100644 (file)
index 0000000..a98dcf4
--- /dev/null
@@ -0,0 +1,87 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "log.h"
+
+static GSList *drivers = NULL;
+
+struct obc_driver *obc_driver_find(const char *pattern)
+{
+       GSList *l;
+
+       for (l = drivers; l; l = l->next) {
+               struct obc_driver *driver = l->data;
+
+               if (strcasecmp(pattern, driver->service) == 0)
+                       return driver;
+
+               if (strcasecmp(pattern, driver->uuid) == 0)
+                       return driver;
+       }
+
+       return NULL;
+}
+
+int obc_driver_register(struct obc_driver *driver)
+{
+       if (!driver) {
+               error("Invalid driver");
+               return -EINVAL;
+       }
+
+       if (obc_driver_find(driver->service)) {
+               error("Permission denied: service %s already registered",
+                       driver->service);
+               return -EPERM;
+       }
+
+       DBG("driver %p service %s registered", driver, driver->service);
+
+       drivers = g_slist_append(drivers, driver);
+
+       return 0;
+}
+
+void obc_driver_unregister(struct obc_driver *driver)
+{
+       if (!g_slist_find(drivers, driver)) {
+               error("Unable to unregister: No such driver %p", driver);
+               return;
+       }
+
+       DBG("driver %p service %s unregistered", driver, driver->service);
+
+       drivers = g_slist_remove(drivers, driver);
+}
diff --git a/obexd/client/driver.h b/obexd/client/driver.h
new file mode 100644 (file)
index 0000000..f1c0646
--- /dev/null
@@ -0,0 +1,35 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct obc_driver {
+       const char *service;
+       const char *uuid;
+       void *target;
+       gsize target_len;
+       int (*probe) (struct obc_session *session);
+       void (*remove) (struct obc_session *session);
+};
+
+int obc_driver_register(struct obc_driver *driver);
+void obc_driver_unregister(struct obc_driver *driver);
+struct obc_driver *obc_driver_find(const char *pattern);
diff --git a/obexd/client/ftp.c b/obexd/client/ftp.c
new file mode 100644 (file)
index 0000000..fa85708
--- /dev/null
@@ -0,0 +1,511 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <gdbus/gdbus.h>
+
+#include "dbus.h"
+#include "log.h"
+
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "ftp.h"
+
+#define OBEX_FTP_UUID \
+       "\xF9\xEC\x7B\xC4\x95\x3C\x11\xD2\x98\x4E\x52\x54\x00\xDC\x9E\x09"
+#define OBEX_FTP_UUID_LEN 16
+
+#define FTP_INTERFACE "org.bluez.obex.FileTransfer1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define FTP_UUID "00001106-0000-1000-8000-00805f9b34fb"
+#define PCSUITE_UUID "00005005-0000-1000-8000-0002ee000001"
+
+static DBusConnection *conn = NULL;
+
+struct ftp_data {
+       struct obc_session *session;
+};
+
+static void async_cb(struct obc_session *session, struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       DBusMessage *reply, *msg = user_data;
+
+       if (err != NULL)
+               reply = g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+       else
+               reply = dbus_message_new_method_return(msg);
+
+       g_dbus_send_message(conn, reply);
+       dbus_message_unref(msg);
+}
+
+static DBusMessage *change_folder(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       const char *folder;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &folder,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       obc_session_setpath(session, folder, async_cb, message, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply =  g_dbus_create_error(message,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               g_error_free(err);
+               return reply;
+       }
+
+       dbus_message_ref(message);
+
+       return NULL;
+}
+
+static void xml_element(GMarkupParseContext *ctxt,
+                       const char *element,
+                       const char **names,
+                       const char **values,
+                       gpointer user_data,
+                       GError **gerr)
+{
+       DBusMessageIter dict, *iter = user_data;
+       char *key;
+       int i;
+
+       if (strcasecmp("folder", element) != 0 && strcasecmp("file", element) != 0)
+               return;
+
+       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);
+
+       obex_dbus_dict_append(&dict, "Type", DBUS_TYPE_STRING, &element);
+
+       /* FIXME: User, Group, Other permission must be reviewed */
+
+       i = 0;
+       for (key = (char *) names[i]; key; key = (char *) names[++i]) {
+               key[0] = g_ascii_toupper(key[0]);
+               if (g_str_equal("Size", key) == TRUE) {
+                       guint64 size;
+                       size = g_ascii_strtoll(values[i], NULL, 10);
+                       obex_dbus_dict_append(&dict, key, DBUS_TYPE_UINT64,
+                                                               &size);
+               } else
+                       obex_dbus_dict_append(&dict, key, DBUS_TYPE_STRING,
+                                                               &values[i]);
+       }
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static const GMarkupParser parser = {
+       xml_element,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+static void list_folder_callback(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       DBusMessage *msg = user_data;
+       GMarkupParseContext *ctxt;
+       DBusMessage *reply;
+       DBusMessageIter iter, array;
+       char *contents;
+       size_t size;
+
+       reply = dbus_message_new_method_return(msg);
+
+       if (obc_transfer_get_contents(transfer, &contents, &size) < 0)
+               goto done;
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_TYPE_ARRAY_AS_STRING
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+       ctxt = g_markup_parse_context_new(&parser, 0, &array, NULL);
+       g_markup_parse_context_parse(ctxt, contents, size, NULL);
+       g_markup_parse_context_free(ctxt);
+       dbus_message_iter_close_container(&iter, &array);
+       g_free(contents);
+
+done:
+       g_dbus_send_message(conn, reply);
+       dbus_message_unref(msg);
+}
+
+static DBusMessage *create_folder(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       const char *folder;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &folder,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       obc_session_mkdir(session, folder, async_cb, message, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply = g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Failed",
+                               "%s", err->message);
+               g_error_free(err);
+               return reply;
+       }
+
+       dbus_message_ref(message);
+
+       return NULL;
+}
+
+static DBusMessage *list_folder(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (obc_session_queue(session, transfer, list_folder_callback,
+                                                       message, &err)) {
+               dbus_message_ref(message);
+               return NULL;
+       }
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *get_file(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       struct obc_transfer *transfer;
+       const char *target_file, *source_file;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &target_file,
+                               DBUS_TYPE_STRING, &source_file,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       transfer = obc_transfer_get(NULL, source_file, target_file, &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *put_file(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       struct obc_transfer *transfer;
+       char *sourcefile, *targetfile;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       if (dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &sourcefile,
+                                       DBUS_TYPE_STRING, &targetfile,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments",
+                               "Invalid arguments in method call");
+
+       transfer = obc_transfer_put(NULL, targetfile, sourcefile, NULL, 0,
+                                                                       &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *copy_file(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       const char *filename, *destname;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &filename,
+                               DBUS_TYPE_STRING, &destname,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       obc_session_copy(session, filename, destname, async_cb, message, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+                                                       "%s", err->message);
+               g_error_free(err);
+               return reply;
+       }
+
+       dbus_message_ref(message);
+
+       return NULL;
+}
+
+static DBusMessage *move_file(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       const char *filename, *destname;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &filename,
+                               DBUS_TYPE_STRING, &destname,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       obc_session_move(session, filename, destname, async_cb, message, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+                                                       "%s", err->message);
+               g_error_free(err);
+               return reply;
+       }
+
+       dbus_message_ref(message);
+
+       return NULL;
+}
+
+static DBusMessage *delete(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct ftp_data *ftp = user_data;
+       struct obc_session *session = ftp->session;
+       const char *file;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &file,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       obc_session_delete(session, file, async_cb, message, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+                                                       "%s", err->message);
+               g_error_free(err);
+               return reply;
+       }
+
+       dbus_message_ref(message);
+
+       return NULL;
+}
+
+static const GDBusMethodTable ftp_methods[] = {
+       { GDBUS_ASYNC_METHOD("ChangeFolder",
+               GDBUS_ARGS({ "folder", "s" }), NULL, change_folder) },
+       { GDBUS_ASYNC_METHOD("CreateFolder",
+               GDBUS_ARGS({ "folder", "s" }), NULL, create_folder) },
+       { GDBUS_ASYNC_METHOD("ListFolder",
+               NULL, GDBUS_ARGS({ "folderinfo", "aa{sv}" }), list_folder) },
+       { GDBUS_METHOD("GetFile",
+               GDBUS_ARGS({ "targetfile", "s" }, { "sourcefile", "s" }),
+               GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+               get_file) },
+       { GDBUS_METHOD("PutFile",
+               GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }),
+               GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+               put_file) },
+       { GDBUS_ASYNC_METHOD("CopyFile",
+               GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }), NULL,
+               copy_file) },
+       { GDBUS_ASYNC_METHOD("MoveFile",
+               GDBUS_ARGS({ "sourcefile", "s" }, { "targetfile", "s" }), NULL,
+               move_file) },
+       { GDBUS_ASYNC_METHOD("Delete",
+               GDBUS_ARGS({ "file", "s" }), NULL, delete) },
+       { }
+};
+
+static void ftp_free(void *data)
+{
+       struct ftp_data *ftp = data;
+
+       obc_session_unref(ftp->session);
+       g_free(ftp);
+}
+
+static int ftp_probe(struct obc_session *session)
+{
+       struct ftp_data *ftp;
+       const char *path;
+
+       path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       ftp = g_try_new0(struct ftp_data, 1);
+       if (!ftp)
+               return -ENOMEM;
+
+       ftp->session = obc_session_ref(session);
+
+       if (!g_dbus_register_interface(conn, path, FTP_INTERFACE, ftp_methods,
+                                               NULL, NULL, ftp, ftp_free)) {
+               ftp_free(ftp);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void ftp_remove(struct obc_session *session)
+{
+       const char *path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(conn, path, FTP_INTERFACE);
+}
+
+static struct obc_driver ftp = {
+       .service = "FTP",
+       .uuid = FTP_UUID,
+       .target = OBEX_FTP_UUID,
+       .target_len = OBEX_FTP_UUID_LEN,
+       .probe = ftp_probe,
+       .remove = ftp_remove
+};
+
+static struct obc_driver pcsuite = {
+       .service = "PCSUITE",
+       .uuid = PCSUITE_UUID,
+       .target = OBEX_FTP_UUID,
+       .target_len = OBEX_FTP_UUID_LEN,
+       .probe = ftp_probe,
+       .remove = ftp_remove
+};
+
+int ftp_init(void)
+{
+       int err;
+
+       DBG("");
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!conn)
+               return -EIO;
+
+       err = obc_driver_register(&ftp);
+       if (err < 0)
+               goto failed;
+
+       err = obc_driver_register(&pcsuite);
+       if (err < 0) {
+               obc_driver_unregister(&ftp);
+               goto failed;
+       }
+
+       return 0;
+
+failed:
+       dbus_connection_unref(conn);
+       conn = NULL;
+       return err;
+}
+
+void ftp_exit(void)
+{
+       DBG("");
+
+       dbus_connection_unref(conn);
+       conn = NULL;
+
+       obc_driver_unregister(&ftp);
+       obc_driver_unregister(&pcsuite);
+}
diff --git a/obexd/client/ftp.h b/obexd/client/ftp.h
new file mode 100644 (file)
index 0000000..3d90968
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int ftp_init(void);
+void ftp_exit(void);
diff --git a/obexd/client/manager.c b/obexd/client/manager.c
new file mode 100644 (file)
index 0000000..8efe1f2
--- /dev/null
@@ -0,0 +1,315 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <syslog.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+#include "transfer.h"
+#include "session.h"
+#include "manager.h"
+#include "bluetooth.h"
+#include "opp.h"
+#include "ftp.h"
+#include "pbap.h"
+#include "sync.h"
+#include "map.h"
+#include "obexd/src/manager.h"
+
+#define CLIENT_INTERFACE       "org.bluez.obex.Client1"
+#define ERROR_INTERFACE                "org.bluez.obex.Error"
+#define CLIENT_PATH            "/org/bluez/obex"
+
+struct send_data {
+       DBusConnection *connection;
+       DBusMessage *message;
+};
+
+static GSList *sessions = NULL;
+
+static void shutdown_session(struct obc_session *session)
+{
+       obc_session_shutdown(session);
+       obc_session_unref(session);
+}
+
+static void release_session(struct obc_session *session)
+{
+       sessions = g_slist_remove(sessions, session);
+       shutdown_session(session);
+}
+
+static void unregister_session(void *data)
+{
+       struct obc_session *session = data;
+
+       if (g_slist_find(sessions, session) == NULL)
+               return;
+
+       sessions = g_slist_remove(sessions, session);
+       obc_session_unref(session);
+}
+
+static void create_callback(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct send_data *data = user_data;
+       const char *path;
+
+       if (err != NULL) {
+               DBusMessage *error = g_dbus_create_error(data->message,
+                                       ERROR_INTERFACE ".Failed",
+                                       "%s", err->message);
+               g_dbus_send_message(data->connection, error);
+               shutdown_session(session);
+               goto done;
+       }
+
+
+       path = obc_session_register(session, unregister_session);
+       if (path == NULL) {
+               DBusMessage *error = g_dbus_create_error(data->message,
+                                       ERROR_INTERFACE ".Failed",
+                                       NULL);
+               g_dbus_send_message(data->connection, error);
+               shutdown_session(session);
+               goto done;
+       }
+
+       sessions = g_slist_append(sessions, session);
+       g_dbus_send_reply(data->connection, data->message,
+                               DBUS_TYPE_OBJECT_PATH, &path,
+                               DBUS_TYPE_INVALID);
+
+done:
+       dbus_message_unref(data->message);
+       dbus_connection_unref(data->connection);
+       g_free(data);
+}
+
+static int parse_device_dict(DBusMessageIter *iter,
+               const char **source, const char **target, uint8_t *channel)
+{
+       while (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry, value;
+               const char *key;
+
+               dbus_message_iter_recurse(iter, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               switch (dbus_message_iter_get_arg_type(&value)) {
+               case DBUS_TYPE_STRING:
+                       if (g_str_equal(key, "Source") == TRUE)
+                               dbus_message_iter_get_basic(&value, source);
+                       else if (g_str_equal(key, "Target") == TRUE)
+                               dbus_message_iter_get_basic(&value, target);
+                       break;
+               case DBUS_TYPE_BYTE:
+                       if (g_str_equal(key, "Channel") == TRUE)
+                               dbus_message_iter_get_basic(&value, channel);
+                       break;
+               }
+
+               dbus_message_iter_next(iter);
+       }
+
+       return 0;
+}
+
+static struct obc_session *find_session(const char *path)
+{
+       GSList *l;
+
+       for (l = sessions; l; l = l->next) {
+               struct obc_session *session = l->data;
+
+               if (g_str_equal(obc_session_get_path(session), path) == TRUE)
+                       return session;
+       }
+
+       return NULL;
+}
+
+static DBusMessage *create_session(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter, dict;
+       struct obc_session *session;
+       struct send_data *data;
+       const char *source = NULL, *dest = NULL, *target = NULL;
+       uint8_t channel = 0;
+
+       dbus_message_iter_init(message, &iter);
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&iter, &dest);
+       dbus_message_iter_next(&iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_recurse(&iter, &dict);
+
+       parse_device_dict(&dict, &source, &target, &channel);
+       if (dest == NULL || target == NULL)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       data = g_try_malloc0(sizeof(*data));
+       if (data == NULL)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Error.NoMemory", NULL);
+
+       data->connection = dbus_connection_ref(connection);
+       data->message = dbus_message_ref(message);
+
+       session = obc_session_create(source, dest, target, channel,
+                                       dbus_message_get_sender(message),
+                                       create_callback, data);
+       if (session != NULL) {
+               return NULL;
+       }
+
+       dbus_message_unref(data->message);
+       dbus_connection_unref(data->connection);
+       g_free(data);
+
+       return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
+}
+
+static DBusMessage *remove_session(DBusConnection *connection,
+                               DBusMessage *message, void *user_data)
+{
+       struct obc_session *session;
+       const char *sender, *path;
+
+       if (dbus_message_get_args(message, NULL,
+                       DBUS_TYPE_OBJECT_PATH, &path,
+                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       session = find_session(path);
+       if (session == NULL)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       sender = dbus_message_get_sender(message);
+       if (g_str_equal(sender, obc_session_get_owner(session)) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".NotAuthorized",
+                               "Not Authorized");
+
+       release_session(session);
+
+       return dbus_message_new_method_return(message);
+}
+
+static const GDBusMethodTable client_methods[] = {
+       { GDBUS_ASYNC_METHOD("CreateSession",
+                       GDBUS_ARGS({ "destination", "s" }, { "args", "a{sv}" }),
+                       GDBUS_ARGS({ "session", "o" }), create_session) },
+       { GDBUS_ASYNC_METHOD("RemoveSession",
+                       GDBUS_ARGS({ "session", "o" }), NULL, remove_session) },
+       { }
+};
+
+static DBusConnection *conn = NULL;
+
+static struct obc_module {
+       const char *name;
+       int (*init) (void);
+       void (*exit) (void);
+} modules[] = {
+       { "bluetooth", bluetooth_init, bluetooth_exit },
+       { "opp", opp_init, opp_exit },
+       { "ftp", ftp_init, ftp_exit },
+       { "pbap", pbap_init, pbap_exit },
+       { "sync", sync_init, sync_exit },
+       { "map", map_init, map_exit },
+       { }
+};
+
+int client_manager_init(void)
+{
+       DBusError derr;
+       struct obc_module *module;
+
+       dbus_error_init(&derr);
+
+       conn = manager_dbus_get_connection();
+       if (conn == NULL) {
+               error("Can't get client D-Bus connection");
+               return -1;
+       }
+
+       if (g_dbus_register_interface(conn, CLIENT_PATH, CLIENT_INTERFACE,
+                                               client_methods, NULL, NULL,
+                                                       NULL, NULL) == FALSE) {
+               error("Can't register client interface");
+               dbus_connection_unref(conn);
+               conn = NULL;
+               return -1;
+       }
+
+       for (module = modules; module && module->init; module++) {
+               if (module->init() < 0)
+                       continue;
+
+               DBG("Module %s loaded", module->name);
+       }
+
+       return 0;
+}
+
+void client_manager_exit(void)
+{
+       struct obc_module *module;
+
+       if (conn == NULL)
+               return;
+
+       for (module = modules; module && module->exit; module++)
+               module->exit();
+
+       g_dbus_unregister_interface(conn, CLIENT_PATH, CLIENT_INTERFACE);
+
+       dbus_connection_unref(conn);
+}
diff --git a/obexd/client/manager.h b/obexd/client/manager.h
new file mode 100644 (file)
index 0000000..e4068de
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int client_manager_init(void);
+void client_manager_exit(void);
diff --git a/obexd/client/map-event.c b/obexd/client/map-event.c
new file mode 100644 (file)
index 0000000..d424924
--- /dev/null
@@ -0,0 +1,112 @@
+/*
+ *
+ *  OBEX
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. 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 <glib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <inttypes.h>
+
+#include "log.h"
+#include "map-event.h"
+
+#include <gdbus/gdbus.h>
+#include "transfer.h"
+#include "session.h"
+
+static GSList *handlers;
+
+struct mns_handler {
+       int mas_id;
+       struct obc_session *session;
+       map_event_cb cb;
+       void *user_data;
+};
+
+static struct mns_handler *find_handler(int mas_id, const char *device)
+{
+       GSList *list;
+
+       for (list = handlers; list; list = list->next) {
+               struct mns_handler *handler = list->data;
+
+               if (mas_id != handler->mas_id)
+                       continue;
+
+               if (g_str_equal(device,
+                               obc_session_get_destination(handler->session)))
+                       return handler;
+       }
+
+       return NULL;
+}
+
+bool map_register_event_handler(struct obc_session *session,
+                                       int mas_id, map_event_cb cb,
+                                       void *user_data)
+{
+       struct mns_handler *handler;
+
+       handler = find_handler(mas_id, obc_session_get_destination(session));
+       if (handler != NULL)
+               return FALSE;
+
+       handler = g_new0(struct mns_handler, 1);
+       handler->mas_id = mas_id;
+       handler->session = session;
+       handler->cb = cb;
+       handler->user_data = user_data;
+
+       handlers = g_slist_prepend(handlers, handler);
+       DBG("Handler %p for %s:%d registered", handler,
+                       obc_session_get_destination(session), mas_id);
+
+       return TRUE;
+}
+
+void map_unregister_event_handler(struct obc_session *session, int mas_id)
+{
+       struct mns_handler *handler;
+
+       handler = find_handler(mas_id, obc_session_get_destination(session));
+       if (handler == NULL)
+               return;
+
+       handlers = g_slist_remove(handlers, handler);
+       DBG("Handler %p for %s:%d unregistered", handler,
+                       obc_session_get_destination(session), mas_id);
+       g_free(handler);
+}
+
+void map_dispatch_event(int mas_id, const char *device,
+                                               struct map_event *event)
+{
+       struct mns_handler *handler;
+
+       handler = find_handler(mas_id, device);
+       if (handler)
+               handler->cb(event, handler->user_data);
+}
diff --git a/obexd/client/map-event.h b/obexd/client/map-event.h
new file mode 100644 (file)
index 0000000..ba5d5d2
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *
+ *  OBEX
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. 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
+ *
+ */
+
+struct obc_session;
+
+enum map_event_type {
+       MAP_ET_NEW_MESSAGE,
+       MAP_ET_DELIVERY_SUCCESS,
+       MAP_ET_SENDING_SUCCESS,
+       MAP_ET_DELIVERY_FAILURE,
+       MAP_ET_SENDING_FAILURE,
+       MAP_ET_MEMORY_FULL,
+       MAP_ET_MEMORY_AVAILABLE,
+       MAP_ET_MESSAGE_DELETED,
+       MAP_ET_MESSAGE_SHIFT
+};
+
+struct map_event {
+       enum map_event_type type;
+       uint64_t handle;
+       char *folder;
+       char *old_folder;
+       char *msg_type;
+};
+
+/* Handle notification in map client.
+ *
+ * event: Event report.
+ *
+ * Callback shall be called for every received event.
+ */
+typedef void (*map_event_cb) (struct map_event *event, void *user_data);
+
+/* Registers client notification handler callback for events that are
+ * addressed to the given mas instance id for the given device.
+ */
+bool map_register_event_handler(struct obc_session *session, int mas_id,
+                                       map_event_cb cb, void *user_data);
+
+/* Unregisters client notification handler callback.
+ */
+void map_unregister_event_handler(struct obc_session *session, int mas_id);
+
+/* Dispatch notification to a registered notification handler callback.
+ */
+void map_dispatch_event(int mas_id, const char *device,
+                                               struct map_event *event);
diff --git a/obexd/client/map.c b/obexd/client/map.c
new file mode 100644 (file)
index 0000000..d2d3d81
--- /dev/null
@@ -0,0 +1,2080 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2011  Bartosz Szatkowski <bulislaw@linux.com> for Comarch
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <stdbool.h>
+#include <inttypes.h>
+#include <stdlib.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+#include <gobex/gobex-apparam.h>
+#include <bluetooth/sdp.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "map_ap.h"
+#include "map-event.h"
+
+#include "map.h"
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+
+#define OBEX_MAS_UUID \
+       "\xBB\x58\x2B\x40\x42\x0C\x11\xDB\xB0\xDE\x08\x00\x20\x0C\x9A\x66"
+#define OBEX_MAS_UUID_LEN 16
+
+#define MAP_INTERFACE "org.bluez.obex.MessageAccess1"
+#define MAP_MSG_INTERFACE "org.bluez.obex.Message1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define MAS_UUID "00001132-0000-1000-8000-00805f9b34fb"
+
+#define DEFAULT_COUNT 1024
+#define DEFAULT_OFFSET 0
+
+#define CHARSET_NATIVE 0
+#define CHARSET_UTF8 1
+
+static const char * const filter_list[] = {
+       "subject",
+       "timestamp",
+       "sender",
+       "sender-address",
+       "recipient",
+       "recipient-address",
+       "type",
+       "size",
+       "status",
+       "text",
+       "attachment",
+       "priority",
+       "read",
+       "sent",
+       "protected",
+       "replyto",
+       NULL
+};
+
+#define FILTER_BIT_MAX 15
+#define FILTER_ALL     0x0000FFFF
+
+#define FILTER_READ_STATUS_NONE                0x00
+#define FILTER_READ_STATUS_ONLY_UNREAD 0x01
+#define FILTER_READ_STATUS_ONLY_READ   0x02
+
+#define FILTER_PRIORITY_NONE           0x00
+#define FILTER_PRIORITY_ONLY_HIGH      0x01
+#define FILTER_PRIORITY_ONLY_NONHIGH   0x02
+
+#define STATUS_READ 0
+#define STATUS_DELETE 1
+#define FILLER_BYTE 0x30
+
+struct map_data {
+       struct obc_session *session;
+       GHashTable *messages;
+       int16_t mas_instance_id;
+       uint8_t supported_message_types;
+};
+
+struct pending_request {
+       struct map_data *map;
+       DBusMessage *msg;
+       char *folder;
+};
+
+#define MAP_MSG_FLAG_PRIORITY  0x01
+#define MAP_MSG_FLAG_READ      0x02
+#define MAP_MSG_FLAG_SENT      0x04
+#define MAP_MSG_FLAG_PROTECTED 0x08
+#define MAP_MSG_FLAG_TEXT      0x10
+
+struct map_msg {
+       struct map_data *data;
+       char *path;
+       uint64_t handle;
+       char *subject;
+       char *timestamp;
+       char *sender;
+       char *sender_address;
+       char *replyto;
+       char *recipient;
+       char *recipient_address;
+       char *type;
+       uint64_t size;
+       char *status;
+       uint64_t attachment_size;
+       uint8_t flags;
+       char *folder;
+       GDBusPendingPropertySet pending;
+};
+
+struct map_parser {
+       struct pending_request *request;
+       DBusMessageIter *iter;
+};
+
+static DBusConnection *conn = NULL;
+
+static struct pending_request *pending_request_new(struct map_data *map,
+                                                       DBusMessage *message)
+{
+       struct pending_request *p;
+
+       p = g_new0(struct pending_request, 1);
+       p->map = map;
+       p->msg = dbus_message_ref(message);
+
+       return p;
+}
+
+static void pending_request_free(struct pending_request *p)
+{
+       dbus_message_unref(p->msg);
+
+       g_free(p->folder);
+       g_free(p);
+}
+
+static void simple_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       DBusMessage *reply;
+
+       if (err != NULL)
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+       else
+               reply = dbus_message_new_method_return(request->msg);
+
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static DBusMessage *map_setpath(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       const char *folder;
+       struct pending_request *request;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL, DBUS_TYPE_STRING, &folder,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       NULL);
+
+       request = pending_request_new(map, message);
+
+       obc_session_setpath(map->session, folder, simple_cb, request, &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply =  g_dbus_create_error(message,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               g_error_free(err);
+               pending_request_free(request);
+               return reply;
+       }
+
+       return NULL;
+}
+
+static void folder_element(GMarkupParseContext *ctxt, const char *element,
+                               const char **names, const char **values,
+                               gpointer user_data, GError **gerr)
+{
+       DBusMessageIter dict, *iter = user_data;
+       const char *key;
+       int i;
+
+       if (strcasecmp("folder", element) != 0)
+               return;
+
+       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);
+
+       for (i = 0, key = names[i]; key; key = names[++i]) {
+               if (strcasecmp("name", key) == 0)
+                       obex_dbus_dict_append(&dict, "Name", DBUS_TYPE_STRING,
+                                                               &values[i]);
+       }
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static const GMarkupParser folder_parser = {
+       folder_element,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+static void folder_listing_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       GMarkupParseContext *ctxt;
+       DBusMessage *reply;
+       DBusMessageIter iter, array;
+       char *contents;
+       size_t size;
+       int perr;
+
+       if (err != NULL) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       perr = obc_transfer_get_contents(transfer, &contents, &size);
+       if (perr < 0) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "Error reading contents: %s",
+                                               strerror(-perr));
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(request->msg);
+       if (reply == NULL)
+               return;
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_TYPE_ARRAY_AS_STRING
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &array);
+       ctxt = g_markup_parse_context_new(&folder_parser, 0, &array, NULL);
+       g_markup_parse_context_parse(ctxt, contents, size, NULL);
+       g_markup_parse_context_free(ctxt);
+       dbus_message_iter_close_container(&iter, &array);
+       g_free(contents);
+
+done:
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static DBusMessage *get_folder_listing(struct map_data *map,
+                                                       DBusMessage *message,
+                                                       GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_get("x-obex/folder-listing", NULL, NULL, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       request = pending_request_new(map, message);
+
+       if (!obc_session_queue(map->session, transfer, folder_listing_cb,
+                                                       request, &err)) {
+               pending_request_free(request);
+               goto fail;
+       }
+
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, MAP_AP_MAXLISTCOUNT, num);
+}
+
+static GObexApparam *parse_folder_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *map_list_folders(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       dbus_message_iter_init(message, &args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_folder_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return get_folder_listing(map, message, apparam);
+}
+
+static void map_msg_free(void *data)
+{
+       struct map_msg *msg = data;
+
+       g_free(msg->path);
+       g_free(msg->subject);
+       g_free(msg->folder);
+       g_free(msg->timestamp);
+       g_free(msg->sender);
+       g_free(msg->sender_address);
+       g_free(msg->replyto);
+       g_free(msg->recipient);
+       g_free(msg->recipient_address);
+       g_free(msg->type);
+       g_free(msg->status);
+       g_free(msg);
+}
+
+static DBusMessage *map_msg_get(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_msg *msg = user_data;
+       struct obc_transfer *transfer;
+       const char *target_file;
+       gboolean attachment;
+       GError *err = NULL;
+       DBusMessage *reply;
+       GObexApparam *apparam;
+       char handle[17];
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &target_file,
+                               DBUS_TYPE_BOOLEAN, &attachment,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       if (snprintf(handle, sizeof(handle), "%" PRIx64, msg->handle) < 0)
+               goto fail;
+
+       transfer = obc_transfer_get("x-bt/message", handle, target_file, &err);
+       if (transfer == NULL)
+               goto fail;
+
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_ATTACHMENT,
+                                                               attachment);
+       apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_CHARSET,
+                                                               CHARSET_UTF8);
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(msg->data->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static void set_message_status_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct map_msg *msg = user_data;
+
+       if (err != NULL) {
+               g_dbus_pending_property_error(msg->pending,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       g_dbus_pending_property_success(msg->pending);
+
+done:
+       msg->pending = 0;
+}
+
+static gboolean get_folder(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->folder);
+
+       return TRUE;
+}
+
+static gboolean subject_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->subject != NULL;
+}
+
+static gboolean get_subject(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->subject);
+
+       return TRUE;
+}
+
+static gboolean timestamp_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->timestamp != NULL;
+}
+
+static gboolean get_timestamp(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->timestamp);
+
+       return TRUE;
+}
+
+static gboolean sender_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->sender != NULL;
+}
+
+static gboolean get_sender(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->sender);
+
+       return TRUE;
+}
+
+static gboolean sender_address_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->sender_address != NULL;
+}
+
+static gboolean get_sender_address(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &msg->sender_address);
+
+       return TRUE;
+}
+
+static gboolean replyto_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->replyto != NULL;
+}
+
+static gboolean get_replyto(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->replyto);
+
+       return TRUE;
+}
+
+static gboolean recipient_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->recipient != NULL;
+}
+
+static gboolean get_recipient(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->recipient);
+
+       return TRUE;
+}
+
+static gboolean recipient_address_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->recipient_address != NULL;
+}
+
+static gboolean get_recipient_address(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                               &msg->recipient_address);
+
+       return TRUE;
+}
+
+static gboolean type_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->type != NULL;
+}
+
+static gboolean get_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->type);
+
+       return TRUE;
+}
+
+static gboolean get_size(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &msg->size);
+
+       return TRUE;
+}
+
+static gboolean reception_status_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct map_msg *msg = data;
+
+       return msg->status != NULL;
+}
+
+static gboolean get_reception_status(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &msg->status);
+
+       return TRUE;
+}
+
+static gboolean get_attachment_size(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct map_msg *msg = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
+                                                       &msg->attachment_size);
+
+       return TRUE;
+}
+
+static gboolean get_flag(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, uint8_t flag,
+                                       void *data)
+{
+       struct map_msg *msg = data;
+       dbus_bool_t value = (msg->flags & flag) != 0;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static gboolean get_priority(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       return get_flag(property, iter, MAP_MSG_FLAG_PRIORITY, data);
+}
+
+static gboolean get_read(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       return get_flag(property, iter, MAP_MSG_FLAG_READ, data);
+}
+
+static gboolean get_sent(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       return get_flag(property, iter, MAP_MSG_FLAG_SENT, data);
+}
+
+static gboolean get_protected(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       return get_flag(property, iter, MAP_MSG_FLAG_PROTECTED, data);
+}
+
+static gboolean get_text(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       return get_flag(property, iter, MAP_MSG_FLAG_TEXT, data);
+}
+
+static void set_status(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       uint8_t status, void *data)
+{
+       struct map_msg *msg = data;
+       struct obc_transfer *transfer;
+       gboolean value;
+       GError *err = NULL;
+       GObexApparam *apparam;
+       char contents[1];
+       char handle[17];
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       contents[0] = FILLER_BYTE;
+
+       if (snprintf(handle, sizeof(handle), "%" PRIx64, msg->handle) < 0)
+               goto fail;
+
+       transfer = obc_transfer_put("x-bt/messageStatus", handle, NULL,
+                                       contents, sizeof(contents), &err);
+       if (transfer == NULL)
+               goto fail;
+
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_STATUSINDICATOR,
+                                                               status);
+       apparam = g_obex_apparam_set_uint8(apparam, MAP_AP_STATUSVALUE,
+                                                               value);
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(msg->data->session, transfer,
+                               set_message_status_cb, msg, &err))
+               goto fail;
+
+       msg->pending = id;
+       return;
+
+fail:
+       g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+}
+
+static void set_read(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       set_status(property, iter, id, STATUS_READ, data);
+}
+
+static void set_deleted(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       set_status(property, iter, id, STATUS_DELETE, data);
+}
+
+static const GDBusMethodTable map_msg_methods[] = {
+       { GDBUS_METHOD("Get",
+                       GDBUS_ARGS({ "targetfile", "s" },
+                                               { "attachment", "b" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                               { "properties", "a{sv}" }),
+                       map_msg_get) },
+       { }
+};
+
+static const GDBusPropertyTable map_msg_properties[] = {
+       { "Folder", "s", get_folder },
+       { "Subject", "s", get_subject, NULL, subject_exists },
+       { "Timestamp", "s", get_timestamp, NULL, timestamp_exists },
+       { "Sender", "s", get_sender, NULL, sender_exists },
+       { "SenderAddress", "s", get_sender_address, NULL,
+                                               sender_address_exists },
+       { "ReplyTo", "s", get_replyto, NULL, replyto_exists },
+       { "Recipient", "s", get_recipient, NULL, recipient_exists },
+       { "RecipientAddress", "s", get_recipient_address, NULL,
+                                               recipient_address_exists },
+       { "Type", "s", get_type, NULL, type_exists },
+       { "Size", "t", get_size },
+       { "Text", "b", get_text },
+       { "Status", "s", get_reception_status, NULL, reception_status_exists },
+       { "AttachmentSize", "t", get_attachment_size },
+       { "Priority", "b", get_priority },
+       { "Read", "b", get_read, set_read },
+       { "Sent", "b", get_sent },
+       { "Protected", "b", get_protected },
+       { "Deleted", "b", NULL, set_deleted },
+       { }
+};
+
+static void parse_type(struct map_msg *msg, const char *value)
+{
+       const char *type = NULL;
+
+       if (strcasecmp(value, "SMS_GSM") == 0)
+               type = "sms-gsm";
+       else if (strcasecmp(value, "SMS_CDMA") == 0)
+               type = "sms-cdma";
+       else if (strcasecmp(value, "EMAIL") == 0)
+               type = "email";
+       else if (strcasecmp(value, "MMS") == 0)
+               type = "mms";
+
+       if (g_strcmp0(msg->type, type) == 0)
+               return;
+
+       g_free(msg->type);
+       msg->type = g_strdup(type);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Type");
+}
+
+static struct map_msg *map_msg_create(struct map_data *data, uint64_t handle,
+                                       const char *folder, const char *type)
+{
+       struct map_msg *msg;
+
+       msg = g_new0(struct map_msg, 1);
+       msg->data = data;
+       msg->handle = handle;
+       msg->path = g_strdup_printf("%s/message%" PRIu64,
+                                       obc_session_get_path(data->session),
+                                       msg->handle);
+       msg->folder = g_strdup(folder);
+
+       if (!g_dbus_register_interface(conn, msg->path, MAP_MSG_INTERFACE,
+                                               map_msg_methods, NULL,
+                                               map_msg_properties,
+                                               msg, map_msg_free)) {
+               map_msg_free(msg);
+               return NULL;
+       }
+
+       g_hash_table_insert(data->messages, &msg->handle, msg);
+
+       if (type)
+               parse_type(msg, type);
+
+       return msg;
+}
+
+static void parse_subject(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->subject, value) == 0)
+               return;
+
+       g_free(msg->subject);
+       msg->subject = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Subject");
+}
+
+static void parse_datetime(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->timestamp, value) == 0)
+               return;
+
+       g_free(msg->timestamp);
+       msg->timestamp = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Timestamp");
+}
+
+static void parse_sender(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->sender, value) == 0)
+               return;
+
+       g_free(msg->sender);
+       msg->sender = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Sender");
+}
+
+static void parse_sender_address(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->sender_address, value) == 0)
+               return;
+
+       g_free(msg->sender_address);
+       msg->sender_address = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                       MAP_MSG_INTERFACE, "SenderAddress");
+}
+
+static void parse_replyto(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->replyto, value) == 0)
+               return;
+
+       g_free(msg->replyto);
+       msg->replyto = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "ReplyTo");
+}
+
+static void parse_recipient(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->recipient, value) == 0)
+               return;
+
+       g_free(msg->recipient);
+       msg->recipient = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Recipient");
+}
+
+static void parse_recipient_address(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->recipient_address, value) == 0)
+               return;
+
+       g_free(msg->recipient_address);
+       msg->recipient_address = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                       MAP_MSG_INTERFACE, "RecipientAddress");
+}
+
+static void parse_size(struct map_msg *msg, const char *value)
+{
+       uint64_t size = g_ascii_strtoll(value, NULL, 10);
+
+       if (msg->size == size)
+               return;
+
+       msg->size = size;
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Size");
+}
+
+static void parse_text(struct map_msg *msg, const char *value)
+{
+       gboolean flag = strcasecmp(value, "no") != 0;
+       uint8_t oldflags = msg->flags;
+
+       if (flag)
+               msg->flags |= MAP_MSG_FLAG_TEXT;
+       else
+               msg->flags &= ~MAP_MSG_FLAG_TEXT;
+
+       if (msg->flags != oldflags)
+               g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Text");
+}
+
+static void parse_status(struct map_msg *msg, const char *value)
+{
+       if (g_strcmp0(msg->status, value) == 0)
+               return;
+
+       g_free(msg->status);
+       msg->status = g_strdup(value);
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Status");
+}
+
+static void parse_attachment_size(struct map_msg *msg, const char *value)
+{
+       uint64_t attachment_size = g_ascii_strtoll(value, NULL, 10);
+
+       if (msg->attachment_size == attachment_size)
+               return;
+
+       msg->attachment_size = attachment_size;
+
+       g_dbus_emit_property_changed(conn, msg->path,
+                                       MAP_MSG_INTERFACE, "AttachmentSize");
+}
+
+static void parse_priority(struct map_msg *msg, const char *value)
+{
+       gboolean flag = strcasecmp(value, "no") != 0;
+       uint8_t oldflags = msg->flags;
+
+       if (flag)
+               msg->flags |= MAP_MSG_FLAG_PRIORITY;
+       else
+               msg->flags &= ~MAP_MSG_FLAG_PRIORITY;
+
+       if (msg->flags != oldflags)
+               g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Priority");
+}
+
+static void parse_read(struct map_msg *msg, const char *value)
+{
+       gboolean flag = strcasecmp(value, "no") != 0;
+       uint8_t oldflags = msg->flags;
+
+       if (flag)
+               msg->flags |= MAP_MSG_FLAG_READ;
+       else
+               msg->flags &= ~MAP_MSG_FLAG_READ;
+
+       if (msg->flags != oldflags)
+               g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Read");
+}
+
+static void parse_sent(struct map_msg *msg, const char *value)
+{
+       gboolean flag = strcasecmp(value, "no") != 0;
+       uint8_t oldflags = msg->flags;
+
+       if (flag)
+               msg->flags |= MAP_MSG_FLAG_SENT;
+       else
+               msg->flags &= ~MAP_MSG_FLAG_SENT;
+
+       if (msg->flags != oldflags)
+               g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Sent");
+}
+
+static void parse_protected(struct map_msg *msg, const char *value)
+{
+       gboolean flag = strcasecmp(value, "no") != 0;
+       uint8_t oldflags = msg->flags;
+
+       if (flag)
+               msg->flags |= MAP_MSG_FLAG_PROTECTED;
+       else
+               msg->flags &= ~MAP_MSG_FLAG_PROTECTED;
+
+       if (msg->flags != oldflags)
+               g_dbus_emit_property_changed(conn, msg->path,
+                                               MAP_MSG_INTERFACE, "Protected");
+}
+
+static struct map_msg_parser {
+       const char *name;
+       void (*func) (struct map_msg *msg, const char *value);
+} msg_parsers[] = {
+               { "subject", parse_subject },
+               { "datetime", parse_datetime },
+               { "sender_name", parse_sender },
+               { "sender_addressing", parse_sender_address },
+               { "replyto_addressing", parse_replyto },
+               { "recipient_name", parse_recipient },
+               { "recipient_addressing", parse_recipient_address },
+               { "type", parse_type },
+               { "size", parse_size },
+               { "text", parse_text },
+               { "reception_status", parse_status },
+               { "attachment_size", parse_attachment_size },
+               { "priority", parse_priority },
+               { "read", parse_read },
+               { "sent", parse_sent },
+               { "protected", parse_protected },
+               { }
+};
+
+static void msg_element(GMarkupParseContext *ctxt, const char *element,
+                               const char **names, const char **values,
+                               gpointer user_data, GError **gerr)
+{
+       struct map_parser *parser = user_data;
+       struct map_data *data = parser->request->map;
+       DBusMessageIter entry, *iter = parser->iter;
+       struct map_msg *msg;
+       const char *key;
+       int i;
+       uint64_t handle;
+
+       if (strcasecmp("msg", element) != 0)
+               return;
+
+       for (i = 0, key = names[i]; key; key = names[++i]) {
+               if (strcasecmp(key, "handle") == 0)
+                       break;
+       }
+
+       handle = strtoull(values[i], NULL, 16);
+
+       msg = g_hash_table_lookup(data->messages, &handle);
+       if (msg == NULL) {
+               msg = map_msg_create(data, handle, parser->request->folder,
+                                                                       NULL);
+               if (msg == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+                                                               &msg->path);
+
+       for (i = 0, key = names[i]; key; key = names[++i]) {
+               struct map_msg_parser *parser;
+
+               for (parser = msg_parsers; parser && parser->name; parser++) {
+                       if (strcasecmp(key, parser->name) == 0) {
+                               parser->func(msg, values[i]);
+                               break;
+                       }
+               }
+       }
+
+       g_dbus_get_properties(conn, msg->path, MAP_MSG_INTERFACE, &entry);
+
+       dbus_message_iter_close_container(iter, &entry);
+}
+
+static const GMarkupParser msg_parser = {
+       msg_element,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+static void message_listing_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       struct map_parser *parser;
+       GMarkupParseContext *ctxt;
+       DBusMessage *reply;
+       DBusMessageIter iter, array;
+       char *contents;
+       size_t size;
+       int perr;
+
+       if (err != NULL) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       perr = obc_transfer_get_contents(transfer, &contents, &size);
+       if (perr < 0) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "Error reading contents: %s",
+                                               strerror(-perr));
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(request->msg);
+       if (reply == NULL)
+               return;
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &array);
+
+       parser = g_new(struct map_parser, 1);
+       parser->request = request;
+       parser->iter = &array;
+
+       ctxt = g_markup_parse_context_new(&msg_parser, 0, parser, NULL);
+       g_markup_parse_context_parse(ctxt, contents, size, NULL);
+       g_markup_parse_context_free(ctxt);
+       dbus_message_iter_close_container(&iter, &array);
+       g_free(contents);
+       g_free(parser);
+
+done:
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static char *get_absolute_folder(struct map_data *map, const char *subfolder)
+{
+       const char *root = obc_session_get_folder(map->session);
+
+       if (!subfolder || strlen(subfolder) == 0)
+               return g_strdup(root);
+       else if (g_str_has_suffix(root, "/"))
+               return g_strconcat(root, subfolder, NULL);
+       else
+               return g_strconcat(root, "/", subfolder, NULL);
+}
+
+static DBusMessage *get_message_listing(struct map_data *map,
+                                                       DBusMessage *message,
+                                                       const char *folder,
+                                                       GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_get("x-bt/MAP-msg-listing", folder, NULL, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       request = pending_request_new(map, message);
+       request->folder = get_absolute_folder(map, folder);
+
+       if (!obc_session_queue(map->session, transfer, message_listing_cb,
+                                                       request, &err)) {
+               pending_request_free(request);
+               goto fail;
+       }
+
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static GObexApparam *parse_subject_length(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint8 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BYTE)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_SUBJECTLENGTH, num);
+}
+
+static uint64_t get_filter_mask(const char *filterstr)
+{
+       int i;
+
+       if (!filterstr)
+               return 0;
+
+       if (!g_ascii_strcasecmp(filterstr, "ALL"))
+               return FILTER_ALL;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+                       return 1ULL << i;
+
+       return 0;
+}
+
+static int set_field(guint32 *filter, const char *filterstr)
+{
+       guint64 mask;
+
+       mask = get_filter_mask(filterstr);
+
+       if (mask == 0)
+               return -EINVAL;
+
+       *filter |= mask;
+       return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       guint32 filter = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (set_field(&filter, string) < 0)
+                       return NULL;
+
+               dbus_message_iter_next(&array);
+       }
+
+       return g_obex_apparam_set_uint32(apparam, MAP_AP_PARAMETERMASK,
+                                                               filter);
+}
+
+static GObexApparam *parse_filter_type(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       guint8 types = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (!g_ascii_strcasecmp(string, "sms"))
+                       types |= 0x03; /* sms-gsm and sms-cdma */
+               else if (!g_ascii_strcasecmp(string, "email"))
+                       types |= 0x04; /* email */
+               else if (!g_ascii_strcasecmp(string, "mms"))
+                       types |= 0x08; /* mms */
+               else
+                       return NULL;
+
+               dbus_message_iter_next(&array);
+       }
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERMESSAGETYPE,
+                                                                       types);
+}
+
+static GObexApparam *parse_period_begin(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODBEGIN,
+                                                               string);
+}
+
+static GObexApparam *parse_period_end(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERPERIODEND,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_read(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint8 status = FILTER_READ_STATUS_NONE;
+       dbus_bool_t dbus_status = FALSE;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &dbus_status);
+
+       if (dbus_status)
+               status = FILTER_READ_STATUS_ONLY_READ;
+       else
+               status = FILTER_READ_STATUS_ONLY_UNREAD;
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERREADSTATUS,
+                                                               status);
+}
+
+static GObexApparam *parse_filter_recipient(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERRECIPIENT,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_sender(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       return g_obex_apparam_set_string(apparam, MAP_AP_FILTERORIGINATOR,
+                                                               string);
+}
+
+static GObexApparam *parse_filter_priority(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint8 priority = FILTER_PRIORITY_NONE;
+       dbus_bool_t dbus_priority = FALSE;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &dbus_priority);
+
+       if (dbus_priority)
+               priority = FILTER_PRIORITY_ONLY_HIGH;
+       else
+               priority = FILTER_PRIORITY_ONLY_NONHIGH;
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_FILTERPRIORITY,
+                                                               priority);
+}
+
+static GObexApparam *parse_message_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       DBG("");
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "SubjectLength") == 0) {
+                       if (parse_subject_length(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Fields") == 0) {
+                       if (parse_fields(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Types") == 0) {
+                       if (parse_filter_type(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "PeriodBegin") == 0) {
+                       if (parse_period_begin(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "PeriodEnd") == 0) {
+                       if (parse_period_end(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Read") == 0) {
+                       if (parse_filter_read(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Recipient") == 0) {
+                       if (parse_filter_recipient(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Sender") == 0) {
+                       if (parse_filter_sender(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Priority") == 0) {
+                       if (parse_filter_priority(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *map_list_messages(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       const char *folder;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &folder);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAP_AP_MAXLISTCOUNT,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, MAP_AP_STARTOFFSET,
+                                                       DEFAULT_OFFSET);
+
+       dbus_message_iter_next(&args);
+
+       if (parse_message_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return get_message_listing(map, message, folder, apparam);
+}
+
+static char **get_filter_strs(uint64_t filter, int *size)
+{
+       char **list, **item;
+       int i;
+
+       list = g_malloc0(sizeof(char **) * (FILTER_BIT_MAX + 2));
+
+       item = list;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup(filter_list[i]);
+
+       *item = NULL;
+       *size = item - list;
+       return list;
+}
+
+static DBusMessage *map_list_filter_fields(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       char **filters = NULL;
+       int size;
+       DBusMessage *reply;
+
+       filters = get_filter_strs(FILTER_ALL, &size);
+       reply = dbus_message_new_method_return(message);
+       dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING, &filters, size,
+                               DBUS_TYPE_INVALID);
+
+       g_strfreev(filters);
+       return reply;
+}
+
+static void update_inbox_cb(struct obc_session *session,
+                               struct obc_transfer *transfer,
+                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       DBusMessage *reply;
+
+       if (err != NULL) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(request->msg);
+
+done:
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static DBusMessage *map_update_inbox(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       DBusMessage *reply;
+       char contents[1];
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       struct pending_request *request;
+
+       contents[0] = FILLER_BYTE;
+
+       transfer = obc_transfer_put("x-bt/MAP-messageUpdate", NULL, NULL,
+                                               contents, sizeof(contents),
+                                               &err);
+       if (transfer == NULL)
+               goto fail;
+
+       request = pending_request_new(map, message);
+
+       if (!obc_session_queue(map->session, transfer, update_inbox_cb,
+                                                       request, &err)) {
+               pending_request_free(request);
+               goto fail;
+       }
+
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *push_message(struct map_data *map,
+                                                       DBusMessage *message,
+                                                       const char *filename,
+                                                       const char *folder,
+                                                       GObexApparam *apparam)
+{
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_put("x-bt/message", folder, filename,
+                                                               NULL, 0, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(map->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static GObexApparam *parse_transparent(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       dbus_bool_t transparent;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &transparent);
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_TRANSPARENT,
+                                               transparent ? TRUE : FALSE);
+}
+
+static GObexApparam *parse_retry(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       dbus_bool_t retry;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &retry);
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_RETRY,
+                                                       retry ? TRUE : FALSE);
+}
+
+static GObexApparam *parse_charset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       guint8 charset = 0;
+       const char *string;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       if (strcasecmp(string, "native") == 0)
+               charset = CHARSET_NATIVE;
+       else if (strcasecmp(string, "utf8") == 0)
+               charset = CHARSET_UTF8;
+       else
+               return NULL;
+
+       return g_obex_apparam_set_uint8(apparam, MAP_AP_CHARSET, charset);
+}
+
+static GObexApparam *parse_push_options(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Transparent") == 0) {
+                       if (parse_transparent(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Retry") == 0) {
+                       if (parse_retry(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Charset") == 0) {
+                       if (parse_charset(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *map_push_message(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct map_data *map = user_data;
+       char *filename;
+       char *folder;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &filename);
+
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       dbus_message_iter_get_basic(&args, &folder);
+
+       dbus_message_iter_next(&args);
+
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_CHARSET, CHARSET_UTF8);
+
+       if (parse_push_options(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return push_message(map, message, filename, folder, apparam);
+}
+
+static const GDBusMethodTable map_methods[] = {
+       { GDBUS_ASYNC_METHOD("SetFolder",
+                               GDBUS_ARGS({ "name", "s" }), NULL,
+                               map_setpath) },
+       { GDBUS_ASYNC_METHOD("ListFolders",
+                       GDBUS_ARGS({ "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "content", "aa{sv}" }),
+                       map_list_folders) },
+       { GDBUS_ASYNC_METHOD("ListMessages",
+                       GDBUS_ARGS({ "folder", "s" }, { "filter", "a{sv}" }),
+                       GDBUS_ARGS({ "messages", "a{oa{sv}}" }),
+                       map_list_messages) },
+       { GDBUS_METHOD("ListFilterFields",
+                       NULL,
+                       GDBUS_ARGS({ "fields", "as" }),
+                       map_list_filter_fields) },
+       { GDBUS_ASYNC_METHOD("UpdateInbox",
+                       NULL,
+                       NULL,
+                       map_update_inbox) },
+       { GDBUS_ASYNC_METHOD("PushMessage",
+                       GDBUS_ARGS({ "file", "s" }, { "folder", "s" },
+                                               { "args", "a{sv}" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                               { "properties", "a{sv}" }),
+                       map_push_message) },
+       { }
+};
+
+static void map_msg_remove(void *data)
+{
+       struct map_msg *msg = data;
+       char *path;
+
+       path = msg->path;
+       msg->path = NULL;
+       g_dbus_unregister_interface(conn, path, MAP_MSG_INTERFACE);
+       g_free(path);
+}
+
+static void map_handle_new_message(struct map_data *map,
+                                                       struct map_event *event)
+{
+       struct map_msg *msg;
+
+       msg = g_hash_table_lookup(map->messages, &event->handle);
+       /* New message event can be used if a new message replaces an old one */
+       if (msg)
+               g_hash_table_remove(map->messages, &event->handle);
+
+       map_msg_create(map, event->handle, event->folder, event->msg_type);
+}
+
+static void map_handle_status_changed(struct map_data *map,
+                                                       struct map_event *event,
+                                                       const char *status)
+{
+       struct map_msg *msg;
+
+       msg = g_hash_table_lookup(map->messages, &event->handle);
+       if (msg == NULL)
+               return;
+
+       if (g_strcmp0(msg->status, status) == 0)
+               return;
+
+       g_free(msg->status);
+       msg->status = g_strdup(status);
+
+       g_dbus_emit_property_changed(conn, msg->path, MAP_MSG_INTERFACE,
+                                                               "Status");
+}
+
+static void map_handle_folder_changed(struct map_data *map,
+                                                       struct map_event *event,
+                                                       const char *folder)
+{
+       struct map_msg *msg;
+
+       if (!folder)
+               return;
+
+       msg = g_hash_table_lookup(map->messages, &event->handle);
+       if (!msg)
+               return;
+
+       if (g_strcmp0(msg->folder, folder) == 0)
+               return;
+
+       g_free(msg->folder);
+       msg->folder = g_strdup(folder);
+
+       g_dbus_emit_property_changed(conn, msg->path, MAP_MSG_INTERFACE,
+                                                               "Folder");
+}
+
+static void map_handle_notification(struct map_event *event, void *user_data)
+{
+       struct map_data *map = user_data;
+
+       DBG("Event report for %s:%d", obc_session_get_destination(map->session),
+                                                       map->mas_instance_id);
+       DBG("type=%x handle=%" PRIx64 " folder=%s old_folder=%s msg_type=%s",
+               event->type, event->handle, event->folder, event->old_folder,
+               event->msg_type);
+
+       switch (event->type) {
+       case MAP_ET_NEW_MESSAGE:
+               map_handle_new_message(map, event);
+               break;
+       case MAP_ET_DELIVERY_SUCCESS:
+               map_handle_status_changed(map, event, "delivery-success");
+               break;
+       case MAP_ET_SENDING_SUCCESS:
+               map_handle_status_changed(map, event, "sending-success");
+               break;
+       case MAP_ET_DELIVERY_FAILURE:
+               map_handle_status_changed(map, event, "delivery-failure");
+               break;
+       case MAP_ET_SENDING_FAILURE:
+               map_handle_status_changed(map, event, "sending-failure");
+               break;
+       case MAP_ET_MESSAGE_DELETED:
+               map_handle_folder_changed(map, event, "/telecom/msg/deleted");
+               break;
+       case MAP_ET_MESSAGE_SHIFT:
+               map_handle_folder_changed(map, event, event->folder);
+               break;
+       default:
+               break;
+       }
+}
+
+static bool set_notification_registration(struct map_data *map, bool status)
+{
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       GObexApparam *apparam;
+       char contents[1];
+       const char *address;
+
+       address = obc_session_get_destination(map->session);
+       if (!address || map->mas_instance_id < 0)
+               return FALSE;
+
+       if (status) {
+               map_register_event_handler(map->session, map->mas_instance_id,
+                                               &map_handle_notification, map);
+       } else {
+               map_unregister_event_handler(map->session,
+                                                       map->mas_instance_id);
+       }
+
+       contents[0] = FILLER_BYTE;
+
+       transfer = obc_transfer_put("x-bt/MAP-NotificationRegistration", NULL,
+                                       NULL, contents, sizeof(contents), &err);
+
+       if (transfer == NULL)
+               return false;
+
+       apparam = g_obex_apparam_set_uint8(NULL, MAP_AP_NOTIFICATIONSTATUS,
+                                                                       status);
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (obc_session_queue(map->session, transfer, NULL, map, &err))
+               return true;
+
+       return false;
+}
+
+static void map_free(void *data)
+{
+       struct map_data *map = data;
+
+       set_notification_registration(map, false);
+
+       obc_session_unref(map->session);
+       g_hash_table_unref(map->messages);
+       g_free(map);
+}
+
+static void parse_service_record(struct map_data *map)
+{
+       const void *data;
+
+       /* MAS instance id */
+       map->mas_instance_id = -1;
+       data = obc_session_get_attribute(map->session,
+                                               SDP_ATTR_MAS_INSTANCE_ID);
+       if (data != NULL)
+               map->mas_instance_id = *(uint8_t *)data;
+       else
+               DBG("Failed to read MAS instance id");
+
+       /* Supported Message Types */
+       data = obc_session_get_attribute(map->session,
+                                       SDP_ATTR_SUPPORTED_MESSAGE_TYPES);
+       if (data != NULL)
+               map->supported_message_types = *(uint8_t *)data;
+       else
+               DBG("Failed to read supported message types");
+}
+
+static int map_probe(struct obc_session *session)
+{
+       struct map_data *map;
+       const char *path;
+
+       path = obc_session_get_path(session);
+
+       map = g_try_new0(struct map_data, 1);
+       if (!map)
+               return -ENOMEM;
+
+       map->session = obc_session_ref(session);
+       map->messages = g_hash_table_new_full(g_int64_hash, g_int64_equal, NULL,
+                                                               map_msg_remove);
+
+       parse_service_record(map);
+
+       DBG("%s, instance id %d", path, map->mas_instance_id);
+
+       set_notification_registration(map, true);
+
+       if (!g_dbus_register_interface(conn, path, MAP_INTERFACE, map_methods,
+                                       NULL, NULL, map, map_free)) {
+               map_free(map);
+
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void map_remove(struct obc_session *session)
+{
+       const char *path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(conn, path, MAP_INTERFACE);
+}
+
+static struct obc_driver map = {
+       .service = "MAP",
+       .uuid = MAS_UUID,
+       .target = OBEX_MAS_UUID,
+       .target_len = OBEX_MAS_UUID_LEN,
+       .probe = map_probe,
+       .remove = map_remove
+};
+
+int map_init(void)
+{
+       int err;
+
+       DBG("");
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!conn)
+               return -EIO;
+
+       err = obc_driver_register(&map);
+       if (err < 0) {
+               dbus_connection_unref(conn);
+               conn = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+void map_exit(void)
+{
+       DBG("");
+
+       dbus_connection_unref(conn);
+       conn = NULL;
+
+       obc_driver_unregister(&map);
+}
diff --git a/obexd/client/map.h b/obexd/client/map.h
new file mode 100644 (file)
index 0000000..86f6b95
--- /dev/null
@@ -0,0 +1,24 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2011  Bartosz Szatkowski <bulislaw@linux.com> for Comarch
+ *
+ *  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 map_init(void);
+void map_exit(void);
diff --git a/obexd/client/mns.c b/obexd/client/mns.c
new file mode 100644 (file)
index 0000000..d638886
--- /dev/null
@@ -0,0 +1,370 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2013  BMW Car IT GmbH. 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 <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <fcntl.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <stdlib.h>
+
+#include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "mimetype.h"
+#include "map_ap.h"
+#include "map-event.h"
+
+#include "obexd/src/manager.h"
+
+struct mns_session {
+       GString *buffer;
+       GObexApparam *inparams;
+       char *remote_address;
+       uint8_t mas_instance_id;
+};
+
+static const uint8_t MNS_TARGET[TARGET_SIZE] = {
+                       0xbb, 0x58, 0x2b, 0x41, 0x42, 0x0c, 0x11, 0xdb,
+                       0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66  };
+
+static int get_params(struct obex_session *os, struct mns_session *mns)
+{
+       const uint8_t *buffer;
+       ssize_t size;
+
+       size = obex_get_apparam(os, &buffer);
+       if (size < 0)
+               size = 0;
+
+       mns->inparams = g_obex_apparam_decode(buffer, size);
+       if (mns->inparams == NULL) {
+               DBG("Error when parsing parameters!");
+               return -EBADR;
+       }
+
+       return 0;
+}
+
+static void reset_request(struct mns_session *mns)
+{
+       if (mns->buffer) {
+               g_string_free(mns->buffer, TRUE);
+               mns->buffer = NULL;
+       }
+
+       if (mns->inparams) {
+               g_obex_apparam_free(mns->inparams);
+               mns->inparams = NULL;
+       }
+}
+
+static void mns_session_free(struct mns_session *mns)
+{
+       reset_request(mns);
+
+       if (mns->remote_address)
+               g_free(mns->remote_address);
+
+       g_free(mns);
+}
+
+static void *mns_connect(struct obex_session *os, int *err)
+{
+       struct mns_session *mns;
+       char *address;
+
+       manager_register_session(os);
+
+       mns = g_new0(struct mns_session, 1);
+
+       if (obex_getpeername(os, &address) == 0) {
+               mns->remote_address = g_strdup(address);
+               g_free(address);
+       }
+
+       DBG("MNS connected to %s", mns->remote_address);
+
+       if (err)
+               *err = 0;
+
+       return mns;
+}
+
+static void mns_disconnect(struct obex_session *os, void *user_data)
+{
+       struct mns_session *mns = user_data;
+
+       DBG("MNS disconnected from %s", mns->remote_address);
+
+       manager_unregister_session(os);
+
+       mns_session_free(mns);
+}
+
+static int mns_put(struct obex_session *os, void *user_data)
+{
+       struct mns_session *mns = user_data;
+       const char *type = obex_get_type(os);
+       const char *name = obex_get_name(os);
+       int ret;
+
+       DBG("PUT: name %s type %s mns %p", name, type, mns);
+
+       if (type == NULL)
+               return -EBADR;
+
+       ret = get_params(os, mns);
+       if (ret < 0)
+               goto failed;
+
+       ret = obex_put_stream_start(os, name);
+       if (ret < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       reset_request(mns);
+
+       return ret;
+}
+
+static void parse_event_report_type(struct map_event *event, const char *value)
+{
+       if (!g_ascii_strcasecmp(value, "NewMessage"))
+               event->type = MAP_ET_NEW_MESSAGE;
+       else if (!g_ascii_strcasecmp(value, "DeliverySuccess"))
+               event->type = MAP_ET_DELIVERY_SUCCESS;
+       else if (!g_ascii_strcasecmp(value, "SendingSuccess"))
+               event->type = MAP_ET_SENDING_SUCCESS;
+       else if (!g_ascii_strcasecmp(value, "DeliveryFailure"))
+               event->type = MAP_ET_DELIVERY_FAILURE;
+       else if (!g_ascii_strcasecmp(value, "SendingFailure"))
+               event->type = MAP_ET_SENDING_FAILURE;
+       else if (!g_ascii_strcasecmp(value, "MemoryFull"))
+               event->type = MAP_ET_MEMORY_FULL;
+       else if (!g_ascii_strcasecmp(value, "MemoryAvailable"))
+               event->type = MAP_ET_MEMORY_AVAILABLE;
+       else if (!g_ascii_strcasecmp(value, "MessageDeleted"))
+               event->type = MAP_ET_MESSAGE_DELETED;
+       else if (!g_ascii_strcasecmp(value, "MessageShift"))
+               event->type = MAP_ET_MESSAGE_SHIFT;
+}
+
+static void parse_event_report_handle(struct map_event *event,
+                                                       const char *value)
+{
+       event->handle = strtoull(value, NULL, 16);
+}
+
+static void parse_event_report_folder(struct map_event *event,
+                                                       const char *value)
+{
+       if (!value)
+               return;
+
+       if (g_str_has_prefix(value, "/"))
+               event->folder = g_strdup(value);
+       else
+               event->folder = g_strconcat("/", value, NULL);
+}
+
+static void parse_event_report_old_folder(struct map_event *event,
+                                                       const char *value)
+{
+       if (!value)
+               return;
+
+       if (g_str_has_prefix(value, "/"))
+               event->old_folder = g_strdup(value);
+       else
+               event->old_folder = g_strconcat("/", value, NULL);
+}
+
+static void parse_event_report_msg_type(struct map_event *event,
+                                                       const char *value)
+{
+       event->msg_type = g_strdup(value);
+}
+
+static struct map_event_report_parser {
+       const char *name;
+       void (*func) (struct map_event *event, const char *value);
+} event_report_parsers[] = {
+               { "type", parse_event_report_type },
+               { "handle", parse_event_report_handle },
+               { "folder", parse_event_report_folder },
+               { "old_folder", parse_event_report_old_folder },
+               { "msg_type", parse_event_report_msg_type },
+               { }
+};
+
+static void event_report_element(GMarkupParseContext *ctxt,
+                               const char *element, const char **names,
+                               const char **values, gpointer user_data,
+                                                               GError **gerr)
+{
+       struct map_event *event = user_data;
+       const char *key;
+       int i;
+
+       if (strcasecmp("event", element) != 0)
+               return;
+
+       for (i = 0, key = names[i]; key; key = names[++i]) {
+               struct map_event_report_parser *parser;
+
+               for (parser = event_report_parsers; parser && parser->name;
+                                                               parser++) {
+                       if (strcasecmp(key, parser->name) == 0) {
+                               parser->func(event, values[i]);
+                               break;
+                       }
+               }
+       }
+}
+
+static const GMarkupParser event_report_parser = {
+       event_report_element,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+
+static void map_event_free(struct map_event *event)
+{
+       g_free(event->folder);
+       g_free(event->old_folder);
+       g_free(event->msg_type);
+       g_free(event);
+}
+
+static void *event_report_open(const char *name, int oflag, mode_t mode,
+                               void *driver_data, size_t *size, int *err)
+{
+       struct mns_session *mns = driver_data;
+
+       DBG("");
+
+       g_obex_apparam_get_uint8(mns->inparams, MAP_AP_MASINSTANCEID,
+                                                       &mns->mas_instance_id);
+
+       mns->buffer = g_string_new("");
+
+       if (err != NULL)
+               *err = 0;
+
+       return mns;
+}
+
+static int event_report_close(void *obj)
+{
+       struct mns_session *mns = obj;
+       GMarkupParseContext *ctxt;
+       struct map_event *event;
+
+       DBG("");
+
+       event = g_new0(struct map_event, 1);
+       ctxt = g_markup_parse_context_new(&event_report_parser, 0, event,
+                                                                       NULL);
+       g_markup_parse_context_parse(ctxt, mns->buffer->str, mns->buffer->len,
+                                                                       NULL);
+       g_markup_parse_context_free(ctxt);
+
+       map_dispatch_event(mns->mas_instance_id, mns->remote_address, event);
+       map_event_free(event);
+
+       reset_request(mns);
+
+       return 0;
+}
+
+static ssize_t event_report_write(void *obj, const void *buf, size_t count)
+{
+       struct mns_session *mns = obj;
+
+       DBG("");
+
+       g_string_append_len(mns->buffer, buf, count);
+       return count;
+}
+
+static struct obex_service_driver mns = {
+       .name = "Message Notification server",
+       .service = OBEX_MNS,
+       .target = MNS_TARGET,
+       .target_size = TARGET_SIZE,
+       .connect = mns_connect,
+       .put = mns_put,
+       .disconnect = mns_disconnect,
+};
+
+static struct obex_mime_type_driver mime_event_report = {
+       .target = MNS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/MAP-event-report",
+       .open = event_report_open,
+       .close = event_report_close,
+       .write = event_report_write,
+};
+
+static int mns_init(void)
+{
+       int err;
+
+       err = obex_mime_type_driver_register(&mime_event_report);
+       if (err < 0)
+               goto fail_mime_event;
+
+       err = obex_service_driver_register(&mns);
+       if (err < 0)
+               goto fail_mns_reg;
+
+       return 0;
+
+fail_mns_reg:
+       obex_mime_type_driver_unregister(&mime_event_report);
+fail_mime_event:
+       return err;
+}
+
+static void mns_exit(void)
+{
+       obex_service_driver_unregister(&mns);
+       obex_mime_type_driver_unregister(&mime_event_report);
+}
+
+OBEX_PLUGIN_DEFINE(mns, mns_init, mns_exit)
diff --git a/obexd/client/opp.c b/obexd/client/opp.c
new file mode 100644 (file)
index 0000000..d6fd1c6
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "opp.h"
+
+#define OPP_UUID "00001105-0000-1000-8000-00805f9b34fb"
+#define OPP_INTERFACE "org.bluez.obex.ObjectPush1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+
+struct opp_data {
+       struct obc_session *session;
+};
+
+static DBusConnection *conn = NULL;
+
+static DBusMessage *opp_send_file(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct opp_data *opp = user_data;
+       struct obc_transfer *transfer;
+       DBusMessage *reply;
+       char *filename;
+       char *basename;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &filename,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       basename = g_path_get_basename(filename);
+
+       transfer = obc_transfer_put(NULL, basename, filename, NULL, 0, &err);
+
+       g_free(basename);
+
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(opp->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Failed", "%s", err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *opp_pull_business_card(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct opp_data *opp = user_data;
+       struct obc_transfer *pull;
+       DBusMessage *reply;
+       const char *filename = NULL;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                               DBUS_TYPE_STRING, &filename,
+                               DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       pull = obc_transfer_get("text/x-vcard", NULL, filename, &err);
+       if (pull == NULL)
+               goto fail;
+
+       if (!obc_session_queue(opp->session, pull, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(pull, message);
+
+fail:
+       reply = g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Failed", "%s", err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *opp_exchange_business_cards(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       return g_dbus_create_error(message, ERROR_INTERFACE ".Failed", NULL);
+}
+
+static const GDBusMethodTable opp_methods[] = {
+       { GDBUS_METHOD("SendFile",
+               GDBUS_ARGS({ "sourcefile", "s" }),
+               GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+               opp_send_file) },
+       { GDBUS_METHOD("PullBusinessCard",
+               GDBUS_ARGS({ "targetfile", "s" }),
+               GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+               opp_pull_business_card) },
+       { GDBUS_METHOD("ExchangeBusinessCards",
+               GDBUS_ARGS({ "clientfile", "s" }, { "targetfile", "s" }),
+               GDBUS_ARGS({ "transfer", "o" }, { "properties", "a{sv}" }),
+               opp_exchange_business_cards) },
+       { }
+};
+
+static void opp_free(void *data)
+{
+       struct opp_data *opp = data;
+
+       obc_session_unref(opp->session);
+       g_free(opp);
+}
+
+static int opp_probe(struct obc_session *session)
+{
+       struct opp_data *opp;
+       const char *path;
+
+       path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       opp = g_try_new0(struct opp_data, 1);
+       if (!opp)
+               return -ENOMEM;
+
+       opp->session = obc_session_ref(session);
+
+       if (!g_dbus_register_interface(conn, path, OPP_INTERFACE, opp_methods,
+                                               NULL, NULL, opp, opp_free)) {
+               opp_free(opp);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void opp_remove(struct obc_session *session)
+{
+       const char *path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(conn, path, OPP_INTERFACE);
+}
+
+static struct obc_driver opp = {
+       .service = "OPP",
+       .uuid = OPP_UUID,
+       .probe = opp_probe,
+       .remove = opp_remove
+};
+
+int opp_init(void)
+{
+       int err;
+
+       DBG("");
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!conn)
+               return -EIO;
+
+       err = obc_driver_register(&opp);
+       if (err < 0) {
+               dbus_connection_unref(conn);
+               conn = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+void opp_exit(void)
+{
+       DBG("");
+
+       dbus_connection_unref(conn);
+       conn = NULL;
+
+       obc_driver_unregister(&opp);
+}
diff --git a/obexd/client/opp.h b/obexd/client/opp.h
new file mode 100644 (file)
index 0000000..a23e94e
--- /dev/null
@@ -0,0 +1,25 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2011 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int opp_init(void);
+void opp_exit(void);
diff --git a/obexd/client/pbap.c b/obexd/client/pbap.c
new file mode 100644 (file)
index 0000000..2089860
--- /dev/null
@@ -0,0 +1,1031 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <stdio.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <gobex/gobex-apparam.h>
+
+#include "log.h"
+
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "pbap.h"
+
+#define OBEX_PBAP_UUID \
+       "\x79\x61\x35\xF0\xF0\xC5\x11\xD8\x09\x66\x08\x00\x20\x0C\x9A\x66"
+#define OBEX_PBAP_UUID_LEN 16
+
+#define FORMAT_VCARD21 0x0
+#define FORMAT_VCARD30 0x1
+
+#define ORDER_INDEXED          0x0
+#define ORDER_ALPHANUMERIC     0x1
+#define ORDER_PHONETIC         0x2
+
+#define ATTRIB_NAME            0x0
+#define ATTRIB_NUMBER          0x1
+#define ATTRIB_SOUND           0x2
+
+#define DEFAULT_COUNT  65535
+#define DEFAULT_OFFSET 0
+
+#define PULLPHONEBOOK          0x1
+#define GETPHONEBOOKSIZE       0x2
+
+#define ORDER_TAG              0x01
+#define SEARCHVALUE_TAG                0x02
+#define SEARCHATTRIB_TAG       0x03
+#define MAXLISTCOUNT_TAG       0x04
+#define LISTSTARTOFFSET_TAG    0x05
+#define FILTER_TAG             0x06
+#define FORMAT_TAG             0X07
+#define PHONEBOOKSIZE_TAG      0X08
+#define NEWMISSEDCALLS_TAG     0X09
+
+static const char *filter_list[] = {
+       "VERSION",
+       "FN",
+       "N",
+       "PHOTO",
+       "BDAY",
+       "ADR",
+       "LABEL",
+       "TEL",
+       "EMAIL",
+       "MAILER",
+       "TZ",
+       "GEO",
+       "TITLE",
+       "ROLE",
+       "LOGO",
+       "AGENT",
+       "ORG",
+       "NOTE",
+       "REV",
+       "SOUND",
+       "URL",
+       "UID",
+       "KEY",
+       "NICKNAME",
+       "CATEGORIES",
+       "PROID",
+       "CLASS",
+       "SORT-STRING",
+       "X-IRMC-CALL-DATETIME",
+       NULL
+};
+
+#define FILTER_BIT_MAX 63
+#define FILTER_ALL     0xFFFFFFFFFFFFFFFFULL
+
+#define PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define PBAP_UUID "0000112f-0000-1000-8000-00805f9b34fb"
+
+struct pbap_data {
+       struct obc_session *session;
+       char *path;
+};
+
+struct pending_request {
+       struct pbap_data *pbap;
+       DBusMessage *msg;
+};
+
+static DBusConnection *conn = NULL;
+
+static struct pending_request *pending_request_new(struct pbap_data *pbap,
+                                                       DBusMessage *message)
+{
+       struct pending_request *p;
+
+       p = g_new0(struct pending_request, 1);
+       p->pbap = pbap;
+       p->msg = dbus_message_ref(message);
+
+       return p;
+}
+
+static void pending_request_free(struct pending_request *p)
+{
+       dbus_message_unref(p->msg);
+       g_free(p);
+}
+
+static void listing_element(GMarkupParseContext *ctxt,
+                               const char *element,
+                               const char **names,
+                               const char **values,
+                               gpointer user_data,
+                               GError **gerr)
+{
+       DBusMessageIter *item = user_data, entry;
+       char **key;
+       const char *handle = NULL, *vcardname = NULL;
+
+       if (g_str_equal(element, "card") != TRUE)
+               return;
+
+       for (key = (char **) names; *key; key++, values++) {
+               if (g_str_equal(*key, "handle") == TRUE)
+                       handle = *values;
+               else if (g_str_equal(*key, "name") == TRUE)
+                       vcardname = *values;
+       }
+
+       if (!handle || !vcardname)
+               return;
+
+       dbus_message_iter_open_container(item, DBUS_TYPE_STRUCT, NULL, &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &handle);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &vcardname);
+       dbus_message_iter_close_container(item, &entry);
+}
+
+static const GMarkupParser listing_parser = {
+       listing_element,
+       NULL,
+       NULL,
+       NULL,
+       NULL
+};
+static char *build_phonebook_path(const char *location, const char *item)
+{
+       char *path = NULL, *tmp, *tmp1;
+
+       if (!g_ascii_strcasecmp(location, "int") ||
+                       !g_ascii_strcasecmp(location, "internal"))
+               path = g_strdup("/telecom");
+       else if (!g_ascii_strncasecmp(location, "sim", 3)) {
+               if (strlen(location) == 3)
+                       tmp = g_strdup("sim1");
+               else
+                       tmp = g_ascii_strup(location, 4);
+
+               path = g_build_filename("/", tmp, "telecom", NULL);
+               g_free(tmp);
+       } else
+               return NULL;
+
+       if (!g_ascii_strcasecmp(item, "pb") ||
+               !g_ascii_strcasecmp(item, "ich") ||
+               !g_ascii_strcasecmp(item, "och") ||
+               !g_ascii_strcasecmp(item, "mch") ||
+               !g_ascii_strcasecmp(item, "cch")) {
+               tmp = path;
+               tmp1 = g_ascii_strdown(item, -1);
+               path = g_build_filename(tmp, tmp1, NULL);
+               g_free(tmp);
+               g_free(tmp1);
+       } else {
+               g_free(path);
+               return NULL;
+       }
+
+       return path;
+}
+
+/* should only be called inside pbap_set_path */
+static void pbap_reset_path(struct pbap_data *pbap)
+{
+       if (!pbap->path)
+               return;
+
+       obc_session_setpath(pbap->session, pbap->path, NULL, NULL, NULL);
+}
+
+static void pbap_setpath_cb(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       struct pbap_data *pbap = request->pbap;
+
+       if (err != NULL)
+               pbap_reset_path(pbap);
+
+       if (err) {
+               DBusMessage *reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               g_dbus_send_message(conn, reply);
+       } else
+               g_dbus_send_reply(conn, request->msg, DBUS_TYPE_INVALID);
+
+       pending_request_free(request);
+}
+
+static void read_return_apparam(struct obc_transfer *transfer,
+                               guint16 *phone_book_size, guint8 *new_missed_calls)
+{
+       GObexApparam *apparam;
+
+       *phone_book_size = 0;
+       *new_missed_calls = 0;
+
+       apparam = obc_transfer_get_apparam(transfer);
+       if (apparam == NULL)
+               return;
+
+       g_obex_apparam_get_uint16(apparam, PHONEBOOKSIZE_TAG,
+                                                       phone_book_size);
+       g_obex_apparam_get_uint8(apparam, NEWMISSEDCALLS_TAG,
+                                                       new_missed_calls);
+}
+
+static void phonebook_size_callback(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       DBusMessage *reply;
+       guint16 phone_book_size;
+       guint8 new_missed_calls;
+
+       if (err) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto send;
+       }
+
+       reply = dbus_message_new_method_return(request->msg);
+
+       read_return_apparam(transfer, &phone_book_size, &new_missed_calls);
+
+       dbus_message_append_args(reply,
+                       DBUS_TYPE_UINT16, &phone_book_size,
+                       DBUS_TYPE_INVALID);
+
+send:
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static void pull_vcard_listing_callback(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *request = user_data;
+       GMarkupParseContext *ctxt;
+       DBusMessage *reply;
+       DBusMessageIter iter, array;
+       char *contents;
+       size_t size;
+       int perr;
+
+       if (err) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", err->message);
+               goto send;
+       }
+
+       perr = obc_transfer_get_contents(transfer, &contents, &size);
+       if (perr < 0) {
+               reply = g_dbus_create_error(request->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "Error reading contents: %s",
+                                               strerror(-perr));
+               goto send;
+       }
+
+       reply = dbus_message_new_method_return(request->msg);
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_STRUCT_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_STRING_AS_STRING
+                       DBUS_STRUCT_END_CHAR_AS_STRING, &array);
+       ctxt = g_markup_parse_context_new(&listing_parser, 0, &array, NULL);
+       g_markup_parse_context_parse(ctxt, contents, size, NULL);
+       g_markup_parse_context_free(ctxt);
+       dbus_message_iter_close_container(&iter, &array);
+       g_free(contents);
+
+send:
+       g_dbus_send_message(conn, reply);
+       pending_request_free(request);
+}
+
+static GObexApparam *parse_format(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       const char *string;
+       guint8 format;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       if (!string || g_str_equal(string, ""))
+               format = FORMAT_VCARD21;
+       else if (!g_ascii_strcasecmp(string, "vcard21"))
+               format = FORMAT_VCARD21;
+       else if (!g_ascii_strcasecmp(string, "vcard30"))
+               format = FORMAT_VCARD30;
+       else
+               return NULL;
+
+       return g_obex_apparam_set_uint8(apparam, FORMAT_TAG, format);
+}
+
+static GObexApparam *parse_order(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       const char *string;
+       guint8 order;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &string);
+
+       if (!string || g_str_equal(string, ""))
+               order = ORDER_INDEXED;
+       else if (!g_ascii_strcasecmp(string, "indexed"))
+               order = ORDER_INDEXED;
+       else if (!g_ascii_strcasecmp(string, "alphanumeric"))
+               order = ORDER_ALPHANUMERIC;
+       else if (!g_ascii_strcasecmp(string, "phonetic"))
+               order = ORDER_PHONETIC;
+       else
+               return NULL;
+
+       return g_obex_apparam_set_uint8(apparam, ORDER_TAG, order);
+}
+
+static GObexApparam *parse_offset(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG, num);
+}
+
+static GObexApparam *parse_max_count(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       guint16 num;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16)
+               return NULL;
+
+       dbus_message_iter_get_basic(iter, &num);
+
+       return g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG, num);
+}
+
+static uint64_t get_filter_mask(const char *filterstr)
+{
+       int i, bit = -1;
+
+       if (!filterstr)
+               return 0;
+
+       if (!g_ascii_strcasecmp(filterstr, "ALL"))
+               return FILTER_ALL;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (!g_ascii_strcasecmp(filterstr, filter_list[i]))
+                       return 1ULL << i;
+
+       if (strlen(filterstr) < 4 || strlen(filterstr) > 5
+                       || g_ascii_strncasecmp(filterstr, "bit", 3) != 0)
+               return 0;
+
+       sscanf(&filterstr[3], "%d", &bit);
+       if (bit >= 0 && bit <= FILTER_BIT_MAX)
+               return 1ULL << bit;
+       else
+               return 0;
+}
+
+static int set_field(guint64 *filter, const char *filterstr)
+{
+       guint64 mask;
+
+       mask = get_filter_mask(filterstr);
+
+       if (mask == 0)
+               return -EINVAL;
+
+       *filter |= mask;
+       return 0;
+}
+
+static GObexApparam *parse_fields(GObexApparam *apparam, DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       guint64 filter = 0;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_STRING) {
+               const char *string;
+
+               dbus_message_iter_get_basic(&array, &string);
+
+               if (set_field(&filter, string) < 0)
+                       return NULL;
+
+               dbus_message_iter_next(&array);
+       }
+
+       return g_obex_apparam_set_uint64(apparam, FILTER_TAG, filter);
+}
+
+static GObexApparam *parse_filters(GObexApparam *apparam,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
+               return NULL;
+
+       dbus_message_iter_recurse(iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_DICT_ENTRY) {
+               const char *key;
+               DBusMessageIter value, entry;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "Format") == 0) {
+                       if (parse_format(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Order") == 0) {
+                       if (parse_order(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Offset") == 0) {
+                       if (parse_offset(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "MaxCount") == 0) {
+                       if (parse_max_count(apparam, &value) == NULL)
+                               return NULL;
+               } else if (strcasecmp(key, "Fields") == 0) {
+                       if (parse_fields(apparam, &value) == NULL)
+                               return NULL;
+               }
+
+               dbus_message_iter_next(&array);
+       }
+
+       return apparam;
+}
+
+static DBusMessage *pull_phonebook(struct pbap_data *pbap,
+                                               DBusMessage *message,
+                                               guint8 type,
+                                               const char *targetfile,
+                                               GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       char *name;
+       session_callback_t func;
+       DBusMessage *reply;
+       GError *err = NULL;
+
+       name = g_strconcat(g_path_skip_root(pbap->path), ".vcf", NULL);
+
+       transfer = obc_transfer_get("x-bt/phonebook", name, targetfile, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       switch (type) {
+       case PULLPHONEBOOK:
+               func = NULL;
+               request = NULL;
+               break;
+       case GETPHONEBOOKSIZE:
+               func = phonebook_size_callback;
+               request = pending_request_new(pbap, message);
+               break;
+       default:
+               error("Unexpected type : 0x%2x", type);
+               return NULL;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(pbap->session, transfer, func, request, &err)) {
+               if (request != NULL)
+                       pending_request_free(request);
+
+               goto fail;
+       }
+
+       g_free(name);
+
+       if (targetfile == NULL)
+               return NULL;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       g_free(name);
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *pull_vcard_listing(struct pbap_data *pbap,
+                                       DBusMessage *message, const char *name,
+                                       GObexApparam *apparam)
+{
+       struct pending_request *request;
+       struct obc_transfer *transfer;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       transfer = obc_transfer_get("x-bt/vcard-listing", name, NULL, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       request = pending_request_new(pbap, message);
+       if (obc_session_queue(pbap->session, transfer,
+                               pull_vcard_listing_callback, request, &err))
+               return NULL;
+
+       pending_request_free(request);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *pbap_select(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       const char *item, *location;
+       char *path;
+       struct pending_request *request;
+       GError *err = NULL;
+
+       if (dbus_message_get_args(message, NULL,
+                       DBUS_TYPE_STRING, &location,
+                       DBUS_TYPE_STRING, &item,
+                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       path = build_phonebook_path(location, item);
+       if (path == NULL)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid path");
+
+       if (pbap->path != NULL && g_str_equal(pbap->path, path)) {
+               g_free(path);
+               return dbus_message_new_method_return(message);
+       }
+
+       request = pending_request_new(pbap, message);
+
+       obc_session_setpath(pbap->session, path, pbap_setpath_cb, request,
+                                                                       &err);
+       if (err != NULL) {
+               DBusMessage *reply;
+               reply =  g_dbus_create_error(message, ERROR_INTERFACE ".Failed",
+                                                       "%s", err->message);
+               g_error_free(err);
+               g_free(path);
+               pending_request_free(request);
+               return reply;
+       }
+
+       g_free(pbap->path);
+       pbap->path = path;
+
+       return NULL;
+}
+
+static DBusMessage *pbap_pull_all(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       const char *targetfile;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       if (!pbap->path)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".Forbidden",
+                                       "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &targetfile);
+       dbus_message_iter_next(&args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_phonebook(pbap, message, PULLPHONEBOOK, targetfile,
+                                                               apparam);
+}
+
+static DBusMessage *pull_vcard(struct pbap_data *pbap, DBusMessage *message,
+                               const char *name, const char *targetfile,
+                               GObexApparam *apparam)
+{
+       struct obc_transfer *transfer;
+       DBusMessage *reply;
+       GError *err = NULL;
+
+       transfer = obc_transfer_get("x-bt/vcard", name, targetfile, &err);
+       if (transfer == NULL) {
+               g_obex_apparam_free(apparam);
+               goto fail;
+       }
+
+       obc_transfer_set_apparam(transfer, apparam);
+
+       if (!obc_session_queue(pbap->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *pbap_pull_vcard(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       GObexApparam *apparam;
+       const char *name, *targetfile;
+       DBusMessageIter args;
+
+       if (!pbap->path)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Forbidden",
+                               "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &name);
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &targetfile);
+       dbus_message_iter_next(&args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_vcard(pbap, message, name, targetfile, apparam);
+}
+
+static DBusMessage *pbap_list(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       if (!pbap->path)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".Forbidden",
+                                       "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_vcard_listing(pbap, message, "", apparam);
+}
+
+static GObexApparam *parse_attribute(GObexApparam *apparam, const char *field)
+{
+       guint8 attrib;
+
+       if (!field || g_str_equal(field, ""))
+               attrib = ATTRIB_NAME;
+       else if (!g_ascii_strcasecmp(field, "name"))
+               attrib = ATTRIB_NAME;
+       else if (!g_ascii_strcasecmp(field, "number"))
+               attrib = ATTRIB_NUMBER;
+       else if (!g_ascii_strcasecmp(field, "sound"))
+               attrib = ATTRIB_SOUND;
+       else
+               return NULL;
+
+       return g_obex_apparam_set_uint8(apparam, SEARCHATTRIB_TAG, attrib);
+}
+
+static DBusMessage *pbap_search(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       char *field, *value;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       if (!pbap->path)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".Forbidden",
+                                       "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &field);
+       dbus_message_iter_next(&args);
+
+       apparam = parse_attribute(NULL, field);
+       if (apparam == NULL)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+
+       dbus_message_iter_get_basic(&args, &value);
+       dbus_message_iter_next(&args);
+
+       apparam = g_obex_apparam_set_uint16(apparam, MAXLISTCOUNT_TAG,
+                                                       DEFAULT_COUNT);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+       apparam = g_obex_apparam_set_string(apparam, SEARCHVALUE_TAG, value);
+
+       if (parse_filters(apparam, &args) == NULL) {
+               g_obex_apparam_free(apparam);
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InvalidArguments", NULL);
+       }
+
+       return pull_vcard_listing(pbap, message, "", apparam);
+}
+
+static DBusMessage *pbap_get_size(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct pbap_data *pbap = user_data;
+       GObexApparam *apparam;
+       DBusMessageIter args;
+
+       if (!pbap->path)
+               return g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".Forbidden",
+                                       "Call Select first of all");
+
+       dbus_message_iter_init(message, &args);
+
+       apparam = g_obex_apparam_set_uint16(NULL, MAXLISTCOUNT_TAG, 0);
+       apparam = g_obex_apparam_set_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                                       DEFAULT_OFFSET);
+
+       return pull_phonebook(pbap, message, GETPHONEBOOKSIZE, NULL, apparam);
+}
+
+static char **get_filter_strs(uint64_t filter, int *size)
+{
+       char **list, **item;
+       int i;
+
+       list = g_malloc0(sizeof(char **) * (FILTER_BIT_MAX + 2));
+
+       item = list;
+
+       for (i = 0; filter_list[i] != NULL; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup(filter_list[i]);
+
+       for (; i <= FILTER_BIT_MAX; i++)
+               if (filter & (1ULL << i))
+                       *(item++) = g_strdup_printf("%s%d", "BIT", i);
+
+       *item = NULL;
+       *size = item - list;
+       return list;
+}
+
+static DBusMessage *pbap_list_filter_fields(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       char **filters = NULL;
+       int size;
+       DBusMessage *reply;
+
+       filters = get_filter_strs(FILTER_ALL, &size);
+       reply = dbus_message_new_method_return(message);
+       dbus_message_append_args(reply, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING, &filters, size,
+                               DBUS_TYPE_INVALID);
+
+       g_strfreev(filters);
+       return reply;
+}
+
+static const GDBusMethodTable pbap_methods[] = {
+       { GDBUS_ASYNC_METHOD("Select",
+                       GDBUS_ARGS({ "location", "s" }, { "phonebook", "s" }),
+                       NULL, pbap_select) },
+       { GDBUS_METHOD("PullAll",
+                       GDBUS_ARGS({ "targetfile", "s" },
+                                       { "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                       { "properties", "a{sv}" }),
+                       pbap_pull_all) },
+       { GDBUS_METHOD("Pull",
+                       GDBUS_ARGS({ "vcard", "s" }, { "targetfile", "s" },
+                                       { "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                       { "properties", "a{sv}" }),
+                       pbap_pull_vcard) },
+       { GDBUS_ASYNC_METHOD("List",
+                       GDBUS_ARGS({ "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+                       pbap_list) },
+       { GDBUS_ASYNC_METHOD("Search",
+                       GDBUS_ARGS({ "field", "s" }, { "value", "s" },
+                                       { "filters", "a{sv}" }),
+                       GDBUS_ARGS({ "vcard_listing", "a(ss)" }),
+                       pbap_search) },
+       { GDBUS_ASYNC_METHOD("GetSize",
+                               NULL, GDBUS_ARGS({ "size", "q" }),
+                               pbap_get_size) },
+       { GDBUS_METHOD("ListFilterFields",
+                               NULL, GDBUS_ARGS({ "fields", "as" }),
+                               pbap_list_filter_fields) },
+       { }
+};
+
+static void pbap_free(void *data)
+{
+       struct pbap_data *pbap = data;
+
+       obc_session_unref(pbap->session);
+       g_free(pbap->path);
+       g_free(pbap);
+}
+
+static int pbap_probe(struct obc_session *session)
+{
+       struct pbap_data *pbap;
+       const char *path;
+
+       path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       pbap = g_try_new0(struct pbap_data, 1);
+       if (!pbap)
+               return -ENOMEM;
+
+       pbap->session = obc_session_ref(session);
+
+       if (!g_dbus_register_interface(conn, path, PBAP_INTERFACE, pbap_methods,
+                                               NULL, NULL, pbap, pbap_free)) {
+               pbap_free(pbap);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void pbap_remove(struct obc_session *session)
+{
+       const char *path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(conn, path, PBAP_INTERFACE);
+}
+
+static struct obc_driver pbap = {
+       .service = "PBAP",
+       .uuid = PBAP_UUID,
+       .target = OBEX_PBAP_UUID,
+       .target_len = OBEX_PBAP_UUID_LEN,
+       .probe = pbap_probe,
+       .remove = pbap_remove
+};
+
+int pbap_init(void)
+{
+       int err;
+
+       DBG("");
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!conn)
+               return -EIO;
+
+       err = obc_driver_register(&pbap);
+       if (err < 0) {
+               dbus_connection_unref(conn);
+               conn = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+void pbap_exit(void)
+{
+       DBG("");
+
+       dbus_connection_unref(conn);
+       conn = NULL;
+
+       obc_driver_unregister(&pbap);
+}
diff --git a/obexd/client/pbap.h b/obexd/client/pbap.h
new file mode 100644 (file)
index 0000000..ce56258
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int pbap_init(void);
+void pbap_exit(void);
diff --git a/obexd/client/session.c b/obexd/client/session.c
new file mode 100644 (file)
index 0000000..8138b1e
--- /dev/null
@@ -0,0 +1,1338 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+#include <gobex/gobex.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "transport.h"
+
+#define SESSION_INTERFACE "org.bluez.obex.Session1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+#define SESSION_BASEPATH "/org/bluez/obex/client"
+
+#define OBEX_IO_ERROR obex_io_error_quark()
+#define OBEX_IO_ERROR_FIRST (0xff + 1)
+
+enum {
+       OBEX_IO_DISCONNECTED = OBEX_IO_ERROR_FIRST,
+       OBEX_IO_BUSY,
+};
+
+static guint64 counter = 0;
+
+struct callback_data {
+       struct obc_session *session;
+       session_callback_t func;
+       void *data;
+};
+
+struct pending_request;
+typedef int (*session_process_t) (struct pending_request *p, GError **err);
+typedef void (*destroy_t) (void *data);
+
+struct pending_request {
+       guint id;
+       guint req_id;
+       struct obc_session *session;
+       session_process_t process;
+       struct obc_transfer *transfer;
+       session_callback_t func;
+       void *data;
+       destroy_t destroy;
+};
+
+struct setpath_data {
+       char **remaining;
+       int index;
+       session_callback_t func;
+       void *user_data;
+};
+
+struct file_data {
+       char *srcname;
+       char *destname;
+       session_callback_t func;
+       void *user_data;
+};
+
+struct obc_session {
+       guint id;
+       int refcount;
+       char *source;
+       char *destination;
+       uint8_t channel;
+       struct obc_transport *transport;
+       struct obc_driver *driver;
+       char *path;             /* Session path */
+       DBusConnection *conn;
+       GObex *obex;
+       struct pending_request *p;
+       char *owner;            /* Session owner */
+       guint watch;
+       GQueue *queue;
+       guint process_id;
+       char *folder;
+};
+
+static GSList *sessions = NULL;
+
+static void session_process_queue(struct obc_session *session);
+static void session_terminate_transfer(struct obc_session *session,
+                                       struct obc_transfer *transfer,
+                                       GError *gerr);
+static void transfer_complete(struct obc_transfer *transfer,
+                                       GError *err, void *user_data);
+
+static GQuark obex_io_error_quark(void)
+{
+       return g_quark_from_static_string("obex-io-error-quark");
+}
+
+struct obc_session *obc_session_ref(struct obc_session *session)
+{
+       int refs = __sync_add_and_fetch(&session->refcount, 1);
+
+       DBG("%p: ref=%d", session, refs);
+
+       return session;
+}
+
+static void session_unregistered(struct obc_session *session)
+{
+       char *path;
+
+       if (session->driver && session->driver->remove)
+               session->driver->remove(session);
+
+       path = session->path;
+       session->path = NULL;
+
+       g_dbus_unregister_interface(session->conn, path, SESSION_INTERFACE);
+
+       DBG("Session(%p) unregistered %s", session, path);
+
+       g_free(path);
+}
+
+static struct pending_request *pending_request_new(struct obc_session *session,
+                                               session_process_t process,
+                                               struct obc_transfer *transfer,
+                                               session_callback_t func,
+                                               void *data,
+                                               destroy_t destroy)
+{
+       struct pending_request *p;
+       static guint id = 0;
+
+       p = g_new0(struct pending_request, 1);
+       p->id = ++id;
+       p->session = obc_session_ref(session);
+       p->process = process;
+       p->destroy = destroy;
+       p->transfer = transfer;
+       p->func = func;
+       p->data = data;
+
+       return p;
+}
+
+static void pending_request_free(struct pending_request *p)
+{
+       if (p->req_id > 0)
+               g_obex_cancel_req(p->session->obex, p->req_id, TRUE);
+
+       if (p->destroy)
+               p->destroy(p->data);
+
+       if (p->transfer)
+               obc_transfer_unregister(p->transfer);
+
+       if (p->session)
+               obc_session_unref(p->session);
+
+       g_free(p);
+}
+
+static void setpath_data_free(void *process_data)
+{
+       struct setpath_data *data = process_data;
+
+       g_strfreev(data->remaining);
+       g_free(data);
+}
+
+static void file_data_free(void *process_data)
+{
+       struct file_data *data = process_data;
+
+       g_free(data->srcname);
+       g_free(data->destname);
+       g_free(data);
+}
+
+static void session_free(struct obc_session *session)
+{
+       DBG("%p", session);
+
+       if (session->process_id != 0)
+               g_source_remove(session->process_id);
+
+       if (session->queue) {
+               g_queue_foreach(session->queue, (GFunc) pending_request_free,
+                                                                       NULL);
+               g_queue_free(session->queue);
+       }
+
+       if (session->watch)
+               g_dbus_remove_watch(session->conn, session->watch);
+
+       if (session->obex != NULL)
+               g_obex_unref(session->obex);
+
+       if (session->id > 0 && session->transport != NULL)
+               session->transport->disconnect(session->id);
+
+       if (session->path)
+               session_unregistered(session);
+
+       if (session->conn)
+               dbus_connection_unref(session->conn);
+
+       if (session->p)
+               pending_request_free(session->p);
+
+       sessions = g_slist_remove(sessions, session);
+
+       g_free(session->path);
+       g_free(session->owner);
+       g_free(session->source);
+       g_free(session->destination);
+       g_free(session->folder);
+       g_free(session);
+}
+
+void obc_session_unref(struct obc_session *session)
+{
+       int refs;
+
+       refs = __sync_sub_and_fetch(&session->refcount, 1);
+
+       DBG("%p: ref=%d", session, refs);
+
+       if (refs > 0)
+               return;
+
+       /* Disconnect transport */
+       if (session->id > 0 && session->transport != NULL) {
+               session->transport->disconnect(session->id);
+               session->id = 0;
+       }
+
+       session_free(session);
+}
+
+static void connect_cb(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct callback_data *callback = user_data;
+       GError *gerr = NULL;
+       uint8_t rsp_code;
+
+       if (err != NULL) {
+               error("connect_cb: %s", err->message);
+               gerr = g_error_copy(err);
+               goto done;
+       }
+
+       rsp_code = g_obex_packet_get_operation(rsp, NULL);
+       if (rsp_code != G_OBEX_RSP_SUCCESS)
+               gerr = g_error_new(OBEX_IO_ERROR, -EIO,
+                               "OBEX Connect failed with 0x%02x", rsp_code);
+
+done:
+       callback->func(callback->session, NULL, gerr, callback->data);
+       if (gerr != NULL)
+               g_error_free(gerr);
+       obc_session_unref(callback->session);
+       g_free(callback);
+}
+
+static void session_disconnected(GObex *obex, GError *err, gpointer user_data)
+{
+       struct obc_session *session = user_data;
+
+       if (err)
+               error("%s", err->message);
+
+       obc_session_shutdown(session);
+}
+
+static void transport_func(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct callback_data *callback = user_data;
+       struct obc_session *session = callback->session;
+       struct obc_driver *driver = session->driver;
+       struct obc_transport *transport = session->transport;
+       GObex *obex;
+       GObexTransportType type;
+       int tx_mtu = -1;
+       int rx_mtu = -1;
+
+       DBG("");
+
+       if (err != NULL) {
+               error("%s", err->message);
+               goto done;
+       }
+
+       g_io_channel_set_close_on_unref(io, FALSE);
+
+       if (transport->getpacketopt &&
+                       transport->getpacketopt(io, &tx_mtu, &rx_mtu) == 0)
+               type = G_OBEX_TRANSPORT_PACKET;
+       else
+               type = G_OBEX_TRANSPORT_STREAM;
+
+       obex = g_obex_new(io, type, tx_mtu, rx_mtu);
+       if (obex == NULL)
+               goto done;
+
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       if (driver->target != NULL)
+               g_obex_connect(obex, connect_cb, callback, &err,
+                       G_OBEX_HDR_TARGET, driver->target, driver->target_len,
+                       G_OBEX_HDR_INVALID);
+       else
+               g_obex_connect(obex, connect_cb, callback, &err,
+                                                       G_OBEX_HDR_INVALID);
+
+       if (err != NULL) {
+               error("%s", err->message);
+               g_obex_unref(obex);
+               goto done;
+       }
+
+       session->obex = obex;
+       sessions = g_slist_prepend(sessions, session);
+
+       g_obex_set_disconnect_function(obex, session_disconnected, session);
+
+       return;
+done:
+       callback->func(callback->session, NULL, err, callback->data);
+       obc_session_unref(callback->session);
+       g_free(callback);
+}
+
+static void owner_disconnected(DBusConnection *connection, void *user_data)
+{
+       struct obc_session *session = user_data;
+
+       DBG("");
+
+       obc_session_shutdown(session);
+}
+
+int obc_session_set_owner(struct obc_session *session, const char *name,
+                       GDBusWatchFunction func)
+{
+       if (session == NULL)
+               return -EINVAL;
+
+       if (session->watch)
+               g_dbus_remove_watch(session->conn, session->watch);
+
+       session->watch = g_dbus_add_disconnect_watch(session->conn, name, func,
+                                                       session, NULL);
+       if (session->watch == 0)
+               return -EINVAL;
+
+       session->owner = g_strdup(name);
+
+       return 0;
+}
+
+
+static struct obc_session *session_find(const char *source,
+                                               const char *destination,
+                                               const char *service,
+                                               uint8_t channel,
+                                               const char *owner)
+{
+       GSList *l;
+
+       for (l = sessions; l; l = l->next) {
+               struct obc_session *session = l->data;
+
+               if (g_strcmp0(session->destination, destination))
+                       continue;
+
+               if (g_strcmp0(service, session->driver->service))
+                       continue;
+
+               if (source && g_strcmp0(session->source, source))
+                       continue;
+
+               if (channel && session->channel != channel)
+                       continue;
+
+               if (g_strcmp0(owner, session->owner))
+                       continue;
+
+               return session;
+       }
+
+       return NULL;
+}
+
+static gboolean connection_complete(gpointer data)
+{
+       struct callback_data *cb = data;
+
+       cb->func(cb->session, NULL, NULL, cb->data);
+
+       obc_session_unref(cb->session);
+
+       g_free(cb);
+
+       return FALSE;
+}
+
+static int session_connect(struct obc_session *session,
+                               session_callback_t function, void *user_data)
+{
+       struct callback_data *callback;
+       struct obc_transport *transport = session->transport;
+       struct obc_driver *driver = session->driver;
+
+       callback = g_try_malloc0(sizeof(*callback));
+       if (callback == NULL)
+               return -ENOMEM;
+
+       callback->func = function;
+       callback->data = user_data;
+       callback->session = obc_session_ref(session);
+
+       /* Connection completed */
+       if (session->obex) {
+               g_idle_add(connection_complete, callback);
+               return 0;
+       }
+
+       /* Ongoing connection */
+       if (session->id > 0) {
+               obc_session_unref(callback->session);
+               g_free(callback);
+               return 0;
+       }
+
+       session->id = transport->connect(session->source, session->destination,
+                                       driver->uuid, session->channel,
+                                       transport_func, callback);
+       if (session->id == 0) {
+               obc_session_unref(callback->session);
+               g_free(callback);
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+struct obc_session *obc_session_create(const char *source,
+                                               const char *destination,
+                                               const char *service,
+                                               uint8_t channel,
+                                               const char *owner,
+                                               session_callback_t function,
+                                               void *user_data)
+{
+       DBusConnection *conn;
+       struct obc_session *session;
+       struct obc_transport *transport;
+       struct obc_driver *driver;
+
+       if (destination == NULL)
+               return NULL;
+
+       session = session_find(source, destination, service, channel, owner);
+       if (session != NULL)
+               goto proceed;
+
+       /* FIXME: Do proper transport lookup when the API supports it */
+       transport = obc_transport_find("Bluetooth");
+       if (transport == NULL)
+               return NULL;
+
+       driver = obc_driver_find(service);
+       if (driver == NULL)
+               return NULL;
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (conn == NULL)
+               return NULL;
+
+       session = g_try_malloc0(sizeof(*session));
+       if (session == NULL)
+               return NULL;
+
+       session->refcount = 1;
+       session->transport = transport;
+       session->driver = driver;
+       session->conn = conn;
+       session->source = g_strdup(source);
+       session->destination = g_strdup(destination);
+       session->channel = channel;
+       session->queue = g_queue_new();
+       session->folder = g_strdup("/");
+
+       if (owner)
+               obc_session_set_owner(session, owner, owner_disconnected);
+
+proceed:
+       if (session_connect(session, function, user_data) < 0) {
+               obc_session_unref(session);
+               return NULL;
+       }
+
+       DBG("session %p transport %s driver %s", session,
+                       session->transport->name, session->driver->service);
+
+       return session;
+}
+
+void obc_session_shutdown(struct obc_session *session)
+{
+       struct pending_request *p;
+       GError *err;
+
+       DBG("%p", session);
+
+       obc_session_ref(session);
+
+       /* Unregister any pending transfer */
+       err = g_error_new(OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session closed by user");
+
+       if (session->p != NULL && session->p->id != 0) {
+               p = session->p;
+               session->p = NULL;
+
+               if (p->func)
+                       p->func(session, p->transfer, err, p->data);
+
+               pending_request_free(p);
+       }
+
+       while ((p = g_queue_pop_head(session->queue))) {
+               if (p->func)
+                       p->func(session, p->transfer, err, p->data);
+
+               pending_request_free(p);
+       }
+
+       g_error_free(err);
+
+       /* Unregister interfaces */
+       if (session->path)
+               session_unregistered(session);
+
+       obc_session_unref(session);
+}
+
+static void capabilities_complete_callback(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       DBusMessage *message = user_data;
+       char *contents;
+       size_t size;
+       int perr;
+
+       if (err != NULL) {
+               DBusMessage *error = g_dbus_create_error(message,
+                                       ERROR_INTERFACE ".Failed",
+                                       "%s", err->message);
+               g_dbus_send_message(session->conn, error);
+               goto done;
+       }
+
+       perr = obc_transfer_get_contents(transfer, &contents, &size);
+       if (perr < 0) {
+               DBusMessage *error = g_dbus_create_error(message,
+                                               ERROR_INTERFACE ".Failed",
+                                               "Error reading contents: %s",
+                                               strerror(-perr));
+               g_dbus_send_message(session->conn, error);
+               goto done;
+       }
+
+       g_dbus_send_reply(session->conn, message,
+                                               DBUS_TYPE_STRING, &contents,
+                                               DBUS_TYPE_INVALID);
+       g_free(contents);
+
+done:
+       dbus_message_unref(message);
+}
+
+static DBusMessage *get_capabilities(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct obc_session *session = user_data;
+       struct obc_transfer *pull;
+       DBusMessage *reply;
+       GError *gerr = NULL;
+
+       pull = obc_transfer_get("x-obex/capability", NULL, NULL, &gerr);
+       if (pull == NULL)
+               goto fail;
+
+       if (!obc_session_queue(session, pull, capabilities_complete_callback,
+                                                               message, &gerr))
+               goto fail;
+
+       dbus_message_ref(message);
+
+       return NULL;
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INTERFACE ".Failed", "%s",
+                                                               gerr->message);
+       g_error_free(gerr);
+       return reply;
+
+}
+
+static gboolean get_source(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_session *session = data;
+
+       if (session->source == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &session->source);
+
+       return TRUE;
+}
+
+static gboolean source_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct obc_session *session = data;
+
+       return session->source != NULL;
+}
+
+static gboolean get_destination(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_session *session = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &session->destination);
+
+       return TRUE;
+}
+
+static gboolean get_channel(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_session *session = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE,
+                                                       &session->channel);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable session_methods[] = {
+       { GDBUS_ASYNC_METHOD("GetCapabilities",
+                               NULL, GDBUS_ARGS({ "capabilities", "s" }),
+                               get_capabilities) },
+       { }
+};
+
+static gboolean get_target(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_session *session = data;
+
+       if (session->driver->uuid == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                               &session->driver->uuid);
+
+       return TRUE;
+}
+
+static gboolean target_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct obc_session *session = data;
+
+       return session->driver->uuid != NULL;
+}
+
+static const GDBusPropertyTable session_properties[] = {
+       { "Source", "s", get_source, NULL, source_exists },
+       { "Destination", "s", get_destination },
+       { "Channel", "y", get_channel },
+       { "Target", "s", get_target, NULL, target_exists },
+       { }
+};
+
+static gboolean session_process(gpointer data)
+{
+       struct obc_session *session = data;
+
+       session->process_id = 0;
+
+       session_process_queue(session);
+
+       return FALSE;
+}
+
+static void session_queue(struct pending_request *p)
+{
+       g_queue_push_tail(p->session->queue, p);
+
+       if (p->session->process_id == 0)
+               p->session->process_id = g_idle_add(session_process,
+                                                               p->session);
+}
+
+static int session_process_transfer(struct pending_request *p, GError **err)
+{
+       if (!obc_transfer_start(p->transfer, p->session->obex, err))
+               return -1;
+
+       DBG("Tranfer(%p) started", p->transfer);
+       p->session->p = p;
+       return 0;
+}
+
+guint obc_session_queue(struct obc_session *session,
+                               struct obc_transfer *transfer,
+                               session_callback_t func, void *user_data,
+                               GError **err)
+{
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               obc_transfer_unregister(transfer);
+               g_set_error(err, OBEX_IO_ERROR, -ENOTCONN,
+                                               "Session not connected");
+               return 0;
+       }
+
+       if (!obc_transfer_register(transfer, session->conn, session->path,
+                                                       session->owner, err)) {
+               obc_transfer_unregister(transfer);
+               return 0;
+       }
+
+       obc_transfer_set_callback(transfer, transfer_complete, session);
+
+       p = pending_request_new(session, session_process_transfer, transfer,
+                                                       func, user_data, NULL);
+       session_queue(p);
+       return p->id;
+}
+
+static void session_process_queue(struct obc_session *session)
+{
+       struct pending_request *p;
+
+       if (session->p != NULL)
+               return;
+
+       if (session->queue == NULL || g_queue_is_empty(session->queue))
+               return;
+
+       obc_session_ref(session);
+
+       while ((p = g_queue_pop_head(session->queue))) {
+               GError *gerr = NULL;
+
+               if (p->process(p, &gerr) == 0)
+                       break;
+
+               if (p->func)
+                       p->func(session, p->transfer, gerr, p->data);
+
+               g_clear_error(&gerr);
+
+               pending_request_free(p);
+       }
+
+       obc_session_unref(session);
+}
+
+static int pending_transfer_cmptransfer(gconstpointer a, gconstpointer b)
+{
+       const struct pending_request *p = a;
+       const struct obc_transfer *transfer = b;
+
+       if (p->transfer == transfer)
+               return 0;
+
+       return -1;
+}
+
+static void session_terminate_transfer(struct obc_session *session,
+                                       struct obc_transfer *transfer,
+                                       GError *gerr)
+{
+       struct pending_request *p = session->p;
+
+       if (p == NULL || p->transfer != transfer) {
+               GList *match;
+
+               match = g_list_find_custom(session->queue->head, transfer,
+                                               pending_transfer_cmptransfer);
+               if (match == NULL)
+                       return;
+
+               p = match->data;
+               g_queue_delete_link(session->queue, match);
+       } else
+               session->p = NULL;
+
+       obc_session_ref(session);
+
+       if (p->func)
+               p->func(session, p->transfer, gerr, p->data);
+
+       pending_request_free(p);
+
+       if (session->p == NULL)
+               session_process_queue(session);
+
+       obc_session_unref(session);
+}
+
+static void session_notify_complete(struct obc_session *session,
+                               struct obc_transfer *transfer)
+{
+       DBG("Transfer(%p) complete", transfer);
+
+       session_terminate_transfer(session, transfer, NULL);
+}
+
+static void session_notify_error(struct obc_session *session,
+                               struct obc_transfer *transfer,
+                               GError *err)
+{
+       error("Transfer(%p) Error: %s", transfer, err->message);
+
+       session_terminate_transfer(session, transfer, err);
+}
+
+static void transfer_complete(struct obc_transfer *transfer,
+                                       GError *err, void *user_data)
+{
+       struct obc_session *session = user_data;
+
+       if (err != 0)
+               goto fail;
+
+       session_notify_complete(session, transfer);
+
+       return;
+
+fail:
+       session_notify_error(session, transfer, err);
+}
+
+const char *obc_session_register(struct obc_session *session,
+                                               GDBusDestroyFunction destroy)
+{
+       if (session->path)
+               return session->path;
+
+       session->path = g_strdup_printf("%s/session%ju",
+                                               SESSION_BASEPATH, counter++);
+
+       if (g_dbus_register_interface(session->conn, session->path,
+                                       SESSION_INTERFACE, session_methods,
+                                       NULL, session_properties, session,
+                                       destroy) == FALSE)
+               goto fail;
+
+       if (session->driver->probe && session->driver->probe(session) < 0) {
+               g_dbus_unregister_interface(session->conn, session->path,
+                                                       SESSION_INTERFACE);
+               goto fail;
+       }
+
+       DBG("Session(%p) registered %s", session, session->path);
+
+       return session->path;
+
+fail:
+       g_free(session->path);
+       session->path = NULL;
+       return NULL;
+}
+
+const void *obc_session_get_attribute(struct obc_session *session,
+                                                       int attribute_id)
+{
+       if (session == NULL || session->id == 0)
+               return NULL;
+
+       return session->transport->getattribute(session->id, attribute_id);
+}
+
+const char *obc_session_get_owner(struct obc_session *session)
+{
+       if (session == NULL)
+               return NULL;
+
+       return session->owner;
+}
+
+const char *obc_session_get_destination(struct obc_session *session)
+{
+       return session->destination;
+}
+
+const char *obc_session_get_path(struct obc_session *session)
+{
+       return session->path;
+}
+
+const char *obc_session_get_target(struct obc_session *session)
+{
+       return session->driver->target;
+}
+
+const char *obc_session_get_folder(struct obc_session *session)
+{
+       return session->folder;
+}
+
+static void setpath_complete(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct pending_request *p = user_data;
+
+       if (p->func)
+               p->func(session, NULL, err, p->data);
+
+       if (session->p == p)
+               session->p = NULL;
+
+       pending_request_free(p);
+
+       session_process_queue(session);
+}
+
+static void setpath_op_complete(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct setpath_data *data = user_data;
+
+       if (data->func)
+               data->func(session, NULL, err, data->user_data);
+}
+
+static void setpath_set_folder(struct obc_session *session, const char *cur)
+{
+       char *folder = NULL;
+       const char *delim;
+
+       delim = strrchr(session->folder, '/');
+       if (strlen(cur) == 0 || delim == NULL ||
+                       (strcmp(cur, "..") == 0 && delim == session->folder)) {
+               folder = g_strdup("/");
+       } else {
+               if (strcmp(cur, "..") == 0) {
+                       folder = g_strndup(session->folder,
+                                               delim - session->folder);
+               } else {
+                       if (g_str_has_suffix(session->folder, "/"))
+                               folder = g_strconcat(session->folder,
+                                                               cur, NULL);
+                       else
+                               folder = g_strconcat(session->folder, "/",
+                                                               cur, NULL);
+               }
+       }
+       g_free(session->folder);
+       session->folder = folder;
+}
+
+static void setpath_cb(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct pending_request *p = user_data;
+       struct setpath_data *data = p->data;
+       char *next;
+       char *current;
+       guint8 code;
+
+       p->req_id = 0;
+
+       if (err != NULL) {
+               setpath_complete(p->session, NULL, err, user_data);
+               return;
+       }
+
+       code = g_obex_packet_get_operation(rsp, NULL);
+       if (code != G_OBEX_RSP_SUCCESS) {
+               GError *gerr = NULL;
+               g_set_error(&gerr, OBEX_IO_ERROR, code, "%s",
+                                                       g_obex_strerror(code));
+               setpath_complete(p->session, NULL, gerr, user_data);
+               g_clear_error(&gerr);
+               return;
+       }
+
+       current = data->remaining[data->index - 1];
+       setpath_set_folder(p->session, current);
+
+       /* Ignore empty folder names to avoid resetting the current path */
+       while ((next = data->remaining[data->index]) && strlen(next) == 0)
+               data->index++;
+
+       if (next == NULL) {
+               setpath_complete(p->session, NULL, NULL, user_data);
+               return;
+       }
+
+       data->index++;
+
+       p->req_id = g_obex_setpath(obex, next, setpath_cb, p, &err);
+       if (err != NULL) {
+               setpath_complete(p->session, NULL, err, user_data);
+               g_error_free(err);
+       }
+}
+
+static int session_process_setpath(struct pending_request *p, GError **err)
+{
+       struct setpath_data *req = p->data;
+       const char *first = "";
+
+       /* Relative path */
+       if (req->remaining[0][0] != '/')
+               first = req->remaining[req->index];
+       req->index++;
+
+       p->req_id = g_obex_setpath(p->session->obex, first, setpath_cb, p, err);
+       if (*err != NULL)
+               goto fail;
+
+       p->session->p = p;
+
+       return 0;
+
+fail:
+       pending_request_free(p);
+       return (*err)->code;
+}
+
+guint obc_session_setpath(struct obc_session *session, const char *path,
+                               session_callback_t func, void *user_data,
+                               GError **err)
+{
+       struct setpath_data *data;
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session disconnected");
+               return 0;
+       }
+
+       data = g_new0(struct setpath_data, 1);
+       data->func = func;
+       data->user_data = user_data;
+       data->remaining = g_strsplit(strlen(path) ? path : "/", "/", 0);
+
+       p = pending_request_new(session, session_process_setpath, NULL,
+                               setpath_op_complete, data, setpath_data_free);
+       session_queue(p);
+       return p->id;
+}
+
+static void async_cb(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct pending_request *p = user_data;
+       struct obc_session *session = p->session;
+       GError *gerr = NULL;
+       uint8_t code;
+
+       p->req_id = 0;
+
+       if (err != NULL) {
+               if (p->func)
+                       p->func(p->session, NULL, err, p->data);
+               goto done;
+       }
+
+       code = g_obex_packet_get_operation(rsp, NULL);
+       if (code != G_OBEX_RSP_SUCCESS)
+               g_set_error(&gerr, OBEX_IO_ERROR, code, "%s",
+                                                       g_obex_strerror(code));
+
+       if (p->func)
+               p->func(p->session, NULL, gerr, p->data);
+
+       if (gerr != NULL)
+               g_clear_error(&gerr);
+
+done:
+       pending_request_free(p);
+       session->p = NULL;
+
+       session_process_queue(session);
+}
+
+static void file_op_complete(struct obc_session *session,
+                                               struct obc_transfer *transfer,
+                                               GError *err, void *user_data)
+{
+       struct file_data *data = user_data;
+
+       if (data->func)
+               data->func(session, NULL, err, data->user_data);
+}
+
+static int session_process_mkdir(struct pending_request *p, GError **err)
+{
+       struct file_data *req = p->data;
+
+       p->req_id = g_obex_mkdir(p->session->obex, req->srcname, async_cb, p,
+                                                                       err);
+       if (*err != NULL)
+               goto fail;
+
+       p->session->p = p;
+
+       return 0;
+
+fail:
+       pending_request_free(p);
+       return (*err)->code;
+}
+
+guint obc_session_mkdir(struct obc_session *session, const char *folder,
+                               session_callback_t func, void *user_data,
+                               GError **err)
+{
+       struct file_data *data;
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session disconnected");
+               return 0;
+       }
+
+       data = g_new0(struct file_data, 1);
+       data->srcname = g_strdup(folder);
+       data->func = func;
+       data->user_data = user_data;
+
+       p = pending_request_new(session, session_process_mkdir, NULL,
+                                       file_op_complete, data, file_data_free);
+       session_queue(p);
+       return p->id;
+}
+
+static int session_process_copy(struct pending_request *p, GError **err)
+{
+       struct file_data *req = p->data;
+
+       p->req_id = g_obex_copy(p->session->obex, req->srcname, req->destname,
+                                                       async_cb, p, err);
+       if (*err != NULL)
+               goto fail;
+
+       p->session->p = p;
+
+       return 0;
+
+fail:
+       pending_request_free(p);
+       return (*err)->code;
+}
+
+guint obc_session_copy(struct obc_session *session, const char *srcname,
+                               const char *destname, session_callback_t func,
+                               void *user_data, GError **err)
+{
+       struct file_data *data;
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session disconnected");
+               return 0;
+       }
+
+       data = g_new0(struct file_data, 1);
+       data->srcname = g_strdup(srcname);
+       data->destname = g_strdup(destname);
+       data->func = func;
+       data->user_data = user_data;
+
+       p = pending_request_new(session, session_process_copy, NULL,
+                               file_op_complete, data, file_data_free);
+       session_queue(p);
+       return p->id;
+}
+
+static int session_process_move(struct pending_request *p, GError **err)
+{
+       struct file_data *req = p->data;
+
+       p->req_id = g_obex_move(p->session->obex, req->srcname, req->destname,
+                                                       async_cb, p, err);
+       if (*err != NULL)
+               goto fail;
+
+       p->session->p = p;
+
+       return 0;
+
+fail:
+       pending_request_free(p);
+       return (*err)->code;
+}
+
+guint obc_session_move(struct obc_session *session, const char *srcname,
+                               const char *destname, session_callback_t func,
+                               void *user_data, GError **err)
+{
+       struct file_data *data;
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session disconnected");
+               return 0;
+       }
+
+       data = g_new0(struct file_data, 1);
+       data->srcname = g_strdup(srcname);
+       data->destname = g_strdup(destname);
+       data->func = func;
+       data->user_data = user_data;
+
+       p = pending_request_new(session, session_process_move, NULL,
+                               file_op_complete, data, file_data_free);
+       session_queue(p);
+       return p->id;
+}
+
+static int session_process_delete(struct pending_request *p, GError **err)
+{
+       struct file_data *req = p->data;
+
+       p->req_id = g_obex_delete(p->session->obex, req->srcname, async_cb, p,
+                                                                       err);
+       if (*err != NULL)
+               goto fail;
+
+       p->session->p = p;
+
+       return 0;
+
+fail:
+       pending_request_free(p);
+       return (*err)->code;
+}
+
+guint obc_session_delete(struct obc_session *session, const char *file,
+                               session_callback_t func, void *user_data,
+                               GError **err)
+{
+       struct file_data *data;
+       struct pending_request *p;
+
+       if (session->obex == NULL) {
+               g_set_error(err, OBEX_IO_ERROR, OBEX_IO_DISCONNECTED,
+                                               "Session disconnected");
+               return 0;
+       }
+
+       data = g_new0(struct file_data, 1);
+       data->srcname = g_strdup(file);
+       data->func = func;
+       data->user_data = user_data;
+
+       p = pending_request_new(session, session_process_delete, NULL,
+                               file_op_complete, data, file_data_free);
+       session_queue(p);
+       return p->id;
+}
+
+void obc_session_cancel(struct obc_session *session, guint id,
+                                                       gboolean remove)
+{
+       struct pending_request *p = session->p;
+
+       if (p == NULL || p->id != id)
+               return;
+
+       if (p->req_id == 0)
+               return;
+
+       g_obex_cancel_req(session->obex, p->req_id, remove);
+       p->req_id = 0;
+
+       if (!remove)
+               return;
+
+       pending_request_free(p);
+       session->p = NULL;
+
+       session_process_queue(session);
+}
diff --git a/obexd/client/session.h b/obexd/client/session.h
new file mode 100644 (file)
index 0000000..35899bc
--- /dev/null
@@ -0,0 +1,83 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. 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
+ *
+ */
+
+#include <stdint.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+struct obc_session;
+
+typedef void (*session_callback_t) (struct obc_session *session,
+                                       struct obc_transfer *transfer,
+                                       GError *err, void *user_data);
+
+struct obc_session *obc_session_create(const char *source,
+                                               const char *destination,
+                                               const char *service,
+                                               uint8_t channel,
+                                               const char *owner,
+                                               session_callback_t function,
+                                               void *user_data);
+
+struct obc_session *obc_session_ref(struct obc_session *session);
+void obc_session_unref(struct obc_session *session);
+void obc_session_shutdown(struct obc_session *session);
+
+int obc_session_set_owner(struct obc_session *session, const char *name,
+                       GDBusWatchFunction func);
+const char *obc_session_get_owner(struct obc_session *session);
+
+const char *obc_session_get_destination(struct obc_session *session);
+const char *obc_session_get_path(struct obc_session *session);
+const char *obc_session_get_target(struct obc_session *session);
+
+const char *obc_session_register(struct obc_session *session,
+                                               GDBusDestroyFunction destroy);
+
+const void *obc_session_get_attribute(struct obc_session *session,
+                                                       int attribute_id);
+
+const char *obc_session_get_folder(struct obc_session *session);
+
+guint obc_session_queue(struct obc_session *session,
+                               struct obc_transfer *transfer,
+                               session_callback_t func, void *user_data,
+                               GError **err);
+guint obc_session_setpath(struct obc_session *session, const char *path,
+                               session_callback_t func, void *user_data,
+                               GError **err);
+guint obc_session_mkdir(struct obc_session *session, const char *folder,
+                               session_callback_t func, void *user_data,
+                               GError **err);
+guint obc_session_copy(struct obc_session *session, const char *srcname,
+                               const char *destname, session_callback_t func,
+                               void *user_data, GError **err);
+guint obc_session_move(struct obc_session *session, const char *srcname,
+                               const char *destname, session_callback_t func,
+                               void *user_data, GError **err);
+guint obc_session_delete(struct obc_session *session, const char *file,
+                               session_callback_t func, void *user_data,
+                               GError **err);
+void obc_session_cancel(struct obc_session *session, guint id,
+                                                       gboolean remove);
diff --git a/obexd/client/sync.c b/obexd/client/sync.c
new file mode 100644 (file)
index 0000000..1a4b482
--- /dev/null
@@ -0,0 +1,261 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+
+#include "transfer.h"
+#include "session.h"
+#include "driver.h"
+#include "sync.h"
+
+#define OBEX_SYNC_UUID "IRMC-SYNC"
+#define OBEX_SYNC_UUID_LEN 9
+
+#define SYNC_INTERFACE "org.bluez.obex.Synchronization1"
+#define ERROR_INF SYNC_INTERFACE ".Error"
+#define SYNC_UUID "00001104-0000-1000-8000-00805f9b34fb"
+
+struct sync_data {
+       struct obc_session *session;
+       char *phonebook_path;
+       DBusMessage *msg;
+};
+
+static DBusConnection *conn = NULL;
+
+static DBusMessage *sync_setlocation(DBusConnection *connection,
+                       DBusMessage *message, void *user_data)
+{
+       struct sync_data *sync = user_data;
+       const char *location;
+       char *path = NULL, *tmp;
+
+       if (dbus_message_get_args(message, NULL,
+                       DBUS_TYPE_STRING, &location,
+                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                       ERROR_INF ".InvalidArguments", NULL);
+
+       if (!g_ascii_strcasecmp(location, "int") ||
+                       !g_ascii_strcasecmp(location, "internal"))
+               path = g_strdup("telecom/pb.vcf");
+       else if (!g_ascii_strncasecmp(location, "sim", 3)) {
+               tmp = g_ascii_strup(location, 4);
+               path = g_build_filename(tmp, "telecom/pb.vcf", NULL);
+               g_free(tmp);
+       } else
+               return g_dbus_create_error(message,
+                       ERROR_INF ".InvalidArguments", "InvalidPhonebook");
+
+       g_free(sync->phonebook_path);
+       sync->phonebook_path = path;
+
+       return dbus_message_new_method_return(message);
+}
+
+static DBusMessage *sync_getphonebook(DBusConnection *connection,
+                       DBusMessage *message, void *user_data)
+{
+       struct sync_data *sync = user_data;
+       struct obc_transfer *transfer;
+       const char *target_file;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       if (dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &target_file,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INF ".InvalidArguments",
+                               "Invalid arguments in method call");
+
+       if (sync->msg)
+               return g_dbus_create_error(message,
+                       ERROR_INF ".InProgress", "Transfer in progress");
+
+       /* set default phonebook_path to memory internal phonebook */
+       if (!sync->phonebook_path)
+               sync->phonebook_path = g_strdup("telecom/pb.vcf");
+
+       transfer = obc_transfer_get("phonebook", sync->phonebook_path,
+                                                       target_file, &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static DBusMessage *sync_putphonebook(DBusConnection *connection,
+                       DBusMessage *message, void *user_data)
+{
+       struct sync_data *sync = user_data;
+       struct obc_transfer *transfer;
+       const char *source_file;
+       GError *err = NULL;
+       DBusMessage *reply;
+
+       if (dbus_message_get_args(message, NULL,
+                                       DBUS_TYPE_STRING, &source_file,
+                                       DBUS_TYPE_INVALID) == FALSE)
+               return g_dbus_create_error(message,
+                               ERROR_INF ".InvalidArguments",
+                               "Invalid arguments in method call");
+
+       /* set default phonebook_path to memory internal phonebook */
+       if (!sync->phonebook_path)
+               sync->phonebook_path = g_strdup("telecom/pb.vcf");
+
+       transfer = obc_transfer_put(NULL, sync->phonebook_path, source_file,
+                                                       NULL, 0, &err);
+       if (transfer == NULL)
+               goto fail;
+
+       if (!obc_session_queue(sync->session, transfer, NULL, NULL, &err))
+               goto fail;
+
+       return obc_transfer_create_dbus_reply(transfer, message);
+
+fail:
+       reply = g_dbus_create_error(message, ERROR_INF ".Failed", "%s",
+                                                               err->message);
+       g_error_free(err);
+       return reply;
+}
+
+static const GDBusMethodTable sync_methods[] = {
+       { GDBUS_METHOD("SetLocation",
+                       GDBUS_ARGS({ "location", "s" }), NULL,
+                       sync_setlocation) },
+       { GDBUS_METHOD("GetPhonebook",
+                       GDBUS_ARGS({ "targetfile", "s" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                       { "properties", "a{sv}" }),
+                       sync_getphonebook) },
+       { GDBUS_METHOD("PutPhonebook",
+                       GDBUS_ARGS({ "sourcefile", "s" }),
+                       GDBUS_ARGS({ "transfer", "o" },
+                                       { "properties", "a{sv}" }),
+                       sync_putphonebook) },
+       { }
+};
+
+static void sync_free(void *data)
+{
+       struct sync_data *sync = data;
+
+       obc_session_unref(sync->session);
+       g_free(sync->phonebook_path);
+       g_free(sync);
+}
+
+static int sync_probe(struct obc_session *session)
+{
+       struct sync_data *sync;
+       const char *path;
+
+       path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       sync = g_try_new0(struct sync_data, 1);
+       if (!sync)
+               return -ENOMEM;
+
+       sync->session = obc_session_ref(session);
+
+       if (!g_dbus_register_interface(conn, path, SYNC_INTERFACE, sync_methods,
+                                               NULL, NULL, sync, sync_free)) {
+               sync_free(sync);
+               return -ENOMEM;
+       }
+
+       return 0;
+}
+
+static void sync_remove(struct obc_session *session)
+{
+       const char *path = obc_session_get_path(session);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(conn, path, SYNC_INTERFACE);
+}
+
+static struct obc_driver sync = {
+       .service = "SYNC",
+       .uuid = SYNC_UUID,
+       .target = OBEX_SYNC_UUID,
+       .target_len = OBEX_SYNC_UUID_LEN,
+       .probe = sync_probe,
+       .remove = sync_remove
+};
+
+int sync_init(void)
+{
+       int err;
+
+       DBG("");
+
+       conn = dbus_bus_get(DBUS_BUS_SESSION, NULL);
+       if (!conn)
+               return -EIO;
+
+       err = obc_driver_register(&sync);
+       if (err < 0) {
+               dbus_connection_unref(conn);
+               conn = NULL;
+               return err;
+       }
+
+       return 0;
+}
+
+void sync_exit(void)
+{
+       DBG("");
+
+       dbus_connection_unref(conn);
+       conn = NULL;
+
+       obc_driver_unregister(&sync);
+}
diff --git a/obexd/client/sync.h b/obexd/client/sync.h
new file mode 100644 (file)
index 0000000..8adc5f8
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+int sync_init(void);
+void sync_exit(void);
diff --git a/obexd/client/transfer.c b/obexd/client/transfer.c
new file mode 100644 (file)
index 0000000..5a8d4f2
--- /dev/null
@@ -0,0 +1,868 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <inttypes.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+#include <gobex/gobex.h>
+
+#include "dbus.h"
+#include "log.h"
+#include "transfer.h"
+
+#define TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
+#define ERROR_INTERFACE "org.bluez.obex.Error"
+
+#define OBC_TRANSFER_ERROR obc_transfer_error_quark()
+
+#define FIRST_PACKET_TIMEOUT 60
+
+static guint64 counter = 0;
+
+struct transfer_callback {
+       transfer_callback_t func;
+       void *data;
+};
+
+enum {
+       TRANSFER_STATUS_QUEUED = 0,
+       TRANSFER_STATUS_ACTIVE,
+       TRANSFER_STATUS_COMPLETE,
+       TRANSFER_STATUS_ERROR
+};
+
+struct obc_transfer {
+       GObex *obex;
+       uint8_t status;
+       GObexApparam *apparam;
+       guint8 op;
+       struct transfer_callback *callback;
+       DBusConnection *conn;
+       DBusMessage *msg;
+       char *session;          /* Session path */
+       char *owner;            /* Transfer initiator */
+       char *path;             /* Transfer path */
+       char *filename;         /* Transfer file location */
+       char *name;             /* Transfer object name */
+       char *type;             /* Transfer object type */
+       int fd;
+       guint xfer;
+       gint64 size;
+       gint64 transferred;
+       gint64 progress;
+       guint progress_id;
+};
+
+static GQuark obc_transfer_error_quark(void)
+{
+       return g_quark_from_static_string("obc-transfer-error-quark");
+}
+
+DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
+                                                       DBusMessage *message)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter;
+
+       reply = dbus_message_new_method_return(message);
+       if (reply == NULL)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &transfer->path);
+       g_dbus_get_properties(transfer->conn, transfer->path,
+                                               TRANSFER_INTERFACE, &iter);
+
+       return reply;
+}
+
+static void abort_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct obc_transfer *transfer = user_data;
+       struct transfer_callback *callback = transfer->callback;
+       DBusMessage *reply;
+
+       transfer->xfer = 0;
+
+       reply = dbus_message_new_method_return(transfer->msg);
+       if (reply)
+               g_dbus_send_message(transfer->conn, reply);
+
+       dbus_message_unref(transfer->msg);
+       transfer->msg = NULL;
+
+       if (callback == NULL)
+               return;
+
+       if (err) {
+               callback->func(transfer, err, callback->data);
+       } else {
+               GError *abort_err;
+
+               abort_err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
+                                               "Transfer cancelled by user");
+               callback->func(transfer, abort_err, callback->data);
+               g_error_free(abort_err);
+       }
+}
+
+static DBusMessage *obc_transfer_cancel(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       struct obc_transfer *transfer = user_data;
+       const char *sender;
+
+       sender = dbus_message_get_sender(message);
+       if (g_strcmp0(transfer->owner, sender) != 0)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".NotAuthorized",
+                               "Not Authorized");
+
+       if (transfer->msg != NULL)
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".InProgress",
+                               "Cancellation already in progress");
+
+       if (transfer->xfer == 0) {
+               struct transfer_callback *callback = transfer->callback;
+
+               if (callback != NULL) {
+                       GError *err;
+
+                       err = g_error_new(OBC_TRANSFER_ERROR, -ECANCELED, "%s",
+                                               "Transfer cancelled by user");
+                       callback->func(transfer, err, callback->data);
+                       g_error_free(err);
+               }
+
+               return dbus_message_new_method_return(message);
+       }
+
+       if (transfer->progress_id != 0) {
+               g_source_remove(transfer->progress_id);
+               transfer->progress_id = 0;
+       }
+
+       if (!g_obex_cancel_transfer(transfer->xfer, abort_complete, transfer))
+               return g_dbus_create_error(message,
+                               ERROR_INTERFACE ".Failed",
+                               "Failed");
+
+       transfer->msg = dbus_message_ref(message);
+
+       return NULL;
+}
+
+static gboolean name_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       return transfer->name != NULL;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       if (transfer->name == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &transfer->name);
+
+       return TRUE;
+}
+
+static gboolean get_size(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
+                                                       &transfer->size);
+
+       return TRUE;
+}
+
+static gboolean filename_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       return transfer->filename != NULL;
+}
+
+static gboolean get_filename(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       if (transfer->filename == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &transfer->filename);
+
+       return TRUE;
+}
+
+static gboolean transferred_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       return transfer->obex != NULL;
+}
+
+static gboolean get_transferred(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       if (transfer->obex == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
+                                                       &transfer->progress);
+
+       return TRUE;
+}
+
+static const char *status2str(uint8_t status)
+{
+       switch (status) {
+       case TRANSFER_STATUS_QUEUED:
+               return "queued";
+       case TRANSFER_STATUS_ACTIVE:
+               return "active";
+       case TRANSFER_STATUS_COMPLETE:
+               return "complete";
+       case TRANSFER_STATUS_ERROR:
+       default:
+               return "error";
+       }
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+       const char *status = status2str(transfer->status);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+       return TRUE;
+}
+
+static gboolean get_session(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obc_transfer *transfer = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &transfer->session);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable obc_transfer_methods[] = {
+       { GDBUS_ASYNC_METHOD("Cancel", NULL, NULL,
+                               obc_transfer_cancel) },
+       { }
+};
+
+static const GDBusPropertyTable obc_transfer_properties[] = {
+       { "Status", "s", get_status },
+       { "Name", "s", get_name, NULL, name_exists },
+       { "Size", "t", get_size },
+       { "Filename", "s", get_filename, NULL, filename_exists },
+       { "Transferred", "t", get_transferred, NULL, transferred_exists },
+       { "Session", "o", get_session },
+       { }
+};
+
+static void obc_transfer_free(struct obc_transfer *transfer)
+{
+       DBG("%p", transfer);
+
+       if (transfer->xfer)
+               g_obex_cancel_transfer(transfer->xfer, NULL, NULL);
+
+       if (transfer->progress_id != 0) {
+               g_source_remove(transfer->progress_id);
+               transfer->progress_id = 0;
+       }
+
+       if (transfer->op == G_OBEX_OP_GET &&
+                               transfer->status != TRANSFER_STATUS_COMPLETE &&
+                               transfer->filename)
+               remove(transfer->filename);
+
+       if (transfer->fd > 0)
+               close(transfer->fd);
+
+       if (transfer->apparam != NULL)
+               g_obex_apparam_free(transfer->apparam);
+
+       if (transfer->conn)
+               dbus_connection_unref(transfer->conn);
+
+       if (transfer->msg)
+               dbus_message_unref(transfer->msg);
+
+       if (transfer->obex)
+               g_obex_unref(transfer->obex);
+
+       g_free(transfer->callback);
+       g_free(transfer->owner);
+       g_free(transfer->filename);
+       g_free(transfer->name);
+       g_free(transfer->type);
+       g_free(transfer->session);
+       g_free(transfer->path);
+       g_free(transfer);
+}
+
+static struct obc_transfer *obc_transfer_create(guint8 op,
+                                               const char *filename,
+                                               const char *name,
+                                               const char *type)
+{
+       struct obc_transfer *transfer;
+
+       transfer = g_new0(struct obc_transfer, 1);
+       transfer->op = op;
+       transfer->filename = g_strdup(filename);
+       transfer->name = g_strdup(name);
+       transfer->type = g_strdup(type);
+
+       return transfer;
+}
+
+gboolean obc_transfer_register(struct obc_transfer *transfer,
+                                               DBusConnection *conn,
+                                               const char *session,
+                                               const char *owner,
+                                               GError **err)
+{
+       transfer->owner = g_strdup(owner);
+
+       transfer->session = g_strdup(session);
+       transfer->path = g_strdup_printf("%s/transfer%ju", session, counter++);
+
+       transfer->conn = dbus_connection_ref(conn);
+       if (transfer->conn == NULL) {
+               g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
+                                               "Unable to connect to D-Bus");
+               return FALSE;
+       }
+
+       if (g_dbus_register_interface(transfer->conn, transfer->path,
+                               TRANSFER_INTERFACE,
+                               obc_transfer_methods, NULL,
+                               obc_transfer_properties, transfer,
+                               NULL) == FALSE) {
+               g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
+                                               "Unable to register to D-Bus");
+               return FALSE;
+       }
+
+       DBG("%p registered %s", transfer, transfer->path);
+
+       return TRUE;
+}
+
+static gboolean transfer_open(struct obc_transfer *transfer, int flags,
+                                               mode_t mode, GError **err)
+{
+       int fd;
+       char *filename;
+
+       if (transfer->filename != NULL && strcmp(transfer->filename, "") != 0) {
+               fd = open(transfer->filename, flags, mode);
+               if (fd < 0) {
+                       error("open(): %s(%d)", strerror(errno), errno);
+                       g_set_error(err, OBC_TRANSFER_ERROR, -errno,
+                                                       "Unable to open file");
+                       return FALSE;
+               }
+               goto done;
+       }
+
+       fd = g_file_open_tmp("obex-clientXXXXXX", &filename, err);
+       if (fd < 0) {
+               error("g_file_open_tmp(): %s", (*err)->message);
+               return FALSE;
+       }
+
+       if (transfer->filename == NULL) {
+               remove(filename); /* remove always only if NULL was given */
+               g_free(filename);
+       } else {
+               g_free(transfer->filename);
+               transfer->filename = filename;
+       }
+
+done:
+       transfer->fd = fd;
+       return TRUE;
+}
+
+struct obc_transfer *obc_transfer_get(const char *type, const char *name,
+                                       const char *filename, GError **err)
+{
+       struct obc_transfer *transfer;
+       int perr;
+
+       transfer = obc_transfer_create(G_OBEX_OP_GET, filename, name, type);
+
+       perr = transfer_open(transfer, O_WRONLY | O_CREAT | O_TRUNC, 0600, err);
+       if (perr < 0) {
+               obc_transfer_free(transfer);
+               return NULL;
+       }
+
+       return transfer;
+}
+
+struct obc_transfer *obc_transfer_put(const char *type, const char *name,
+                                       const char *filename,
+                                       const void *contents, size_t size,
+                                       GError **err)
+{
+       struct obc_transfer *transfer;
+       struct stat st;
+       int perr;
+
+       if ((filename == NULL || strcmp(filename, "") == 0) &&
+                                                       contents == NULL) {
+               g_set_error(err, OBC_TRANSFER_ERROR, -EINVAL,
+                                               "Invalid filename given");
+               return NULL;
+       }
+
+       transfer = obc_transfer_create(G_OBEX_OP_PUT, filename, name, type);
+
+       if (contents != NULL) {
+               ssize_t w;
+
+               if (!transfer_open(transfer, O_RDWR, 0, err))
+                       goto fail;
+
+               w = write(transfer->fd, contents, size);
+               if (w < 0) {
+                       perr = errno;
+                       error("write(): %s(%d)", strerror(perr), perr);
+                       g_set_error(err, OBC_TRANSFER_ERROR, -perr,
+                                               "Writing to file failed");
+                       goto fail;
+               } else if ((size_t) w != size) {
+                       error("Unable to write all contents to file");
+                       g_set_error(err, OBC_TRANSFER_ERROR, -EFAULT,
+                                       "Writing all contents to file failed");
+                       goto fail;
+               }
+               lseek(transfer->fd, 0, SEEK_SET);
+       } else {
+               if (!transfer_open(transfer, O_RDONLY, 0, err))
+                       goto fail;
+       }
+
+       if (fstat(transfer->fd, &st) < 0) {
+               perr = errno;
+               error("fstat(): %s(%d)", strerror(perr), perr);
+               g_set_error(err, OBC_TRANSFER_ERROR, -perr,
+                                               "Unable to get file status");
+               goto fail;
+       }
+
+       transfer->size = st.st_size;
+
+       return transfer;
+
+fail:
+       obc_transfer_free(transfer);
+       return NULL;
+}
+
+void obc_transfer_unregister(struct obc_transfer *transfer)
+{
+       if (transfer->path) {
+               g_dbus_unregister_interface(transfer->conn,
+                       transfer->path, TRANSFER_INTERFACE);
+       }
+
+       DBG("%p unregistered %s", transfer, transfer->path);
+
+       obc_transfer_free(transfer);
+}
+
+static gboolean get_xfer_progress(const void *buf, gsize len,
+                                                       gpointer user_data)
+{
+       struct obc_transfer *transfer = user_data;
+
+       if (transfer->fd > 0) {
+               int w;
+
+               w = write(transfer->fd, buf, len);
+               if (w < 0)
+                       return FALSE;
+
+               transfer->transferred += w;
+       }
+
+       return TRUE;
+}
+
+static void transfer_set_status(struct obc_transfer *transfer, uint8_t status)
+{
+       transfer->status = status;
+
+       g_dbus_emit_property_changed(transfer->conn, transfer->path,
+                                       TRANSFER_INTERFACE, "Status");
+}
+
+static void xfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct obc_transfer *transfer = user_data;
+       struct transfer_callback *callback = transfer->callback;
+
+       transfer->xfer = 0;
+
+       if (transfer->progress_id != 0) {
+               g_source_remove(transfer->progress_id);
+               transfer->progress_id = 0;
+       }
+
+       if (err)
+               transfer_set_status(transfer, TRANSFER_STATUS_ERROR);
+       else
+               transfer_set_status(transfer, TRANSFER_STATUS_COMPLETE);
+
+       if (callback)
+               callback->func(transfer, err, callback->data);
+}
+
+static void get_xfer_progress_first(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct obc_transfer *transfer = user_data;
+       GObexPacket *req;
+       GObexHeader *hdr;
+       GObexApparam *apparam;
+       const guint8 *buf;
+       gsize len;
+       guint8 rspcode;
+       gboolean final;
+
+       if (err != NULL) {
+               xfer_complete(obex, err, transfer);
+               return;
+       }
+
+       rspcode = g_obex_packet_get_operation(rsp, &final);
+       if (rspcode != G_OBEX_RSP_SUCCESS && rspcode != G_OBEX_RSP_CONTINUE) {
+               err = g_error_new(OBC_TRANSFER_ERROR, rspcode, "%s",
+                                               g_obex_strerror(rspcode));
+               xfer_complete(obex, err, transfer);
+               g_error_free(err);
+               return;
+       }
+
+       hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_LENGTH);
+       if (hdr) {
+               uint32_t len;
+               if (g_obex_header_get_uint32(hdr, &len)) {
+                       transfer->size = len;
+                       g_dbus_emit_property_changed(transfer->conn,
+                                               transfer->path,
+                                               TRANSFER_INTERFACE, "Size");
+               }
+       }
+
+       hdr = g_obex_packet_get_header(rsp, G_OBEX_HDR_APPARAM);
+       if (hdr) {
+               apparam = g_obex_header_get_apparam(hdr);
+               if (apparam != NULL)
+                       obc_transfer_set_apparam(transfer, apparam);
+       }
+
+       hdr = g_obex_packet_get_body(rsp);
+       if (hdr) {
+               g_obex_header_get_bytes(hdr, &buf, &len);
+               if (len != 0)
+                       get_xfer_progress(buf, len, transfer);
+       }
+
+       if (rspcode == G_OBEX_RSP_SUCCESS) {
+               xfer_complete(obex, err, transfer);
+               return;
+       }
+
+       if (!g_obex_srm_active(obex)) {
+               req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
+
+               transfer->xfer = g_obex_get_req_pkt(obex, req, get_xfer_progress,
+                                               xfer_complete, transfer,
+                                               &err);
+       }
+}
+
+static gssize put_xfer_progress(void *buf, gsize len, gpointer user_data)
+{
+       struct obc_transfer *transfer = user_data;
+       gssize size;
+
+       size = read(transfer->fd, buf, len);
+       if (size <= 0)
+               return size;
+
+       transfer->transferred += size;
+
+       return size;
+}
+
+gboolean obc_transfer_set_callback(struct obc_transfer *transfer,
+                                       transfer_callback_t func,
+                                       void *user_data)
+{
+       struct transfer_callback *callback;
+
+       if (transfer->callback != NULL)
+               return FALSE;
+
+       callback = g_new0(struct transfer_callback, 1);
+       callback->func = func;
+       callback->data = user_data;
+
+       transfer->callback = callback;
+
+       return TRUE;
+}
+
+static gboolean report_progress(gpointer data)
+{
+       struct obc_transfer *transfer = data;
+
+       if (transfer->transferred == transfer->progress)
+               return TRUE;
+
+       transfer->progress = transfer->transferred;
+
+       if (transfer->transferred == transfer->size) {
+               transfer->progress_id = 0;
+               return FALSE;
+       }
+
+       if (transfer->status != TRANSFER_STATUS_ACTIVE)
+               transfer_set_status(transfer, TRANSFER_STATUS_ACTIVE);
+
+       g_dbus_emit_property_changed(transfer->conn, transfer->path,
+                                       TRANSFER_INTERFACE, "Transferred");
+
+       return TRUE;
+}
+
+static gboolean transfer_start_get(struct obc_transfer *transfer, GError **err)
+{
+       GObexPacket *req;
+       GObexHeader *hdr;
+
+       if (transfer->xfer > 0) {
+               g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
+                                               "Transfer already started");
+               return FALSE;
+       }
+
+       req = g_obex_packet_new(G_OBEX_OP_GET, TRUE, G_OBEX_HDR_INVALID);
+
+       if (transfer->name != NULL)
+               g_obex_packet_add_unicode(req, G_OBEX_HDR_NAME,
+                                                       transfer->name);
+
+       if (transfer->type != NULL)
+               g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
+                                               strlen(transfer->type) + 1);
+
+       if (transfer->apparam != NULL) {
+               hdr = g_obex_header_new_apparam(transfer->apparam);
+               g_obex_packet_add_header(req, hdr);
+       }
+
+       transfer->xfer = g_obex_send_req(transfer->obex, req,
+                                               FIRST_PACKET_TIMEOUT,
+                                               get_xfer_progress_first,
+                                               transfer, err);
+       if (transfer->xfer == 0)
+               return FALSE;
+
+       if (transfer->path == NULL)
+               return TRUE;
+
+       transfer->progress_id = g_timeout_add_seconds(1, report_progress,
+                                                               transfer);
+
+       return TRUE;
+}
+
+static gboolean transfer_start_put(struct obc_transfer *transfer, GError **err)
+{
+       GObexPacket *req;
+       GObexHeader *hdr;
+
+       if (transfer->xfer > 0) {
+               g_set_error(err, OBC_TRANSFER_ERROR, -EALREADY,
+                                               "Transfer already started");
+               return FALSE;
+       }
+
+       req = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
+
+       if (transfer->name != NULL)
+               g_obex_packet_add_unicode(req, G_OBEX_HDR_NAME,
+                                                       transfer->name);
+
+       if (transfer->type != NULL)
+               g_obex_packet_add_bytes(req, G_OBEX_HDR_TYPE, transfer->type,
+                                               strlen(transfer->type) + 1);
+
+       if (transfer->size < UINT32_MAX)
+               g_obex_packet_add_uint32(req, G_OBEX_HDR_LENGTH, transfer->size);
+
+       if (transfer->apparam != NULL) {
+               hdr = g_obex_header_new_apparam(transfer->apparam);
+               g_obex_packet_add_header(req, hdr);
+       }
+
+       transfer->xfer = g_obex_put_req_pkt(transfer->obex, req,
+                                       put_xfer_progress, xfer_complete,
+                                       transfer, err);
+       if (transfer->xfer == 0)
+               return FALSE;
+
+       if (transfer->path == NULL)
+               return TRUE;
+
+       transfer->progress_id = g_timeout_add_seconds(1, report_progress,
+                                                               transfer);
+
+       return TRUE;
+}
+
+gboolean obc_transfer_start(struct obc_transfer *transfer, void *obex,
+                                                               GError **err)
+{
+       transfer->obex = g_obex_ref(obex);
+
+       switch (transfer->op) {
+       case G_OBEX_OP_GET:
+               return transfer_start_get(transfer, err);
+       case G_OBEX_OP_PUT:
+               return transfer_start_put(transfer, err);
+       }
+
+       g_set_error(err, OBC_TRANSFER_ERROR, -ENOTSUP, "Not supported");
+       return FALSE;
+}
+
+guint8 obc_transfer_get_operation(struct obc_transfer *transfer)
+{
+       return transfer->op;
+}
+
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data)
+{
+       if (transfer->apparam != NULL)
+               g_obex_apparam_free(transfer->apparam);
+
+       if (data == NULL)
+               return;
+
+       transfer->apparam = data;
+}
+
+void *obc_transfer_get_apparam(struct obc_transfer *transfer)
+{
+       return transfer->apparam;
+}
+
+int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
+                                                               size_t *size)
+{
+       struct stat st;
+       ssize_t ret;
+
+       if (contents == NULL)
+               return -EINVAL;
+
+       if (fstat(transfer->fd, &st) < 0) {
+               error("fstat(): %s(%d)", strerror(errno), errno);
+               return -errno;
+       }
+
+       if (lseek(transfer->fd, 0, SEEK_SET) < 0) {
+               error("lseek(): %s(%d)", strerror(errno), errno);
+               return -errno;
+       }
+
+       *contents = g_malloc(st.st_size + 1);
+
+       ret = read(transfer->fd, *contents, st.st_size);
+       if (ret < 0) {
+               error("read(): %s(%d)", strerror(errno), errno);
+               g_free(*contents);
+               return -errno;
+       }
+
+       (*contents)[ret] = '\0';
+
+       if (size)
+               *size = ret;
+
+       return 0;
+}
+
+const char *obc_transfer_get_path(struct obc_transfer *transfer)
+{
+       return transfer->path;
+}
+
+gint64 obc_transfer_get_size(struct obc_transfer *transfer)
+{
+       return transfer->size;
+}
diff --git a/obexd/client/transfer.h b/obexd/client/transfer.h
new file mode 100644 (file)
index 0000000..b6b835d
--- /dev/null
@@ -0,0 +1,62 @@
+/*
+ *
+ *  OBEX Client
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011-2012  BMW Car IT GmbH. 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
+ *
+ */
+
+struct obc_transfer;
+
+typedef void (*transfer_callback_t) (struct obc_transfer *transfer,
+                                       GError *err, void *user_data);
+
+struct obc_transfer *obc_transfer_get(const char *type, const char *name,
+                                       const char *filename, GError **err);
+struct obc_transfer *obc_transfer_put(const char *type, const char *name,
+                                       const char *filename,
+                                       const void *contents, size_t size,
+                                       GError **err);
+
+gboolean obc_transfer_register(struct obc_transfer *transfer,
+                                       DBusConnection *conn,
+                                       const char *session,
+                                       const char *owner,
+                                       GError **err);
+
+void obc_transfer_unregister(struct obc_transfer *transfer);
+
+gboolean obc_transfer_set_callback(struct obc_transfer *transfer,
+                                       transfer_callback_t func,
+                                       void *user_data);
+
+gboolean obc_transfer_start(struct obc_transfer *transfer, void *obex,
+                                                               GError **err);
+guint8 obc_transfer_get_operation(struct obc_transfer *transfer);
+
+void obc_transfer_set_apparam(struct obc_transfer *transfer, void *data);
+void *obc_transfer_get_apparam(struct obc_transfer *transfer);
+int obc_transfer_get_contents(struct obc_transfer *transfer, char **contents,
+                                                               size_t *size);
+
+const char *obc_transfer_get_path(struct obc_transfer *transfer);
+gint64 obc_transfer_get_size(struct obc_transfer *transfer);
+
+DBusMessage *obc_transfer_create_dbus_reply(struct obc_transfer *transfer,
+                                                       DBusMessage *message);
diff --git a/obexd/client/transport.c b/obexd/client/transport.c
new file mode 100644 (file)
index 0000000..77e52f7
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2012 Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <inttypes.h>
+
+#include "transport.h"
+#include "log.h"
+
+static GSList *transports = NULL;
+
+struct obc_transport *obc_transport_find(const char *name)
+{
+       GSList *l;
+
+       for (l = transports; l; l = l->next) {
+               struct obc_transport *transport = l->data;
+
+               if (strcasecmp(name, transport->name) == 0)
+                       return transport;
+       }
+
+       return NULL;
+}
+
+int obc_transport_register(struct obc_transport *transport)
+{
+       if (!transport) {
+               error("Invalid transport");
+               return -EINVAL;
+       }
+
+       if (obc_transport_find(transport->name)) {
+               error("Permission denied: transport %s already registered",
+                                                       transport->name);
+               return -EPERM;
+       }
+
+       DBG("transport %p name %s registered", transport, transport->name);
+
+       transports = g_slist_append(transports, transport);
+
+       return 0;
+}
+
+void obc_transport_unregister(struct obc_transport *transport)
+{
+       if (!g_slist_find(transports, transport)) {
+               error("Unable to unregister: No such transport %p", transport);
+               return;
+       }
+
+       DBG("transport %p name %s unregistered", transport, transport->name);
+
+       transports = g_slist_remove(transports, transport);
+}
similarity index 52%
rename from input/fakehid.h
rename to obexd/client/transport.h
index 3a5d7c4..b035cfc 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *
- *  BlueZ - Bluetooth protocol stack for Linux
+ *  OBEX Server
  *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012 Intel Corporation
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-struct fake_hid;
-struct fake_input;
+typedef void (*obc_transport_func)(GIOChannel *io, GError *err,
+                                                       gpointer user_data);
 
-struct fake_hid {
-       uint16_t vendor;
-       uint16_t product;
-       gboolean (*connect) (struct fake_input *fake_input, GError **err);
-       int (*disconnect) (struct fake_input *fake_input);
-       gboolean (*event) (GIOChannel *chan, GIOCondition cond, gpointer data);
-       int (*setup_uinput) (struct fake_input *fake, struct fake_hid *fake_hid);
-       GList *devices;
+struct obc_transport {
+       const char *name;
+       guint (*connect) (const char *source, const char *destination,
+                               const char *service, uint16_t port,
+                               obc_transport_func func, void *user_data);
+       int (*getpacketopt) (GIOChannel *io, int *tx_mtu, int *rx_mtu);
+       void (*disconnect) (guint id);
+       const void *(*getattribute) (guint id, int attribute_id);
 };
 
-struct fake_hid *get_fake_hid(uint16_t vendor, uint16_t product);
-
-struct fake_input *fake_hid_connadd(struct fake_input *fake, GIOChannel *intr_io,
-                                               struct fake_hid *fake_hid);
+int obc_transport_register(struct obc_transport *transport);
+void obc_transport_unregister(struct obc_transport *transport);
+struct obc_transport *obc_transport_find(const char *name);
diff --git a/obexd/plugins/bluetooth.c b/obexd/plugins/bluetooth.c
new file mode 100644 (file)
index 0000000..143d0c2
--- /dev/null
@@ -0,0 +1,495 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+#include <fcntl.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+#include <btio/btio.h>
+
+#include "lib/uuid.h"
+
+#include "obexd.h"
+#include "plugin.h"
+#include "server.h"
+#include "obex.h"
+#include "transport.h"
+#include "service.h"
+#include "log.h"
+
+#define BT_RX_MTU 32767
+#define BT_TX_MTU 32767
+
+struct bluetooth_profile {
+       struct obex_server *server;
+       struct obex_service_driver *driver;
+       char *uuid;
+       char *path;
+};
+
+static GSList *profiles = NULL;
+
+static DBusConnection *connection = NULL;
+
+static DBusMessage *profile_release(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static void connect_event(GIOChannel *io, GError *err, void *user_data)
+{
+       int sk = g_io_channel_unix_get_fd(io);
+       struct bluetooth_profile *profile = user_data;
+       struct obex_server *server = profile->server;
+       int type;
+       int omtu = BT_TX_MTU;
+       int imtu = BT_RX_MTU;
+       gboolean stream = TRUE;
+       socklen_t len = sizeof(int);
+
+       if (err)
+               goto drop;
+
+       if (getsockopt(sk, SOL_SOCKET, SO_TYPE, &type, &len) < 0)
+               goto done;
+
+       if (type != SOCK_SEQPACKET)
+               goto done;
+
+       stream = FALSE;
+
+       /* Read MTU if io is an L2CAP socket */
+       bt_io_get(io, NULL, BT_IO_OPT_OMTU, &omtu, BT_IO_OPT_IMTU, &imtu,
+                                                       BT_IO_OPT_INVALID);
+
+done:
+       if (obex_server_new_connection(server, io, omtu, imtu, stream) < 0)
+               g_io_channel_shutdown(io, TRUE, NULL);
+
+       return;
+
+drop:
+       error("%s", err->message);
+       g_io_channel_shutdown(io, TRUE, NULL);
+       return;
+}
+
+static DBusMessage *invalid_args(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
+                                       "Invalid arguments in method call");
+}
+
+static DBusMessage *profile_new_connection(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       DBusMessageIter args;
+       const char *device;
+       int fd;
+       GIOChannel *io;
+
+       dbus_message_iter_init(msg, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_OBJECT_PATH)
+               return invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &device);
+
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_UNIX_FD)
+               return invalid_args(msg);
+
+       dbus_message_iter_get_basic(&args, &fd);
+
+       if (fd < 0) {
+               error("bluetooth: NewConnection invalid fd");
+               return invalid_args(msg);
+       }
+
+       /* Read fd flags to make sure it can be used */
+       if (fcntl(fd, F_GETFD) < 0) {
+               error("bluetooth: fcntl(%d, F_GETFD): %s (%d)", fd,
+                                               strerror(errno), errno);
+               return invalid_args(msg);
+       }
+
+       io = g_io_channel_unix_new(fd);
+       if (io == NULL)
+               return invalid_args(msg);
+
+       DBG("device %s", device);
+
+       connect_event(io, NULL, data);
+       g_io_channel_unref(io);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *profile_request_disconnection(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *profile_cancel(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable profile_methods[] = {
+       { GDBUS_METHOD("Release",
+                       NULL, NULL,
+                       profile_release) },
+       { GDBUS_METHOD("NewConnection",
+                       GDBUS_ARGS({ "device", "o" }, { "fd", "h" },
+                       { "options", "a{sv}" }), NULL,
+                       profile_new_connection) },
+       { GDBUS_METHOD("RequestDisconnection",
+                       GDBUS_ARGS({ "device", "o" }), NULL,
+                       profile_request_disconnection) },
+       { GDBUS_METHOD("Cancel",
+                       NULL, NULL,
+                       profile_cancel) },
+       { }
+};
+
+static void unregister_profile(struct bluetooth_profile *profile)
+{
+       g_dbus_unregister_interface(connection, profile->path,
+                                               "org.bluez.Profile1");
+       g_free(profile->path);
+       profile->path = NULL;
+}
+
+static void register_profile_reply(DBusPendingCall *call, void *user_data)
+{
+       struct bluetooth_profile *profile = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError derr;
+
+       dbus_error_init(&derr);
+       if (!dbus_set_error_from_message(&derr, reply)) {
+               DBG("Profile %s registered", profile->path);
+               goto done;
+       }
+
+       unregister_profile(profile);
+
+       error("bluetooth: RequestProfile error: %s, %s", derr.name,
+                                                               derr.message);
+       dbus_error_free(&derr);
+done:
+       dbus_message_unref(reply);
+}
+
+static void profile_free(void *data)
+{
+       struct bluetooth_profile *profile = data;
+
+       if (profile->path != NULL)
+               unregister_profile(profile);
+
+       g_free(profile->uuid);
+       g_free(profile);
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+       DBusMessageIter value;
+       char sig[2] = { type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+       dbus_message_iter_append_basic(&value, type, val);
+
+       dbus_message_iter_close_container(iter, &value);
+}
+
+
+static void dict_append_entry(DBusMessageIter *dict,
+                       const char *key, int type, void *val)
+{
+       DBusMessageIter entry;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) val);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static int register_profile(struct bluetooth_profile *profile)
+{
+       DBusMessage *msg;
+       DBusMessageIter iter, opt;
+       DBusPendingCall *call;
+       dbus_bool_t auto_connect = FALSE;
+       char *xml;
+       int ret = 0;
+
+       profile->path = g_strconcat("/org/bluez/obex/", profile->uuid, NULL);
+       g_strdelimit(profile->path, "-", '_');
+
+       if (!g_dbus_register_interface(connection, profile->path,
+                                       "org.bluez.Profile1", profile_methods,
+                                       NULL, NULL,
+                                       profile, NULL)) {
+               error("D-Bus failed to register %s", profile->path);
+               g_free(profile->path);
+               profile->path = NULL;
+               return -1;
+       }
+
+       msg = dbus_message_new_method_call("org.bluez", "/org/bluez",
+                                               "org.bluez.ProfileManager1",
+                                               "RegisterProfile");
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &profile->path);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING,
+                                                       &profile->uuid);
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &opt);
+       dict_append_entry(&opt, "AutoConnect", DBUS_TYPE_BOOLEAN,
+                                                               &auto_connect);
+       if (profile->driver->record) {
+               if (profile->driver->port != 0)
+                       xml = g_markup_printf_escaped(profile->driver->record,
+                                               profile->driver->channel,
+                                               profile->driver->name,
+                                               profile->driver->port);
+               else
+                       xml = g_markup_printf_escaped(profile->driver->record,
+                                               profile->driver->channel,
+                                               profile->driver->name);
+               dict_append_entry(&opt, "ServiceRecord", DBUS_TYPE_STRING,
+                                                               &xml);
+               g_free(xml);
+       }
+       dbus_message_iter_close_container(&iter, &opt);
+
+       if (!g_dbus_send_message_with_reply(connection, msg, &call, -1)) {
+               ret = -1;
+               unregister_profile(profile);
+               goto failed;
+       }
+
+       dbus_pending_call_set_notify(call, register_profile_reply, profile,
+                                                                       NULL);
+       dbus_pending_call_unref(call);
+
+failed:
+       dbus_message_unref(msg);
+       return ret;
+}
+
+static const char *service2uuid(uint16_t service)
+{
+       switch (service) {
+       case OBEX_OPP:
+               return OBEX_OPP_UUID;
+       case OBEX_FTP:
+               return OBEX_FTP_UUID;
+       case OBEX_PBAP:
+               return OBEX_PSE_UUID;
+       case OBEX_IRMC:
+               return OBEX_SYNC_UUID;
+       case OBEX_PCSUITE:
+               return "00005005-0000-1000-8000-0002ee000001";
+       case OBEX_SYNCEVOLUTION:
+               return "00000002-0000-1000-8000-0002ee000002";
+       case OBEX_MAS:
+               return OBEX_MAS_UUID;
+       case OBEX_MNS:
+               return OBEX_MNS_UUID;
+       }
+
+       return NULL;
+}
+
+static void name_acquired(DBusConnection *conn, void *user_data)
+{
+       GSList *l;
+
+       DBG("org.bluez appeared");
+
+       for (l = profiles; l; l = l->next) {
+               struct bluetooth_profile *profile = l->data;
+
+               if (profile->path != NULL)
+                       continue;
+
+               if (register_profile(profile) < 0) {
+                       error("bluetooth: Failed to register profile %s",
+                                                       profile->path);
+                       g_free(profile->path);
+                       profile->path = NULL;
+               }
+       }
+}
+
+static void name_released(DBusConnection *conn, void *user_data)
+{
+       GSList *l;
+
+       DBG("org.bluez disappered");
+
+       for (l = profiles; l; l = l->next) {
+               struct bluetooth_profile *profile = l->data;
+
+               if (profile->path == NULL)
+                       continue;
+
+               unregister_profile(profile);
+       }
+}
+
+static void *bluetooth_start(struct obex_server *server, int *err)
+{
+       const GSList *l;
+
+       for (l = server->drivers; l; l = l->next) {
+               struct obex_service_driver *driver = l->data;
+               struct bluetooth_profile *profile;
+               const char *uuid;
+
+               uuid = service2uuid(driver->service);
+               if (uuid == NULL)
+                       continue;
+
+               profile = g_new0(struct bluetooth_profile, 1);
+               profile->driver = driver;
+               profile->server = server;
+               profile->uuid = g_strdup(uuid);
+
+               profiles = g_slist_prepend(profiles, profile);
+       }
+
+       return profiles;
+}
+
+static void bluetooth_stop(void *data)
+{
+       g_slist_free_full(profiles, profile_free);
+       profiles = NULL;
+}
+
+static int bluetooth_getpeername(GIOChannel *io, char **name)
+{
+       GError *gerr = NULL;
+       char address[18];
+
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST, address, BT_IO_OPT_INVALID);
+
+       if (gerr) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               return -EINVAL;
+       }
+
+       *name = g_strdup(address);
+
+       return 0;
+}
+
+static int bluetooth_getsockname(GIOChannel *io, char **name)
+{
+       GError *gerr = NULL;
+       char address[18];
+
+       bt_io_get(io, &gerr, BT_IO_OPT_SOURCE, address, BT_IO_OPT_INVALID);
+
+       if (gerr) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               return -EINVAL;
+       }
+
+       *name = g_strdup(address);
+
+       return 0;
+}
+
+static struct obex_transport_driver driver = {
+       .name = "bluetooth",
+       .start = bluetooth_start,
+       .getpeername = bluetooth_getpeername,
+       .getsockname = bluetooth_getsockname,
+       .stop = bluetooth_stop
+};
+
+static unsigned int listener_id = 0;
+
+static int bluetooth_init(void)
+{
+       connection = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
+       if (connection == NULL)
+               return -EPERM;
+
+       listener_id = g_dbus_add_service_watch(connection, "org.bluez",
+                               name_acquired, name_released, NULL, NULL);
+
+       return obex_transport_driver_register(&driver);
+}
+
+static void bluetooth_exit(void)
+{
+       g_dbus_remove_watch(connection, listener_id);
+
+       g_slist_free_full(profiles, profile_free);
+
+       if (connection)
+               dbus_connection_unref(connection);
+
+       obex_transport_driver_unregister(&driver);
+}
+
+OBEX_PLUGIN_DEFINE(bluetooth, bluetooth_init, bluetooth_exit)
diff --git a/obexd/plugins/filesystem.c b/obexd/plugins/filesystem.c
new file mode 100644 (file)
index 0000000..1132a34
--- /dev/null
@@ -0,0 +1,722 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2009-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <dirent.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <sys/sendfile.h>
+#include <fcntl.h>
+#include <wait.h>
+#include <inttypes.h>
+
+#include <glib.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "mimetype.h"
+#include "filesystem.h"
+
+#define EOL_CHARS "\n"
+
+#define FL_VERSION "<?xml version=\"1.0\" encoding=\"UTF-8\"?>" EOL_CHARS
+
+#define FL_TYPE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">" EOL_CHARS
+
+#define FL_TYPE_PCSUITE "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\"" EOL_CHARS \
+                       "  [ <!ATTLIST folder mem-type CDATA #IMPLIED> ]>" EOL_CHARS
+
+#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">" EOL_CHARS
+
+#define FL_BODY_END "</folder-listing>" EOL_CHARS
+
+#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>" EOL_CHARS
+
+#define FL_FILE_ELEMENT "<file name=\"%s\" size=\"%" PRIu64 "\"" \
+                       " %s accessed=\"%s\" " \
+                       "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
+
+#define FL_FOLDER_ELEMENT "<folder name=\"%s\" %s accessed=\"%s\" " \
+                       "modified=\"%s\" created=\"%s\"/>" EOL_CHARS
+
+#define FL_FOLDER_ELEMENT_PCSUITE "<folder name=\"%s\" %s accessed=\"%s\"" \
+                       " modified=\"%s\" mem-type=\"DEV\"" \
+                       " created=\"%s\"/>" EOL_CHARS
+
+#define FTP_TARGET_SIZE 16
+
+static const uint8_t FTP_TARGET[FTP_TARGET_SIZE] = {
+                       0xF9, 0xEC, 0x7B, 0xC4,  0x95, 0x3C, 0x11, 0xD2,
+                       0x98, 0x4E, 0x52, 0x54,  0x00, 0xDC, 0x9E, 0x09  };
+
+#define PCSUITE_WHO_SIZE 8
+
+static const uint8_t PCSUITE_WHO[PCSUITE_WHO_SIZE] = {
+                       'P', 'C', ' ', 'S', 'u', 'i', 't', 'e' };
+
+gboolean is_filename(const char *name)
+{
+       if (strchr(name, '/'))
+               return FALSE;
+
+       if (strcmp(name, ".") == 0)
+               return FALSE;
+
+       if (strcmp(name, "..") == 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+int verify_path(const char *path)
+{
+       char *t;
+       int ret = 0;
+
+       if (obex_option_symlinks())
+               return 0;
+
+       t = realpath(path, NULL);
+       if (t == NULL)
+               return -errno;
+
+       if (!g_str_has_prefix(t, obex_option_root_folder()))
+               ret = -EPERM;
+
+       free(t);
+
+       return ret;
+}
+
+static char *file_stat_line(char *filename, struct stat *fstat,
+                                       struct stat *dstat, gboolean root,
+                                       gboolean pcsuite)
+{
+       char perm[51], atime[18], ctime[18], mtime[18];
+       char *escaped, *ret = NULL;
+
+       snprintf(perm, 50, "user-perm=\"%s%s%s\" group-perm=\"%s%s%s\" "
+                       "other-perm=\"%s%s%s\"",
+                       (fstat->st_mode & S_IRUSR ? "R" : ""),
+                       (fstat->st_mode & S_IWUSR ? "W" : ""),
+                       (dstat->st_mode & S_IWUSR ? "D" : ""),
+                       (fstat->st_mode & S_IRGRP ? "R" : ""),
+                       (fstat->st_mode & S_IWGRP ? "W" : ""),
+                       (dstat->st_mode & S_IWGRP ? "D" : ""),
+                       (fstat->st_mode & S_IROTH ? "R" : ""),
+                       (fstat->st_mode & S_IWOTH ? "W" : ""),
+                       (dstat->st_mode & S_IWOTH ? "D" : ""));
+
+       strftime(atime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_atime));
+       strftime(ctime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_ctime));
+       strftime(mtime, 17, "%Y%m%dT%H%M%SZ", gmtime(&fstat->st_mtime));
+
+       escaped = g_markup_escape_text(filename, -1);
+
+       if (S_ISDIR(fstat->st_mode)) {
+               if (pcsuite && root && g_str_equal(filename, "Data"))
+                       ret = g_strdup_printf(FL_FOLDER_ELEMENT_PCSUITE,
+                                               escaped, perm, atime,
+                                               mtime, ctime);
+               else
+                       ret = g_strdup_printf(FL_FOLDER_ELEMENT, escaped, perm,
+                                                       atime, mtime, ctime);
+       } else if (S_ISREG(fstat->st_mode))
+               ret = g_strdup_printf(FL_FILE_ELEMENT, escaped,
+                                       (uint64_t) fstat->st_size,
+                                       perm, atime, mtime, ctime);
+
+       g_free(escaped);
+
+       return ret;
+}
+
+static void *filesystem_open(const char *name, int oflag, mode_t mode,
+                                       void *context, size_t *size, int *err)
+{
+       struct stat stats;
+       struct statvfs buf;
+       int fd, ret;
+       uint64_t avail;
+
+       fd = open(name, oflag, mode);
+       if (fd < 0) {
+               if (err)
+                       *err = -errno;
+               return NULL;
+       }
+
+       if (fstat(fd, &stats) < 0) {
+               if (err)
+                       *err = -errno;
+               goto failed;
+       }
+
+       ret = verify_path(name);
+       if (ret < 0) {
+               if (err)
+                       *err = ret;
+               goto failed;
+       }
+
+       if (oflag == O_RDONLY) {
+               if (size)
+                       *size = stats.st_size;
+               goto done;
+       }
+
+       if (fstatvfs(fd, &buf) < 0) {
+               if (err)
+                       *err = -errno;
+               goto failed;
+       }
+
+       if (size == NULL)
+               goto done;
+
+       avail = (uint64_t) buf.f_bsize * buf.f_bavail;
+       if (avail < *size) {
+               if (err)
+                       *err = -ENOSPC;
+               goto failed;
+       }
+
+done:
+       if (err)
+               *err = 0;
+
+       return GINT_TO_POINTER(fd);
+
+failed:
+       close(fd);
+       return NULL;
+}
+
+static int filesystem_close(void *object)
+{
+       if (close(GPOINTER_TO_INT(object)) < 0)
+               return -errno;
+
+       return 0;
+}
+
+static ssize_t filesystem_read(void *object, void *buf, size_t count)
+{
+       ssize_t ret;
+
+       ret = read(GPOINTER_TO_INT(object), buf, count);
+       if (ret < 0)
+               return -errno;
+
+       return ret;
+}
+
+static ssize_t filesystem_write(void *object, const void *buf, size_t count)
+{
+       ssize_t ret;
+
+       ret = write(GPOINTER_TO_INT(object), buf, count);
+       if (ret < 0)
+               return -errno;
+
+       return ret;
+}
+
+static int filesystem_rename(const char *name, const char *destname)
+{
+       int ret;
+
+       ret = rename(name, destname);
+       if (ret < 0) {
+               error("rename(%s, %s): %s (%d)", name, destname,
+                                               strerror(errno), errno);
+               return -errno;
+       }
+
+       return ret;
+}
+
+static int sendfile_async(int out_fd, int in_fd, off_t *offset, size_t count)
+{
+       int pid;
+
+       /* Run sendfile on child process */
+       pid = fork();
+       switch (pid) {
+               case 0:
+                       break;
+               case -1:
+                       error("fork() %s (%d)", strerror(errno), errno);
+                       return -errno;
+               default:
+                       DBG("child %d forked", pid);
+                       return pid;
+       }
+
+       /* At child */
+       if (sendfile(out_fd, in_fd, offset, count) < 0)
+               error("sendfile(): %s (%d)", strerror(errno), errno);
+
+       close(in_fd);
+       close(out_fd);
+
+       exit(errno);
+}
+
+static int filesystem_copy(const char *name, const char *destname)
+{
+       void *in, *out;
+       ssize_t ret;
+       size_t size;
+       struct stat st;
+       int in_fd, out_fd, err;
+
+       in = filesystem_open(name, O_RDONLY, 0, NULL, &size, &err);
+       if (in == NULL) {
+               error("open(%s): %s (%d)", name, strerror(-err), -err);
+               return -err;
+       }
+
+       in_fd = GPOINTER_TO_INT(in);
+       ret = fstat(in_fd, &st);
+       if (ret < 0) {
+               error("stat(%s): %s (%d)", name, strerror(errno), errno);
+               return -errno;
+       }
+
+       out = filesystem_open(destname, O_WRONLY | O_CREAT | O_TRUNC,
+                                       st.st_mode, NULL, &size, &err);
+       if (out == NULL) {
+               error("open(%s): %s (%d)", destname, strerror(-err), -err);
+               filesystem_close(in);
+               return -errno;
+       }
+
+       out_fd = GPOINTER_TO_INT(out);
+
+       /* Check if sendfile is supported */
+       ret = sendfile(out_fd, in_fd, NULL, 0);
+       if (ret < 0) {
+               ret = -errno;
+               error("sendfile: %s (%zd)", strerror(-ret), -ret);
+               goto done;
+       }
+
+       ret = sendfile_async(out_fd, in_fd, NULL, st.st_size);
+       if (ret < 0)
+               goto done;
+
+       return 0;
+
+done:
+       filesystem_close(in);
+       filesystem_close(out);
+
+       return ret;
+}
+
+struct capability_object {
+       int pid;
+       int output;
+       int err;
+       gboolean aborted;
+       GString *buffer;
+};
+
+static void script_exited(GPid pid, int status, void *data)
+{
+       struct capability_object *object = data;
+       char buf[128];
+
+       object->pid = -1;
+
+       DBG("pid: %d status: %d", pid, status);
+
+       g_spawn_close_pid(pid);
+
+       /* free the object if aborted */
+       if (object->aborted) {
+               if (object->buffer != NULL)
+                       g_string_free(object->buffer, TRUE);
+
+               g_free(object);
+               return;
+       }
+
+       if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+               memset(buf, 0, sizeof(buf));
+               if (read(object->err, buf, sizeof(buf)) > 0)
+                       error("%s", buf);
+               obex_object_set_io_flags(data, G_IO_ERR, -EPERM);
+       } else
+               obex_object_set_io_flags(data, G_IO_IN, 0);
+}
+
+static int capability_exec(const char **argv, int *output, int *err)
+{
+       GError *gerr = NULL;
+       int pid;
+       GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
+
+       if (!g_spawn_async_with_pipes(NULL, (char **) argv, NULL, flags, NULL,
+                               NULL, &pid, NULL, output, err, &gerr)) {
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               return -EPERM;
+       }
+
+       DBG("executing %s pid %d", argv[0], pid);
+
+       return pid;
+}
+
+static void *capability_open(const char *name, int oflag, mode_t mode,
+                                       void *context, size_t *size, int *err)
+{
+       struct capability_object *object = NULL;
+       char *buf;
+       const char *argv[2];
+
+       if (oflag != O_RDONLY)
+               goto fail;
+
+       object = g_new0(struct capability_object, 1);
+       object->pid = -1;
+       object->output = -1;
+       object->err = -1;
+
+       if (name[0] != '!') {
+               GError *gerr = NULL;
+               gboolean ret;
+
+               ret = g_file_get_contents(name, &buf, NULL, &gerr);
+               if (ret == FALSE) {
+                       error("%s", gerr->message);
+                       g_error_free(gerr);
+                       goto fail;
+               }
+
+               object->buffer = g_string_new(buf);
+
+               if (size)
+                       *size = object->buffer->len;
+
+               goto done;
+       }
+
+       argv[0] = &name[1];
+       argv[1] = NULL;
+
+       object->pid = capability_exec(argv, &object->output, &object->err);
+       if (object->pid < 0)
+               goto fail;
+
+       /* Watch cannot be removed while the process is still running */
+       g_child_watch_add(object->pid, script_exited, object);
+
+done:
+       if (err)
+               *err = 0;
+
+       return object;
+
+fail:
+       if (err)
+               *err = -EPERM;
+
+       g_free(object);
+       return NULL;
+}
+
+static GString *append_pcsuite_preamble(GString *object)
+{
+       return g_string_append(object, FL_TYPE_PCSUITE);
+}
+
+static GString *append_folder_preamble(GString *object)
+{
+       return g_string_append(object, FL_TYPE);
+}
+
+static GString *append_listing(GString *object, const char *name,
+                               gboolean pcsuite, size_t *size, int *err)
+{
+       struct stat fstat, dstat;
+       struct dirent *ep;
+       DIR *dp;
+       gboolean root;
+       int ret;
+
+       root = g_str_equal(name, obex_option_root_folder());
+
+       dp = opendir(name);
+       if (dp == NULL) {
+               if (err)
+                       *err = -ENOENT;
+               goto failed;
+       }
+
+       if (!root)
+               object = g_string_append(object, FL_PARENT_FOLDER_ELEMENT);
+
+       ret = verify_path(name);
+       if (ret < 0) {
+               *err = ret;
+               goto failed;
+       }
+
+       ret = stat(name, &dstat);
+       if (ret < 0) {
+               if (err)
+                       *err = -errno;
+               goto failed;
+       }
+
+       while ((ep = readdir(dp))) {
+               char *filename;
+               char *fullname;
+               char *line;
+
+               if (ep->d_name[0] == '.')
+                       continue;
+
+               filename = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
+               if (filename == NULL) {
+                       error("g_filename_to_utf8: invalid filename");
+                       continue;
+               }
+
+               fullname = g_build_filename(name, ep->d_name, NULL);
+
+               ret = stat(fullname, &fstat);
+               if (ret < 0) {
+                       DBG("stat: %s(%d)", strerror(errno), errno);
+                       g_free(filename);
+                       g_free(fullname);
+                       continue;
+               }
+
+               g_free(fullname);
+
+               line = file_stat_line(filename, &fstat, &dstat, root, FALSE);
+               if (line == NULL) {
+                       g_free(filename);
+                       continue;
+               }
+
+               g_free(filename);
+
+               object = g_string_append(object, line);
+               g_free(line);
+       }
+
+       closedir(dp);
+
+       object = g_string_append(object, FL_BODY_END);
+       if (size)
+               *size = object->len;
+
+       if (err)
+               *err = 0;
+
+       return object;
+
+failed:
+       if (dp)
+               closedir(dp);
+
+       g_string_free(object, TRUE);
+       return NULL;
+}
+
+static void *folder_open(const char *name, int oflag, mode_t mode,
+                                       void *context, size_t *size, int *err)
+{
+       GString *object;
+
+       object = g_string_new(FL_VERSION);
+       object = append_folder_preamble(object);
+       object = g_string_append(object, FL_BODY_BEGIN);
+
+       return append_listing(object, name, FALSE, size, err);
+}
+
+static void *pcsuite_open(const char *name, int oflag, mode_t mode,
+                                       void *context, size_t *size, int *err)
+{
+       GString *object;
+
+       object = g_string_new(FL_VERSION);
+       object = append_pcsuite_preamble(object);
+       object = g_string_append(object, FL_BODY_BEGIN);
+
+       return append_listing(object, name, TRUE, size, err);
+}
+
+static int string_free(void *object)
+{
+       GString *string = object;
+
+       g_string_free(string, TRUE);
+
+       return 0;
+}
+
+ssize_t string_read(void *object, void *buf, size_t count)
+{
+       GString *string = object;
+       ssize_t len;
+
+       if (string->len == 0)
+               return 0;
+
+       len = MIN(string->len, count);
+       memcpy(buf, string->str, len);
+       g_string_erase(string, 0, len);
+
+       return len;
+}
+
+static ssize_t folder_read(void *object, void *buf, size_t count)
+{
+       return string_read(object, buf, count);
+}
+
+static ssize_t capability_read(void *object, void *buf, size_t count)
+{
+       struct capability_object *obj = object;
+
+       if (obj->buffer)
+               return string_read(obj->buffer, buf, count);
+
+       if (obj->pid >= 0)
+               return -EAGAIN;
+
+       return read(obj->output, buf, count);
+}
+
+static int capability_close(void *object)
+{
+       struct capability_object *obj = object;
+       int err = 0;
+
+       if (obj->pid < 0)
+               goto done;
+
+       DBG("kill: pid %d", obj->pid);
+       err = kill(obj->pid, SIGTERM);
+       if (err < 0) {
+               err = -errno;
+               error("kill: %s (%d)", strerror(-err), -err);
+               goto done;
+       }
+
+       obj->aborted = TRUE;
+       return 0;
+
+done:
+       if (obj->buffer != NULL)
+               g_string_free(obj->buffer, TRUE);
+
+       g_free(obj);
+
+       return err;
+}
+
+static struct obex_mime_type_driver file = {
+       .open = filesystem_open,
+       .close = filesystem_close,
+       .read = filesystem_read,
+       .write = filesystem_write,
+       .remove = remove,
+       .move = filesystem_rename,
+       .copy = filesystem_copy,
+};
+
+static struct obex_mime_type_driver capability = {
+       .target = FTP_TARGET,
+       .target_size = FTP_TARGET_SIZE,
+       .mimetype = "x-obex/capability",
+       .open = capability_open,
+       .close = capability_close,
+       .read = capability_read,
+};
+
+static struct obex_mime_type_driver folder = {
+       .target = FTP_TARGET,
+       .target_size = FTP_TARGET_SIZE,
+       .mimetype = "x-obex/folder-listing",
+       .open = folder_open,
+       .close = string_free,
+       .read = folder_read,
+};
+
+static struct obex_mime_type_driver pcsuite = {
+       .target = FTP_TARGET,
+       .target_size = FTP_TARGET_SIZE,
+       .who = PCSUITE_WHO,
+       .who_size = PCSUITE_WHO_SIZE,
+       .mimetype = "x-obex/folder-listing",
+       .open = pcsuite_open,
+       .close = string_free,
+       .read = folder_read,
+};
+
+static int filesystem_init(void)
+{
+       int err;
+
+       err = obex_mime_type_driver_register(&folder);
+       if (err < 0)
+               return err;
+
+       err = obex_mime_type_driver_register(&capability);
+       if (err < 0)
+               return err;
+
+       err = obex_mime_type_driver_register(&pcsuite);
+       if (err < 0)
+               return err;
+
+       return obex_mime_type_driver_register(&file);
+}
+
+static void filesystem_exit(void)
+{
+       obex_mime_type_driver_unregister(&folder);
+       obex_mime_type_driver_unregister(&capability);
+       obex_mime_type_driver_unregister(&file);
+}
+
+OBEX_PLUGIN_DEFINE(filesystem, filesystem_init, filesystem_exit)
diff --git a/obexd/plugins/filesystem.h b/obexd/plugins/filesystem.h
new file mode 100644 (file)
index 0000000..f95773b
--- /dev/null
@@ -0,0 +1,26 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+ssize_t string_read(void *object, void *buf, size_t count);
+gboolean is_filename(const char *name);
+int verify_path(const char *path);
diff --git a/obexd/plugins/ftp.c b/obexd/plugins/ftp.c
new file mode 100644 (file)
index 0000000..773861d
--- /dev/null
@@ -0,0 +1,502 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <glib.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "manager.h"
+#include "mimetype.h"
+#include "service.h"
+#include "ftp.h"
+#include "filesystem.h"
+
+#define LST_TYPE "x-obex/folder-listing"
+#define CAP_TYPE "x-obex/capability"
+
+static const uint8_t FTP_TARGET[TARGET_SIZE] = {
+                       0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
+                       0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
+
+struct ftp_session {
+       struct obex_session *os;
+       char *folder;
+};
+
+static void set_folder(struct ftp_session *ftp, const char *new_folder)
+{
+       DBG("%p folder %s", ftp, new_folder);
+
+       g_free(ftp->folder);
+
+       ftp->folder = new_folder ? g_strdup(new_folder) : NULL;
+}
+
+static int get_by_type(struct ftp_session *ftp, const char *type)
+{
+       struct obex_session *os = ftp->os;
+       const char *capability = obex_option_capability();
+       const char *name = obex_get_name(os);
+       char *path;
+       int err;
+
+       DBG("%p name %s type %s", ftp, name, type);
+
+       if (type == NULL && name == NULL)
+               return -EBADR;
+
+       if (type != NULL && g_ascii_strcasecmp(type, CAP_TYPE) == 0)
+               return obex_get_stream_start(os, capability);
+
+       if (name != NULL && !is_filename(name))
+               return -EBADR;
+
+       path = g_build_filename(ftp->folder, name, NULL);
+       err = obex_get_stream_start(os, path);
+
+       g_free(path);
+
+       return err;
+}
+
+void *ftp_connect(struct obex_session *os, int *err)
+{
+       struct ftp_session *ftp;
+       const char *root_folder;
+
+       DBG("");
+
+       root_folder = obex_option_root_folder();
+
+       manager_register_session(os);
+
+       ftp = g_new0(struct ftp_session, 1);
+       set_folder(ftp, root_folder);
+       ftp->os = os;
+
+       if (err)
+               *err = 0;
+
+       DBG("session %p created", ftp);
+
+       return ftp;
+}
+
+int ftp_get(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+       const char *type = obex_get_type(os);
+       int ret;
+
+       DBG("%p", ftp);
+
+       if (ftp->folder == NULL)
+               return -ENOENT;
+
+       ret = get_by_type(ftp, type);
+       if (ret < 0)
+               return ret;
+
+       return 0;
+}
+
+static int ftp_delete(struct ftp_session *ftp, const char *name)
+{
+       char *path;
+       int ret = 0;
+
+       DBG("%p name %s", ftp, name);
+
+       if (!(ftp->folder && name))
+               return -EINVAL;
+
+       path = g_build_filename(ftp->folder, name, NULL);
+
+       if (obex_remove(ftp->os, path) < 0)
+               ret = -errno;
+
+       g_free(path);
+
+       return ret;
+}
+
+int ftp_chkput(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+       const char *name = obex_get_name(os);
+       char *path;
+       int ret;
+
+       DBG("%p name %s", ftp, name);
+
+       if (name == NULL)
+               return -EBADR;
+
+       if (!is_filename(name))
+               return -EBADR;
+
+       if (obex_get_size(os) == OBJECT_SIZE_DELETE)
+               return 0;
+
+       path = g_build_filename(ftp->folder, name, NULL);
+
+       ret = obex_put_stream_start(os, path);
+
+       g_free(path);
+
+       return ret;
+}
+
+int ftp_put(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+       const char *name = obex_get_name(os);
+       ssize_t size = obex_get_size(os);
+
+       DBG("%p name %s size %zd", ftp, name, size);
+
+       if (ftp->folder == NULL)
+               return -EPERM;
+
+       if (name == NULL)
+               return -EBADR;
+
+       if (!is_filename(name))
+               return -EBADR;
+
+       if (size == OBJECT_SIZE_DELETE)
+               return ftp_delete(ftp, name);
+
+       return 0;
+}
+
+int ftp_setpath(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+       const char *root_folder, *name;
+       const uint8_t *nonhdr;
+       char *fullname;
+       struct stat dstat;
+       gboolean root;
+       int err;
+
+       if (obex_get_non_header_data(os, &nonhdr) != 2) {
+               error("Set path failed: flag and constants not found!");
+               return -EBADMSG;
+       }
+
+       name = obex_get_name(os);
+       root_folder = obex_option_root_folder();
+       root = g_str_equal(root_folder, ftp->folder);
+
+       DBG("%p name %s", ftp, name);
+
+       /* Check flag "Backup" */
+       if ((nonhdr[0] & 0x01) == 0x01) {
+               DBG("Set to parent path");
+
+               if (root)
+                       return -EPERM;
+
+               fullname = g_path_get_dirname(ftp->folder);
+               set_folder(ftp, fullname);
+               g_free(fullname);
+
+               DBG("Set to parent path: %s", ftp->folder);
+
+               return 0;
+       }
+
+       if (!name) {
+               DBG("Set path failed: name missing!");
+               return -EINVAL;
+       }
+
+       if (strlen(name) == 0) {
+               DBG("Set to root");
+               set_folder(ftp, root_folder);
+               return 0;
+       }
+
+       /* Check and set to name path */
+       if (!is_filename(name)) {
+               error("Set path failed: name incorrect!");
+               return -EPERM;
+       }
+
+       fullname = g_build_filename(ftp->folder, name, NULL);
+
+       DBG("Fullname: %s", fullname);
+
+       err = verify_path(fullname);
+
+       if (err < 0)
+               goto done;
+
+       err = stat(fullname, &dstat);
+
+       if (err < 0) {
+               err = -errno;
+
+               if (err == -ENOENT)
+                       goto not_found;
+
+               DBG("stat: %s(%d)", strerror(-err), -err);
+
+               goto done;
+       }
+
+       if (S_ISDIR(dstat.st_mode) && (dstat.st_mode & S_IRUSR) &&
+                                               (dstat.st_mode & S_IXUSR)) {
+               set_folder(ftp, fullname);
+               goto done;
+       }
+
+       err = -EPERM;
+       goto done;
+
+not_found:
+       if (nonhdr[0] != 0) {
+               err = -ENOENT;
+               goto done;
+       }
+
+       if (mkdir(fullname, 0755) <  0) {
+               err = -errno;
+               DBG("mkdir: %s(%d)", strerror(-err), -err);
+               goto done;
+       }
+
+       err = 0;
+       set_folder(ftp, fullname);
+
+done:
+       g_free(fullname);
+       return err;
+}
+
+static gboolean is_valid_path(const char *path)
+{
+       char **elements, **cur;
+       int depth = 0;
+
+       elements = g_strsplit(path, "/", 0);
+
+       for (cur = elements; *cur != NULL; cur++) {
+               if (**cur == '\0' || strcmp(*cur, ".") == 0)
+                       continue;
+
+               if (strcmp(*cur, "..") == 0) {
+                       depth--;
+                       if (depth < 0)
+                               break;
+                       continue;
+               }
+
+               depth++;
+       }
+
+       g_strfreev(elements);
+
+       if (depth < 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+static char *ftp_build_filename(struct ftp_session *ftp, const char *destname)
+{
+       char *filename;
+
+       /* DestName can either be relative or absolute (FTP style) */
+       if (destname[0] == '/')
+               filename = g_build_filename(obex_option_root_folder(),
+                                                                destname, NULL);
+       else
+               filename = g_build_filename(ftp->folder, destname, NULL);
+
+       if (is_valid_path(filename + strlen(obex_option_root_folder())))
+               return filename;
+
+       g_free(filename);
+
+       return NULL;
+}
+
+static int ftp_copy(struct ftp_session *ftp, const char *name,
+                                                       const char *destname)
+{
+       char *source, *destination, *destdir;
+       int ret;
+
+       DBG("%p name %s destination %s", ftp, name, destname);
+
+       if (ftp->folder == NULL) {
+               error("No folder set");
+               return -ENOENT;
+       }
+
+       if (name == NULL || destname == NULL)
+               return -EINVAL;
+
+       destination = ftp_build_filename(ftp, destname);
+
+       if (destination == NULL)
+               return -EBADR;
+
+       destdir = g_path_get_dirname(destination);
+       ret = verify_path(destdir);
+       g_free(destdir);
+
+       if (ret < 0)
+               return ret;
+
+       source = g_build_filename(ftp->folder, name, NULL);
+
+       ret = obex_copy(ftp->os, source, destination);
+
+       g_free(source);
+       g_free(destination);
+
+       return ret;
+}
+
+static int ftp_move(struct ftp_session *ftp, const char *name,
+                                                       const char *destname)
+{
+       char *source, *destination, *destdir;
+       int ret;
+
+       DBG("%p name %s destname %s", ftp, name, destname);
+
+       if (ftp->folder == NULL) {
+               error("No folder set");
+               return -ENOENT;
+       }
+
+       if (name == NULL || destname == NULL)
+               return -EINVAL;
+
+       destination = ftp_build_filename(ftp, destname);
+
+       if (destination == NULL)
+               return -EBADR;
+
+       destdir = g_path_get_dirname(destination);
+       ret = verify_path(destdir);
+       g_free(destdir);
+
+       if (ret < 0)
+               return ret;
+
+       source = g_build_filename(ftp->folder, name, NULL);
+
+       ret = obex_move(ftp->os, source, destination);
+
+       g_free(source);
+       g_free(destination);
+
+       return ret;
+}
+
+int ftp_action(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+       const char *name, *destname;
+       uint8_t action_id;
+
+       name = obex_get_name(os);
+       if (name == NULL || !is_filename(name))
+               return -EBADR;
+
+       destname = obex_get_destname(os);
+       action_id = obex_get_action_id(os);
+
+       DBG("%p action 0x%x", ftp, action_id);
+
+       switch (action_id) {
+       case 0x00: /* Copy Object */
+               return ftp_copy(ftp, name, destname);
+       case 0x01: /* Move/Rename Object */
+               return ftp_move(ftp, name, destname);
+       default:
+               return -ENOSYS;
+       }
+}
+
+void ftp_disconnect(struct obex_session *os, void *user_data)
+{
+       struct ftp_session *ftp = user_data;
+
+       DBG("%p", ftp);
+
+       manager_unregister_session(os);
+
+       g_free(ftp->folder);
+       g_free(ftp);
+}
+
+static struct obex_service_driver ftp = {
+       .name = "File Transfer server",
+       .service = OBEX_FTP,
+       .target = FTP_TARGET,
+       .target_size = TARGET_SIZE,
+       .connect = ftp_connect,
+       .get = ftp_get,
+       .put = ftp_put,
+       .chkput = ftp_chkput,
+       .setpath = ftp_setpath,
+       .action = ftp_action,
+       .disconnect = ftp_disconnect
+};
+
+static int ftp_init(void)
+{
+       return obex_service_driver_register(&ftp);
+}
+
+static void ftp_exit(void)
+{
+       obex_service_driver_unregister(&ftp);
+}
+
+OBEX_PLUGIN_DEFINE(ftp, ftp_init, ftp_exit)
diff --git a/obexd/plugins/ftp.h b/obexd/plugins/ftp.h
new file mode 100644 (file)
index 0000000..f06de84
--- /dev/null
@@ -0,0 +1,30 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void *ftp_connect(struct obex_session *os, int *err);
+int ftp_get(struct obex_session *os, void *user_data);
+int ftp_chkput(struct obex_session *os, void *user_data);
+int ftp_put(struct obex_session *os, void *user_data);
+int ftp_setpath(struct obex_session *os, void *user_data);
+void ftp_disconnect(struct obex_session *os, void *user_data);
+int ftp_action(struct obex_session *os, void *user_data);
diff --git a/obexd/plugins/irmc.c b/obexd/plugins/irmc.c
new file mode 100644 (file)
index 0000000..d343977
--- /dev/null
@@ -0,0 +1,488 @@
+/*
+ *
+ *  OBEX IrMC Sync Server
+ *
+ *  Copyright (C) 2010  Marcel Mol <marcel@mesa.nl>
+ *
+ *  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 <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "phonebook.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "manager.h"
+
+struct aparam_header {
+       uint8_t tag;
+       uint8_t len;
+       uint8_t val[0];
+} __attribute__ ((packed));
+
+#define DID_LEN 18
+
+struct irmc_session {
+       struct obex_session *os;
+       struct apparam_field *params;
+       uint16_t entries;
+       GString *buffer;
+       char sn[DID_LEN];
+       char did[DID_LEN];
+       char manu[DID_LEN];
+       char model[DID_LEN];
+       void *request;
+};
+
+#define IRMC_TARGET_SIZE 9
+
+static const guint8 IRMC_TARGET[IRMC_TARGET_SIZE] = {
+                       0x49, 0x52, 0x4d, 0x43,  0x2d, 0x53, 0x59, 0x4e, 0x43 };
+
+/* FIXME:
+ * the IrMC specs state the first vcard should be the owner
+ * vcard. As there is no simple way to collect ownerdetails
+ * just create an empty vcard (which is allowed according to the
+ * specs).
+ */
+static const char *owner_vcard =
+               "BEGIN:VCARD\r\n"
+               "VERSION:2.1\r\n"
+               "N:\r\n"
+               "TEL:\r\n"
+               "X-IRMX-LUID:0\r\n"
+               "END:VCARD\r\n";
+
+static void phonebook_size_result(const char *buffer, size_t bufsize,
+                                       int vcards, int missed,
+                                       gboolean lastpart, void *user_data)
+{
+       struct irmc_session *irmc = user_data;
+
+       DBG("vcards %d", vcards);
+
+       irmc->params->maxlistcount = vcards;
+
+       if (irmc->request) {
+               phonebook_req_finalize(irmc->request);
+               irmc->request = NULL;
+       }
+}
+
+static void query_result(const char *buffer, size_t bufsize, int vcards,
+                               int missed, gboolean lastpart, void *user_data)
+{
+       struct irmc_session *irmc = user_data;
+       const char *s, *t;
+
+       DBG("bufsize %zu vcards %d missed %d", bufsize, vcards, missed);
+
+       if (irmc->request) {
+               phonebook_req_finalize(irmc->request);
+               irmc->request = NULL;
+       }
+
+       /* first add a 'owner' vcard */
+       if (!irmc->buffer)
+               irmc->buffer = g_string_new(owner_vcard);
+       else
+               irmc->buffer = g_string_append(irmc->buffer, owner_vcard);
+
+       if (buffer == NULL)
+               goto done;
+
+       /* loop around buffer and add X-IRMC-LUID attribs */
+       s = buffer;
+       while ((t = strstr(s, "UID:")) != NULL) {
+               /* add up to UID: into buffer */
+               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+               /*
+                * add UID: line into buffer
+                * Not sure if UID is still needed if X-IRMC-LUID is there
+                */
+               s = t;
+               t = strstr(s, "\r\n");
+               t += 2;
+               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+               /* add X-IRMC-LUID with same number as UID */
+               irmc->buffer = g_string_append_len(irmc->buffer,
+                                                       "X-IRMC-LUID:", 12);
+               s += 4; /* point to uid number */
+               irmc->buffer = g_string_append_len(irmc->buffer, s, t-s);
+               s = t;
+       }
+       /* add remaining bit of buffer */
+       irmc->buffer = g_string_append(irmc->buffer, s);
+
+done:
+       obex_object_set_io_flags(irmc, G_IO_IN, 0);
+}
+
+static void *irmc_connect(struct obex_session *os, int *err)
+{
+       struct irmc_session *irmc;
+       struct apparam_field *param;
+       int ret;
+
+       DBG("");
+
+       manager_register_session(os);
+
+       irmc = g_new0(struct irmc_session, 1);
+       irmc->os = os;
+
+       /* FIXME:
+        * Ideally get capabilities info here and use that to define
+        * IrMC DID and SN etc parameters.
+        * For now lets used hostname and some 'random' value
+        */
+       gethostname(irmc->did, DID_LEN);
+       strncpy(irmc->sn, "12345", sizeof(irmc->sn) - 1);
+       strncpy(irmc->manu, "obex", sizeof(irmc->manu) - 1);
+       strncpy(irmc->model, "mymodel", sizeof(irmc->model) - 1);
+
+       /* We need to know the number of contact/cal/nt entries
+        * somewhere so why not do it now.
+        */
+       param = g_new0(struct apparam_field, 1);
+       param->maxlistcount = 0; /* to count the number of vcards... */
+       param->filter = 0x200085; /* UID TEL N VERSION */
+       irmc->params = param;
+       irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
+                                       phonebook_size_result, irmc, err);
+       ret = phonebook_pull_read(irmc->request);
+       if (err)
+               *err = ret;
+
+       return irmc;
+}
+
+static int irmc_get(struct obex_session *os, void *user_data)
+{
+       struct irmc_session *irmc = user_data;
+       const char *type = obex_get_type(os);
+       const char *name = obex_get_name(os);
+       char *path;
+       int ret;
+
+       DBG("name %s type %s irmc %p", name, type ? type : "NA", irmc);
+
+       path = g_strdup(name);
+
+       ret = obex_get_stream_start(os, path);
+
+       g_free(path);
+
+       return ret;
+}
+
+static void irmc_disconnect(struct obex_session *os, void *user_data)
+{
+       struct irmc_session *irmc = user_data;
+
+       DBG("");
+
+       manager_unregister_session(os);
+
+       if (irmc->params) {
+               if (irmc->params->searchval)
+                       g_free(irmc->params->searchval);
+               g_free(irmc->params);
+       }
+
+       if (irmc->buffer)
+               g_string_free(irmc->buffer, TRUE);
+
+       g_free(irmc);
+}
+
+static int irmc_chkput(struct obex_session *os, void *user_data)
+{
+       DBG("");
+       /* Reject all PUTs */
+       return -EBADR;
+}
+
+static int irmc_open_devinfo(struct irmc_session *irmc)
+{
+       if (!irmc->buffer)
+               irmc->buffer = g_string_new("");
+
+       g_string_append_printf(irmc->buffer,
+                               "MANU:%s\r\n"
+                               "MOD:%s\r\n"
+                               "SN:%s\r\n"
+                               "IRMC-VERSION:1.1\r\n"
+                               "PB-TYPE-TX:VCARD2.1\r\n"
+                               "PB-TYPE-RX:NONE\r\n"
+                               "CAL-TYPE-TX:NONE\r\n"
+                               "CAL-TYPE-RX:NONE\r\n"
+                               "MSG-TYPE-TX:NONE\r\n"
+                               "MSG-TYPE-RX:NONE\r\n"
+                               "NOTE-TYPE-TX:NONE\r\n"
+                               "NOTE-TYPE-RX:NONE\r\n",
+                               irmc->manu, irmc->model, irmc->sn);
+
+       return 0;
+}
+
+static int irmc_open_pb(struct irmc_session *irmc)
+{
+       int ret;
+
+       /* how can we tell if the vcard count call already finished? */
+       irmc->request = phonebook_pull(PB_CONTACTS, irmc->params,
+                                               query_result, irmc, &ret);
+       if (ret < 0) {
+               DBG("phonebook_pull failed...");
+               return ret;
+       }
+
+       ret = phonebook_pull_read(irmc->request);
+       if (ret < 0) {
+               DBG("phonebook_pull_read failed...");
+               return ret;
+       }
+
+       return 0;
+}
+
+static int irmc_open_info(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
+
+       g_string_printf(irmc->buffer, "Total-Records:%d\r\n"
+                               "Maximum-Records:%d\r\n"
+                               "IEL:2\r\n"
+                               "DID:%s\r\n",
+                               irmc->params->maxlistcount,
+                               irmc->params->maxlistcount, irmc->did);
+
+       return 0;
+}
+
+static int irmc_open_cc(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
+
+       g_string_printf(irmc->buffer, "%d\r\n", irmc->params->maxlistcount);
+
+       return 0;
+}
+
+static int irmc_open_cal(struct irmc_session *irmc)
+{
+       /* no suport yet. Just return an empty buffer. cal.vcs */
+       DBG("unsupported, returning empty buffer");
+
+       if (!irmc->buffer)
+               irmc->buffer = g_string_new("");
+
+       return 0;
+}
+
+static int irmc_open_nt(struct irmc_session *irmc)
+{
+       /* no suport yet. Just return an empty buffer. nt.vnt */
+       DBG("unsupported, returning empty buffer");
+
+       if (!irmc->buffer)
+               irmc->buffer = g_string_new("");
+
+       return 0;
+}
+
+static int irmc_open_luid(struct irmc_session *irmc)
+{
+       if (irmc->buffer == NULL)
+               irmc->buffer = g_string_new("");
+
+       DBG("changelog request, force whole book");
+       g_string_printf(irmc->buffer, "SN:%s\r\n"
+                                       "DID:%s\r\n"
+                                       "Total-Records:%d\r\n"
+                                       "Maximum-Records:%d\r\n"
+                                       "*\r\n",
+                                       irmc->sn, irmc->did,
+                                       irmc->params->maxlistcount,
+                                       irmc->params->maxlistcount);
+
+       return 0;
+}
+
+static void *irmc_open(const char *name, int oflag, mode_t mode, void *context,
+                                                       size_t *size, int *err)
+{
+       struct irmc_session *irmc = context;
+       int ret = 0;
+       char *path;
+
+       DBG("name %s context %p", name, context);
+
+       if (oflag != O_RDONLY) {
+               ret = -EPERM;
+               goto fail;
+       }
+
+       if (name == NULL) {
+               ret = -EBADR;
+               goto fail;
+       }
+
+       /* Always contains the absolute path */
+       if (g_path_is_absolute(name))
+               path = g_strdup(name);
+       else
+               path = g_build_filename("/", name, NULL);
+
+       if (g_str_equal(path, PB_DEVINFO))
+               ret = irmc_open_devinfo(irmc);
+       else if (g_str_equal(path, PB_CONTACTS))
+               ret = irmc_open_pb(irmc);
+       else if (g_str_equal(path, PB_INFO_LOG))
+               ret = irmc_open_info(irmc);
+       else if (g_str_equal(path, PB_CC_LOG))
+               ret = irmc_open_cc(irmc);
+       else if (g_str_has_prefix(path, PB_CALENDAR_FOLDER))
+               ret = irmc_open_cal(irmc);
+       else if (g_str_has_prefix(path, PB_NOTES_FOLDER))
+               ret = irmc_open_nt(irmc);
+       else if (g_str_has_prefix(path, PB_LUID_FOLDER))
+               ret = irmc_open_luid(irmc);
+       else
+               ret = -EBADR;
+
+       g_free(path);
+
+       if (ret == 0)
+               return irmc;
+
+fail:
+       if (err)
+               *err = ret;
+
+       return NULL;
+}
+
+static int irmc_close(void *object)
+{
+       struct irmc_session *irmc = object;
+
+       DBG("");
+
+       if (irmc->buffer) {
+               g_string_free(irmc->buffer, TRUE);
+               irmc->buffer = NULL;
+       }
+
+       if (irmc->request) {
+               phonebook_req_finalize(irmc->request);
+               irmc->request = NULL;
+       }
+
+       return 0;
+}
+
+static ssize_t irmc_read(void *object, void *buf, size_t count)
+{
+       struct irmc_session *irmc = object;
+       int len;
+
+       DBG("buffer %p count %zu", irmc->buffer, count);
+       if (!irmc->buffer)
+                return -EAGAIN;
+
+       len = string_read(irmc->buffer, buf, count);
+       DBG("returning %d bytes", len);
+       return len;
+}
+
+static struct obex_mime_type_driver irmc_driver = {
+       .target = IRMC_TARGET,
+       .target_size = IRMC_TARGET_SIZE,
+       .open = irmc_open,
+       .close = irmc_close,
+       .read = irmc_read,
+};
+
+static struct obex_service_driver irmc = {
+       .name = "IRMC Sync server",
+       .service = OBEX_IRMC,
+       .target = IRMC_TARGET,
+       .target_size = IRMC_TARGET_SIZE,
+       .connect = irmc_connect,
+       .get = irmc_get,
+       .disconnect = irmc_disconnect,
+       .chkput = irmc_chkput
+};
+
+static int irmc_init(void)
+{
+       int err;
+
+       DBG("");
+       err = phonebook_init();
+       if (err < 0)
+               return err;
+
+       err = obex_mime_type_driver_register(&irmc_driver);
+       if (err < 0)
+               goto fail_mime_irmc;
+
+       err = obex_service_driver_register(&irmc);
+       if (err < 0)
+               goto fail_irmc_reg;
+
+       return 0;
+
+fail_irmc_reg:
+       obex_mime_type_driver_unregister(&irmc_driver);
+fail_mime_irmc:
+       phonebook_exit();
+
+       return err;
+}
+
+static void irmc_exit(void)
+{
+       DBG("");
+       obex_service_driver_unregister(&irmc);
+       obex_mime_type_driver_unregister(&irmc_driver);
+       phonebook_exit();
+}
+
+OBEX_PLUGIN_DEFINE(irmc, irmc_init, irmc_exit)
diff --git a/obexd/plugins/mas.c b/obexd/plugins/mas.c
new file mode 100644 (file)
index 0000000..5729c22
--- /dev/null
@@ -0,0 +1,853 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2010-2011  Nokia 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 <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <gobex/gobex.h>
+#include <gobex/gobex-apparam.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "manager.h"
+#include "map_ap.h"
+
+#include "messages.h"
+
+#define READ_STATUS_REQ 0
+#define DELETE_STATUS_REQ 1
+
+#define XML_DECL "<?xml version=\"1.0\" encoding=\"UTF-8\"?>"
+
+/* Building blocks for x-obex/folder-listing */
+#define FL_DTD "<!DOCTYPE folder-listing SYSTEM \"obex-folder-listing.dtd\">"
+#define FL_BODY_BEGIN "<folder-listing version=\"1.0\">"
+#define FL_BODY_EMPTY "<folder-listing version=\"1.0\"/>"
+#define FL_PARENT_FOLDER_ELEMENT "<parent-folder/>"
+#define FL_FOLDER_ELEMENT "<folder name=\"%s\"/>"
+#define FL_BODY_END "</folder-listing>"
+
+#define ML_BODY_BEGIN "<MAP-msg-listing version=\"1.0\">"
+#define ML_BODY_END "</MAP-msg-listing>"
+
+struct mas_session {
+       struct mas_request *request;
+       void *backend_data;
+       gboolean finished;
+       gboolean nth_call;
+       GString *buffer;
+       GObexApparam *inparams;
+       GObexApparam *outparams;
+       gboolean ap_sent;
+};
+
+static const uint8_t MAS_TARGET[TARGET_SIZE] = {
+                       0xbb, 0x58, 0x2b, 0x40, 0x42, 0x0c, 0x11, 0xdb,
+                       0xb0, 0xde, 0x08, 0x00, 0x20, 0x0c, 0x9a, 0x66  };
+
+static int get_params(struct obex_session *os, struct mas_session *mas)
+{
+       const uint8_t *buffer;
+       ssize_t size;
+
+       size = obex_get_apparam(os, &buffer);
+       if (size < 0)
+               size = 0;
+
+       mas->inparams = g_obex_apparam_decode(buffer, size);
+       if (mas->inparams == NULL) {
+               DBG("Error when parsing parameters!");
+               return -EBADR;
+       }
+
+       return 0;
+}
+
+static void reset_request(struct mas_session *mas)
+{
+       if (mas->buffer) {
+               g_string_free(mas->buffer, TRUE);
+               mas->buffer = NULL;
+       }
+
+       if (mas->inparams) {
+               g_obex_apparam_free(mas->inparams);
+               mas->inparams = NULL;
+       }
+
+       if (mas->outparams) {
+               g_obex_apparam_free(mas->outparams);
+               mas->outparams = NULL;
+       }
+
+       mas->nth_call = FALSE;
+       mas->finished = FALSE;
+       mas->ap_sent = FALSE;
+}
+
+static void mas_clean(struct mas_session *mas)
+{
+       reset_request(mas);
+       g_free(mas);
+}
+
+static void *mas_connect(struct obex_session *os, int *err)
+{
+       struct mas_session *mas;
+
+       DBG("");
+
+       mas = g_new0(struct mas_session, 1);
+
+       *err = messages_connect(&mas->backend_data);
+       if (*err < 0)
+               goto failed;
+
+       manager_register_session(os);
+
+       return mas;
+
+failed:
+       g_free(mas);
+
+       return NULL;
+}
+
+static void mas_disconnect(struct obex_session *os, void *user_data)
+{
+       struct mas_session *mas = user_data;
+
+       DBG("");
+
+       manager_unregister_session(os);
+       messages_disconnect(mas->backend_data);
+
+       mas_clean(mas);
+}
+
+static int mas_get(struct obex_session *os, void *user_data)
+{
+       struct mas_session *mas = user_data;
+       const char *type = obex_get_type(os);
+       const char *name = obex_get_name(os);
+       int ret;
+
+       DBG("GET: name %s type %s mas %p",
+                       name, type, mas);
+
+       if (type == NULL)
+               return -EBADR;
+
+       ret = get_params(os, mas);
+       if (ret < 0)
+               goto failed;
+
+       ret = obex_get_stream_start(os, name);
+       if (ret < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       reset_request(mas);
+
+       return ret;
+}
+
+static int mas_put(struct obex_session *os, void *user_data)
+{
+       struct mas_session *mas = user_data;
+       const char *type = obex_get_type(os);
+       const char *name = obex_get_name(os);
+       int ret;
+
+       DBG("PUT: name %s type %s mas %p", name, type, mas);
+
+       if (type == NULL)
+               return -EBADR;
+
+       ret = get_params(os, mas);
+       if (ret < 0)
+               goto failed;
+
+       ret = obex_put_stream_start(os, name);
+       if (ret < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       reset_request(mas);
+
+       return ret;
+}
+
+/* FIXME: Preserve whitespaces */
+static void g_string_append_escaped_printf(GString *string,
+                                               const char *format, ...)
+{
+       va_list ap;
+       char *escaped;
+
+       va_start(ap, format);
+       escaped = g_markup_vprintf_escaped(format, ap);
+       g_string_append(string, escaped);
+       g_free(escaped);
+       va_end(ap);
+}
+
+static const char *yesorno(gboolean a)
+{
+       if (a)
+               return "yes";
+
+       return "no";
+}
+
+static void get_messages_listing_cb(void *session, int err, uint16_t size,
+                                       gboolean newmsg,
+                                       const struct messages_message *entry,
+                                       void *user_data)
+{
+       struct mas_session *mas = user_data;
+       uint16_t max = 1024;
+
+       if (err < 0 && err != -EAGAIN) {
+               obex_object_set_io_flags(mas, G_IO_ERR, err);
+               return;
+       }
+
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+
+       if (max == 0) {
+               if (!entry)
+                       mas->finished = TRUE;
+
+               goto proceed;
+       }
+
+       if (!mas->nth_call) {
+               g_string_append(mas->buffer, ML_BODY_BEGIN);
+               mas->nth_call = TRUE;
+       }
+
+       if (!entry) {
+               g_string_append(mas->buffer, ML_BODY_END);
+               mas->finished = TRUE;
+
+               goto proceed;
+       }
+
+       g_string_append(mas->buffer, "<msg");
+
+       g_string_append_escaped_printf(mas->buffer, " handle=\"%s\"",
+                                                               entry->handle);
+
+       if (entry->mask & PMASK_SUBJECT)
+               g_string_append_escaped_printf(mas->buffer, " subject=\"%s\"",
+                               entry->subject);
+
+       if (entry->mask & PMASK_DATETIME)
+               g_string_append_escaped_printf(mas->buffer, " datetime=\"%s\"",
+                               entry->datetime);
+
+       if (entry->mask & PMASK_SENDER_NAME)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " sender_name=\"%s\"",
+                                               entry->sender_name);
+
+       if (entry->mask & PMASK_SENDER_ADDRESSING)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " sender_addressing=\"%s\"",
+                                               entry->sender_addressing);
+
+       if (entry->mask & PMASK_REPLYTO_ADDRESSING)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " replyto_addressing=\"%s\"",
+                                               entry->replyto_addressing);
+
+       if (entry->mask & PMASK_RECIPIENT_NAME)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " recipient_name=\"%s\"",
+                                               entry->recipient_name);
+
+       if (entry->mask & PMASK_RECIPIENT_ADDRESSING)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " recipient_addressing=\"%s\"",
+                                               entry->recipient_addressing);
+
+       if (entry->mask & PMASK_TYPE)
+               g_string_append_escaped_printf(mas->buffer, " type=\"%s\"",
+                               entry->type);
+
+       if (entry->mask & PMASK_RECEPTION_STATUS)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " reception_status=\"%s\"",
+                                               entry->reception_status);
+
+       if (entry->mask & PMASK_SIZE)
+               g_string_append_escaped_printf(mas->buffer, " size=\"%s\"",
+                               entry->size);
+
+       if (entry->mask & PMASK_ATTACHMENT_SIZE)
+               g_string_append_escaped_printf(mas->buffer,
+                                               " attachment_size=\"%s\"",
+                                               entry->attachment_size);
+
+       if (entry->mask & PMASK_TEXT)
+               g_string_append_escaped_printf(mas->buffer, " text=\"%s\"",
+                               yesorno(entry->text));
+
+       if (entry->mask & PMASK_READ)
+               g_string_append_escaped_printf(mas->buffer, " read=\"%s\"",
+                               yesorno(entry->read));
+
+       if (entry->mask & PMASK_SENT)
+               g_string_append_escaped_printf(mas->buffer, " sent=\"%s\"",
+                               yesorno(entry->sent));
+
+       if (entry->mask & PMASK_PROTECTED)
+               g_string_append_escaped_printf(mas->buffer, " protected=\"%s\"",
+                               yesorno(entry->protect));
+
+       if (entry->mask & PMASK_PRIORITY)
+               g_string_append_escaped_printf(mas->buffer, " priority=\"%s\"",
+                               yesorno(entry->priority));
+
+       g_string_append(mas->buffer, "/>\n");
+
+proceed:
+       if (!entry) {
+               mas->outparams = g_obex_apparam_set_uint16(mas->outparams,
+                                               MAP_AP_MESSAGESLISTINGSIZE,
+                                               size);
+               mas->outparams = g_obex_apparam_set_uint8(mas->outparams,
+                                               MAP_AP_NEWMESSAGE,
+                                               newmsg ? 1 : 0);
+       }
+
+       if (err != -EAGAIN)
+               obex_object_set_io_flags(mas, G_IO_IN, 0);
+}
+
+static void get_message_cb(void *session, int err, gboolean fmore,
+                                       const char *chunk, void *user_data)
+{
+       struct mas_session *mas = user_data;
+
+       DBG("");
+
+       if (err < 0 && err != -EAGAIN) {
+               obex_object_set_io_flags(mas, G_IO_ERR, err);
+               return;
+       }
+
+       if (!chunk) {
+               mas->finished = TRUE;
+               goto proceed;
+       }
+
+       g_string_append(mas->buffer, chunk);
+
+proceed:
+       if (err != -EAGAIN)
+               obex_object_set_io_flags(mas, G_IO_IN, 0);
+}
+
+static void get_folder_listing_cb(void *session, int err, uint16_t size,
+                                       const char *name, void *user_data)
+{
+       struct mas_session *mas = user_data;
+       uint16_t max = 1024;
+
+       if (err < 0 && err != -EAGAIN) {
+               obex_object_set_io_flags(mas, G_IO_ERR, err);
+               return;
+       }
+
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+
+       if (max == 0) {
+               if (err != -EAGAIN)
+                       mas->outparams = g_obex_apparam_set_uint16(
+                                               mas->outparams,
+                                               MAP_AP_FOLDERLISTINGSIZE,
+                                               size);
+
+               if (!name)
+                       mas->finished = TRUE;
+
+               goto proceed;
+       }
+
+       if (!mas->nth_call) {
+               g_string_append(mas->buffer, XML_DECL);
+               g_string_append(mas->buffer, FL_DTD);
+               if (!name) {
+                       g_string_append(mas->buffer, FL_BODY_EMPTY);
+                       mas->finished = TRUE;
+                       goto proceed;
+               }
+               g_string_append(mas->buffer, FL_BODY_BEGIN);
+               mas->nth_call = TRUE;
+       }
+
+       if (!name) {
+               g_string_append(mas->buffer, FL_BODY_END);
+               mas->finished = TRUE;
+               goto proceed;
+       }
+
+       if (g_strcmp0(name, "..") == 0)
+               g_string_append(mas->buffer, FL_PARENT_FOLDER_ELEMENT);
+       else
+               g_string_append_escaped_printf(mas->buffer, FL_FOLDER_ELEMENT,
+                                                                       name);
+
+proceed:
+       if (err != -EAGAIN)
+               obex_object_set_io_flags(mas, G_IO_IN, err);
+}
+
+static void set_status_cb(void *session, int err, void *user_data)
+{
+       struct mas_session *mas = user_data;
+
+       DBG("");
+
+       mas->finished = TRUE;
+
+       if (err < 0)
+               obex_object_set_io_flags(mas, G_IO_ERR, err);
+       else
+               obex_object_set_io_flags(mas, G_IO_OUT, 0);
+}
+
+static int mas_setpath(struct obex_session *os, void *user_data)
+{
+       const char *name;
+       const uint8_t *nonhdr;
+       struct mas_session *mas = user_data;
+
+       if (obex_get_non_header_data(os, &nonhdr) != 2) {
+               error("Set path failed: flag and constants not found!");
+               return -EBADR;
+       }
+
+       name = obex_get_name(os);
+
+       DBG("SETPATH: name %s nonhdr 0x%x%x", name, nonhdr[0], nonhdr[1]);
+
+       if ((nonhdr[0] & 0x02) != 0x02) {
+               DBG("Error: requested directory creation");
+               return -EBADR;
+       }
+
+       return messages_set_folder(mas->backend_data, name, nonhdr[0] & 0x01);
+}
+
+static void *folder_listing_open(const char *name, int oflag, mode_t mode,
+                               void *driver_data, size_t *size, int *err)
+{
+       struct mas_session *mas = driver_data;
+       /* 1024 is the default when there was no MaxListCount sent */
+       uint16_t max = 1024;
+       uint16_t offset = 0;
+
+       if (oflag != O_RDONLY) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       DBG("name = %s", name);
+
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+
+       *err = messages_get_folder_listing(mas->backend_data, name, max,
+                                       offset, get_folder_listing_cb, mas);
+
+       mas->buffer = g_string_new("");
+
+       if (*err < 0)
+               return NULL;
+       else
+               return mas;
+}
+
+static void *msg_listing_open(const char *name, int oflag, mode_t mode,
+                               void *driver_data, size_t *size, int *err)
+{
+       struct mas_session *mas = driver_data;
+       struct messages_filter filter = { 0, };
+       /* 1024 is the default when there was no MaxListCount sent */
+       uint16_t max = 1024;
+       uint16_t offset = 0;
+       /* If MAP client does not specify the subject length,
+          then subject_len = 0 and subject should be sent unaltered. */
+       uint8_t subject_len = 0;
+
+       DBG("");
+
+       if (oflag != O_RDONLY) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_MAXLISTCOUNT, &max);
+       g_obex_apparam_get_uint16(mas->inparams, MAP_AP_STARTOFFSET, &offset);
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_SUBJECTLENGTH,
+                                               &subject_len);
+
+       g_obex_apparam_get_uint32(mas->inparams, MAP_AP_PARAMETERMASK,
+                                               &filter.parameter_mask);
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERMESSAGETYPE,
+                                               &filter.type);
+       filter.period_begin = g_obex_apparam_get_string(mas->inparams,
+                                               MAP_AP_FILTERPERIODBEGIN);
+       filter.period_end = g_obex_apparam_get_string(mas->inparams,
+                                               MAP_AP_FILTERPERIODEND);
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERREADSTATUS,
+                                               &filter.read_status);
+       filter.recipient = g_obex_apparam_get_string(mas->inparams,
+                                               MAP_AP_FILTERRECIPIENT);
+       filter.originator = g_obex_apparam_get_string(mas->inparams,
+                                               MAP_AP_FILTERORIGINATOR);
+       g_obex_apparam_get_uint8(mas->inparams, MAP_AP_FILTERPRIORITY,
+                                               &filter.priority);
+
+       *err = messages_get_messages_listing(mas->backend_data, name, max,
+                       offset, subject_len, &filter,
+                       get_messages_listing_cb, mas);
+
+       mas->buffer = g_string_new("");
+
+       if (*err < 0)
+               return NULL;
+       else
+               return mas;
+}
+
+static void *message_open(const char *name, int oflag, mode_t mode,
+                               void *driver_data, size_t *size, int *err)
+{
+       struct mas_session *mas = driver_data;
+
+       DBG("");
+
+       if (oflag != O_RDONLY) {
+               DBG("Message pushing unsupported");
+               *err = -ENOSYS;
+
+               return NULL;
+       }
+
+       *err = messages_get_message(mas->backend_data, name, 0,
+                       get_message_cb, mas);
+
+       mas->buffer = g_string_new("");
+
+       if (*err < 0)
+               return NULL;
+       else
+               return mas;
+}
+
+static void *message_update_open(const char *name, int oflag, mode_t mode,
+                                       void *driver_data, size_t *size,
+                                       int *err)
+{
+       struct mas_session *mas = driver_data;
+
+       DBG("");
+
+       if (oflag == O_RDONLY) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       *err = messages_update_inbox(mas->backend_data, set_status_cb, mas);
+       if (*err < 0)
+               return NULL;
+       else
+               return mas;
+}
+
+static void *message_set_status_open(const char *name, int oflag, mode_t mode,
+                                       void *driver_data, size_t *size,
+                                       int *err)
+
+{
+       struct mas_session *mas = driver_data;
+       uint8_t indicator;
+       uint8_t value;
+
+       DBG("");
+
+       if (oflag == O_RDONLY) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSINDICATOR,
+                                                               &indicator)) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (!g_obex_apparam_get_uint8(mas->inparams, MAP_AP_STATUSVALUE,
+                                                               &value)) {
+               *err = -EBADR;
+               return NULL;
+       }
+
+       if (indicator == READ_STATUS_REQ)
+               *err = messages_set_read(mas->backend_data, name, value,
+                                                       set_status_cb, mas);
+       else if (indicator == DELETE_STATUS_REQ)
+               *err = messages_set_delete(mas->backend_data, name, value,
+                                                       set_status_cb, mas);
+       else
+               *err = -EBADR;
+
+       if (*err < 0)
+               return NULL;
+
+       return mas;
+}
+
+static ssize_t any_get_next_header(void *object, void *buf, size_t mtu,
+                                                               uint8_t *hi)
+{
+       struct mas_session *mas = object;
+
+       DBG("");
+
+       if (mas->buffer->len == 0 && !mas->finished)
+               return -EAGAIN;
+
+       *hi = G_OBEX_HDR_APPARAM;
+
+       if (mas->ap_sent)
+               return 0;
+
+       mas->ap_sent = TRUE;
+       return g_obex_apparam_encode(mas->outparams, buf, mtu);
+}
+
+static void *any_open(const char *name, int oflag, mode_t mode,
+                               void *driver_data, size_t *size, int *err)
+{
+       DBG("");
+
+       *err = -ENOSYS;
+
+       return NULL;
+}
+
+static ssize_t any_write(void *object, const void *buf, size_t count)
+{
+       DBG("");
+
+       return count;
+}
+
+static ssize_t any_read(void *obj, void *buf, size_t count)
+{
+       struct mas_session *mas = obj;
+       ssize_t len;
+
+       DBG("");
+
+       len = string_read(mas->buffer, buf, count);
+
+       if (len == 0 && !mas->finished)
+               return -EAGAIN;
+
+       return len;
+}
+
+static int any_close(void *obj)
+{
+       struct mas_session *mas = obj;
+
+       DBG("");
+
+       if (!mas->finished)
+               messages_abort(mas->backend_data);
+
+       reset_request(mas);
+
+       return 0;
+}
+
+static struct obex_service_driver mas = {
+       .name = "Message Access server",
+       .service = OBEX_MAS,
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .connect = mas_connect,
+       .get = mas_get,
+       .put = mas_put,
+       .setpath = mas_setpath,
+       .disconnect = mas_disconnect,
+};
+
+static struct obex_mime_type_driver mime_map = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = NULL,
+       .open = any_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_message = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/message",
+       .open = message_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_folder_listing = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-obex/folder-listing",
+       .get_next_header = any_get_next_header,
+       .open = folder_listing_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_msg_listing = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/MAP-msg-listing",
+       .get_next_header = any_get_next_header,
+       .open = msg_listing_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_notification_registration = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/MAP-NotificationRegistration",
+       .open = any_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_message_status = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/messageStatus",
+       .open = message_set_status_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver mime_message_update = {
+       .target = MAS_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/MAP-messageUpdate",
+       .open = message_update_open,
+       .close = any_close,
+       .read = any_read,
+       .write = any_write,
+};
+
+static struct obex_mime_type_driver *map_drivers[] = {
+       &mime_map,
+       &mime_message,
+       &mime_folder_listing,
+       &mime_msg_listing,
+       &mime_notification_registration,
+       &mime_message_status,
+       &mime_message_update,
+       NULL
+};
+
+static int mas_init(void)
+{
+       int err;
+       int i;
+
+       err = messages_init();
+       if (err < 0)
+               return err;
+
+       for (i = 0; map_drivers[i] != NULL; ++i) {
+               err = obex_mime_type_driver_register(map_drivers[i]);
+               if (err < 0)
+                       goto failed;
+       }
+
+       err = obex_service_driver_register(&mas);
+       if (err < 0)
+               goto failed;
+
+       return 0;
+
+failed:
+       for (--i; i >= 0; --i)
+               obex_mime_type_driver_unregister(map_drivers[i]);
+
+       messages_exit();
+
+       return err;
+}
+
+static void mas_exit(void)
+{
+       int i;
+
+       obex_service_driver_unregister(&mas);
+
+       for (i = 0; map_drivers[i] != NULL; ++i)
+               obex_mime_type_driver_unregister(map_drivers[i]);
+
+       messages_exit();
+}
+
+OBEX_PLUGIN_DEFINE(mas, mas_init, mas_exit)
diff --git a/obexd/plugins/messages-dummy.c b/obexd/plugins/messages-dummy.c
new file mode 100644 (file)
index 0000000..bb0627f
--- /dev/null
@@ -0,0 +1,376 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2010-2011  Nokia 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 <sys/types.h>
+#include <dirent.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "log.h"
+
+#include "messages.h"
+
+static char *root_folder = NULL;
+
+struct session {
+       char *cwd;
+       char *cwd_absolute;
+       void *request;
+};
+
+struct folder_listing_data {
+       struct session *session;
+       const char *name;
+       uint16_t max;
+       uint16_t offset;
+       messages_folder_listing_cb callback;
+       void *user_data;
+};
+
+/* NOTE: Neither IrOBEX nor MAP specs says that folder listing needs to
+ * be sorted (in IrOBEX examples it is not). However existing implementations
+ * seem to follow the fig. 3-2 from MAP specification v1.0, and I've seen a
+ * test suite requiring folder listing to be in that order.
+ */
+static int folder_names_cmp(gconstpointer a, gconstpointer b,
+                                               gpointer user_data)
+{
+       static const char *order[] = {
+               "inbox", "outbox", "sent", "deleted", "draft", NULL
+       };
+       struct session *session = user_data;
+       int ia, ib;
+
+       if (g_strcmp0(session->cwd, "telecom/msg") == 0) {
+               for (ia = 0; order[ia]; ia++) {
+                       if (g_strcmp0(a, order[ia]) == 0)
+                               break;
+               }
+               for (ib = 0; order[ib]; ib++) {
+                       if (g_strcmp0(b, order[ib]) == 0)
+                               break;
+               }
+               if (ia != ib)
+                       return ia - ib;
+       }
+
+       return g_strcmp0(a, b);
+}
+
+static char *get_next_subdir(DIR *dp, char *path)
+{
+       struct dirent *ep;
+       char *abs, *name;
+
+       for (;;) {
+               if ((ep = readdir(dp)) == NULL)
+                       return NULL;
+
+               if (strcmp(ep->d_name, ".") == 0 || strcmp(ep->d_name, "..") == 0)
+                       continue;
+
+               abs = g_build_filename(path, ep->d_name, NULL);
+
+               if (g_file_test(abs, G_FILE_TEST_IS_DIR)) {
+                       g_free(abs);
+                       break;
+               }
+
+               g_free(abs);
+       }
+
+       name = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
+
+       if (name == NULL) {
+               DBG("g_filename_to_utf8(): invalid filename");
+               return NULL;
+       }
+
+       return name;
+}
+
+static ssize_t get_subdirs(struct folder_listing_data *fld, GSList **list)
+{
+       DIR *dp;
+       char *path, *name;
+       size_t n;
+
+       path = g_build_filename(fld->session->cwd_absolute, fld->name, NULL);
+       dp = opendir(path);
+
+       if (dp == NULL) {
+               int err = -errno;
+
+               DBG("opendir(): %d, %s", -err, strerror(-err));
+               g_free(path);
+
+               return err;
+       }
+
+       n = 0;
+
+       while ((name = get_next_subdir(dp, path)) != NULL) {
+               n++;
+               if (fld->max > 0)
+                       *list = g_slist_prepend(*list, name);
+       }
+
+       closedir(dp);
+       g_free(path);
+
+       *list = g_slist_sort_with_data(*list, folder_names_cmp, fld->session);
+
+       return n;
+}
+
+static void return_folder_listing(struct folder_listing_data *fld, GSList *list)
+{
+       struct session *session = fld->session;
+       GSList *cur;
+       uint16_t num = 0;
+       uint16_t offs = 0;
+
+       /* XXX: This isn't really documented for MAP. I need to take a look how
+        * other implementations choose to deal with parent folder.
+        */
+       if (session->cwd[0] != 0 && fld->offset == 0) {
+               num++;
+               fld->callback(session, -EAGAIN, 0, "..", fld->user_data);
+       } else {
+               offs++;
+       }
+
+       for (cur = list; offs < fld->offset; offs++) {
+               cur = cur->next;
+               if (cur == NULL)
+                       break;
+       }
+
+       for (; cur != NULL && num < fld->max; cur = cur->next, num++)
+               fld->callback(session, -EAGAIN, 0, cur->data, fld->user_data);
+
+       fld->callback(session, 0, 0, NULL, fld->user_data);
+}
+
+static gboolean get_folder_listing(void *d)
+{
+       struct folder_listing_data *fld = d;
+       ssize_t n;
+       GSList *list = NULL;
+
+       n = get_subdirs(fld, &list);
+
+       if (n < 0) {
+               fld->callback(fld->session, n, 0, NULL, fld->user_data);
+               return FALSE;
+       }
+
+       if (fld->max == 0) {
+               fld->callback(fld->session, 0, n, NULL, fld->user_data);
+               return FALSE;
+       }
+
+       return_folder_listing(fld, list);
+       g_slist_free_full(list, g_free);
+
+       return FALSE;
+}
+
+int messages_init(void)
+{
+       char *tmp;
+
+       if (root_folder)
+               return 0;
+
+       tmp = getenv("MAP_ROOT");
+       if (tmp) {
+               root_folder = g_strdup(tmp);
+               return 0;
+       }
+
+       tmp = getenv("HOME");
+       if (!tmp)
+               return -ENOENT;
+
+       root_folder = g_build_filename(tmp, "map-messages", NULL);
+
+       return 0;
+}
+
+void messages_exit(void)
+{
+       g_free(root_folder);
+       root_folder = NULL;
+}
+
+int messages_connect(void **s)
+{
+       struct session *session;
+
+       session = g_new0(struct session, 1);
+       session->cwd = g_strdup("");
+       session->cwd_absolute = g_strdup(root_folder);
+
+       *s = session;
+
+       return 0;
+}
+
+void messages_disconnect(void *s)
+{
+       struct session *session = s;
+
+       g_free(session->cwd);
+       g_free(session->cwd_absolute);
+       g_free(session);
+}
+
+int messages_set_notification_registration(void *session,
+               void (*send_event)(void *session,
+                       const struct messages_event *event, void *user_data),
+               void *user_data)
+{
+       return -ENOSYS;
+}
+
+int messages_set_folder(void *s, const char *name, gboolean cdup)
+{
+       struct session *session = s;
+       char *newrel = NULL;
+       char *newabs;
+       char *tmp;
+
+       if (name && (strchr(name, '/') || strcmp(name, "..") == 0))
+               return -EBADR;
+
+       if (cdup) {
+               if (session->cwd[0] == 0)
+                       return -ENOENT;
+
+               newrel = g_path_get_dirname(session->cwd);
+
+               /* We use empty string for indication of the root directory */
+               if (newrel[0] == '.' && newrel[1] == 0)
+                       newrel[0] = 0;
+       }
+
+       tmp = newrel;
+       if (!cdup && (!name || name[0] == 0))
+               newrel = g_strdup("");
+       else
+               newrel = g_build_filename(newrel ? newrel : session->cwd, name,
+                               NULL);
+       g_free(tmp);
+
+       newabs = g_build_filename(root_folder, newrel, NULL);
+
+       if (!g_file_test(newabs, G_FILE_TEST_IS_DIR)) {
+               g_free(newrel);
+               g_free(newabs);
+               return -ENOENT;
+       }
+
+       g_free(session->cwd);
+       session->cwd = newrel;
+
+       g_free(session->cwd_absolute);
+       session->cwd_absolute = newabs;
+
+       return 0;
+}
+
+int messages_get_folder_listing(void *s, const char *name, uint16_t max,
+                                       uint16_t offset,
+                                       messages_folder_listing_cb callback,
+                                       void *user_data)
+{
+       struct session *session =  s;
+       struct folder_listing_data *fld;
+
+       fld = g_new0(struct folder_listing_data, 1);
+       fld->session = session;
+       fld->name = name;
+       fld->max = max;
+       fld->offset = offset;
+       fld->callback = callback;
+       fld->user_data = user_data;
+
+       session->request = fld;
+
+       g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, get_folder_listing,
+                                                               fld, g_free);
+
+       return 0;
+}
+
+int messages_get_messages_listing(void *session, const char *name,
+                               uint16_t max, uint16_t offset,
+                               uint8_t subject_len,
+                               const struct messages_filter *filter,
+                               messages_get_messages_listing_cb callback,
+                               void *user_data)
+{
+       return -ENOSYS;
+}
+
+int messages_get_message(void *session, const char *handle,
+                                       unsigned long flags,
+                                       messages_get_message_cb callback,
+                                       void *user_data)
+{
+       return -ENOSYS;
+}
+
+int messages_update_inbox(void *session, messages_status_cb callback,
+                                                       void *user_data)
+{
+       return -ENOSYS;
+}
+
+int messages_set_read(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data)
+{
+       return -ENOSYS;
+}
+
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data)
+{
+       return -ENOSYS;
+}
+
+void messages_abort(void *s)
+{
+       struct session *session = s;
+
+       if (session->request) {
+               g_idle_remove_by_data(session->request);
+               session->request = NULL;
+       }
+}
diff --git a/obexd/plugins/messages.h b/obexd/plugins/messages.h
new file mode 100644 (file)
index 0000000..00a16b1
--- /dev/null
@@ -0,0 +1,309 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2010-2011  Nokia 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
+ *
+ */
+
+#include <glib.h>
+#include <stdint.h>
+
+/* Those are used by backend to notify transport plugin which properties did it
+ * send.
+ */
+#define PMASK_SUBJECT                  0x0001
+#define PMASK_DATETIME                 0x0002
+#define PMASK_SENDER_NAME              0x0004
+#define PMASK_SENDER_ADDRESSING                0x0008
+#define PMASK_RECIPIENT_NAME           0x0010
+#define PMASK_RECIPIENT_ADDRESSING     0x0020
+#define PMASK_TYPE                     0x0040
+#define PMASK_SIZE                     0x0080
+#define PMASK_RECEPTION_STATUS         0x0100
+#define PMASK_TEXT                     0x0200
+#define PMASK_ATTACHMENT_SIZE          0x0400
+#define PMASK_PRIORITY                 0x0800
+#define PMASK_READ                     0x1000
+#define PMASK_SENT                     0x2000
+#define PMASK_PROTECTED                        0x4000
+#define PMASK_REPLYTO_ADDRESSING       0x8000
+
+/* This one is used in a response to GetMessagesListing. Use PMASK_* values to
+ * notify the plugin which members are actually set. Backend shall not omit
+ * properties required by MAP specification (subject, datetime,
+ * recipient_addressing, type, size, reception_status, attachment_size) unless
+ * ordered by PARAMETERMASK. Boolean values should be probably
+ * always sent (need checking). Handle is mandatory. Plugin will filter out any
+ * properties that were not wanted by MCE.
+ *
+ * Handle shall be set to hexadecimal representation with upper-case letters. No
+ * prefix shall be appended and without no zeros. This corresponds to PTS
+ * behaviour described in comments to the MAP specification.
+ *
+ * The rest of char * fields shall be set according to the MAP specification
+ * rules.
+ */
+struct messages_message {
+       uint32_t mask;
+       char *handle;
+       char *subject;
+       char *datetime;
+       char *sender_name;
+       char *sender_addressing;
+       char *replyto_addressing;
+       char *recipient_name;
+       char *recipient_addressing;
+       char *type;
+       char *reception_status;
+       char *size;
+       char *attachment_size;
+       gboolean text;
+       gboolean read;
+       gboolean sent;
+       gboolean protect;
+       gboolean priority;
+};
+
+/* Type of message event to be delivered to MNS server */
+enum messages_event_type {
+       MET_NEW_MESSAGE,
+       MET_DELIVERY_SUCCESS,
+       MET_SENDING_SUCCESS,
+       MET_DELIVERY_FAILURE,
+       MET_SENDING_FAILURE,
+       MET_MEMORY_FULL,
+       MET_MEMORY_AVAILABLE,
+       MET_MESSAGE_DELETED,
+       MET_MESSAGE_SHIFT
+};
+
+/* Data for sending MNS notification. Handle shall be formatted as described in
+ * messages_message.
+ */
+struct messages_event {
+       enum messages_event_type type;
+       uint8_t instance_id;
+       char *handle;
+       char *folder;
+       char *old_folder;
+       char *msg_type;
+};
+
+/* parameter_mask: |-ed PMASK_* values
+ * See MAP specification for the rest.
+ */
+struct messages_filter {
+       uint32_t parameter_mask;
+       uint8_t type;
+       const char *period_begin;
+       const char *period_end;
+       uint8_t read_status;
+       const char *recipient;
+       const char *originator;
+       uint8_t priority;
+};
+
+/* This is called once after server starts.
+ *
+ * Returns value less than zero if error. This will prevent MAP plugin from
+ * starting.
+ */
+int messages_init(void);
+
+/* This gets called right before server finishes
+ */
+void messages_exit(void);
+
+/* Starts a new MAP session.
+ *
+ * session: variable to store pointer to backend session data. This one shall be
+ * passed to all in-session calls.
+ *
+ * If session start succeeded, backend shall return 0. Otherwise the error value
+ * will be sent as a response to OBEX connect.
+ */
+int messages_connect(void **session);
+
+/* Closes a MAP session.
+ *
+ * This call should free buffer reserved by messages_connect.
+ */
+void messages_disconnect(void *session);
+
+/******************************************************************************
+ * NOTE on callbacks.
+ *
+ * All functions requiring callbacks have to call them asynchronously.
+ * 'user_data' is for passing arbitrary user data.
+ *
+ * Functions for GetMessagesListing, GetFolder listing and GetMessage call their
+ * callbacks multiple times - one for each listing entry or message body chunk.
+ * To indicate the end of operation backend must call callback with the data
+ * pointer parameter set to NULL.
+ *
+ * If err == -EAGAIN the transport * plugin does not wake IO.
+ *
+ * Keep in mind that application parameters has to be send first. Therefore the
+ * first time err == 0 and thus sending is started, callback will use provided
+ * parameters (e.g. size in case of folder listing) to build applications
+ * parameters header used in response. In any other case those parameters will
+ * be ignored.
+ *
+ * If err != 0 && err != -EAGAIN, the operation is finished immediately and err
+ * value is used to set the error code in OBEX response.
+ ******************************************************************************/
+
+/* Registers for messaging events notifications.
+ *
+ * session: Backend session.
+ * send_event: Function that will be called to indicate a new event.
+ *
+ * To unregister currently registered notifications, call this with send_event
+ * set to NULL.
+ */
+int messages_set_notification_registration(void *session,
+               void (*send_event)(void *session,
+                       const struct messages_event *event, void *user_data),
+               void *user_data);
+
+/* Changes current directory.
+ *
+ * session: Backend session.
+ * name: Subdirectory to go to. If empty or null and cdup is false, go to the
+ *     root directory.
+ * cdup: If true, go up one level first.
+ */
+int messages_set_folder(void *session, const char *name, gboolean cdup);
+
+/* Retrieves subdirectories listing from a current directory.
+ *
+ * session: Backend session.
+ * name: Optional subdirectory name (not strictly required by MAP).
+ * max: Maximum number of entries to retrieve.
+ * offset: Offset of the first entry.
+ * size: Total size of listing to be returned.
+ *
+ * Callback shall be called for every entry of the listing. 'name' is the
+ * subdirectory name.
+ */
+typedef void (*messages_folder_listing_cb)(void *session, int err,
+               uint16_t size, const char *name, void *user_data);
+
+int messages_get_folder_listing(void *session, const char *name, uint16_t max,
+                               uint16_t offset,
+                               messages_folder_listing_cb callback,
+                               void *user_data);
+
+/* Retrieves messages listing from a current directory.
+ *
+ * session: Backend session.
+ * name: Optional subdirectory name.
+ * max: Maximum number of entries to retrieve.
+ * offset: Offset of the first entry.
+ * subject_len: Maximum string length of the "subject" parameter in the entries.
+ * filter: Filter to apply on returned message listing.
+ * size: Total size of listing to be returned.
+ * newmsg: Indicates presence of unread messages.
+ *
+ * Callback shall be called for every entry of the listing, giving message data
+ * in 'message'.
+ */
+typedef void (*messages_get_messages_listing_cb)(void *session, int err,
+                                       uint16_t size, gboolean newmsg,
+                                       const struct messages_message *message,
+                                       void *user_data);
+
+int messages_get_messages_listing(void *session, const char *name,
+                               uint16_t max, uint16_t offset,
+                               uint8_t subject_len,
+                               const struct messages_filter *filter,
+                               messages_get_messages_listing_cb callback,
+                               void *user_data);
+
+#define MESSAGES_ATTACHMENT    (1 << 0)
+#define MESSAGES_UTF8          (1 << 1)
+#define MESSAGES_FRACTION      (1 << 2)
+#define MESSAGES_NEXT          (1 << 3)
+
+/* Retrieves bMessage object (see MAP specification, ch. 3.1.3) of a given
+ * message.
+ *
+ * session: Backend session.
+ * handle: Handle of the message to retrieve.
+ * flags: or-ed mask of following:
+ *     MESSAGES_ATTACHMENT: Selects whether or not attachments (if any) are to
+ *             be included.
+ *     MESSAGES_UTF8: If true, convert message to utf-8. Otherwise use native
+ *             encoding.
+ *     MESSAGES_FRACTION: If true, deliver fractioned message.
+ *     MESSAGES_NEXT: If fraction is true this indicates whether to retrieve
+ *             first fraction
+ *     or the next one.
+ * fmore: Indicates whether next fraction is available.
+ * chunk: chunk of bMessage body
+ *
+ * Callback allows for returning bMessage in chunks.
+ */
+typedef void (*messages_get_message_cb)(void *session, int err, gboolean fmore,
+       const char *chunk, void *user_data);
+
+int messages_get_message(void *session, const char *handle,
+                                       unsigned long flags,
+                                       messages_get_message_cb callback,
+                                       void *user_data);
+
+typedef void (*messages_status_cb)(void *session, int err, void *user_data);
+
+/* Informs Message Server to Update Inbox via network.
+ *
+ * session: Backend session.
+ * user_data: User data if any to be sent.
+ * Callback shall be called for every update inbox request received from MCE.
+ */
+int messages_update_inbox(void *session, messages_status_cb callback,
+                                                       void *user_data);
+/* Informs Message Server to modify read status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the read status for a given message.
+ * Callback shall be called for every read status update request
+ *     recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+int messages_set_read(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data);
+
+/* Informs Message Server to modify delete status of a given message.
+ *
+ * session: Backend session.
+ * handle: Unique identifier to the message.
+ * value: Indicates the new value of the delete status for a given message.
+ * Callback shall be called for every delete status update request
+ *     recieved from MCE.
+ * user_data: User data if any to be sent.
+ */
+int messages_set_delete(void *session, const char *handle, uint8_t value,
+                               messages_status_cb callback, void *user_data);
+
+/* Aborts currently pending request.
+ *
+ * session: Backend session.
+ */
+void messages_abort(void *session);
diff --git a/obexd/plugins/opp.c b/obexd/plugins/opp.c
new file mode 100644 (file)
index 0000000..ee0204c
--- /dev/null
@@ -0,0 +1,189 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <string.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <glib.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "obex.h"
+#include "service.h"
+#include "log.h"
+#include "manager.h"
+#include "filesystem.h"
+
+#define VCARD_TYPE "text/x-vcard"
+#define VCARD_FILE CONFIGDIR "/vcard.vcf"
+
+static void *opp_connect(struct obex_session *os, int *err)
+{
+       manager_register_session(os);
+
+       if (err)
+               *err = 0;
+
+       return manager_register_transfer(os);
+}
+
+static void opp_progress(struct obex_session *os, void *user_data)
+{
+       manager_emit_transfer_progress(user_data);
+}
+
+static int opp_chkput(struct obex_session *os, void *user_data)
+{
+       char *folder, *name, *path;
+       int32_t time;
+       const char *t;
+       int err;
+
+       if (obex_get_size(os) == OBJECT_SIZE_DELETE)
+               return -ENOSYS;
+
+       t = obex_get_name(os);
+       if (t != NULL && !is_filename(t))
+               return -EBADR;
+
+       if (obex_option_auto_accept()) {
+               folder = g_strdup(obex_option_root_folder());
+               name = g_strdup(obex_get_name(os));
+               goto skip_auth;
+       }
+
+       time = 0;
+       err = manager_request_authorization(user_data, time, &folder, &name);
+       if (err < 0)
+               return -EPERM;
+
+       if (folder == NULL)
+               folder = g_strdup(obex_option_root_folder());
+
+       if (name == NULL)
+               name = g_strdup(obex_get_name(os));
+
+skip_auth:
+       if (name == NULL || strlen(name) == 0) {
+               err = -EBADR;
+               goto failed;
+       }
+
+       if (g_strcmp0(name, obex_get_name(os)) != 0)
+               obex_set_name(os, name);
+
+       path = g_build_filename(folder, name, NULL);
+
+       err = obex_put_stream_start(os, path);
+
+       g_free(path);
+
+       if (err < 0)
+               goto failed;
+
+       manager_emit_transfer_started(user_data);
+
+failed:
+       g_free(folder);
+       g_free(name);
+
+       return err;
+}
+
+static int opp_put(struct obex_session *os, void *user_data)
+{
+       const char *name = obex_get_name(os);
+       const char *folder = obex_option_root_folder();
+
+       if (folder == NULL)
+               return -EPERM;
+
+       if (name == NULL)
+               return -EBADR;
+
+       return 0;
+}
+
+static int opp_get(struct obex_session *os, void *user_data)
+{
+       const char *type;
+
+       if (obex_get_name(os))
+               return -EPERM;
+
+       type = obex_get_type(os);
+
+       if (type == NULL)
+               return -EPERM;
+
+       if (g_ascii_strcasecmp(type, VCARD_TYPE) == 0) {
+               if (obex_get_stream_start(os, VCARD_FILE) < 0)
+                       return -ENOENT;
+
+       } else
+               return -EPERM;
+
+       return 0;
+}
+
+static void opp_disconnect(struct obex_session *os, void *user_data)
+{
+       manager_unregister_transfer(user_data);
+       manager_unregister_session(os);
+}
+
+static void opp_reset(struct obex_session *os, void *user_data)
+{
+       manager_emit_transfer_completed(user_data);
+}
+
+static struct obex_service_driver driver = {
+       .name = "Object Push server",
+       .service = OBEX_OPP,
+       .connect = opp_connect,
+       .progress = opp_progress,
+       .disconnect = opp_disconnect,
+       .get = opp_get,
+       .put = opp_put,
+       .chkput = opp_chkput,
+       .reset = opp_reset
+};
+
+static int opp_init(void)
+{
+       return obex_service_driver_register(&driver);
+}
+
+static void opp_exit(void)
+{
+       obex_service_driver_unregister(&driver);
+}
+
+OBEX_PLUGIN_DEFINE(opp, opp_init, opp_exit)
diff --git a/obexd/plugins/pbap.c b/obexd/plugins/pbap.c
new file mode 100644 (file)
index 0000000..4740188
--- /dev/null
@@ -0,0 +1,991 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2009-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <arpa/inet.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <gobex/gobex.h>
+#include <gobex-apparam.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "service.h"
+#include "phonebook.h"
+#include "mimetype.h"
+#include "filesystem.h"
+#include "manager.h"
+
+#define PHONEBOOK_TYPE         "x-bt/phonebook"
+#define VCARDLISTING_TYPE      "x-bt/vcard-listing"
+#define VCARDENTRY_TYPE                "x-bt/vcard"
+
+#define ORDER_TAG              0x01
+#define SEARCHVALUE_TAG                0x02
+#define SEARCHATTRIB_TAG       0x03
+#define MAXLISTCOUNT_TAG       0x04
+#define LISTSTARTOFFSET_TAG    0x05
+#define FILTER_TAG             0x06
+#define FORMAT_TAG             0X07
+#define PHONEBOOKSIZE_TAG      0X08
+#define NEWMISSEDCALLS_TAG     0X09
+
+struct cache {
+       gboolean valid;
+       uint32_t index;
+       GSList *entries;
+};
+
+struct cache_entry {
+       uint32_t handle;
+       char *id;
+       char *name;
+       char *sound;
+       char *tel;
+};
+
+struct pbap_session {
+       struct apparam_field *params;
+       char *folder;
+       uint32_t find_handle;
+       struct cache cache;
+       struct pbap_object *obj;
+};
+
+struct pbap_object {
+       GString *buffer;
+       GObexApparam *apparam;
+       gboolean firstpacket;
+       gboolean lastpart;
+       struct pbap_session *session;
+       void *request;
+};
+
+static const uint8_t PBAP_TARGET[TARGET_SIZE] = {
+                       0x79, 0x61, 0x35, 0xF0,  0xF0, 0xC5, 0x11, 0xD8,
+                       0x09, 0x66, 0x08, 0x00,  0x20, 0x0C, 0x9A, 0x66  };
+
+typedef int (*cache_entry_find_f) (const struct cache_entry *entry,
+                       const char *value);
+
+static void cache_entry_free(void *data)
+{
+       struct cache_entry *entry = data;
+
+       g_free(entry->id);
+       g_free(entry->name);
+       g_free(entry->sound);
+       g_free(entry->tel);
+       g_free(entry);
+}
+
+static gboolean entry_name_find(const struct cache_entry *entry,
+               const char *value)
+{
+       char *name;
+       gboolean ret;
+
+       if (!entry->name)
+               return FALSE;
+
+       if (strlen(value) == 0)
+               return TRUE;
+
+       name = g_utf8_strdown(entry->name, -1);
+       ret = (g_strstr_len(name, -1, value) ? TRUE : FALSE);
+       g_free(name);
+
+       return ret;
+}
+
+static gboolean entry_sound_find(const struct cache_entry *entry,
+               const char *value)
+{
+       if (!entry->sound)
+               return FALSE;
+
+       return (g_strstr_len(entry->sound, -1, value) ? TRUE : FALSE);
+}
+
+static gboolean entry_tel_find(const struct cache_entry *entry,
+               const char *value)
+{
+       if (!entry->tel)
+               return FALSE;
+
+       return (g_strstr_len(entry->tel, -1, value) ? TRUE : FALSE);
+}
+
+static const char *cache_find(struct cache *cache, uint32_t handle)
+{
+       GSList *l;
+
+       for (l = cache->entries; l; l = l->next) {
+               struct cache_entry *entry = l->data;
+
+               if (entry->handle == handle)
+                       return entry->id;
+       }
+
+       return NULL;
+}
+
+static void cache_clear(struct cache *cache)
+{
+       g_slist_free_full(cache->entries, cache_entry_free);
+       cache->entries = NULL;
+}
+
+static void phonebook_size_result(const char *buffer, size_t bufsize,
+                                       int vcards, int missed,
+                                       gboolean lastpart, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       uint16_t phonebooksize;
+
+       if (pbap->obj->request) {
+               phonebook_req_finalize(pbap->obj->request);
+               pbap->obj->request = NULL;
+       }
+
+       if (vcards < 0)
+               vcards = 0;
+
+       DBG("vcards %d", vcards);
+
+       phonebooksize = htons(vcards);
+
+       pbap->obj->apparam = g_obex_apparam_set_uint16(NULL, PHONEBOOKSIZE_TAG,
+                                                               phonebooksize);
+
+       if (missed > 0) {
+               DBG("missed %d", missed);
+
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       NEWMISSEDCALLS_TAG,
+                                                       missed);
+       }
+
+       obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
+}
+
+static void query_result(const char *buffer, size_t bufsize, int vcards,
+                               int missed, gboolean lastpart, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+
+       DBG("");
+
+       if (pbap->obj->request && lastpart) {
+               phonebook_req_finalize(pbap->obj->request);
+               pbap->obj->request = NULL;
+       }
+
+       pbap->obj->lastpart = lastpart;
+
+       if (vcards < 0) {
+               obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
+               return;
+       }
+
+       if (!pbap->obj->buffer)
+               pbap->obj->buffer = g_string_new_len(buffer, bufsize);
+       else
+               pbap->obj->buffer = g_string_append_len(pbap->obj->buffer,
+                                                       buffer, bufsize);
+
+       if (missed > 0) {
+               DBG("missed %d", missed);
+
+               pbap->obj->firstpacket = TRUE;
+
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       NEWMISSEDCALLS_TAG,
+                                                       missed);
+       }
+
+       obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
+}
+
+static void cache_entry_notify(const char *id, uint32_t handle,
+                                       const char *name, const char *sound,
+                                       const char *tel, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       struct cache_entry *entry = g_new0(struct cache_entry, 1);
+       struct cache *cache = &pbap->cache;
+
+       if (handle != PHONEBOOK_INVALID_HANDLE)
+               entry->handle = handle;
+       else
+               entry->handle = ++pbap->cache.index;
+
+       entry->id = g_strdup(id);
+       entry->name = g_strdup(name);
+       entry->sound = g_strdup(sound);
+       entry->tel = g_strdup(tel);
+
+       cache->entries = g_slist_append(cache->entries, entry);
+}
+
+static int alpha_sort(gconstpointer a, gconstpointer b)
+{
+       const struct cache_entry *e1 = a;
+       const struct cache_entry *e2 = b;
+
+       return g_strcmp0(e1->name, e2->name);
+}
+
+static int indexed_sort(gconstpointer a, gconstpointer b)
+{
+       const struct cache_entry *e1 = a;
+       const struct cache_entry *e2 = b;
+
+       return (e1->handle - e2->handle);
+}
+
+static int phonetical_sort(gconstpointer a, gconstpointer b)
+{
+       const struct cache_entry *e1 = a;
+       const struct cache_entry *e2 = b;
+
+       /* SOUND attribute is optional. Use Indexed sort if not present. */
+       if (!e1->sound || !e2->sound)
+               return indexed_sort(a, b);
+
+       return g_strcmp0(e1->sound, e2->sound);
+}
+
+static GSList *sort_entries(GSList *l, uint8_t order, uint8_t search_attrib,
+                                                       const char *value)
+{
+       GSList *sorted = NULL;
+       cache_entry_find_f find;
+       GCompareFunc sort;
+       char *searchval;
+
+       /*
+        * Default sorter is "Indexed". Some backends doesn't inform the index,
+        * for this case a sequential internal index is assigned.
+        * 0x00 = indexed
+        * 0x01 = alphanumeric
+        * 0x02 = phonetic
+        */
+       switch (order) {
+       case 0x01:
+               sort = alpha_sort;
+               break;
+       case 0x02:
+               sort = phonetical_sort;
+               break;
+       default:
+               sort = indexed_sort;
+               break;
+       }
+
+       /*
+        * This implementation checks if the given field CONTAINS the
+        * search value(case insensitive). Name is the default field
+        * when the attribute is not provided.
+        */
+       switch (search_attrib) {
+               /* Number */
+               case 1:
+                       find = entry_tel_find;
+                       break;
+               /* Sound */
+               case 2:
+                       find = entry_sound_find;
+                       break;
+               default:
+                       find = entry_name_find;
+                       break;
+       }
+
+       searchval = value ? g_utf8_strdown(value, -1) : NULL;
+       for (; l; l = l->next) {
+               struct cache_entry *entry = l->data;
+
+               if (searchval && !find(entry, (const char *) searchval))
+                       continue;
+
+               sorted = g_slist_insert_sorted(sorted, entry, sort);
+       }
+
+       g_free(searchval);
+
+       return sorted;
+}
+
+static int generate_response(void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       GSList *sorted;
+       GSList *l;
+       uint16_t max = pbap->params->maxlistcount;
+
+       DBG("");
+
+       if (max == 0) {
+               /* Ignore all other parameter and return PhoneBookSize */
+               uint16_t size = htons(g_slist_length(pbap->cache.entries));
+
+               pbap->obj->apparam = g_obex_apparam_set_uint16(
+                                                       pbap->obj->apparam,
+                                                       PHONEBOOKSIZE_TAG,
+                                                       size);
+
+               return 0;
+       }
+
+       /*
+        * Don't free the sorted list content: this list contains
+        * only the reference for the "real" cache entry.
+        */
+       sorted = sort_entries(pbap->cache.entries, pbap->params->order,
+                               pbap->params->searchattrib,
+                               (const char *) pbap->params->searchval);
+
+       /* Computing offset considering first entry of the phonebook */
+       l = g_slist_nth(sorted, pbap->params->liststartoffset);
+
+       pbap->obj->buffer = g_string_new(VCARD_LISTING_BEGIN);
+       for (; l && max; l = l->next, max--) {
+               const struct cache_entry *entry = l->data;
+               char *escaped_name = g_markup_escape_text(entry->name, -1);
+
+               g_string_append_printf(pbap->obj->buffer,
+                       VCARD_LISTING_ELEMENT, entry->handle, escaped_name);
+
+               g_free(escaped_name);
+       }
+
+       pbap->obj->buffer = g_string_append(pbap->obj->buffer,
+                                                       VCARD_LISTING_END);
+       g_slist_free(sorted);
+
+       return 0;
+}
+
+static void cache_ready_notify(void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+
+       DBG("");
+
+       phonebook_req_finalize(pbap->obj->request);
+       pbap->obj->request = NULL;
+
+       pbap->cache.valid = TRUE;
+
+       generate_response(pbap);
+       obex_object_set_io_flags(pbap->obj, G_IO_IN, 0);
+}
+
+static void cache_entry_done(void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       const char *id;
+       int ret;
+
+       DBG("");
+
+       pbap->cache.valid = TRUE;
+
+       id = cache_find(&pbap->cache, pbap->find_handle);
+       if (id == NULL) {
+               DBG("Entry %d not found on cache", pbap->find_handle);
+               obex_object_set_io_flags(pbap->obj, G_IO_ERR, -ENOENT);
+               return;
+       }
+
+       phonebook_req_finalize(pbap->obj->request);
+       pbap->obj->request = phonebook_get_entry(pbap->folder, id,
+                               pbap->params, query_result, pbap, &ret);
+       if (ret < 0)
+               obex_object_set_io_flags(pbap->obj, G_IO_ERR, ret);
+}
+
+static struct apparam_field *parse_aparam(const uint8_t *buffer, uint32_t hlen)
+{
+       GObexApparam *apparam;
+       struct apparam_field *param;
+
+       apparam = g_obex_apparam_decode(buffer, hlen);
+       if (apparam == NULL)
+               return NULL;
+
+       param = g_new0(struct apparam_field, 1);
+
+       g_obex_apparam_get_uint8(apparam, ORDER_TAG, &param->order);
+       g_obex_apparam_get_uint8(apparam, SEARCHATTRIB_TAG,
+                                               &param->searchattrib);
+       g_obex_apparam_get_uint8(apparam, FORMAT_TAG, &param->format);
+       g_obex_apparam_get_uint16(apparam, MAXLISTCOUNT_TAG,
+                                               &param->maxlistcount);
+       g_obex_apparam_get_uint16(apparam, LISTSTARTOFFSET_TAG,
+                                               &param->liststartoffset);
+       g_obex_apparam_get_uint64(apparam, FILTER_TAG, &param->filter);
+       param->searchval = g_obex_apparam_get_string(apparam, SEARCHVALUE_TAG);
+
+       DBG("o %x sa %x sv %s fil %" G_GINT64_MODIFIER "x for %x max %x off %x",
+                       param->order, param->searchattrib, param->searchval,
+                       param->filter, param->format, param->maxlistcount,
+                       param->liststartoffset);
+
+       g_obex_apparam_free(apparam);
+
+       return param;
+}
+
+static void *pbap_connect(struct obex_session *os, int *err)
+{
+       struct pbap_session *pbap;
+
+       manager_register_session(os);
+
+       pbap = g_new0(struct pbap_session, 1);
+       pbap->folder = g_strdup("/");
+       pbap->find_handle = PHONEBOOK_INVALID_HANDLE;
+
+       if (err)
+               *err = 0;
+
+       return pbap;
+}
+
+static int pbap_get(struct obex_session *os, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       const char *type = obex_get_type(os);
+       const char *name = obex_get_name(os);
+       struct apparam_field *params;
+       const uint8_t *buffer;
+       char *path;
+       ssize_t rsize;
+       int ret;
+
+       DBG("name %s type %s pbap %p", name, type, pbap);
+
+       if (type == NULL)
+               return -EBADR;
+
+       rsize = obex_get_apparam(os, &buffer);
+       if (rsize < 0) {
+               if (g_ascii_strcasecmp(type, VCARDENTRY_TYPE) != 0)
+                       return -EBADR;
+
+               rsize = 0;
+       }
+
+       params = parse_aparam(buffer, rsize);
+       if (params == NULL)
+               return -EBADR;
+
+       if (pbap->params) {
+               g_free(pbap->params->searchval);
+               g_free(pbap->params);
+       }
+
+       pbap->params = params;
+
+       if (g_ascii_strcasecmp(type, PHONEBOOK_TYPE) == 0) {
+               /* Always contains the absolute path */
+               if (g_path_is_absolute(name))
+                       path = g_strdup(name);
+               else
+                       path = g_build_filename("/", name, NULL);
+
+       } else if (g_ascii_strcasecmp(type, VCARDLISTING_TYPE) == 0) {
+               /* Always relative */
+               if (!name || strlen(name) == 0)
+                       /* Current folder */
+                       path = g_strdup(pbap->folder);
+               else
+                       /* Current folder + relative path */
+                       path = g_build_filename(pbap->folder, name, NULL);
+
+       } else if (g_ascii_strcasecmp(type, VCARDENTRY_TYPE) == 0) {
+               /* File name only */
+               path = g_strdup(name);
+       } else
+               return -EBADR;
+
+       if (path == NULL)
+               return -EBADR;
+
+       ret = obex_get_stream_start(os, path);
+
+       g_free(path);
+
+       return ret;
+}
+
+static int pbap_setpath(struct obex_session *os, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+       const char *name;
+       const uint8_t *nonhdr;
+       char *fullname;
+       int err;
+
+       if (obex_get_non_header_data(os, &nonhdr) != 2) {
+               error("Set path failed: flag and constants not found!");
+               return -EBADMSG;
+       }
+
+       name = obex_get_name(os);
+
+       DBG("name %s folder %s nonhdr 0x%x%x", name, pbap->folder,
+                                                       nonhdr[0], nonhdr[1]);
+
+       fullname = phonebook_set_folder(pbap->folder, name, nonhdr[0], &err);
+       if (err < 0)
+               return err;
+
+       g_free(pbap->folder);
+       pbap->folder = fullname;
+
+       /*
+        * FIXME: Define a criteria to mark the cache as invalid
+        */
+       pbap->cache.valid = FALSE;
+       pbap->cache.index = 0;
+       cache_clear(&pbap->cache);
+
+       return 0;
+}
+
+static void pbap_disconnect(struct obex_session *os, void *user_data)
+{
+       struct pbap_session *pbap = user_data;
+
+       manager_unregister_session(os);
+
+       if (pbap->obj)
+               pbap->obj->session = NULL;
+
+       if (pbap->params) {
+               g_free(pbap->params->searchval);
+               g_free(pbap->params);
+       }
+
+       cache_clear(&pbap->cache);
+       g_free(pbap->folder);
+       g_free(pbap);
+}
+
+static int pbap_chkput(struct obex_session *os, void *user_data)
+{
+       /* Rejects all PUTs */
+       return -EBADR;
+}
+
+static struct obex_service_driver pbap = {
+       .name = "Phonebook Access server",
+       .service = OBEX_PBAP,
+       .target = PBAP_TARGET,
+       .target_size = TARGET_SIZE,
+       .connect = pbap_connect,
+       .get = pbap_get,
+       .setpath = pbap_setpath,
+       .disconnect = pbap_disconnect,
+       .chkput = pbap_chkput
+};
+
+static struct pbap_object *vobject_create(struct pbap_session *pbap,
+                                                               void *request)
+{
+       struct pbap_object *obj;
+
+       obj = g_new0(struct pbap_object, 1);
+       obj->session = pbap;
+       pbap->obj = obj;
+       obj->request = request;
+
+       return obj;
+}
+
+static void *vobject_pull_open(const char *name, int oflag, mode_t mode,
+                               void *context, size_t *size, int *err)
+{
+       struct pbap_session *pbap = context;
+       phonebook_cb cb;
+       int ret;
+       void *request;
+
+       DBG("name %s context %p maxlistcount %d", name, context,
+                                               pbap->params->maxlistcount);
+
+       if (oflag != O_RDONLY) {
+               ret = -EPERM;
+               goto fail;
+       }
+
+       if (name == NULL) {
+               ret = -EBADR;
+               goto fail;
+       }
+
+       if (pbap->params->maxlistcount == 0)
+               cb = phonebook_size_result;
+       else
+               cb = query_result;
+
+       request = phonebook_pull(name, pbap->params, cb, pbap, &ret);
+
+       if (ret < 0)
+               goto fail;
+
+       /* reading first part of results from backend */
+       ret = phonebook_pull_read(request);
+       if (ret < 0)
+               goto fail;
+
+       if (err)
+               *err = 0;
+
+       return vobject_create(pbap, request);
+
+fail:
+       if (err)
+               *err = ret;
+
+       return NULL;
+}
+
+static int vobject_close(void *object)
+{
+       struct pbap_object *obj = object;
+
+       DBG("");
+
+       if (obj->session)
+               obj->session->obj = NULL;
+
+       if (obj->buffer)
+               g_string_free(obj->buffer, TRUE);
+
+       if (obj->apparam)
+               g_obex_apparam_free(obj->apparam);
+
+       if (obj->request)
+               phonebook_req_finalize(obj->request);
+
+       g_free(obj);
+
+       return 0;
+}
+
+static void *vobject_list_open(const char *name, int oflag, mode_t mode,
+                               void *context, size_t *size, int *err)
+{
+       struct pbap_session *pbap = context;
+       struct pbap_object *obj = NULL;
+       int ret;
+       void *request;
+
+       DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
+
+       if (oflag != O_RDONLY) {
+               ret = -EPERM;
+               goto fail;
+       }
+
+       if (name == NULL) {
+               ret = -EBADR;
+               goto fail;
+       }
+
+       /* PullvCardListing always get the contacts from the cache */
+
+       if (pbap->cache.valid) {
+               obj = vobject_create(pbap, NULL);
+               ret = generate_response(pbap);
+       } else {
+               request = phonebook_create_cache(name, cache_entry_notify,
+                                       cache_ready_notify, pbap, &ret);
+               if (ret == 0)
+                       obj = vobject_create(pbap, request);
+       }
+       if (ret < 0)
+               goto fail;
+
+       if (err)
+               *err = 0;
+
+       return obj;
+
+fail:
+       if (obj)
+               vobject_close(obj);
+
+       if (err)
+               *err = ret;
+
+       return NULL;
+}
+
+static void *vobject_vcard_open(const char *name, int oflag, mode_t mode,
+                                       void *context, size_t *size, int *err)
+{
+       struct pbap_session *pbap = context;
+       const char *id;
+       uint32_t handle;
+       int ret;
+       void *request;
+
+       DBG("name %s context %p valid %d", name, context, pbap->cache.valid);
+
+       if (oflag != O_RDONLY) {
+               ret = -EPERM;
+               goto fail;
+       }
+
+       if (name == NULL || sscanf(name, "%u.vcf", &handle) != 1) {
+               ret = -EBADR;
+               goto fail;
+       }
+
+       if (pbap->cache.valid == FALSE) {
+               pbap->find_handle = handle;
+               request = phonebook_create_cache(pbap->folder,
+                       cache_entry_notify, cache_entry_done, pbap, &ret);
+               goto done;
+       }
+
+       id = cache_find(&pbap->cache, handle);
+       if (!id) {
+               ret = -ENOENT;
+               goto fail;
+       }
+
+       request = phonebook_get_entry(pbap->folder, id, pbap->params,
+                                               query_result, pbap, &ret);
+
+done:
+       if (ret < 0)
+               goto fail;
+
+       if (err)
+               *err = 0;
+
+       return vobject_create(pbap, request);
+
+fail:
+       if (err)
+               *err = ret;
+
+       return NULL;
+}
+
+static ssize_t vobject_pull_get_next_header(void *object, void *buf, size_t mtu,
+                                                               uint8_t *hi)
+{
+       struct pbap_object *obj = object;
+       struct pbap_session *pbap = obj->session;
+
+       if (!obj->buffer && !obj->apparam)
+               return -EAGAIN;
+
+       *hi = G_OBEX_HDR_APPARAM;
+
+       if (pbap->params->maxlistcount == 0 || obj->firstpacket) {
+               obj->firstpacket = FALSE;
+
+               return g_obex_apparam_encode(obj->apparam, buf, mtu);
+       }
+
+       return 0;
+}
+
+static ssize_t vobject_pull_read(void *object, void *buf, size_t count)
+{
+       struct pbap_object *obj = object;
+       struct pbap_session *pbap = obj->session;
+       int len, ret;
+
+       DBG("buffer %p maxlistcount %d", obj->buffer,
+                                               pbap->params->maxlistcount);
+
+       if (!obj->buffer) {
+               if (pbap->params->maxlistcount == 0)
+                       return -ENOSTR;
+
+               return -EAGAIN;
+       }
+
+       len = string_read(obj->buffer, buf, count);
+       if (len == 0 && !obj->lastpart) {
+               /* in case when buffer is empty and we know that more
+                * data is still available in backend, requesting new
+                * data part via phonebook_pull_read and returning
+                * -EAGAIN to suspend request for now */
+               ret = phonebook_pull_read(obj->request);
+               if (ret)
+                       return -EPERM;
+
+               return -EAGAIN;
+       }
+
+       return len;
+}
+
+static ssize_t vobject_list_get_next_header(void *object, void *buf, size_t mtu,
+                                                               uint8_t *hi)
+{
+       struct pbap_object *obj = object;
+       struct pbap_session *pbap = obj->session;
+
+       /* Backend still busy reading contacts */
+       if (!pbap->cache.valid)
+               return -EAGAIN;
+
+       *hi = G_OBEX_HDR_APPARAM;
+
+       if (pbap->params->maxlistcount == 0)
+               return g_obex_apparam_encode(obj->apparam, buf, mtu);
+
+       return 0;
+}
+
+static ssize_t vobject_list_read(void *object, void *buf, size_t count)
+{
+       struct pbap_object *obj = object;
+       struct pbap_session *pbap = obj->session;
+
+       DBG("valid %d maxlistcount %d", pbap->cache.valid,
+                                               pbap->params->maxlistcount);
+
+       if (pbap->params->maxlistcount == 0)
+               return -ENOSTR;
+
+       return string_read(obj->buffer, buf, count);
+}
+
+static ssize_t vobject_vcard_read(void *object, void *buf, size_t count)
+{
+       struct pbap_object *obj = object;
+
+       DBG("buffer %p", obj->buffer);
+
+       if (!obj->buffer)
+               return -EAGAIN;
+
+       return string_read(obj->buffer, buf, count);
+}
+
+static struct obex_mime_type_driver mime_pull = {
+       .target = PBAP_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/phonebook",
+       .open = vobject_pull_open,
+       .close = vobject_close,
+       .read = vobject_pull_read,
+       .get_next_header = vobject_pull_get_next_header,
+};
+
+static struct obex_mime_type_driver mime_list = {
+       .target = PBAP_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/vcard-listing",
+       .open = vobject_list_open,
+       .close = vobject_close,
+       .read = vobject_list_read,
+       .get_next_header = vobject_list_get_next_header,
+};
+
+static struct obex_mime_type_driver mime_vcard = {
+       .target = PBAP_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "x-bt/vcard",
+       .open = vobject_vcard_open,
+       .close = vobject_close,
+       .read = vobject_vcard_read,
+};
+
+static int pbap_init(void)
+{
+       int err;
+
+       err = phonebook_init();
+       if (err < 0)
+               return err;
+
+       err = obex_mime_type_driver_register(&mime_pull);
+       if (err < 0)
+               goto fail_mime_pull;
+
+       err = obex_mime_type_driver_register(&mime_list);
+       if (err < 0)
+               goto fail_mime_list;
+
+       err = obex_mime_type_driver_register(&mime_vcard);
+       if (err < 0)
+               goto fail_mime_vcard;
+
+       err = obex_service_driver_register(&pbap);
+       if (err < 0)
+               goto fail_pbap_reg;
+
+       return 0;
+
+fail_pbap_reg:
+       obex_mime_type_driver_unregister(&mime_vcard);
+fail_mime_vcard:
+       obex_mime_type_driver_unregister(&mime_list);
+fail_mime_list:
+       obex_mime_type_driver_unregister(&mime_pull);
+fail_mime_pull:
+       phonebook_exit();
+
+       return err;
+}
+
+static void pbap_exit(void)
+{
+       obex_service_driver_unregister(&pbap);
+       obex_mime_type_driver_unregister(&mime_pull);
+       obex_mime_type_driver_unregister(&mime_list);
+       obex_mime_type_driver_unregister(&mime_vcard);
+       phonebook_exit();
+}
+
+OBEX_PLUGIN_DEFINE(pbap, pbap_init, pbap_exit)
diff --git a/obexd/plugins/pcsuite.c b/obexd/plugins/pcsuite.c
new file mode 100644 (file)
index 0000000..6460aa9
--- /dev/null
@@ -0,0 +1,512 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+#include <inttypes.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+#include "obex.h"
+#include "mimetype.h"
+#include "service.h"
+#include "ftp.h"
+
+#define PCSUITE_CHANNEL 24
+#define PCSUITE_WHO_SIZE 8
+
+#define PCSUITE_RECORD "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>    \
+<record>                                                               \
+  <attribute id=\"0x0001\">                                            \
+    <sequence>                                                         \
+      <uuid value=\"00005005-0000-1000-8000-0002ee000001\"/>           \
+    </sequence>                                                                \
+  </attribute>                                                         \
+                                                                       \
+  <attribute id=\"0x0004\">                                            \
+    <sequence>                                                         \
+      <sequence>                                                       \
+        <uuid value=\"0x0100\"/>                                       \
+      </sequence>                                                      \
+      <sequence>                                                       \
+        <uuid value=\"0x0003\"/>                                       \
+        <uint8 value=\"%u\" name=\"channel\"/>                         \
+      </sequence>                                                      \
+      <sequence>                                                       \
+        <uuid value=\"0x0008\"/>                                       \
+      </sequence>                                                      \
+    </sequence>                                                                \
+  </attribute>                                                         \
+                                                                       \
+  <attribute id=\"0x0005\">                                            \
+    <sequence>                                                         \
+      <uuid value=\"0x1002\"/>                                         \
+    </sequence>                                                                \
+  </attribute>                                                         \
+                                                                       \
+  <attribute id=\"0x0009\">                                            \
+    <sequence>                                                         \
+      <sequence>                                                       \
+        <uuid value=\"00005005-0000-1000-8000-0002ee000001\"/>         \
+        <uint16 value=\"0x0100\" name=\"version\"/>                    \
+      </sequence>                                                      \
+    </sequence>                                                                \
+  </attribute>                                                         \
+                                                                       \
+  <attribute id=\"0x0100\">                                            \
+    <text value=\"%s\" name=\"name\"/>                                 \
+  </attribute>                                                         \
+</record>"
+
+#define BACKUP_BUS_NAME                "com.nokia.backup.plugin"
+#define BACKUP_PATH            "/com/nokia/backup"
+#define BACKUP_PLUGIN_INTERFACE        "com.nokia.backup.plugin"
+#define BACKUP_DBUS_TIMEOUT    (1000 * 60 * 15)
+
+static const uint8_t FTP_TARGET[TARGET_SIZE] = {
+                       0xF9, 0xEC, 0x7B, 0xC4, 0x95, 0x3C, 0x11, 0xD2,
+                       0x98, 0x4E, 0x52, 0x54, 0x00, 0xDC, 0x9E, 0x09 };
+
+static const uint8_t PCSUITE_WHO[PCSUITE_WHO_SIZE] = {
+                       'P', 'C', ' ', 'S', 'u', 'i', 't', 'e' };
+
+struct pcsuite_session {
+       struct ftp_session *ftp;
+       char *lock_file;
+       int fd;
+};
+
+static void *pcsuite_connect(struct obex_session *os, int *err)
+{
+       struct pcsuite_session *pcsuite;
+       struct ftp_session *ftp;
+       int fd;
+       char *filename;
+
+       DBG("");
+
+       ftp = ftp_connect(os, err);
+       if (ftp == NULL)
+               return NULL;
+
+       filename = g_build_filename(g_get_home_dir(), ".pcsuite", NULL);
+
+       fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
+       if (fd < 0 && errno != EEXIST) {
+               error("open(%s): %s(%d)", filename, strerror(errno), errno);
+               goto fail;
+       }
+
+       /* Try to remove the file before retrying since it could be
+          that some process left/crash without removing it */
+       if (fd < 0) {
+               if (remove(filename) < 0) {
+                       error("remove(%s): %s(%d)", filename, strerror(errno),
+                                                                       errno);
+                       goto fail;
+               }
+
+               fd = open(filename, O_WRONLY | O_CREAT | O_EXCL, 0644);
+               if (fd < 0) {
+                       error("open(%s): %s(%d)", filename, strerror(errno),
+                                                                       errno);
+                       goto fail;
+               }
+       }
+
+       DBG("%s created", filename);
+
+       pcsuite = g_new0(struct pcsuite_session, 1);
+       pcsuite->ftp = ftp;
+       pcsuite->lock_file = filename;
+       pcsuite->fd = fd;
+
+       DBG("session %p created", pcsuite);
+
+       if (err)
+               *err = 0;
+
+       return pcsuite;
+
+fail:
+       if (ftp)
+               ftp_disconnect(os, ftp);
+       if (err)
+               *err = -errno;
+
+       g_free(filename);
+
+       return NULL;
+}
+
+static int pcsuite_get(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       return ftp_get(os, pcsuite->ftp);
+}
+
+static int pcsuite_chkput(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       return ftp_chkput(os, pcsuite->ftp);
+}
+
+static int pcsuite_put(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       return ftp_put(os, pcsuite->ftp);
+}
+
+static int pcsuite_setpath(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       return ftp_setpath(os, pcsuite->ftp);
+}
+
+static int pcsuite_action(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       return ftp_action(os, pcsuite->ftp);
+}
+
+static void pcsuite_disconnect(struct obex_session *os, void *user_data)
+{
+       struct pcsuite_session *pcsuite = user_data;
+
+       DBG("%p", pcsuite);
+
+       if (pcsuite->fd >= 0)
+               close(pcsuite->fd);
+
+       if (pcsuite->lock_file) {
+               remove(pcsuite->lock_file);
+               g_free(pcsuite->lock_file);
+       }
+
+       if (pcsuite->ftp)
+               ftp_disconnect(os, pcsuite->ftp);
+
+       g_free(pcsuite);
+}
+
+static struct obex_service_driver pcsuite = {
+       .name = "Nokia OBEX PC Suite Services",
+       .service = OBEX_PCSUITE,
+       .channel = PCSUITE_CHANNEL,
+       .secure = TRUE,
+       .record = PCSUITE_RECORD,
+       .target = FTP_TARGET,
+       .target_size = TARGET_SIZE,
+       .who = PCSUITE_WHO,
+       .who_size = PCSUITE_WHO_SIZE,
+       .connect = pcsuite_connect,
+       .get = pcsuite_get,
+       .put = pcsuite_put,
+       .chkput = pcsuite_chkput,
+       .setpath = pcsuite_setpath,
+       .action = pcsuite_action,
+       .disconnect = pcsuite_disconnect
+};
+
+struct backup_object {
+       char *cmd;
+       int fd;
+       int oflag;
+       int error_code;
+       mode_t mode;
+       DBusPendingCall *pending_call;
+       DBusConnection *conn;
+};
+
+static void on_backup_dbus_notify(DBusPendingCall *pending_call,
+                                       void *user_data)
+{
+       struct backup_object *obj = user_data;
+       DBusMessage *reply;
+       const char *filename;
+       int error_code;
+
+       DBG("Notification received for pending call - %s", obj->cmd);
+
+       reply = dbus_pending_call_steal_reply(pending_call);
+
+       if (reply && dbus_message_get_args(reply, NULL, DBUS_TYPE_INT32,
+                                       &error_code, DBUS_TYPE_STRING,
+                                       &filename, DBUS_TYPE_INVALID)) {
+
+               obj->error_code = error_code;
+
+               if (filename) {
+                       DBG("Notification - file path = %s, error_code = %d",
+                                       filename, error_code);
+                       if (error_code == 0)
+                               obj->fd = open(filename,obj->oflag,obj->mode);
+               }
+
+       } else
+               DBG("Notification timed out or connection got closed");
+
+       if (reply)
+               dbus_message_unref(reply);
+
+       dbus_pending_call_unref(pending_call);
+       obj->pending_call = NULL;
+       dbus_connection_unref(obj->conn);
+       obj->conn = NULL;
+
+       if (obj->fd >= 0) {
+               DBG("File opened, setting io flags, cmd = %s",
+                               obj->cmd);
+               if (obj->oflag == O_RDONLY)
+                       obex_object_set_io_flags(user_data, G_IO_IN, 0);
+               else
+                       obex_object_set_io_flags(user_data, G_IO_OUT, 0);
+       } else {
+               DBG("File open error, setting io error, cmd = %s",
+                               obj->cmd);
+               obex_object_set_io_flags(user_data, G_IO_ERR, -EPERM);
+       }
+}
+
+static gboolean send_backup_dbus_message(const char *oper,
+                                       struct backup_object *obj,
+                                       size_t *size)
+{
+       DBusConnection *conn;
+       DBusMessage *msg;
+       DBusPendingCall *pending_call;
+       gboolean ret = FALSE;
+       dbus_uint32_t file_size;
+
+       file_size = size ? *size : 0;
+
+       conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
+
+       if (conn == NULL)
+               return FALSE;
+
+       msg = dbus_message_new_method_call(BACKUP_BUS_NAME, BACKUP_PATH,
+                                               BACKUP_PLUGIN_INTERFACE,
+                                               "request");
+       if (msg == NULL) {
+               dbus_connection_unref(conn);
+               return FALSE;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &oper,
+                                       DBUS_TYPE_STRING, &obj->cmd,
+                                       DBUS_TYPE_INT32, &file_size,
+                                       DBUS_TYPE_INVALID);
+
+       if (strcmp(oper, "open") == 0) {
+               ret = g_dbus_send_message_with_reply(conn, msg, &pending_call,
+                                                       BACKUP_DBUS_TIMEOUT);
+               dbus_message_unref(msg);
+               if (ret) {
+                       obj->conn = conn;
+                       obj->pending_call = pending_call;
+                       ret = dbus_pending_call_set_notify(pending_call,
+                                                       on_backup_dbus_notify,
+                                                       obj, NULL);
+               } else
+                       dbus_connection_unref(conn);
+       } else {
+               g_dbus_send_message(conn, msg);
+               dbus_connection_unref(conn);
+       }
+
+       return ret;
+}
+
+static void *backup_open(const char *name, int oflag, mode_t mode,
+                               void *context, size_t *size, int *err)
+{
+       struct backup_object *obj = g_new0(struct backup_object, 1);
+
+       DBG("cmd = %s", name);
+
+       obj->cmd = g_path_get_basename(name);
+       obj->oflag = oflag;
+       obj->mode = mode;
+       obj->fd = -1;
+       obj->pending_call = NULL;
+       obj->conn = NULL;
+       obj->error_code = 0;
+
+       if (send_backup_dbus_message("open", obj, size) == FALSE) {
+               g_free(obj);
+               obj = NULL;
+       }
+
+       if (err)
+               *err = 0;
+
+       return obj;
+}
+
+static int backup_close(void *object)
+{
+       struct backup_object *obj = object;
+       size_t size = 0;
+
+       DBG("cmd = %s", obj->cmd);
+
+       if (obj->fd != -1)
+               close(obj->fd);
+
+       if (obj->pending_call) {
+               dbus_pending_call_cancel(obj->pending_call);
+               dbus_pending_call_unref(obj->pending_call);
+               dbus_connection_unref(obj->conn);
+       }
+
+       send_backup_dbus_message("close", obj, &size);
+
+       g_free(obj->cmd);
+       g_free(obj);
+
+       return 0;
+}
+
+static ssize_t backup_read(void *object, void *buf, size_t count)
+{
+       struct backup_object *obj = object;
+       ssize_t ret = 0;
+
+       if (obj->pending_call) {
+               DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
+               return -EAGAIN;
+       }
+
+       if (obj->fd != -1) {
+               DBG("cmd = %s, READING DATA", obj->cmd);
+               ret = read(obj->fd, buf, count);
+               if (ret < 0)
+                       ret = -errno;
+       } else {
+               DBG("cmd = %s, PERMANENT FAILURE", obj->cmd);
+               ret = obj->error_code ? -obj->error_code : -ENOENT;
+       }
+
+       return ret;
+}
+
+static ssize_t backup_write(void *object, const void *buf, size_t count)
+{
+       struct backup_object *obj = object;
+       ssize_t ret = 0;
+
+       if (obj->pending_call) {
+               DBG("cmd = %s, IN WAITING STAGE", obj->cmd);
+               return -EAGAIN;
+       }
+
+       if (obj->fd != -1) {
+               ret = write(obj->fd, buf, count);
+
+               DBG("cmd = %s, WRITTING", obj->cmd);
+
+               if (ret < 0) {
+                       error("backup: cmd = %s", obj->cmd);
+                       ret = -errno;
+               }
+       } else {
+               error("backup: cmd = %s", obj->cmd);
+               ret = obj->error_code ? -obj->error_code : -ENOENT;
+       }
+
+       return ret;
+}
+
+static int backup_flush(void *object)
+{
+       DBG("%p", object);
+
+       return 0;
+}
+
+static struct obex_mime_type_driver backup = {
+       .target = FTP_TARGET,
+       .target_size = TARGET_SIZE,
+       .mimetype = "application/vnd.nokia-backup",
+       .open = backup_open,
+       .close = backup_close,
+       .read = backup_read,
+       .write = backup_write,
+       .flush = backup_flush,
+};
+
+static int pcsuite_init(void)
+{
+       int err;
+
+       err = obex_service_driver_register(&pcsuite);
+       if (err < 0)
+               return err;
+
+       err = obex_mime_type_driver_register(&backup);
+       if (err < 0)
+               obex_service_driver_unregister(&pcsuite);
+
+       return err;
+}
+
+static void pcsuite_exit(void)
+{
+       obex_mime_type_driver_unregister(&backup);
+       obex_service_driver_unregister(&pcsuite);
+}
+
+OBEX_PLUGIN_DEFINE(pcsuite, pcsuite_init, pcsuite_exit)
diff --git a/obexd/plugins/phonebook-dummy.c b/obexd/plugins/phonebook-dummy.c
new file mode 100644 (file)
index 0000000..6b9d040
--- /dev/null
@@ -0,0 +1,582 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2009-2010  Intel Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <stdio.h>
+#include <stdint.h>
+#include <string.h>
+#include <glib.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <libical/ical.h>
+#include <libical/vobject.h>
+#include <libical/vcc.h>
+
+#include "log.h"
+#include "phonebook.h"
+
+typedef void (*vcard_func_t) (const char *file, VObject *vo, void *user_data);
+
+struct dummy_data {
+       phonebook_cb cb;
+       void *user_data;
+       const struct apparam_field *apparams;
+       char *folder;
+       int fd;
+       guint id;
+};
+
+struct cache_query {
+       phonebook_entry_cb entry_cb;
+       phonebook_cache_ready_cb ready_cb;
+       void *user_data;
+       DIR *dp;
+};
+
+static char *root_folder = NULL;
+
+static void dummy_free(void *user_data)
+{
+       struct dummy_data *dummy = user_data;
+
+       if (dummy->fd >= 0)
+               close(dummy->fd);
+
+       g_free(dummy->folder);
+       g_free(dummy);
+}
+
+static void query_free(void *user_data)
+{
+       struct cache_query *query = user_data;
+
+       if (query->dp)
+               closedir(query->dp);
+
+       g_free(query);
+}
+
+int phonebook_init(void)
+{
+       if (root_folder)
+               return 0;
+
+       /* FIXME: It should NOT be hard-coded */
+       root_folder = g_build_filename(getenv("HOME"), "phonebook", NULL);
+
+       return 0;
+}
+
+void phonebook_exit(void)
+{
+       g_free(root_folder);
+       root_folder = NULL;
+}
+
+static int handle_cmp(gconstpointer a, gconstpointer b)
+{
+       const char *f1 = a;
+       const char *f2 = b;
+       unsigned int i1, i2;
+
+       if (sscanf(f1, "%u.vcf", &i1) != 1)
+               return -1;
+
+       if (sscanf(f2, "%u.vcf", &i2) != 1)
+               return -1;
+
+       return (i1 - i2);
+}
+
+static int foreach_vcard(DIR *dp, vcard_func_t func, uint16_t offset,
+                       uint16_t maxlistcount, void *user_data, uint16_t *count)
+{
+       struct dirent *ep;
+       GSList *sorted = NULL, *l;
+       VObject *v;
+       FILE *fp;
+       int err, fd, folderfd;
+       uint16_t n = 0;
+
+       folderfd = dirfd(dp);
+       if (folderfd < 0) {
+               err = errno;
+               error("dirfd(): %s(%d)", strerror(err), err);
+               return -err;
+       }
+
+       /*
+        * Sorting vcards by file name. versionsort is a GNU extension.
+        * The simple sorting function implemented on handle_cmp address
+        * vcards handle only(handle is always a number). This sort function
+        * doesn't address filename started by "0".
+        */
+       while ((ep = readdir(dp))) {
+               char *filename;
+
+               if (ep->d_name[0] == '.')
+                       continue;
+
+               filename = g_filename_to_utf8(ep->d_name, -1, NULL, NULL, NULL);
+               if (filename == NULL) {
+                       error("g_filename_to_utf8: invalid filename");
+                       continue;
+               }
+
+               if (!g_str_has_suffix(filename, ".vcf")) {
+                       g_free(filename);
+                       continue;
+               }
+
+               sorted = g_slist_insert_sorted(sorted, filename, handle_cmp);
+       }
+
+       /*
+        * Filtering only the requested vCards attributes. Offset
+        * shall be based on the first entry of the phonebook.
+        */
+       for (l = g_slist_nth(sorted, offset);
+                       l && n < maxlistcount; l = l->next) {
+               const char *filename = l->data;
+
+               fd = openat(folderfd, filename, O_RDONLY);
+               if (fd < 0) {
+                       err = errno;
+                       error("openat(%s): %s(%d)", filename, strerror(err), err);
+                       continue;
+               }
+
+               fp = fdopen(fd, "r");
+               v = Parse_MIME_FromFile(fp);
+               if (v != NULL) {
+                       func(filename, v, user_data);
+                       deleteVObject(v);
+                       n++;
+               }
+
+               close(fd);
+       }
+
+       g_slist_free_full(sorted, g_free);
+
+       if (count)
+               *count = n;
+
+       return 0;
+}
+
+static void entry_concat(const char *filename, VObject *v, void *user_data)
+{
+       GString *buffer = user_data;
+       char tmp[1024];
+       int len;
+
+       /*
+        * VObject API uses len for IN and OUT
+        * Written bytes is also returned in the len variable
+        */
+       len = sizeof(tmp);
+       memset(tmp, 0, len);
+
+       writeMemVObject(tmp, &len, v);
+
+       /* FIXME: only the requested fields must be added */
+       g_string_append_len(buffer, tmp, len);
+}
+
+static gboolean read_dir(void *user_data)
+{
+       struct dummy_data *dummy = user_data;
+       GString *buffer;
+       DIR *dp;
+       uint16_t count = 0, max, offset;
+
+       buffer = g_string_new("");
+
+       dp = opendir(dummy->folder);
+       if (dp == NULL) {
+               int err = errno;
+               DBG("opendir(): %s(%d)", strerror(err), err);
+               goto done;
+       }
+
+       /*
+        * For PullPhoneBook function, the decision of returning the size
+        * or contacts is made in the PBAP core. When MaxListCount is ZERO,
+        * PCE wants to know the size of a given folder, PSE shall ignore all
+        * other applicattion parameters that may be present in the request.
+        */
+       if (dummy->apparams->maxlistcount == 0) {
+               max = 0xffff;
+               offset = 0;
+       } else {
+               max = dummy->apparams->maxlistcount;
+               offset = dummy->apparams->liststartoffset;
+       }
+
+       foreach_vcard(dp, entry_concat, offset, max, buffer, &count);
+
+       closedir(dp);
+done:
+       /* FIXME: Missing vCards fields filtering */
+       dummy->cb(buffer->str, buffer->len, count, 0, TRUE, dummy->user_data);
+
+       g_string_free(buffer, TRUE);
+
+       return FALSE;
+}
+
+static void entry_notify(const char *filename, VObject *v, void *user_data)
+{
+       struct cache_query *query = user_data;
+       VObject *property, *subproperty;
+       GString *name;
+       const char *tel;
+       long unsigned int handle;
+
+       property = isAPropertyOf(v, VCNameProp);
+       if (!property)
+               return;
+
+       if (sscanf(filename, "%lu.vcf", &handle) != 1)
+               return;
+
+       if (handle > UINT32_MAX)
+               return;
+
+       /* LastName; FirstName; MiddleName; Prefix; Suffix */
+
+       name = g_string_new("");
+       subproperty = isAPropertyOf(property, VCFamilyNameProp);
+       if (subproperty) {
+               g_string_append(name,
+                               fakeCString(vObjectUStringZValue(subproperty)));
+       }
+
+       subproperty = isAPropertyOf(property, VCGivenNameProp);
+       if (subproperty)
+               g_string_append_printf(name, ";%s",
+                               fakeCString(vObjectUStringZValue(subproperty)));
+
+       subproperty = isAPropertyOf(property, VCAdditionalNamesProp);
+       if (subproperty)
+               g_string_append_printf(name, ";%s",
+                               fakeCString(vObjectUStringZValue(subproperty)));
+
+       subproperty = isAPropertyOf(property, VCNamePrefixesProp);
+       if (subproperty)
+               g_string_append_printf(name, ";%s",
+                               fakeCString(vObjectUStringZValue(subproperty)));
+
+
+       subproperty = isAPropertyOf(property, VCNameSuffixesProp);
+       if (subproperty)
+               g_string_append_printf(name, ";%s",
+                               fakeCString(vObjectUStringZValue(subproperty)));
+
+       property = isAPropertyOf(v, VCTelephoneProp);
+
+       tel = property ? fakeCString(vObjectUStringZValue(property)) : NULL;
+
+       query->entry_cb(filename, handle, name->str, NULL, tel,
+                                                       query->user_data);
+       g_string_free(name, TRUE);
+}
+
+static gboolean create_cache(void *user_data)
+{
+       struct cache_query *query = user_data;
+
+       /*
+        * MaxListCount and ListStartOffset shall not be used
+        * when creating the cache. All entries shall be fetched.
+        * PBAP core is responsible for consider these application
+        * parameters before reply the entries.
+        */
+       foreach_vcard(query->dp, entry_notify, 0, 0xffff, query, NULL);
+
+       query->ready_cb(query->user_data);
+
+       return FALSE;
+}
+
+static gboolean read_entry(void *user_data)
+{
+       struct dummy_data *dummy = user_data;
+       char buffer[1024];
+       ssize_t count;
+
+       memset(buffer, 0, sizeof(buffer));
+       count = read(dummy->fd, buffer, sizeof(buffer));
+
+       if (count < 0) {
+               int err = errno;
+               error("read(): %s(%d)", strerror(err), err);
+               count = 0;
+       }
+
+       /* FIXME: Missing vCards fields filtering */
+
+       dummy->cb(buffer, count, 1, 0, TRUE, dummy->user_data);
+
+       return FALSE;
+}
+
+static gboolean is_dir(const char *dir)
+{
+       struct stat st;
+
+       if (stat(dir, &st) < 0) {
+               int err = errno;
+               error("stat(%s): %s (%d)", dir, strerror(err), err);
+               return FALSE;
+       }
+
+       return S_ISDIR(st.st_mode);
+}
+
+char *phonebook_set_folder(const char *current_folder,
+               const char *new_folder, uint8_t flags, int *err)
+{
+       gboolean root, child;
+       char *tmp1, *tmp2, *base, *absolute, *relative = NULL;
+       int len, ret = 0;
+
+       root = (g_strcmp0("/", current_folder) == 0);
+       child = (new_folder && strlen(new_folder) != 0);
+
+       switch (flags) {
+       case 0x02:
+               /* Go back to root */
+               if (!child) {
+                       relative = g_strdup("/");
+                       goto done;
+               }
+
+               relative = g_build_filename(current_folder, new_folder, NULL);
+               break;
+       case 0x03:
+               /* Go up 1 level */
+               if (root) {
+                       /* Already root */
+                       ret = -EBADR;
+                       goto done;
+               }
+
+               /*
+                * Removing one level of the current folder. Current folder
+                * contains AT LEAST one level since it is not at root folder.
+                * Use glib utility functions to handle invalid chars in the
+                * folder path properly.
+                */
+               tmp1 = g_path_get_basename(current_folder);
+               tmp2 = g_strrstr(current_folder, tmp1);
+               len = tmp2 - (current_folder + 1);
+
+               g_free(tmp1);
+
+               if (len == 0)
+                       base = g_strdup("/");
+               else
+                       base = g_strndup(current_folder, len);
+
+               /* Return: one level only */
+               if (!child) {
+                       relative = base;
+                       goto done;
+               }
+
+               relative = g_build_filename(base, new_folder, NULL);
+               g_free(base);
+
+               break;
+       default:
+               ret = -EBADR;
+               break;
+       }
+
+done:
+       if (!relative) {
+               if (err)
+                       *err = ret;
+
+               return NULL;
+       }
+
+       absolute = g_build_filename(root_folder, relative, NULL);
+       if (!is_dir(absolute)) {
+               g_free(relative);
+               relative = NULL;
+               ret = -ENOENT;
+       }
+
+       g_free(absolute);
+
+       if (err)
+               *err = ret;
+
+       return relative;
+}
+
+void phonebook_req_finalize(void *request)
+{
+       struct dummy_data *dummy = request;
+
+       /* dummy_data will be cleaned when request will be finished via
+        * g_source_remove */
+       if (dummy && dummy->id)
+               g_source_remove(dummy->id);
+}
+
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+                               phonebook_cb cb, void *user_data, int *err)
+{
+       struct dummy_data *dummy;
+       char *filename, *folder;
+
+       /*
+        * Main phonebook objects will be created dinamically based on the
+        * folder content. All vcards inside the given folder will be appended
+        * in the "virtual" main phonebook object.
+        */
+
+       filename = g_build_filename(root_folder, name, NULL);
+
+       if (!g_str_has_suffix(filename, ".vcf")) {
+               g_free(filename);
+               if (err)
+                       *err = -EBADR;
+               return NULL;
+       }
+
+       folder = g_strndup(filename, strlen(filename) - 4);
+       g_free(filename);
+       if (!is_dir(folder)) {
+               g_free(folder);
+               if (err)
+                       *err = -ENOENT;
+               return NULL;
+       }
+
+       dummy = g_new0(struct dummy_data, 1);
+       dummy->cb = cb;
+       dummy->user_data = user_data;
+       dummy->apparams = params;
+       dummy->folder = folder;
+       dummy->fd = -1;
+
+       if (err)
+               *err = 0;
+
+       return dummy;
+}
+
+int phonebook_pull_read(void *request)
+{
+       struct dummy_data *dummy = request;
+
+       if (!dummy)
+               return -ENOENT;
+
+       dummy->id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_dir, dummy,
+                                                               dummy_free);
+
+       return 0;
+}
+
+void *phonebook_get_entry(const char *folder, const char *id,
+                       const struct apparam_field *params, phonebook_cb cb,
+                       void *user_data, int *err)
+{
+       struct dummy_data *dummy;
+       char *filename;
+       int fd;
+       guint ret;
+
+       filename = g_build_filename(root_folder, folder, id, NULL);
+
+       fd = open(filename, O_RDONLY);
+       if (fd < 0) {
+               DBG("open(): %s(%d)", strerror(errno), errno);
+               if (err)
+                       *err = -ENOENT;
+               return NULL;
+       }
+
+       dummy = g_new0(struct dummy_data, 1);
+       dummy->cb = cb;
+       dummy->user_data = user_data;
+       dummy->apparams = params;
+       dummy->fd = fd;
+
+       ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, read_entry, dummy,
+                                                               dummy_free);
+
+       if (err)
+               *err = 0;
+
+       return GINT_TO_POINTER(ret);
+}
+
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+               phonebook_cache_ready_cb ready_cb, void *user_data, int *err)
+{
+       struct cache_query *query;
+       char *foldername;
+       DIR *dp;
+       guint ret;
+
+       foldername = g_build_filename(root_folder, name, NULL);
+       dp = opendir(foldername);
+       g_free(foldername);
+
+       if (dp == NULL) {
+               DBG("opendir(): %s(%d)", strerror(errno), errno);
+               if (err)
+                       *err = -ENOENT;
+               return NULL;
+       }
+
+       query = g_new0(struct cache_query, 1);
+       query->entry_cb = entry_cb;
+       query->ready_cb = ready_cb;
+       query->user_data = user_data;
+       query->dp = dp;
+
+       ret = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE, create_cache, query,
+                                                               query_free);
+
+       if (err)
+               *err = 0;
+
+       return GINT_TO_POINTER(ret);
+}
diff --git a/obexd/plugins/phonebook.h b/obexd/plugins/phonebook.h
new file mode 100644 (file)
index 0000000..441cff2
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define EOL    "\r\n"
+#define VCARD_LISTING_BEGIN \
+       "<?xml version=\"1.0\"?>" EOL\
+       "<!DOCTYPE vcard-listing SYSTEM \"vcard-listing.dtd\">" EOL\
+       "<vCard-listing version=\"1.0\">" EOL
+#define VCARD_LISTING_ELEMENT "<card handle = \"%d.vcf\" name = \"%s\"/>" EOL
+#define VCARD_LISTING_END "</vCard-listing>"
+
+#define PB_TELECOM_FOLDER "/telecom"
+#define PB_CONTACTS_FOLDER "/telecom/pb"
+#define PB_CALENDAR_FOLDER "/telecom/cal"
+#define PB_NOTES_FOLDER "/telecom/nt"
+#define PB_CALLS_COMBINED_FOLDER "/telecom/cch"
+#define PB_CALLS_INCOMING_FOLDER "/telecom/ich"
+#define PB_CALLS_MISSED_FOLDER "/telecom/mch"
+#define PB_CALLS_OUTGOING_FOLDER "/telecom/och"
+#define PB_LUID_FOLDER "/telecom/luid"
+
+#define PB_CONTACTS "/telecom/pb.vcf"
+#define PB_CALLS_COMBINED "/telecom/cch.vcf"
+#define PB_CALLS_INCOMING "/telecom/ich.vcf"
+#define PB_CALLS_MISSED "/telecom/mch.vcf"
+#define PB_CALLS_OUTGOING "/telecom/och.vcf"
+#define PB_DEVINFO "/telecom/devinfo.txt"
+#define PB_INFO_LOG "/telecom/pb/info.log"
+#define PB_CC_LOG "/telecom/pb/luid/cc.log"
+
+
+struct apparam_field {
+       /* list and pull attributes */
+       uint16_t maxlistcount;
+       uint16_t liststartoffset;
+
+       /* pull and vcard attributes */
+       uint64_t filter;
+       uint8_t format;
+
+       /* list attributes only */
+       uint8_t order;
+       uint8_t searchattrib;
+       char *searchval;
+};
+
+/*
+ * Interface between the PBAP core and backends to retrieve
+ * all contacts that match the application parameters rules.
+ * Contacts will be returned in the vcard format.
+ */
+typedef void (*phonebook_cb) (const char *buffer, size_t bufsize,
+               int vcards, int missed, gboolean lastpart, void *user_data);
+
+/*
+ * Interface between the PBAP core and backends to
+ * append a new entry in the PBAP folder cache.
+ */
+#define PHONEBOOK_INVALID_HANDLE 0xffffffff
+typedef void (*phonebook_entry_cb) (const char *id, uint32_t handle,
+                                       const char *name, const char *sound,
+                                       const char *tel, void *user_data);
+
+/*
+ * After notify all entries to PBAP core, the backend
+ * needs to notify that the operation has finished.
+ */
+typedef void (*phonebook_cache_ready_cb) (void *user_data);
+
+
+int phonebook_init(void);
+void phonebook_exit(void);
+
+/*
+ * Changes the current folder in the phonebook back-end. The PBAP core
+ * doesn't validate or restrict the possible values for the folders,
+ * allowing non-standard backends implementation which doesn't follow
+ * the PBAP virtual folder architecture. Validate the folder's name
+ * is responsibility of the back-ends.
+*/
+char *phonebook_set_folder(const char *current_folder,
+               const char *new_folder, uint8_t flags, int *err);
+
+/*
+ * phonebook_pull should be used only to prepare pull request - prepared
+ * request data is returned by this function. Start of fetching data from
+ * back-end will be done only after calling phonebook_pull_read with this
+ * returned request given as a parameter.
+ *
+ * phonebook_req_finalize MUST always be used to free associated resources.
+ */
+void *phonebook_pull(const char *name, const struct apparam_field *params,
+                               phonebook_cb cb, void *user_data, int *err);
+
+/*
+ * phonebook_pull_read should be used to start getting results from back-end.
+ * The back-end can return data as one response or can return it many parts.
+ * After obtaining one part, PBAP core need to call phonebook_pull_read with
+ * the same request again to get more results from back-end.
+ * The back-end MUST return only the content based on the application
+ * parameters requested by the client.
+ *
+ * Returns error code or 0 in case of success
+ */
+int phonebook_pull_read(void *request);
+
+/*
+ * Function used to retrieve a contact from the backend. Only contacts
+ * found in the cache are requested to the back-ends. The back-end MUST
+ * return only the content based on the application parameters requested
+ * by the client.
+ *
+ * Return value is a pointer to asynchronous request to phonebook back-end.
+ * phonebook_req_finalize MUST always be used to free associated resources.
+ */
+void *phonebook_get_entry(const char *folder, const char *id,
+                               const struct apparam_field *params,
+                               phonebook_cb cb, void *user_data, int *err);
+
+/*
+ * PBAP core will keep the contacts cache per folder. SetPhoneBook or
+ * PullvCardListing can invalidate the cache if the current folder changes.
+ * Cache will store only the necessary information required to reply to
+ * PullvCardListing request and verify if a given contact belongs to the
+ * source.
+ *
+ * Return value is a pointer to asynchronous request to phonebook back-end.
+ * phonebook_req_finalize MUST always be used to free associated resources.
+ */
+void *phonebook_create_cache(const char *name, phonebook_entry_cb entry_cb,
+               phonebook_cache_ready_cb ready_cb, void *user_data, int *err);
+
+/*
+ * Finalizes request to phonebook back-end and deallocates associated
+ * resources. Operation is canceled if not completed. This function MUST
+ * always be used after any of phonebook_pull, phonebook_get_entry, and
+ * phonebook_create_cache invoked.
+ *
+ * request is a pointer to asynchronous operation returned by phonebook_pull,
+ * phonebook_get_entry, and phonebook_create_cache.
+ */
+void phonebook_req_finalize(void *request);
diff --git a/obexd/plugins/vcard.c b/obexd/plugins/vcard.c
new file mode 100644 (file)
index 0000000..b36e4bf
--- /dev/null
@@ -0,0 +1,924 @@
+/*
+ * OBEX Server
+ *
+ * Copyright (C) 2008-2010 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 <string.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <ctype.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "vcard.h"
+
+#define ADDR_FIELD_AMOUNT 7
+#define LEN_MAX 128
+#define TYPE_INTERNATIONAL 145
+
+#define PHONEBOOK_FLAG_CACHED 0x1
+
+#define FILTER_VERSION (1 << 0)
+#define FILTER_FN (1 << 1)
+#define FILTER_N (1 << 2)
+#define FILTER_PHOTO (1 << 3)
+#define FILTER_BDAY (1 << 4)
+#define FILTER_ADR (1 << 5)
+#define FILTER_LABEL (1 << 6)
+#define FILTER_TEL (1 << 7)
+#define FILTER_EMAIL (1 << 8)
+#define FILTER_MAILER (1 << 9)
+#define FILTER_TZ (1 << 10)
+#define FILTER_GEO (1 << 11)
+#define FILTER_TITLE (1 << 12)
+#define FILTER_ROLE (1 << 13)
+#define FILTER_LOGO (1 << 14)
+#define FILTER_AGENT (1 << 15)
+#define FILTER_ORG (1 << 16)
+#define FILTER_NOTE (1 << 17)
+#define FILTER_REV (1 << 18)
+#define FILTER_SOUND (1 << 19)
+#define FILTER_URL (1 << 20)
+#define FILTER_UID (1 << 21)
+#define FILTER_KEY (1 << 22)
+#define FILTER_NICKNAME (1 << 23)
+#define FILTER_CATEGORIES (1 << 24)
+#define FILTER_PROID (1 << 25)
+#define FILTER_CLASS (1 << 26)
+#define FILTER_SORT_STRING (1 << 27)
+#define FILTER_X_IRMC_CALL_DATETIME (1 << 28)
+
+#define FORMAT_VCARD21 0x00
+#define FORMAT_VCARD30 0x01
+
+#define QP_LINE_LEN 75
+#define QP_CHAR_LEN 3
+#define QP_CR 0x0D
+#define QP_LF 0x0A
+#define QP_ESC 0x5C
+#define QP_SOFT_LINE_BREAK "="
+#define QP_SELECT "\n!\"#$=@[\\]^`{|}~"
+#define ASCII_LIMIT 0x7F
+
+/* according to RFC 2425, the output string may need folding */
+static void vcard_printf(GString *str, const char *fmt, ...)
+{
+       char buf[1024];
+       va_list ap;
+       int len_temp, line_number, i;
+       unsigned int line_delimit = 75;
+
+       va_start(ap, fmt);
+       vsnprintf(buf, sizeof(buf), fmt, ap);
+       va_end(ap);
+
+       line_number = strlen(buf) / line_delimit + 1;
+
+       for (i = 0; i < line_number; i++) {
+               len_temp = MIN(line_delimit, strlen(buf) - line_delimit * i);
+               g_string_append_len(str,  buf + line_delimit * i, len_temp);
+               if (i != line_number - 1)
+                       g_string_append(str, "\r\n ");
+       }
+
+       g_string_append(str, "\r\n");
+}
+
+/* According to RFC 2426, we need escape following characters:
+ *  '\n', '\r', ';', ',', '\'.
+ */
+static void add_slash(char *dest, const char *src, int len_max, int len)
+{
+       int i, j;
+
+       for (i = 0, j = 0; i < len && j + 1 < len_max; i++, j++) {
+               /* filling dest buffer - last field need to be reserved
+                * for '\0'*/
+               switch (src[i]) {
+               case '\n':
+                       if (j + 2 >= len_max)
+                               /* not enough space in the buffer to put char
+                                * preceded with escaping sequence (and '\0' in
+                                * the end) */
+                               goto done;
+
+                       dest[j++] = '\\';
+                       dest[j] = 'n';
+                       break;
+               case '\r':
+                       if (j + 2 >= len_max)
+                               goto done;
+
+                       dest[j++] = '\\';
+                       dest[j] = 'r';
+                       break;
+               case '\\':
+               case ';':
+               case ',':
+                       if (j + 2 >= len_max)
+                               goto done;
+
+                       dest[j++] = '\\';
+               default:
+                       dest[j] = src[i];
+                       break;
+               }
+       }
+
+done:
+       dest[j] = 0;
+}
+
+static void escape_semicolon(char *dest, const char *src, int len_max, int len)
+{
+       int i, j;
+
+       for (i = 0, j = 0; i < len && j + 1 < len_max; i++, j++) {
+               if (src[i] == ';') {
+                       if (j + 2 >= len_max)
+                               break;
+
+                       dest[j++] = '\\';
+               }
+
+               dest[j] = src[i];
+       }
+
+       dest[j] = 0;
+}
+
+static void set_escape(uint8_t format, char *dest, const char *src,
+                                                       int len_max, int len)
+{
+       if (format == FORMAT_VCARD30)
+               add_slash(dest, src, len_max, len);
+       else if (format == FORMAT_VCARD21)
+               escape_semicolon(dest, src, len_max, len);
+}
+
+static void get_escaped_fields(uint8_t format, char **fields, ...)
+{
+       va_list ap;
+       GString *line;
+       char *field;
+       char escaped[LEN_MAX];
+
+       va_start(ap, fields);
+       line = g_string_new("");
+
+       for (field = va_arg(ap, char *); field; ) {
+               set_escape(format, escaped, field, LEN_MAX, strlen(field));
+               g_string_append(line, escaped);
+
+               field = va_arg(ap, char *);
+
+               if (field)
+                       g_string_append(line, ";");
+       }
+
+       va_end(ap);
+
+       *fields = g_string_free(line, FALSE);
+}
+
+static gboolean set_qp_encoding(char c)
+{
+       unsigned char q = c;
+
+       if (strchr(QP_SELECT, q) != NULL)
+               return TRUE;
+
+       if (q < '!' || q > '~')
+               return TRUE;
+
+       return FALSE;
+}
+
+static void append_qp_break_line(GString *vcards, size_t *limit)
+{
+       /* Quoted Printable lines of text must be limited to less than 76
+        * characters and terminated by Quoted Printable softline break
+        * sequence of "=" (if some more characters left) */
+       g_string_append(vcards, QP_SOFT_LINE_BREAK);
+       g_string_append(vcards, "\r\n ");
+       *limit = QP_LINE_LEN - 1;
+}
+
+static void append_qp_ascii(GString *vcards, size_t *limit, char c)
+{
+       if (*limit == 0)
+               append_qp_break_line(vcards, limit);
+
+       g_string_append_c(vcards, c);
+       --*limit;
+}
+
+static void append_qp_hex(GString *vcards, size_t *limit, char c)
+{
+       if (*limit < QP_CHAR_LEN)
+               append_qp_break_line(vcards, limit);
+
+       g_string_append_printf(vcards, "=%2.2X", (unsigned char) c);
+       *limit -= QP_CHAR_LEN;
+}
+
+static void append_qp_new_line(GString *vcards, size_t *limit)
+{
+       /* Multiple lines of text are separated with a Quoted Printable CRLF
+        * sequence of "=0D" followed by "=0A" followed by a Quoted Printable
+        * softline break sequence of "=" */
+       append_qp_hex(vcards, limit, QP_CR);
+       append_qp_hex(vcards, limit, QP_LF);
+       append_qp_break_line(vcards, limit);
+}
+
+static gboolean utf8_select(const char *field)
+{
+       const char *pos;
+
+       if (g_utf8_validate(field, -1, NULL) == FALSE)
+               return FALSE;
+
+       for (pos = field; *pos != '\0'; pos = g_utf8_next_char(pos)) {
+               /* Test for non-standard UTF-8 character (out of range
+                * standard ASCII set), composed of more than single byte
+                * and represented by 32-bit value greater than 0x7F */
+               if (g_utf8_get_char(pos) > ASCII_LIMIT)
+                       return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void vcard_qp_print_encoded(GString *vcards, const char *desc, ...)
+{
+       const char *field, *charset = "";
+       const char *encoding = ";ENCODING=QUOTED-PRINTABLE";
+       size_t limit, param_len;
+       va_list ap;
+
+       va_start(ap, desc);
+
+       for (field = va_arg(ap, char *); field; field = va_arg(ap, char *)) {
+               if (utf8_select(field) == TRUE) {
+                       charset = ";CHARSET=UTF-8";
+                       break;
+               }
+       }
+
+       va_end(ap);
+
+       vcard_printf(vcards, "%s%s%s:", desc, encoding, charset);
+       g_string_truncate(vcards, vcards->len - 2);
+
+       param_len = strlen(desc) + strlen(encoding) + strlen(charset) + 1;
+       limit = QP_LINE_LEN - param_len;
+
+       va_start(ap, desc);
+
+       for (field = va_arg(ap, char *); field != NULL; ) {
+               size_t i, size = strlen(field);
+
+               for (i = 0; i < size; ++i) {
+                       if (set_qp_encoding(field[i])) {
+                               if (field[i] == '\n') {
+                                       append_qp_new_line(vcards, &limit);
+                                       continue;
+                               }
+
+                               append_qp_hex(vcards, &limit, field[i]);
+                       } else {
+                               /* According to vCard 2.1 spec. semicolons in
+                                * property parameter value must be escaped */
+                               if (field[i] == ';')
+                                       append_qp_hex(vcards, &limit, QP_ESC);
+
+                               append_qp_ascii(vcards, &limit, field[i]);
+                       }
+               }
+
+               field = va_arg(ap, char *);
+               if (field)
+                       append_qp_ascii(vcards, &limit, ';');
+       }
+
+       va_end(ap);
+
+       g_string_append(vcards, "\r\n");
+}
+
+static gboolean select_qp_encoding(uint8_t format, ...)
+{
+       char *field;
+       va_list ap;
+
+       if (format != FORMAT_VCARD21)
+               return FALSE;
+
+       va_start(ap, format);
+
+       for (field = va_arg(ap, char *); field; field = va_arg(ap, char *)) {
+               int i;
+               unsigned char c;
+
+               if (strpbrk(field, QP_SELECT)) {
+                       va_end(ap);
+                       return TRUE;
+               }
+
+               /* Quoted Printable encoding is selected if there is
+                * a character, which value is out of range standard
+                * ASCII set, since it may be a part of some
+                * non-standard character such as specified by UTF-8 */
+               for (i = 0; (c = field[i]) != '\0'; ++i) {
+                       if (c > ASCII_LIMIT) {
+                               va_end(ap);
+                               return TRUE;
+                       }
+               }
+       }
+
+       va_end(ap);
+
+       return FALSE;
+}
+
+static void vcard_printf_begin(GString *vcards, uint8_t format)
+{
+       vcard_printf(vcards, "BEGIN:VCARD");
+
+       if (format == FORMAT_VCARD30)
+               vcard_printf(vcards, "VERSION:3.0");
+       else if (format == FORMAT_VCARD21)
+               vcard_printf(vcards, "VERSION:2.1");
+}
+
+/* check if there is at least one contact field with personal data present */
+static gboolean contact_fields_present(struct phonebook_contact * contact)
+{
+       if (contact->family && strlen(contact->family) > 0)
+               return TRUE;
+
+       if (contact->given && strlen(contact->given) > 0)
+               return TRUE;
+
+       if (contact->additional && strlen(contact->additional) > 0)
+               return TRUE;
+
+       if (contact->prefix && strlen(contact->prefix) > 0)
+               return TRUE;
+
+       if (contact->suffix && strlen(contact->suffix) > 0)
+               return TRUE;
+
+       /* none of the personal data fields are present*/
+       return FALSE;
+}
+
+static void vcard_printf_name(GString *vcards, uint8_t format,
+                                       struct phonebook_contact *contact)
+{
+       char *fields;
+
+       if (contact_fields_present(contact) == FALSE) {
+               /* If fields are empty, add only 'N:' as parameter.
+                * This is crucial for some devices (Nokia BH-903) which
+                * have problems with history listings and can't determine
+                * that a parameter is really empty if there are unnecessary
+                * characters after 'N:' (e.g. 'N:;;;;').
+                * We need to add only'N:' param - without semicolons.
+                */
+               vcard_printf(vcards, "N:");
+               return;
+       }
+
+       if (select_qp_encoding(format, contact->family, contact->given,
+                                       contact->additional, contact->prefix,
+                                       contact->suffix, NULL)) {
+               vcard_qp_print_encoded(vcards, "N", contact->family,
+                                       contact->given, contact->additional,
+                                       contact->prefix, contact->suffix,
+                                       NULL);
+               return;
+       }
+
+       get_escaped_fields(format, &fields, contact->family,
+                               contact->given, contact->additional,
+                               contact->prefix, contact->suffix,
+                               NULL);
+
+       vcard_printf(vcards, "N:%s", fields);
+
+       g_free(fields);
+}
+
+static void vcard_printf_fullname(GString *vcards, uint8_t format,
+                                                       const char *text)
+{
+       char field[LEN_MAX];
+
+       if (!text || strlen(text) == 0) {
+               vcard_printf(vcards, "FN:");
+               return;
+       }
+
+       if (select_qp_encoding(format, text, NULL)) {
+               vcard_qp_print_encoded(vcards, "FN", text, NULL);
+               return;
+       }
+
+       set_escape(format, field, text, LEN_MAX, strlen(text));
+       vcard_printf(vcards, "FN:%s", field);
+}
+
+static void vcard_printf_number(GString *vcards, uint8_t format,
+                                       const char *number, int type,
+                                       enum phonebook_number_type category)
+{
+       const char *intl = "", *category_string = "";
+       char buf[LEN_MAX], field[LEN_MAX];
+
+       /* TEL is a mandatory field, include even if empty */
+       if (!number || !strlen(number) || !type) {
+               vcard_printf(vcards, "TEL:");
+               return;
+       }
+
+       switch (category) {
+       case TEL_TYPE_HOME:
+               if (format == FORMAT_VCARD21)
+                       category_string = "HOME;VOICE";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=HOME;TYPE=VOICE";
+               break;
+       case TEL_TYPE_MOBILE:
+               if (format == FORMAT_VCARD21)
+                       category_string = "CELL;VOICE";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=CELL;TYPE=VOICE";
+               break;
+       case TEL_TYPE_FAX:
+               if (format == FORMAT_VCARD21)
+                       category_string = "FAX";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=FAX";
+               break;
+       case TEL_TYPE_WORK:
+               if (format == FORMAT_VCARD21)
+                       category_string = "WORK;VOICE";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=WORK;TYPE=VOICE";
+               break;
+       case TEL_TYPE_OTHER:
+               if (format == FORMAT_VCARD21)
+                       category_string = "OTHER;VOICE";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=OTHER;TYPE=VOICE";
+               break;
+       }
+
+       if ((type == TYPE_INTERNATIONAL) && (number[0] != '+'))
+               intl = "+";
+
+       snprintf(field, sizeof(field), "%s%s", intl, number);
+
+       if (select_qp_encoding(format, number, NULL)) {
+               snprintf(buf, sizeof(buf), "TEL;%s", category_string);
+               vcard_qp_print_encoded(vcards, buf, field, NULL);
+               return;
+       }
+
+       vcard_printf(vcards, "TEL;%s:%s", category_string, field);
+}
+
+static void vcard_printf_tag(GString *vcards, uint8_t format,
+                                       const char *tag, const char *category,
+                                       const char *fld)
+{
+       int len;
+       char *separator = "", *type = "";
+       char buf[LEN_MAX], field[LEN_MAX];
+
+       if (tag == NULL || strlen(tag) == 0)
+               return;
+
+       if (fld == NULL || (len = strlen(fld)) == 0) {
+               vcard_printf(vcards, "%s:", tag);
+               return;
+       }
+
+       if (category && strlen(category)) {
+               separator = ";";
+               if (format == FORMAT_VCARD30)
+                       type = "TYPE=";
+       } else {
+               category = "";
+       }
+
+       snprintf(buf, LEN_MAX, "%s%s%s%s", tag, separator, type, category);
+
+       if (select_qp_encoding(format, fld, NULL)) {
+               vcard_qp_print_encoded(vcards, buf, fld, NULL);
+               return;
+       }
+
+       set_escape(format, field, fld, LEN_MAX, len);
+       vcard_printf(vcards, "%s:%s", buf, field);
+}
+
+static void vcard_printf_email(GString *vcards, uint8_t format,
+                                       const char *address,
+                                       enum phonebook_field_type category)
+{
+       const char *category_string = "";
+       char buf[LEN_MAX], field[LEN_MAX];
+       int len = 0;
+
+       if (!address || !(len = strlen(address))) {
+               vcard_printf(vcards, "EMAIL:");
+               return;
+       }
+       switch (category) {
+       case FIELD_TYPE_HOME:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET;HOME";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET;TYPE=HOME";
+               break;
+       case FIELD_TYPE_WORK:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET;WORK";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET;TYPE=WORK";
+               break;
+       default:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET;TYPE=OTHER";
+       }
+
+       if (select_qp_encoding(format, address, NULL)) {
+               snprintf(buf, sizeof(buf), "EMAIL;%s", category_string);
+               vcard_qp_print_encoded(vcards, buf, address, NULL);
+               return;
+       }
+
+       set_escape(format, field, address, LEN_MAX, len);
+       vcard_printf(vcards, "EMAIL;%s:%s", category_string, field);
+}
+
+static void vcard_printf_url(GString *vcards, uint8_t format,
+                                       const char *url,
+                                       enum phonebook_field_type category)
+{
+       const char *category_string = "";
+       char buf[LEN_MAX], field[LEN_MAX];
+
+       if (!url || strlen(url) == 0) {
+               vcard_printf(vcards, "URL:");
+               return;
+       }
+
+       switch (category) {
+       case FIELD_TYPE_HOME:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET;HOME";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET;TYPE=HOME";
+               break;
+       case FIELD_TYPE_WORK:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET;WORK";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET;TYPE=WORK";
+               break;
+       default:
+               if (format == FORMAT_VCARD21)
+                       category_string = "INTERNET";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=INTERNET";
+               break;
+       }
+
+       if (select_qp_encoding(format, url, NULL)) {
+               snprintf(buf, sizeof(buf), "URL;%s", category_string);
+               vcard_qp_print_encoded(vcards, buf, url, NULL);
+               return;
+       }
+
+       set_escape(format, field, url, LEN_MAX, strlen(url));
+       vcard_printf(vcards, "URL;%s:%s", category_string, field);
+}
+
+static gboolean org_fields_present(struct phonebook_contact *contact)
+{
+       if (contact->company && strlen(contact->company))
+               return TRUE;
+
+       if (contact->department && strlen(contact->department))
+               return TRUE;
+
+       return FALSE;
+}
+
+static void vcard_printf_org(GString *vcards, uint8_t format,
+                                       struct phonebook_contact *contact)
+{
+       char *fields;
+
+       if (org_fields_present(contact) == FALSE)
+               return;
+
+       if (select_qp_encoding(format, contact->company,
+                                               contact->department, NULL)) {
+               vcard_qp_print_encoded(vcards, "ORG", contact->company,
+                                               contact->department, NULL);
+               return;
+       }
+
+       get_escaped_fields(format, &fields, contact->company,
+                                       contact->department, NULL);
+
+       vcard_printf(vcards, "ORG:%s", fields);
+
+       g_free(fields);
+}
+
+static void vcard_printf_address(GString *vcards, uint8_t format,
+                                       struct phonebook_addr *address)
+{
+       char *fields, field_esc[LEN_MAX];
+       const char *category_string = "";
+       char buf[LEN_MAX], *address_fields[ADDR_FIELD_AMOUNT];
+       int i;
+       size_t len;
+       GSList *l;
+
+       if (!address) {
+               vcard_printf(vcards, "ADR:");
+               return;
+       }
+
+       switch (address->type) {
+       case FIELD_TYPE_HOME:
+               if (format == FORMAT_VCARD21)
+                       category_string = "HOME";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=HOME";
+               break;
+       case FIELD_TYPE_WORK:
+               if (format == FORMAT_VCARD21)
+                       category_string = "WORK";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=WORK";
+               break;
+       default:
+               if (format == FORMAT_VCARD21)
+                       category_string = "OTHER";
+               else if (format == FORMAT_VCARD30)
+                       category_string = "TYPE=OTHER";
+               break;
+       }
+
+       for (i = 0, l = address->fields; l; l = l->next)
+               address_fields[i++] = l->data;
+
+       if (select_qp_encoding(format, address_fields[0], address_fields[1],
+                                       address_fields[2], address_fields[3],
+                                       address_fields[4], address_fields[5],
+                                       address_fields[6], NULL)) {
+               snprintf(buf, sizeof(buf), "ADR;%s", category_string);
+               vcard_qp_print_encoded(vcards, buf,
+                                       address_fields[0], address_fields[1],
+                                       address_fields[2], address_fields[3],
+                                       address_fields[4], address_fields[5],
+                                       address_fields[6], NULL);
+               return;
+       }
+
+       /* allocate enough memory to insert address fields separated by ';'
+        * and terminated by '\0' */
+       len = ADDR_FIELD_AMOUNT * LEN_MAX;
+       fields = g_malloc0(len);
+
+       for (l = address->fields; l; l = l->next) {
+               char *field = l->data;
+
+               if (field) {
+                       set_escape(format, field_esc, field, LEN_MAX,
+                                                               strlen(field));
+                       g_strlcat(fields, field_esc, len);
+               }
+
+               if (l->next)
+                       /* not adding ';' after last addr field */
+                       g_strlcat(fields, ";", len);
+       }
+
+       vcard_printf(vcards,"ADR;%s:%s", category_string, fields);
+
+       g_free(fields);
+}
+
+static void vcard_printf_datetime(GString *vcards, uint8_t format,
+                                       struct phonebook_contact *contact)
+{
+       const char *type;
+       char buf[LEN_MAX];
+
+       switch (contact->calltype) {
+       case CALL_TYPE_MISSED:
+               type = "MISSED";
+               break;
+
+       case CALL_TYPE_INCOMING:
+               type = "RECEIVED";
+               break;
+
+       case CALL_TYPE_OUTGOING:
+               type = "DIALED";
+               break;
+
+       case CALL_TYPE_NOT_A_CALL:
+       default:
+               return;
+       }
+
+       if (select_qp_encoding(format, contact->datetime, NULL)) {
+               snprintf(buf, sizeof(buf), "X-IRMC-CALL-DATETIME;%s", type);
+               vcard_qp_print_encoded(vcards, buf, contact->datetime, NULL);
+               return;
+       }
+
+       vcard_printf(vcards, "X-IRMC-CALL-DATETIME;%s:%s", type,
+                                                       contact->datetime);
+}
+
+static void vcard_printf_end(GString *vcards)
+{
+       vcard_printf(vcards, "END:VCARD");
+}
+
+void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
+                                       uint64_t filter, uint8_t format)
+{
+       if (format == FORMAT_VCARD30 && filter)
+               filter |= (FILTER_VERSION | FILTER_FN | FILTER_N | FILTER_TEL);
+       else if (format == FORMAT_VCARD21 && filter)
+               filter |= (FILTER_VERSION | FILTER_N | FILTER_TEL);
+       else
+               filter = (FILTER_VERSION | FILTER_UID | FILTER_N | FILTER_FN |
+                               FILTER_TEL | FILTER_EMAIL | FILTER_ADR |
+                               FILTER_BDAY | FILTER_NICKNAME | FILTER_URL |
+                               FILTER_PHOTO | FILTER_ORG | FILTER_ROLE |
+                               FILTER_TITLE | FILTER_X_IRMC_CALL_DATETIME);
+
+       vcard_printf_begin(vcards, format);
+
+       if (filter & FILTER_UID && *contact->uid)
+               vcard_printf_tag(vcards, format, "UID", NULL, contact->uid);
+
+       if (filter & FILTER_N)
+               vcard_printf_name(vcards, format, contact);
+
+       if (filter & FILTER_FN && (*contact->fullname ||
+                                       format == FORMAT_VCARD30))
+               vcard_printf_fullname(vcards, format, contact->fullname);
+
+       if (filter & FILTER_TEL) {
+               GSList *l = contact->numbers;
+
+               if (g_slist_length(l) == 0)
+                       vcard_printf_number(vcards, format, NULL, 1,
+                                                       TEL_TYPE_OTHER);
+
+               for (; l; l = l->next) {
+                       struct phonebook_field *number = l->data;
+
+                       vcard_printf_number(vcards, format, number->text, 1,
+                                                               number->type);
+               }
+       }
+
+       if (filter & FILTER_EMAIL) {
+               GSList *l = contact->emails;
+
+               for (; l; l = l->next) {
+                       struct phonebook_field *email = l->data;
+                       vcard_printf_email(vcards, format, email->text,
+                                                               email->type);
+               }
+       }
+
+       if (filter & FILTER_ADR) {
+               GSList *l = contact->addresses;
+
+               for (; l; l = l->next) {
+                       struct phonebook_addr *addr = l->data;
+                       vcard_printf_address(vcards, format, addr);
+               }
+       }
+
+       if (filter & FILTER_BDAY && *contact->birthday)
+               vcard_printf_tag(vcards, format, "BDAY", NULL,
+                                               contact->birthday);
+
+       if (filter & FILTER_NICKNAME && *contact->nickname)
+               vcard_printf_tag(vcards, format, "NICKNAME", NULL,
+                                                       contact->nickname);
+
+       if (filter & FILTER_URL) {
+               GSList *l = contact->urls;
+
+               for (; l; l = l->next) {
+                       struct phonebook_field *url = l->data;
+                       vcard_printf_url(vcards, format, url->text, url->type);
+               }
+       }
+
+       if (filter & FILTER_PHOTO && *contact->photo)
+               vcard_printf_tag(vcards, format, "PHOTO", NULL,
+                                                       contact->photo);
+
+       if (filter & FILTER_ORG)
+               vcard_printf_org(vcards, format, contact);
+
+       if (filter & FILTER_ROLE && *contact->role)
+               vcard_printf_tag(vcards, format, "ROLE", NULL, contact->role);
+
+       if (filter & FILTER_TITLE && *contact->title)
+               vcard_printf_tag(vcards, format, "TITLE", NULL, contact->title);
+
+       if (filter & FILTER_X_IRMC_CALL_DATETIME)
+               vcard_printf_datetime(vcards, format, contact);
+
+       vcard_printf_end(vcards);
+}
+
+static void field_free(gpointer data)
+{
+       struct phonebook_field *field = data;
+
+       g_free(field->text);
+       g_free(field);
+}
+
+void phonebook_addr_free(gpointer addr)
+{
+       struct phonebook_addr *address = addr;
+
+       g_slist_free_full(address->fields, g_free);
+       g_free(address);
+}
+
+void phonebook_contact_free(struct phonebook_contact *contact)
+{
+       if (contact == NULL)
+               return;
+
+       g_slist_free_full(contact->numbers, field_free);
+       g_slist_free_full(contact->emails, field_free);
+       g_slist_free_full(contact->addresses, phonebook_addr_free);
+       g_slist_free_full(contact->urls, field_free);
+
+       g_free(contact->uid);
+       g_free(contact->fullname);
+       g_free(contact->given);
+       g_free(contact->family);
+       g_free(contact->additional);
+       g_free(contact->prefix);
+       g_free(contact->suffix);
+       g_free(contact->birthday);
+       g_free(contact->nickname);
+       g_free(contact->photo);
+       g_free(contact->company);
+       g_free(contact->department);
+       g_free(contact->role);
+       g_free(contact->title);
+       g_free(contact->datetime);
+       g_free(contact);
+}
diff --git a/obexd/plugins/vcard.h b/obexd/plugins/vcard.h
new file mode 100644 (file)
index 0000000..22c3f68
--- /dev/null
@@ -0,0 +1,81 @@
+/*
+ * OBEX Server
+ *
+ * Copyright (C) 2008-2010 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
+ *
+ */
+
+enum phonebook_number_type {
+       TEL_TYPE_HOME,
+       TEL_TYPE_MOBILE,
+       TEL_TYPE_FAX,
+       TEL_TYPE_WORK,
+       TEL_TYPE_OTHER,
+};
+
+enum phonebook_field_type {
+       FIELD_TYPE_HOME,
+       FIELD_TYPE_WORK,
+       FIELD_TYPE_OTHER,
+};
+
+enum phonebook_call_type {
+       CALL_TYPE_NOT_A_CALL,
+       CALL_TYPE_MISSED,
+       CALL_TYPE_INCOMING,
+       CALL_TYPE_OUTGOING,
+};
+
+struct phonebook_field {
+       char *text;
+       int type;
+};
+
+struct phonebook_addr {
+       GSList *fields;
+       int type;
+};
+
+struct phonebook_contact {
+       char *uid;
+       char *fullname;
+       char *given;
+       char *family;
+       char *additional;
+       GSList *numbers;
+       GSList *emails;
+       char *prefix;
+       char *suffix;
+       GSList *addresses;
+       char *birthday;
+       char *nickname;
+       GSList *urls;
+       char *photo;
+       char *company;
+       char *department;
+       char *role;
+       char *title;
+       char *datetime;
+       int calltype;
+};
+
+void phonebook_add_contact(GString *vcards, struct phonebook_contact *contact,
+                                       uint64_t filter, uint8_t format);
+
+void phonebook_contact_free(struct phonebook_contact *contact);
+
+void phonebook_addr_free(gpointer addr);
diff --git a/obexd/src/genbuiltin b/obexd/src/genbuiltin
new file mode 100755 (executable)
index 0000000..39f7735
--- /dev/null
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+for i in $*
+do
+       echo "extern struct obex_plugin_desc __obex_builtin_$i;"
+done
+
+echo
+echo "static struct obex_plugin_desc *__obex_builtin[] = {"
+
+for i in $*
+do
+       echo "  &__obex_builtin_$i,"
+done
+
+echo "  NULL"
+echo "};"
diff --git a/obexd/src/log.c b/obexd/src/log.c
new file mode 100644 (file)
index 0000000..ace7ab6
--- /dev/null
@@ -0,0 +1,136 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <stdarg.h>
+#include <syslog.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+void info(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vsyslog(LOG_INFO, format, ap);
+
+       va_end(ap);
+}
+
+void error(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vsyslog(LOG_ERR, format, ap);
+
+       va_end(ap);
+}
+
+void obex_debug(const char *format, ...)
+{
+       va_list ap;
+
+       va_start(ap, format);
+
+       vsyslog(LOG_DEBUG, format, ap);
+
+       va_end(ap);
+}
+
+extern struct obex_debug_desc __start___debug[];
+extern struct obex_debug_desc __stop___debug[];
+
+static char **enabled = NULL;
+
+static gboolean is_enabled(struct obex_debug_desc *desc)
+{
+       int i;
+
+       if (enabled == NULL)
+               return 0;
+
+       for (i = 0; enabled[i] != NULL; i++) {
+               if (desc->name != NULL && g_pattern_match_simple(enabled[i],
+                                                       desc->name) == TRUE)
+                       return 1;
+               if (desc->file != NULL && g_pattern_match_simple(enabled[i],
+                                                       desc->file) == TRUE)
+                       return 1;
+       }
+
+       return 0;
+}
+
+void __obex_log_enable_debug(void)
+{
+       struct obex_debug_desc *desc;
+
+       for (desc = __start___debug; desc < __stop___debug; desc++)
+               desc->flags |= OBEX_DEBUG_FLAG_PRINT;
+}
+
+void __obex_log_init(const char *debug, int detach)
+{
+       int option = LOG_NDELAY | LOG_PID;
+       struct obex_debug_desc *desc;
+       const char *name = NULL, *file = NULL;
+
+       if (debug != NULL)
+               enabled = g_strsplit_set(debug, ":, ", 0);
+
+       for (desc = __start___debug; desc < __stop___debug; desc++) {
+               if (file != NULL || name != NULL) {
+                       if (g_strcmp0(desc->file, file) == 0) {
+                               if (desc->name == NULL)
+                                       desc->name = name;
+                       } else
+                               file = NULL;
+               }
+
+               if (is_enabled(desc))
+                       desc->flags |= OBEX_DEBUG_FLAG_PRINT;
+       }
+
+       if (!detach)
+               option |= LOG_PERROR;
+
+       openlog("obexd", option, LOG_DAEMON);
+
+       syslog(LOG_INFO, "OBEX daemon %s", VERSION);
+}
+
+void __obex_log_cleanup(void)
+{
+       closelog();
+
+       g_strfreev(enabled);
+}
diff --git a/obexd/src/log.h b/obexd/src/log.h
new file mode 100644 (file)
index 0000000..d9fb867
--- /dev/null
@@ -0,0 +1,56 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+void info(const char *format, ...) __attribute__((format(printf, 1, 2)));
+void error(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void obex_debug(const char *format, ...) __attribute__((format(printf, 1, 2)));
+
+void __obex_log_init(const char *debug, int detach);
+void __obex_log_cleanup(void);
+void __obex_log_enable_debug(void);
+
+struct obex_debug_desc {
+       const char *name;
+       const char *file;
+#define OBEX_DEBUG_FLAG_DEFAULT (0)
+#define OBEX_DEBUG_FLAG_PRINT   (1 << 0)
+       unsigned int flags;
+} __attribute__((aligned(8)));
+
+/**
+ * DBG:
+ * @fmt: format string
+ * @arg...: list of arguments
+ *
+ * Simple macro around debug() which also include the function
+ * name it is called in.
+ */
+#define DBG(fmt, arg...) do { \
+       static struct obex_debug_desc __obex_debug_desc \
+       __attribute__((used, section("__debug"), aligned(8))) = { \
+               .file = __FILE__, .flags = OBEX_DEBUG_FLAG_DEFAULT, \
+       }; \
+       if (__obex_debug_desc.flags & OBEX_DEBUG_FLAG_PRINT) \
+               obex_debug("%s:%s() " fmt,  __FILE__, __func__ , ## arg); \
+} while (0)
diff --git a/obexd/src/main.c b/obexd/src/main.c
new file mode 100644 (file)
index 0000000..61a06b2
--- /dev/null
@@ -0,0 +1,339 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <stdint.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include <sys/signalfd.h>
+#include <fcntl.h>
+#include <termios.h>
+#include <getopt.h>
+#include <syslog.h>
+#include <glib.h>
+
+#include <gdbus/gdbus.h>
+
+#include "../client/manager.h"
+
+#include "log.h"
+#include "obexd.h"
+#include "server.h"
+
+#define DEFAULT_ROOT_PATH "/tmp"
+
+#define DEFAULT_CAP_FILE CONFIGDIR "/capability.xml"
+
+static GMainLoop *main_loop = NULL;
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+       case SIGTERM:
+               if (__terminated == 0) {
+                       info("Terminating");
+                       g_main_loop_quit(main_loop);
+               }
+
+               __terminated = 1;
+               break;
+       case SIGUSR2:
+               __obex_log_enable_debug();
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+       sigaddset(&mask, SIGUSR2);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean option_detach = TRUE;
+static char *option_debug = NULL;
+
+static char *option_root = NULL;
+static char *option_root_setup = NULL;
+static char *option_capability = NULL;
+static char *option_plugin = NULL;
+static char *option_noplugin = NULL;
+
+static gboolean option_autoaccept = FALSE;
+static gboolean option_symlinks = FALSE;
+
+static gboolean parse_debug(const char *key, const char *value,
+                               gpointer user_data, GError **error)
+{
+       if (value)
+               option_debug = g_strdup(value);
+       else
+               option_debug = g_strdup("*");
+
+       return TRUE;
+}
+
+static GOptionEntry options[] = {
+       { "debug", 'd', G_OPTION_FLAG_OPTIONAL_ARG,
+                               G_OPTION_ARG_CALLBACK, parse_debug,
+                               "Enable debug information output", "DEBUG" },
+       { "plugin", 'p', 0, G_OPTION_ARG_STRING, &option_plugin,
+                               "Specify plugins to load", "NAME,..." },
+       { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
+                               "Specify plugins not to load", "NAME,..." },
+       { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
+                               G_OPTION_ARG_NONE, &option_detach,
+                               "Run with logging in foreground" },
+       { "root", 'r', 0, G_OPTION_ARG_STRING, &option_root,
+                               "Specify root folder location. Both absolute "
+                               "and relative can be used, but relative paths "
+                               "are assumed to be relative to user $HOME "
+                               "folder", "PATH" },
+       { "root-setup", 'S', 0, G_OPTION_ARG_STRING, &option_root_setup,
+                               "Root folder setup script", "SCRIPT" },
+       { "symlinks", 'l', 0, G_OPTION_ARG_NONE, &option_symlinks,
+                               "Allow symlinks leading outside of the root "
+                               "folder" },
+       { "capability", 'c', 0, G_OPTION_ARG_STRING, &option_capability,
+                               "Specify capability file, use '!' mark for "
+                               "scripts", "FILE" },
+       { "auto-accept", 'a', 0, G_OPTION_ARG_NONE, &option_autoaccept,
+                               "Automatically accept push requests" },
+       { NULL },
+};
+
+gboolean obex_option_auto_accept(void)
+{
+       return option_autoaccept;
+}
+
+const char *obex_option_root_folder(void)
+{
+       return option_root;
+}
+
+gboolean obex_option_symlinks(void)
+{
+       return option_symlinks;
+}
+
+const char *obex_option_capability(void)
+{
+       return option_capability;
+}
+
+static gboolean is_dir(const char *dir) {
+       struct stat st;
+
+       if (stat(dir, &st) < 0) {
+               error("stat(%s): %s (%d)", dir, strerror(errno), errno);
+               return FALSE;
+       }
+
+       return S_ISDIR(st.st_mode);
+}
+
+static gboolean root_folder_setup(char *root, char *root_setup)
+{
+       int status;
+       char *argv[3] = { root_setup, root, NULL };
+
+       if (is_dir(root))
+               return TRUE;
+
+       if (root_setup == NULL)
+               return FALSE;
+
+       DBG("Setting up %s using %s", root, root_setup);
+
+       if (!g_spawn_sync(NULL, argv, NULL, 0, NULL, NULL, NULL, NULL,
+                                                       &status, NULL)) {
+               error("Unable to execute %s", root_setup);
+               return FALSE;
+       }
+
+       if (WEXITSTATUS(status) != EXIT_SUCCESS) {
+               error("%s exited with status %d", root_setup,
+                                                       WEXITSTATUS(status));
+               return FALSE;
+       }
+
+       return is_dir(root);
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *err = NULL;
+       guint signal;
+
+#ifdef NEED_THREADS
+       if (g_thread_supported() == FALSE)
+               g_thread_init(NULL);
+#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(EXIT_FAILURE);
+       }
+
+       g_option_context_free(context);
+
+       __obex_log_init(option_debug, option_detach);
+
+       DBG("Entering main loop");
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       signal = setup_signalfd();
+
+#ifdef NEED_THREADS
+       if (dbus_threads_init_default() == FALSE) {
+               fprintf(stderr, "Can't init usage of threads\n");
+               exit(EXIT_FAILURE);
+       }
+#endif
+
+       if (manager_init() == FALSE) {
+               error("manager_init failed");
+               exit(EXIT_FAILURE);
+       }
+
+       if (option_root == NULL)
+               option_root = g_strdup(DEFAULT_ROOT_PATH);
+
+       if (option_root[0] != '/') {
+               char *old_root = option_root, *home = getenv("HOME");
+               if (home) {
+                       option_root = g_strdup_printf("%s/%s", home, old_root);
+                       g_free(old_root);
+               }
+       }
+
+       if (option_capability == NULL)
+               option_capability = g_strdup(DEFAULT_CAP_FILE);
+
+       plugin_init(option_plugin, option_noplugin);
+
+       if (obex_server_init() < 0) {
+               error("obex_server_init failed");
+               exit(EXIT_FAILURE);
+       }
+
+       if (!root_folder_setup(option_root, option_root_setup)) {
+               error("Unable to setup root folder %s", option_root);
+               exit(EXIT_FAILURE);
+       }
+
+       if (client_manager_init() < 0) {
+               error("client_manager_init failed");
+               exit(EXIT_FAILURE);
+       }
+
+       g_main_loop_run(main_loop);
+
+       g_source_remove(signal);
+
+       client_manager_exit();
+
+       obex_server_exit();
+
+       plugin_cleanup();
+
+       manager_cleanup();
+
+       g_main_loop_unref(main_loop);
+
+       g_free(option_capability);
+       g_free(option_root);
+
+       __obex_log_cleanup();
+
+       return 0;
+}
diff --git a/obexd/src/manager.c b/obexd/src/manager.c
new file mode 100644 (file)
index 0000000..cec8a39
--- /dev/null
@@ -0,0 +1,807 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <gdbus/gdbus.h>
+#include <sys/socket.h>
+#include <inttypes.h>
+
+#include <btio/btio.h>
+#include <gobex/gobex.h>
+
+#include "obexd.h"
+#include "obex.h"
+#include "obex-priv.h"
+#include "server.h"
+#include "manager.h"
+#include "log.h"
+#include "service.h"
+
+#define OBEX_BASE_PATH "/org/bluez/obex"
+#define SESSION_BASE_PATH OBEX_BASE_PATH "/server"
+#define OBEX_MANAGER_INTERFACE OBEXD_SERVICE ".AgentManager1"
+#define ERROR_INTERFACE OBEXD_SERVICE ".Error"
+#define TRANSFER_INTERFACE OBEXD_SERVICE ".Transfer1"
+#define SESSION_INTERFACE OBEXD_SERVICE ".Session1"
+#define AGENT_INTERFACE OBEXD_SERVICE ".Agent1"
+
+#define TIMEOUT 60*1000 /* Timeout for user response (miliseconds) */
+
+struct agent {
+       char *bus_name;
+       char *path;
+       gboolean auth_pending;
+       char *new_name;
+       char *new_folder;
+       unsigned int watch_id;
+};
+
+enum {
+       TRANSFER_STATUS_QUEUED = 0,
+       TRANSFER_STATUS_ACTIVE,
+       TRANSFER_STATUS_COMPLETE,
+       TRANSFER_STATUS_ERROR
+};
+
+struct obex_transfer {
+       uint8_t status;
+       char *path;
+       struct obex_session *session;
+};
+
+static struct agent *agent = NULL;
+
+static DBusConnection *connection = NULL;
+
+static void agent_free(struct agent *agent)
+{
+       if (!agent)
+               return;
+
+       g_free(agent->new_folder);
+       g_free(agent->new_name);
+       g_free(agent->bus_name);
+       g_free(agent->path);
+       g_free(agent);
+}
+
+static inline DBusMessage *invalid_args(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg,
+                       ERROR_INTERFACE ".InvalidArguments",
+                       "Invalid arguments in method call");
+}
+
+static inline DBusMessage *not_supported(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg,
+                       ERROR_INTERFACE ".NotSupported",
+                       "Operation is not supported");
+}
+
+static inline DBusMessage *agent_already_exists(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg,
+                       ERROR_INTERFACE ".AlreadyExists",
+                       "Agent already exists");
+}
+
+static inline DBusMessage *agent_does_not_exist(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg,
+                       ERROR_INTERFACE ".DoesNotExist",
+                       "Agent does not exist");
+}
+
+static inline DBusMessage *not_authorized(DBusMessage *msg)
+{
+       return g_dbus_create_error(msg,
+                       ERROR_INTERFACE ".NotAuthorized",
+                       "Not authorized");
+}
+
+static void agent_disconnected(DBusConnection *conn, void *user_data)
+{
+       DBG("Agent exited");
+       agent_free(agent);
+       agent = NULL;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       const char *path, *sender;
+
+       if (agent)
+               return agent_already_exists(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_OBJECT_PATH, &path,
+                               DBUS_TYPE_INVALID))
+               return invalid_args(msg);
+
+       sender = dbus_message_get_sender(msg);
+       agent = g_new0(struct agent, 1);
+       agent->bus_name = g_strdup(sender);
+       agent->path = g_strdup(path);
+
+       agent->watch_id = g_dbus_add_disconnect_watch(conn, sender,
+                                       agent_disconnected, NULL, NULL);
+
+       DBG("Agent registered");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+                                       DBusMessage *msg, void *data)
+{
+       const char *path, *sender;
+
+       if (!agent)
+               return agent_does_not_exist(msg);
+
+       if (!dbus_message_get_args(msg, NULL,
+                               DBUS_TYPE_OBJECT_PATH, &path,
+                               DBUS_TYPE_INVALID))
+               return invalid_args(msg);
+
+       if (strcmp(agent->path, path) != 0)
+               return agent_does_not_exist(msg);
+
+       sender = dbus_message_get_sender(msg);
+       if (strcmp(agent->bus_name, sender) != 0)
+               return not_authorized(msg);
+
+       g_dbus_remove_watch(conn, agent->watch_id);
+
+       agent_free(agent);
+       agent = NULL;
+
+       DBG("Agent unregistered");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static gboolean get_source(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_session *os = data;
+       char *s;
+
+       s = os->src;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
+
+       return TRUE;
+}
+
+static gboolean get_destination(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_session *os = data;
+       char *s;
+
+       s = os->dst;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &s);
+
+       return TRUE;
+}
+
+static gboolean session_target_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_session *os = data;
+
+       return os->service->target ? TRUE : FALSE;
+}
+
+static char *target2str(const uint8_t *t)
+{
+       if (!t)
+               return NULL;
+
+       return g_strdup_printf("%02X%02X%02X%02X-%02X%02X-%02X%02X-"
+                               "%02X%02X-%02X%02X%02X%02X%02X%02X",
+                               t[0], t[1], t[2], t[3], t[4], t[5], t[6], t[7],
+                               t[8], t[9], t[10], t[11], t[12], t[13], t[14],
+                               t[15]);
+}
+
+static gboolean get_target(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_session *os = data;
+       char *uuid;
+
+       uuid = target2str(os->service->target);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+       g_free(uuid);
+
+       return TRUE;
+}
+
+static gboolean get_root(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       const char *root;
+
+       root = obex_option_root_folder();
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &root);
+
+       return TRUE;
+}
+
+static DBusMessage *transfer_cancel(DBusConnection *connection,
+                               DBusMessage *msg, void *user_data)
+{
+       struct obex_transfer *transfer = user_data;
+       struct obex_session *os = transfer->session;
+       const char *sender;
+
+       if (!os)
+               return invalid_args(msg);
+
+       sender = dbus_message_get_sender(msg);
+       if (strcmp(agent->bus_name, sender) != 0)
+               return not_authorized(msg);
+
+       os->aborted = TRUE;
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const char *status2str(uint8_t status)
+{
+       switch (status) {
+       case TRANSFER_STATUS_QUEUED:
+               return "queued";
+       case TRANSFER_STATUS_ACTIVE:
+               return "active";
+       case TRANSFER_STATUS_COMPLETE:
+               return "complete";
+       case TRANSFER_STATUS_ERROR:
+       default:
+               return "error";
+       }
+}
+
+static gboolean transfer_get_status(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       const char *status = status2str(transfer->status);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+       return TRUE;
+}
+
+static gboolean transfer_get_session(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+       char *path;
+
+       if (session == NULL)
+               return FALSE;
+
+       path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, session->id);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       g_free(path);
+
+       return TRUE;
+}
+
+static gboolean transfer_name_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       return session->name != NULL;
+}
+
+static gboolean transfer_get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       if (session->name == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->name);
+
+       return TRUE;
+}
+
+static gboolean transfer_type_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       return session->type != NULL;
+}
+
+static gboolean transfer_get_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       if (session->type == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->type);
+
+       return TRUE;
+}
+
+static gboolean transfer_size_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       return session->size != OBJECT_SIZE_UNKNOWN;
+}
+
+static gboolean transfer_get_size(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       if (session->size == OBJECT_SIZE_UNKNOWN)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &session->size);
+
+       return TRUE;
+}
+
+static gboolean transfer_time_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       return session->time != 0;
+}
+
+static gboolean transfer_get_time(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+       dbus_uint64_t time_u64;
+
+       if (session->size == 0)
+               return FALSE;
+
+       time_u64 = session->time;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &time_u64);
+
+       return TRUE;
+}
+
+static gboolean transfer_filename_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       return session->path != NULL;
+}
+
+static gboolean transfer_get_filename(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       if (session->path == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &session->path);
+
+       return TRUE;
+}
+
+static gboolean transfer_get_transferred(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct obex_transfer *transfer = data;
+       struct obex_session *session = transfer->session;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64,
+                                                       &session->offset);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable manager_methods[] = {
+       { GDBUS_METHOD("RegisterAgent",
+                       GDBUS_ARGS({ "agent", "o" }), NULL, register_agent) },
+       { GDBUS_METHOD("UnregisterAgent",
+                       GDBUS_ARGS({ "agent", "o" }), NULL, unregister_agent) },
+       { }
+};
+
+static const GDBusMethodTable transfer_methods[] = {
+       { GDBUS_METHOD("Cancel", NULL, NULL, transfer_cancel) },
+       { }
+};
+
+static const GDBusPropertyTable transfer_properties[] = {
+       { "Status", "s", transfer_get_status },
+       { "Session", "o", transfer_get_session },
+       { "Name", "s", transfer_get_name, NULL, transfer_name_exists },
+       { "Type", "s", transfer_get_type, NULL, transfer_type_exists },
+       { "Size", "t", transfer_get_size, NULL, transfer_size_exists },
+       { "Time", "t", transfer_get_time, NULL, transfer_time_exists },
+       { "Filename", "s", transfer_get_filename, NULL,
+                                               transfer_filename_exists },
+       { "Transferred", "t", transfer_get_transferred },
+       { }
+};
+
+static const GDBusPropertyTable session_properties[] = {
+       { "Source", "s", get_source },
+       { "Destination", "s", get_destination },
+       { "Target", "s", get_target, NULL, session_target_exists },
+       { "Root", "s", get_root },
+       { }
+};
+
+gboolean manager_init(void)
+{
+       DBusError err;
+
+       DBG("");
+
+       dbus_error_init(&err);
+
+       connection = g_dbus_setup_bus(DBUS_BUS_SESSION, OBEXD_SERVICE, &err);
+       if (connection == NULL) {
+               if (dbus_error_is_set(&err) == TRUE) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               } else
+                       fprintf(stderr, "Can't register with session bus\n");
+               return FALSE;
+       }
+
+       g_dbus_attach_object_manager(connection);
+
+       return g_dbus_register_interface(connection, OBEX_BASE_PATH,
+                                       OBEX_MANAGER_INTERFACE,
+                                       manager_methods, NULL, NULL,
+                                       NULL, NULL);
+}
+
+void manager_cleanup(void)
+{
+       DBG("");
+
+       g_dbus_unregister_interface(connection, OBEX_BASE_PATH,
+                                               OBEX_MANAGER_INTERFACE);
+
+       /* FIXME: Release agent? */
+
+       if (agent)
+               agent_free(agent);
+
+       g_dbus_detach_object_manager(connection);
+
+       dbus_connection_unref(connection);
+}
+
+void manager_emit_transfer_started(struct obex_transfer *transfer)
+{
+       transfer->status = TRANSFER_STATUS_ACTIVE;
+
+       g_dbus_emit_property_changed(connection, transfer->path,
+                                       TRANSFER_INTERFACE, "Status");
+}
+
+static void emit_transfer_completed(struct obex_transfer *transfer,
+                                                       gboolean success)
+{
+       if (transfer->path == NULL)
+               return;
+
+       transfer->status = success ? TRANSFER_STATUS_COMPLETE :
+                                               TRANSFER_STATUS_ERROR;
+
+       g_dbus_emit_property_changed(connection, transfer->path,
+                                       TRANSFER_INTERFACE, "Status");
+}
+
+static void emit_transfer_progress(struct obex_transfer *transfer,
+                                       uint32_t total, uint32_t transferred)
+{
+       if (transfer->path == NULL)
+               return;
+
+       g_dbus_emit_property_changed(connection, transfer->path,
+                                       TRANSFER_INTERFACE, "Transferred");
+}
+
+static void transfer_free(struct obex_transfer *transfer)
+{
+       g_free(transfer->path);
+       g_free(transfer);
+}
+
+struct obex_transfer *manager_register_transfer(struct obex_session *os)
+{
+       struct obex_transfer *transfer;
+       static unsigned int id = 0;
+
+       transfer = g_new0(struct obex_transfer, 1);
+       transfer->path = g_strdup_printf("%s/session%u/transfer%u",
+                                       SESSION_BASE_PATH, os->id, id++);
+       transfer->session = os;
+
+       if (!g_dbus_register_interface(connection, transfer->path,
+                               TRANSFER_INTERFACE,
+                               transfer_methods, NULL,
+                               transfer_properties, transfer, NULL)) {
+               error("Cannot register Transfer interface.");
+               transfer_free(transfer);
+               return NULL;
+       }
+
+       return transfer;
+}
+
+void manager_unregister_transfer(struct obex_transfer *transfer)
+{
+       struct obex_session *os;
+
+       if (transfer == NULL)
+               return;
+
+       os = transfer->session;
+
+       if (transfer->status == TRANSFER_STATUS_ACTIVE)
+               emit_transfer_completed(transfer, os->offset == os->size);
+
+       g_dbus_unregister_interface(connection, transfer->path,
+                                                       TRANSFER_INTERFACE);
+
+       transfer_free(transfer);
+}
+
+static void agent_cancel(void)
+{
+       DBusMessage *msg;
+
+       if (agent == NULL)
+               return;
+
+       msg = dbus_message_new_method_call(agent->bus_name, agent->path,
+                                               AGENT_INTERFACE, "Cancel");
+
+       g_dbus_send_message(connection, msg);
+}
+
+static void agent_reply(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       const char *name;
+       DBusError derr;
+       gboolean *got_reply = user_data;
+
+       *got_reply = TRUE;
+
+       /* Received a reply after the agent exited */
+       if (!agent)
+               return;
+
+       agent->auth_pending = FALSE;
+
+       dbus_error_init(&derr);
+       if (dbus_set_error_from_message(&derr, reply)) {
+               error("Agent replied with an error: %s, %s",
+                               derr.name, derr.message);
+
+               if (dbus_error_has_name(&derr, DBUS_ERROR_NO_REPLY))
+                       agent_cancel();
+
+               dbus_error_free(&derr);
+               dbus_message_unref(reply);
+               return;
+       }
+
+       if (dbus_message_get_args(reply, NULL,
+                               DBUS_TYPE_STRING, &name,
+                               DBUS_TYPE_INVALID)) {
+               /* Splits folder and name */
+               const char *slash = strrchr(name, '/');
+               DBG("Agent replied with %s", name);
+               if (!slash) {
+                       agent->new_name = g_strdup(name);
+                       agent->new_folder = NULL;
+               } else {
+                       agent->new_name = g_strdup(slash + 1);
+                       agent->new_folder = g_strndup(name, slash - name);
+               }
+       }
+
+       dbus_message_unref(reply);
+}
+
+static gboolean auth_error(GIOChannel *io, GIOCondition cond, void *user_data)
+{
+       agent->auth_pending = FALSE;
+
+       return FALSE;
+}
+
+int manager_request_authorization(struct obex_transfer *transfer, int32_t time,
+                                       char **new_folder, char **new_name)
+{
+       struct obex_session *os = transfer->session;
+       DBusMessage *msg;
+       DBusPendingCall *call;
+       unsigned int watch;
+       gboolean got_reply;
+
+       if (!agent)
+               return -1;
+
+       if (agent->auth_pending)
+               return -EPERM;
+
+       if (!new_folder || !new_name)
+               return -EINVAL;
+
+       msg = dbus_message_new_method_call(agent->bus_name, agent->path,
+                                                       AGENT_INTERFACE,
+                                                       "AuthorizePush");
+
+       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &transfer->path,
+                                                       DBUS_TYPE_INVALID);
+
+       if (!g_dbus_send_message_with_reply(connection, msg, &call, TIMEOUT)) {
+               dbus_message_unref(msg);
+               return -EPERM;
+       }
+
+       dbus_message_unref(msg);
+
+       agent->auth_pending = TRUE;
+       got_reply = FALSE;
+
+       /* Catches errors before authorization response comes */
+       watch = g_io_add_watch_full(os->io, G_PRIORITY_DEFAULT,
+                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                       auth_error, NULL, NULL);
+
+       dbus_pending_call_set_notify(call, agent_reply, &got_reply, NULL);
+
+       /* Workaround: process events while agent doesn't reply */
+       while (agent && agent->auth_pending)
+               g_main_context_iteration(NULL, TRUE);
+
+       g_source_remove(watch);
+
+       if (!got_reply) {
+               dbus_pending_call_cancel(call);
+               agent_cancel();
+       }
+
+       dbus_pending_call_unref(call);
+
+       if (!agent || !agent->new_name)
+               return -EPERM;
+
+       *new_folder = agent->new_folder;
+       *new_name = agent->new_name;
+       agent->new_folder = NULL;
+       agent->new_name = NULL;
+
+       return 0;
+}
+
+static DBusMessage *session_get_capabilities(DBusConnection *connection,
+                                       DBusMessage *message, void *user_data)
+{
+       return not_supported(message);
+}
+
+static const GDBusMethodTable session_methods[] = {
+       { GDBUS_ASYNC_METHOD("GetCapabilities",
+                               NULL, GDBUS_ARGS({ "capabilities", "s" }),
+                               session_get_capabilities) },
+       { }
+};
+
+void manager_register_session(struct obex_session *os)
+{
+       char *path;
+
+       path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
+
+       if (!g_dbus_register_interface(connection, path,
+                               SESSION_INTERFACE,
+                               session_methods, NULL,
+                               session_properties, os, NULL))
+               error("Cannot register Session interface.");
+
+       g_free(path);
+}
+
+void manager_unregister_session(struct obex_session *os)
+{
+       char *path;
+
+       path = g_strdup_printf("%s/session%u", SESSION_BASE_PATH, os->id);
+
+       g_dbus_unregister_interface(connection, path, SESSION_INTERFACE);
+
+       g_free(path);
+}
+
+void manager_emit_transfer_progress(struct obex_transfer *transfer)
+{
+       emit_transfer_progress(transfer, transfer->session->size,
+                                               transfer->session->offset);
+}
+
+void manager_emit_transfer_completed(struct obex_transfer *transfer)
+{
+       struct obex_session *session;
+
+       if (transfer == NULL)
+               return;
+
+       session = transfer->session;
+
+       if (session == NULL || session->object == NULL)
+               return;
+
+       emit_transfer_completed(transfer, !session->aborted);
+}
+
+DBusConnection *manager_dbus_get_connection(void)
+{
+       if (connection == NULL)
+               return NULL;
+
+       return dbus_connection_ref(connection);
+}
diff --git a/obexd/src/manager.h b/obexd/src/manager.h
new file mode 100644 (file)
index 0000000..669b223
--- /dev/null
@@ -0,0 +1,42 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia 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
+ *
+ */
+
+#include <dbus/dbus.h>
+
+#define OBEXD_SERVICE  "org.bluez.obex"
+
+struct obex_session;
+struct obex_transfer;
+
+void manager_register_session(struct obex_session *os);
+void manager_unregister_session(struct obex_session *os);
+
+struct obex_transfer *manager_register_transfer(struct obex_session *os);
+void manager_unregister_transfer(struct obex_transfer *transfer);
+void manager_emit_transfer_started(struct obex_transfer *transfer);
+void manager_emit_transfer_progress(struct obex_transfer *transfer);
+void manager_emit_transfer_completed(struct obex_transfer *transfer);
+int manager_request_authorization(struct obex_transfer *transfer, int32_t time,
+                                       char **new_folder, char **new_name);
+
+DBusConnection *manager_dbus_get_connection(void);
diff --git a/obexd/src/map_ap.h b/obexd/src/map_ap.h
new file mode 100644 (file)
index 0000000..da108fe
--- /dev/null
@@ -0,0 +1,51 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2010-2011  Nokia 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
+ *
+ */
+
+/* List of OBEX application parameters tags as per MAP specification. */
+enum map_ap_tag {
+       MAP_AP_MAXLISTCOUNT             = 0x01,         /* uint16_t     */
+       MAP_AP_STARTOFFSET              = 0x02,         /* uint16_t     */
+       MAP_AP_FILTERMESSAGETYPE        = 0x03,         /* uint8_t      */
+       MAP_AP_FILTERPERIODBEGIN        = 0x04,         /* char *       */
+       MAP_AP_FILTERPERIODEND          = 0x05,         /* char *       */
+       MAP_AP_FILTERREADSTATUS         = 0x06,         /* uint8_t      */
+       MAP_AP_FILTERRECIPIENT          = 0x07,         /* char *       */
+       MAP_AP_FILTERORIGINATOR         = 0x08,         /* char *       */
+       MAP_AP_FILTERPRIORITY           = 0x09,         /* uint8_t      */
+       MAP_AP_ATTACHMENT               = 0x0A,         /* uint8_t      */
+       MAP_AP_TRANSPARENT              = 0x0B,         /* uint8_t      */
+       MAP_AP_RETRY                    = 0x0C,         /* uint8_t      */
+       MAP_AP_NEWMESSAGE               = 0x0D,         /* uint8_t      */
+       MAP_AP_NOTIFICATIONSTATUS       = 0x0E,         /* uint8_t      */
+       MAP_AP_MASINSTANCEID            = 0x0F,         /* uint8_t      */
+       MAP_AP_PARAMETERMASK            = 0x10,         /* uint32_t     */
+       MAP_AP_FOLDERLISTINGSIZE        = 0x11,         /* uint16_t     */
+       MAP_AP_MESSAGESLISTINGSIZE      = 0x12,         /* uint16_t     */
+       MAP_AP_SUBJECTLENGTH            = 0x13,         /* uint8_t      */
+       MAP_AP_CHARSET                  = 0x14,         /* uint8_t      */
+       MAP_AP_FRACTIONREQUEST          = 0x15,         /* uint8_t      */
+       MAP_AP_FRACTIONDELIVER          = 0x16,         /* uint8_t      */
+       MAP_AP_STATUSINDICATOR          = 0x17,         /* uint8_t      */
+       MAP_AP_STATUSVALUE              = 0x18,         /* uint8_t      */
+       MAP_AP_MSETIME                  = 0x19,         /* char *       */
+};
diff --git a/obexd/src/mimetype.c b/obexd/src/mimetype.c
new file mode 100644 (file)
index 0000000..833ddc7
--- /dev/null
@@ -0,0 +1,216 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+
+#include "log.h"
+#include "obex.h"
+#include "mimetype.h"
+
+static GSList *drivers = NULL;
+
+static GSList *watches = NULL;
+
+struct io_watch {
+       void *object;
+       obex_object_io_func func;
+       void *user_data;
+};
+
+void obex_object_set_io_flags(void *object, int flags, int err)
+{
+       GSList *l;
+
+       for (l = watches; l;) {
+               struct io_watch *watch = l->data;
+
+               l = l->next;
+
+               if (watch->object != object)
+                       continue;
+
+               if (watch->func(object, flags, err, watch->user_data) == TRUE)
+                       continue;
+
+               if (g_slist_find(watches, watch) == NULL)
+                       continue;
+
+               watches = g_slist_remove(watches, watch);
+               g_free(watch);
+       }
+}
+
+static struct io_watch *find_io_watch(void *object)
+{
+       GSList *l;
+
+       for (l = watches; l; l = l->next) {
+               struct io_watch *watch = l->data;
+
+               if (watch->object == object)
+                       return watch;
+       }
+
+       return NULL;
+}
+
+static void reset_io_watch(void *object)
+{
+       struct io_watch *watch;
+
+       watch = find_io_watch(object);
+       if (watch == NULL)
+               return;
+
+       watches = g_slist_remove(watches, watch);
+       g_free(watch);
+}
+
+static int set_io_watch(void *object, obex_object_io_func func,
+                               void *user_data)
+{
+       struct io_watch *watch;
+
+       if (func == NULL) {
+               reset_io_watch(object);
+               return 0;
+       }
+
+       watch = find_io_watch(object);
+       if (watch)
+               return -EPERM;
+
+       watch = g_new0(struct io_watch, 1);
+       watch->object = object;
+       watch->func = func;
+       watch->user_data = user_data;
+
+       watches = g_slist_append(watches, watch);
+
+       return 0;
+}
+
+static struct obex_mime_type_driver *find_driver(const uint8_t *target,
+                               unsigned int target_size,
+                               const char *mimetype, const uint8_t *who,
+                               unsigned int who_size)
+{
+       GSList *l;
+
+       for (l = drivers; l; l = l->next) {
+               struct obex_mime_type_driver *driver = l->data;
+
+               if (memncmp0(target, target_size, driver->target, driver->target_size))
+                       continue;
+
+               if (memncmp0(who, who_size, driver->who, driver->who_size))
+                       continue;
+
+               if (mimetype == NULL || driver->mimetype == NULL) {
+                       if (mimetype == driver->mimetype)
+                               return driver;
+                       else
+                               continue;
+               }
+
+               if (g_ascii_strcasecmp(mimetype, driver->mimetype) == 0)
+                       return driver;
+       }
+
+       return NULL;
+}
+
+struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
+                               unsigned int target_size,
+                               const char *mimetype, const uint8_t *who,
+                               unsigned int who_size)
+{
+       struct obex_mime_type_driver *driver;
+
+       driver = find_driver(target, target_size, mimetype, who, who_size);
+       if (driver == NULL) {
+               if (who != NULL) {
+                       /* Fallback to non-who specific */
+                       driver = find_driver(target, target_size, mimetype, NULL, 0);
+                       if (driver != NULL)
+                               return driver;
+               }
+
+               if (mimetype != NULL)
+                       /* Fallback to target default */
+                       driver = find_driver(target, target_size, NULL, NULL, 0);
+
+               if (driver == NULL)
+                       /* Fallback to general default */
+                       driver = find_driver(NULL, 0, NULL, NULL, 0);
+       }
+
+       return driver;
+}
+
+int obex_mime_type_driver_register(struct obex_mime_type_driver *driver)
+{
+       if (!driver) {
+               error("Invalid driver");
+               return -EINVAL;
+       }
+
+       if (find_driver(driver->target, driver->target_size, driver->mimetype,
+                                       driver->who, driver->who_size)) {
+               error("Permission denied: %s could not be registered",
+                               driver->mimetype);
+               return -EPERM;
+       }
+
+       if (driver->set_io_watch == NULL)
+               driver->set_io_watch = set_io_watch;
+
+       DBG("driver %p mimetype %s registered", driver, driver->mimetype);
+
+       drivers = g_slist_append(drivers, driver);
+
+       return 0;
+}
+
+void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver)
+{
+       if (!g_slist_find(drivers, driver)) {
+               error("Unable to unregister: No such driver %p", driver);
+               return;
+       }
+
+       DBG("driver %p mimetype %s unregistered", driver, driver->mimetype);
+
+       drivers = g_slist_remove(drivers, driver);
+}
diff --git a/obexd/src/mimetype.h b/obexd/src/mimetype.h
new file mode 100644 (file)
index 0000000..79529b8
--- /dev/null
@@ -0,0 +1,55 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef gboolean (*obex_object_io_func) (void *object, int flags, int err,
+                                                       void *user_data);
+
+struct obex_mime_type_driver {
+       const uint8_t *target;
+       unsigned int target_size;
+       const char *mimetype;
+       const uint8_t *who;
+       unsigned int who_size;
+       void *(*open) (const char *name, int oflag, mode_t mode,
+                       void *driver_data, size_t *size, int *err);
+       int (*close) (void *object);
+       ssize_t (*get_next_header)(void *object, void *buf, size_t mtu,
+                                                               uint8_t *hi);
+       ssize_t (*read) (void *object, void *buf, size_t count);
+       ssize_t (*write) (void *object, const void *buf, size_t count);
+       int (*flush) (void *object);
+       int (*copy) (const char *name, const char *destname);
+       int (*move) (const char *name, const char *destname);
+       int (*remove) (const char *name);
+       int (*set_io_watch) (void *object, obex_object_io_func func,
+                               void *user_data);
+};
+
+int obex_mime_type_driver_register(struct obex_mime_type_driver *driver);
+void obex_mime_type_driver_unregister(struct obex_mime_type_driver *driver);
+struct obex_mime_type_driver *obex_mime_type_driver_find(const uint8_t *target,
+                               unsigned int target_size,
+                               const char *mimetype, const uint8_t *who,
+                               unsigned int who_size);
+
+void obex_object_set_io_flags(void *object, int flags, int err);
diff --git a/obexd/src/obex-priv.h b/obexd/src/obex-priv.h
new file mode 100644 (file)
index 0000000..355a7f8
--- /dev/null
@@ -0,0 +1,59 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct obex_session {
+       GIOChannel *io;
+       uint32_t id;
+       uint8_t cmd;
+       uint8_t action_id;
+       char *src;
+       char *dst;
+       char *name;
+       char *destname;
+       char *type;
+       char *path;
+       time_t time;
+       uint8_t *apparam;
+       size_t apparam_len;
+       const void *nonhdr;
+       size_t nonhdr_len;
+       guint get_rsp;
+       uint8_t *buf;
+       int64_t pending;
+       int64_t offset;
+       int64_t size;
+       void *object;
+       gboolean aborted;
+       int err;
+       struct obex_service_driver *service;
+       void *service_data;
+       struct obex_server *server;
+       gboolean checked;
+       GObex *obex;
+       struct obex_mime_type_driver *driver;
+       gboolean headers_sent;
+};
+
+int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
+                               gboolean stream, struct obex_server *server);
diff --git a/obexd/src/obex.c b/obexd/src/obex.c
new file mode 100644 (file)
index 0000000..8a7a8a3
--- /dev/null
@@ -0,0 +1,1257 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <time.h>
+#include <string.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/statvfs.h>
+#include <fcntl.h>
+#include <inttypes.h>
+
+#include <glib.h>
+#include <btio/btio.h>
+#include <gobex/gobex.h>
+
+#include "obexd.h"
+#include "log.h"
+#include "obex.h"
+#include "obex-priv.h"
+#include "server.h"
+#include "manager.h"
+#include "mimetype.h"
+#include "service.h"
+#include "transport.h"
+
+/* Challenge request */
+#define NONCE_TAG 0x00
+#define OPTIONS_TAG 0x01 /* Optional */
+#define REALM_TAG 0x02 /* Optional */
+
+#define NONCE_LEN 16
+
+/* Challenge response */
+#define DIGEST_TAG 0x00
+#define USER_ID_TAG 0x01 /* Optional */
+#define DIGEST_NONCE_TAG 0x02 /* Optional */
+
+static GSList *sessions = NULL;
+
+typedef struct {
+       uint8_t  version;
+       uint8_t  flags;
+       uint16_t mtu;
+} __attribute__ ((packed)) obex_connect_hdr_t;
+
+struct auth_header {
+       uint8_t tag;
+       uint8_t len;
+       uint8_t val[0];
+} __attribute__ ((packed));
+
+/* Possible commands */
+static struct {
+       int cmd;
+       const char *name;
+} obex_command[] = {
+       { G_OBEX_OP_CONNECT,    "CONNECT"       },
+       { G_OBEX_OP_DISCONNECT, "DISCONNECT"    },
+       { G_OBEX_OP_PUT,        "PUT"           },
+       { G_OBEX_OP_GET,        "GET"           },
+       { G_OBEX_OP_SETPATH,    "SETPATH"       },
+       { G_OBEX_OP_SESSION,    "SESSION"       },
+       { G_OBEX_OP_ABORT,      "ABORT"         },
+       { G_OBEX_OP_ACTION,     "ACTION"        },
+       { 0xFF,                 NULL            },
+};
+
+/* Possible Response */
+static struct {
+       int rsp;
+       const char *name;
+} obex_response[] = {
+       { G_OBEX_RSP_CONTINUE,                  "CONTINUE"              },
+       { G_OBEX_RSP_SUCCESS,                   "SUCCESS"               },
+       { G_OBEX_RSP_CREATED,                   "CREATED"               },
+       { G_OBEX_RSP_ACCEPTED,                  "ACCEPTED"              },
+       { G_OBEX_RSP_NON_AUTHORITATIVE,         "NON_AUTHORITATIVE"     },
+       { G_OBEX_RSP_NO_CONTENT,                "NO_CONTENT"            },
+       { G_OBEX_RSP_RESET_CONTENT,             "RESET_CONTENT"         },
+       { G_OBEX_RSP_PARTIAL_CONTENT,           "PARTIAL_CONTENT"       },
+       { G_OBEX_RSP_MULTIPLE_CHOICES,          "MULTIPLE_CHOICES"      },
+       { G_OBEX_RSP_MOVED_PERMANENTLY,         "MOVED_PERMANENTLY"     },
+       { G_OBEX_RSP_MOVED_TEMPORARILY,         "MOVED_TEMPORARILY"     },
+       { G_OBEX_RSP_SEE_OTHER,                 "SEE_OTHER"             },
+       { G_OBEX_RSP_NOT_MODIFIED,              "NOT_MODIFIED"          },
+       { G_OBEX_RSP_USE_PROXY,                 "USE_PROXY"             },
+       { G_OBEX_RSP_BAD_REQUEST,               "BAD_REQUEST"           },
+       { G_OBEX_RSP_UNAUTHORIZED,              "UNAUTHORIZED"          },
+       { G_OBEX_RSP_PAYMENT_REQUIRED,          "PAYMENT_REQUIRED"      },
+       { G_OBEX_RSP_FORBIDDEN,                 "FORBIDDEN"             },
+       { G_OBEX_RSP_NOT_FOUND,                 "NOT_FOUND"             },
+       { G_OBEX_RSP_METHOD_NOT_ALLOWED,        "METHOD_NOT_ALLOWED"    },
+       { G_OBEX_RSP_NOT_ACCEPTABLE,            "NOT_ACCEPTABLE"        },
+       { G_OBEX_RSP_PROXY_AUTH_REQUIRED,       "PROXY_AUTH_REQUIRED"   },
+       { G_OBEX_RSP_REQUEST_TIME_OUT,          "REQUEST_TIME_OUT"      },
+       { G_OBEX_RSP_CONFLICT,                  "CONFLICT"              },
+       { G_OBEX_RSP_GONE,                      "GONE"                  },
+       { G_OBEX_RSP_LENGTH_REQUIRED,           "LENGTH_REQUIRED"       },
+       { G_OBEX_RSP_PRECONDITION_FAILED,       "PRECONDITION_FAILED"   },
+       { G_OBEX_RSP_REQ_ENTITY_TOO_LARGE,      "REQ_ENTITY_TOO_LARGE"  },
+       { G_OBEX_RSP_REQ_URL_TOO_LARGE,         "REQ_URL_TOO_LARGE"     },
+       { G_OBEX_RSP_UNSUPPORTED_MEDIA_TYPE,    "UNSUPPORTED_MEDIA_TYPE"},
+       { G_OBEX_RSP_INTERNAL_SERVER_ERROR,     "INTERNAL_SERVER_ERROR" },
+       { G_OBEX_RSP_NOT_IMPLEMENTED,           "NOT_IMPLEMENTED"       },
+       { G_OBEX_RSP_BAD_GATEWAY,               "BAD_GATEWAY"           },
+       { G_OBEX_RSP_SERVICE_UNAVAILABLE,       "SERVICE_UNAVAILABLE"   },
+       { G_OBEX_RSP_GATEWAY_TIMEOUT,           "GATEWAY_TIMEOUT"       },
+       { G_OBEX_RSP_VERSION_NOT_SUPPORTED,     "VERSION_NOT_SUPPORTED" },
+       { G_OBEX_RSP_DATABASE_FULL,             "DATABASE_FULL"         },
+       { G_OBEX_RSP_DATABASE_LOCKED,           "DATABASE_LOCKED"       },
+       { 0xFF,                                 NULL                    },
+};
+
+static gboolean handle_async_io(void *object, int flags, int err,
+                                               void *user_data);
+
+static void print_event(int cmd, int rsp)
+{
+       const char *cmdstr = NULL, *rspstr = NULL;
+       int i;
+       static int lastcmd;
+
+       if (cmd < 0)
+               cmd = lastcmd;
+       else
+               lastcmd = cmd;
+
+       for (i = 0; obex_command[i].cmd != 0xFF; i++) {
+               if (obex_command[i].cmd != cmd)
+                       continue;
+               cmdstr = obex_command[i].name;
+       }
+
+       for (i = 0; obex_response[i].rsp != 0xFF; i++) {
+               if (obex_response[i].rsp != rsp)
+                       continue;
+               rspstr = obex_response[i].name;
+       }
+
+       obex_debug("%s(0x%x), %s(0x%x)", cmdstr, cmd, rspstr, rsp);
+}
+
+static void os_set_response(struct obex_session *os, int err)
+{
+       uint8_t rsp;
+
+       rsp = g_obex_errno_to_rsp(err);
+
+       print_event(-1, rsp);
+
+       g_obex_send_rsp(os->obex, rsp, NULL, G_OBEX_HDR_INVALID);
+}
+
+static void os_session_mark_aborted(struct obex_session *os)
+{
+       /* the session was already cancelled/aborted or size in unknown */
+       if (os->aborted || os->size == OBJECT_SIZE_UNKNOWN)
+               return;
+
+       os->aborted = (os->size != os->offset);
+}
+
+static void os_reset_session(struct obex_session *os)
+{
+       os_session_mark_aborted(os);
+
+       if (os->object) {
+               os->driver->set_io_watch(os->object, NULL, NULL);
+               os->driver->close(os->object);
+               if (os->aborted && os->cmd == G_OBEX_OP_PUT && os->path &&
+                               os->driver->remove)
+                       os->driver->remove(os->path);
+       }
+
+       if (os->service && os->service->reset)
+               os->service->reset(os, os->service_data);
+
+       if (os->name) {
+               g_free(os->name);
+               os->name = NULL;
+       }
+       if (os->type) {
+               g_free(os->type);
+               os->type = NULL;
+       }
+       if (os->buf) {
+               g_free(os->buf);
+               os->buf = NULL;
+       }
+       if (os->path) {
+               g_free(os->path);
+               os->path = NULL;
+       }
+       if (os->apparam) {
+               g_free(os->apparam);
+               os->apparam = NULL;
+               os->apparam_len = 0;
+       }
+
+       if (os->get_rsp > 0) {
+               g_obex_remove_request_function(os->obex, os->get_rsp);
+               os->get_rsp = 0;
+       }
+
+       os->object = NULL;
+       os->driver = NULL;
+       os->aborted = FALSE;
+       os->pending = 0;
+       os->offset = 0;
+       os->size = OBJECT_SIZE_DELETE;
+       os->headers_sent = FALSE;
+       os->checked = FALSE;
+}
+
+static void obex_session_free(struct obex_session *os)
+{
+       sessions = g_slist_remove(sessions, os);
+
+       if (os->io)
+               g_io_channel_unref(os->io);
+
+       if (os->obex)
+               g_obex_unref(os->obex);
+
+       g_free(os->src);
+       g_free(os->dst);
+
+       g_free(os);
+}
+
+/* From Imendio's GnomeVFS OBEX module (om-utils.c) */
+static time_t parse_iso8610(const char *val, int size)
+{
+       time_t time, tz_offset = 0;
+       struct tm tm;
+       char *date;
+       char tz;
+       int nr;
+
+       memset(&tm, 0, sizeof(tm));
+       /* According to spec the time doesn't have to be null terminated */
+       date = g_strndup(val, size);
+       nr = sscanf(date, "%04u%02u%02uT%02u%02u%02u%c",
+                       &tm.tm_year, &tm.tm_mon, &tm.tm_mday,
+                       &tm.tm_hour, &tm.tm_min, &tm.tm_sec,
+                       &tz);
+       g_free(date);
+       if (nr < 6) {
+               /* Invalid time format */
+               return -1;
+       }
+
+       tm.tm_year -= 1900;     /* Year since 1900 */
+       tm.tm_mon--;            /* Months since January, values 0-11 */
+       tm.tm_isdst = -1;       /* Daylight savings information not avail */
+
+#if defined(HAVE_TM_GMTOFF)
+       tz_offset = tm.tm_gmtoff;
+#elif defined(HAVE_TIMEZONE)
+       tz_offset = -timezone;
+       if (tm.tm_isdst > 0)
+               tz_offset += 3600;
+#endif
+
+       time = mktime(&tm);
+       if (nr == 7) {
+               /*
+                * Date/Time was in localtime (to remote device)
+                * already. Since we don't know anything about the
+                * timezone on that one we won't try to apply UTC offset
+                */
+               time += tz_offset;
+       }
+
+       return time;
+}
+
+static uint8_t *extract_nonce(const uint8_t *buffer, unsigned int hlen)
+{
+       struct auth_header *hdr;
+       uint8_t *nonce = NULL;
+       uint32_t len = 0;
+
+       while (len < hlen) {
+               hdr = (void *) buffer + len;
+
+               switch (hdr->tag) {
+               case NONCE_TAG:
+                       if (hdr->len != NONCE_LEN)
+                               return NULL;
+
+                       nonce = hdr->val;
+                       break;
+               }
+
+               len += hdr->len + sizeof(struct auth_header);
+       }
+
+       return nonce;
+}
+
+static uint8_t *challenge_response(const uint8_t *nonce)
+{
+       GChecksum *md5;
+       uint8_t *result;
+       size_t size;
+
+       result = g_new0(uint8_t, NONCE_LEN);
+
+       md5 = g_checksum_new(G_CHECKSUM_MD5);
+       if (md5 == NULL)
+               return result;
+
+       g_checksum_update(md5, nonce, NONCE_LEN);
+       g_checksum_update(md5, (uint8_t *) ":BlueZ", 6);
+
+       size = NONCE_LEN;
+       g_checksum_get_digest(md5, result, &size);
+
+       g_checksum_free(md5);
+
+       return result;
+}
+
+static void parse_service(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const guint8 *target = NULL, *who = NULL;
+       gsize target_size = 0, who_size = 0;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_WHO);
+       if (hdr == NULL)
+               goto target;
+
+       g_obex_header_get_bytes(hdr, &who, &who_size);
+
+target:
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TARGET);
+       if (hdr == NULL)
+               goto probe;
+
+       g_obex_header_get_bytes(hdr, &target, &target_size);
+
+probe:
+       os->service = obex_service_driver_find(os->server->drivers,
+                                               target, target_size,
+                                               who, who_size);
+}
+
+static void parse_authchal(struct obex_session *session, GObexPacket *req,
+                                                       GObexPacket *rsp)
+{
+       GObexHeader *hdr;
+       const guint8 *data, *nonce = NULL;
+       gsize len;
+       uint8_t challenge[18];
+       struct auth_header *auth = (struct auth_header *) challenge;
+       uint8_t *response;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_AUTHCHAL);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_bytes(hdr, &data, &len))
+               return;
+
+       nonce = extract_nonce(data, len);
+       DBG("AUTH CHALLENGE REQUEST");
+
+       response = challenge_response(nonce);
+       auth->tag = DIGEST_TAG;
+       auth->len = NONCE_LEN;
+       memcpy(auth->val, response, NONCE_LEN);
+
+       hdr = g_obex_header_new_bytes(G_OBEX_HDR_AUTHRESP, challenge,
+                                                       sizeof(challenge));
+       g_obex_packet_add_header(rsp, hdr);
+}
+
+static void cmd_connect(GObex *obex, GObexPacket *req, void *user_data)
+{
+       struct obex_session *os = user_data;
+       GObexPacket *rsp;
+       GObexHeader *hdr;
+       int err;
+
+       DBG("");
+
+       print_event(G_OBEX_OP_CONNECT, -1);
+
+       parse_service(os, req);
+
+       if (os->service == NULL || os->service->connect == NULL) {
+               error("Connect attempt to a non-supported target");
+               os_set_response(os, -EPERM);
+               return;
+       }
+
+       DBG("Selected driver: %s", os->service->name);
+
+       os->service_data = os->service->connect(os, &err);
+       if (err < 0) {
+               os_set_response(os, err);
+               return;
+       }
+
+       os->cmd = G_OBEX_OP_CONNECT;
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
+
+       parse_authchal(os, req, rsp);
+
+       if (os->service->target) {
+               hdr = g_obex_header_new_bytes(G_OBEX_HDR_WHO,
+                                               os->service->target,
+                                               os->service->target_size);
+               g_obex_packet_add_header(rsp, hdr);
+       }
+
+       g_obex_send(obex, rsp, NULL);
+
+       print_event(-1, 0);
+}
+
+static void cmd_disconnect(GObex *obex, GObexPacket *req, void *user_data)
+{
+       struct obex_session *os = user_data;
+
+       DBG("session %p", os);
+
+       print_event(G_OBEX_OP_DISCONNECT, -1);
+
+       os->cmd = G_OBEX_OP_DISCONNECT;
+
+       os_set_response(os, 0);
+}
+
+static ssize_t driver_write(struct obex_session *os)
+{
+       ssize_t len = 0;
+
+       while (os->pending > 0) {
+               ssize_t w;
+
+               w = os->driver->write(os->object, os->buf + len, os->pending);
+               if (w < 0) {
+                       error("write(): %s (%zd)", strerror(-w), -w);
+                       if (w == -EINTR)
+                               continue;
+                       else if (w == -EINVAL)
+                               memmove(os->buf, os->buf + len, os->pending);
+
+                       return w;
+               }
+
+               len += w;
+               os->offset += w;
+               os->pending -= w;
+       }
+
+       DBG("%zd written", len);
+
+       if (os->service->progress != NULL)
+               os->service->progress(os, os->service_data);
+
+       return len;
+}
+
+static gssize driver_read(struct obex_session *os, void *buf, gsize size)
+{
+       gssize len;
+
+       if (os->object == NULL)
+               return -EIO;
+
+       if (os->service->progress != NULL)
+               os->service->progress(os, os->service_data);
+
+       len = os->driver->read(os->object, buf, size);
+       if (len < 0) {
+               error("read(): %s (%zd)", strerror(-len), -len);
+               if (len == -ENOSTR)
+                       return 0;
+               if (len == -EAGAIN)
+                       os->driver->set_io_watch(os->object, handle_async_io,
+                                                                       os);
+       }
+
+       os->offset += len;
+
+       DBG("%zd read", len);
+
+       return len;
+}
+
+static gssize send_data(void *buf, gsize size, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+
+       DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
+                                                                       size);
+
+       if (os->aborted)
+               return os->err < 0 ? os->err : -EPERM;
+
+       return driver_read(os, buf, size);
+}
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+
+       DBG("");
+
+       if (err != NULL) {
+               error("transfer failed: %s\n", err->message);
+               goto reset;
+       }
+
+       if (os->object && os->driver && os->driver->flush) {
+               if (os->driver->flush(os->object) == -EAGAIN) {
+                       g_obex_suspend(os->obex);
+                       os->driver->set_io_watch(os->object, handle_async_io,
+                                                                       os);
+                       return;
+               }
+       }
+
+reset:
+       os_reset_session(os);
+}
+
+static int driver_get_headers(struct obex_session *os)
+{
+       GObexPacket *rsp;
+       gssize len;
+       guint8 data[255];
+       guint8 id;
+       GObexHeader *hdr;
+
+       DBG("name=%s type=%s object=%p", os->name, os->type, os->object);
+
+       if (os->aborted)
+               return os->err < 0 ? os->err : -EPERM;
+
+       if (os->object == NULL)
+               return -EIO;
+
+       if (os->headers_sent)
+               return 0;
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
+
+       if (os->driver->get_next_header == NULL)
+               goto done;
+
+       while ((len = os->driver->get_next_header(os->object, &data,
+                                                       sizeof(data), &id))) {
+               if (len < 0) {
+                       error("get_next_header(): %s (%zd)", strerror(-len),
+                                                               -len);
+
+                       g_obex_packet_free(rsp);
+
+                       if (len == -EAGAIN)
+                               return len;
+
+                       g_free(os->buf);
+                       os->buf = NULL;
+
+                       return len;
+               }
+
+               hdr = g_obex_header_new_bytes(id, data, len);
+               g_obex_packet_add_header(rsp, hdr);
+       }
+
+done:
+       if (os->size != OBJECT_SIZE_UNKNOWN && os->size < UINT32_MAX) {
+               hdr = g_obex_header_new_uint32(G_OBEX_HDR_LENGTH, os->size);
+               g_obex_packet_add_header(rsp, hdr);
+       }
+
+       g_obex_get_rsp_pkt(os->obex, rsp, send_data, transfer_complete, os,
+                                                                       NULL);
+
+       os->headers_sent = TRUE;
+
+       print_event(-1, G_OBEX_RSP_CONTINUE);
+
+       return 0;
+}
+
+static gboolean handle_async_io(void *object, int flags, int err,
+                                               void *user_data)
+{
+       struct obex_session *os = user_data;
+
+       if (err < 0)
+               goto done;
+
+       if (flags & G_IO_OUT)
+               err = driver_write(os);
+       if ((flags & G_IO_IN) && !os->headers_sent)
+               err = driver_get_headers(os);
+
+       if (err == -EAGAIN)
+               return TRUE;
+
+done:
+       if (err < 0) {
+               os->err = err;
+               os->aborted = TRUE;
+       }
+
+       g_obex_resume(os->obex);
+
+       return FALSE;
+}
+
+static gboolean recv_data(const void *buf, gsize size, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+       ssize_t ret;
+
+       DBG("name=%s type=%s file=%p size=%zu", os->name, os->type, os->object,
+                                                                       size);
+
+       if (os->aborted)
+               return FALSE;
+
+       /* workaround: client didn't send the object length */
+       if (os->size == OBJECT_SIZE_DELETE)
+               os->size = OBJECT_SIZE_UNKNOWN;
+
+       os->buf = g_realloc(os->buf, os->pending + size);
+       memcpy(os->buf + os->pending, buf, size);
+       os->pending += size;
+
+       /* only write if both object and driver are valid */
+       if (os->object == NULL || os->driver == NULL) {
+               DBG("Stored %" PRIu64 " bytes into temporary buffer",
+                                                               os->pending);
+               return TRUE;
+       }
+
+       ret = driver_write(os);
+       if (ret >= 0)
+               return TRUE;
+
+       if (ret == -EAGAIN) {
+               g_obex_suspend(os->obex);
+               os->driver->set_io_watch(os->object, handle_async_io, os);
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void parse_type(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const guint8 *type;
+       gsize len;
+
+       g_free(os->type);
+       os->type = NULL;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TYPE);
+       if (hdr == NULL)
+               goto probe;
+
+       if (!g_obex_header_get_bytes(hdr, &type, &len))
+               goto probe;
+
+       /* Ensure null termination */
+       if (type[len - 1] != '\0')
+               goto probe;
+
+       os->type = g_strndup((const char *) type, len);
+       DBG("TYPE: %s", os->type);
+
+probe:
+       os->driver = obex_mime_type_driver_find(os->service->target,
+                                               os->service->target_size,
+                                               os->type,
+                                               os->service->who,
+                                               os->service->who_size);
+}
+
+static void parse_name(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const char *name;
+
+       g_free(os->name);
+       os->name = NULL;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_NAME);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_unicode(hdr, &name))
+               return;
+
+       os->name = g_strdup(name);
+       DBG("NAME: %s", os->name);
+}
+
+static void parse_apparam(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const guint8 *apparam;
+       gsize len;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_APPARAM);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_bytes(hdr, &apparam, &len))
+               return;
+
+       os->apparam = g_memdup(apparam, len);
+       os->apparam_len = len;
+       DBG("APPARAM");
+}
+
+static void cmd_get(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+       int err;
+
+       DBG("session %p", os);
+
+       print_event(G_OBEX_OP_GET, -1);
+
+       if (os->service == NULL) {
+               os_set_response(os, -EPERM);
+               return;
+       }
+
+       if (os->service->get == NULL) {
+               os_set_response(os, -ENOSYS);
+               return;
+       }
+
+       os->headers_sent = FALSE;
+
+       if (os->type) {
+               g_free(os->type);
+               os->type = NULL;
+       }
+
+       parse_type(os, req);
+
+       if (!os->driver) {
+               error("No driver found");
+               os_set_response(os, -ENOSYS);
+               return;
+       }
+
+       os->cmd = G_OBEX_OP_GET;
+
+       parse_name(os, req);
+
+       parse_apparam(os, req);
+
+       err = os->service->get(os, os->service_data);
+       if (err == 0)
+               return;
+
+       os_set_response(os, err);
+}
+
+static void cmd_setpath(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+       int err;
+
+       DBG("");
+
+       print_event(G_OBEX_OP_SETPATH, -1);
+
+       if (os->service == NULL) {
+               err = -EPERM;
+               goto done;
+       }
+
+       if (os->service->setpath == NULL) {
+               err = -ENOSYS;
+               goto done;
+       }
+
+       os->cmd = G_OBEX_OP_SETPATH;
+
+       parse_name(os, req);
+
+       os->nonhdr = g_obex_packet_get_data(req, &os->nonhdr_len);
+
+       err = os->service->setpath(os, os->service_data);
+done:
+       os_set_response(os, err);
+}
+
+int obex_get_stream_start(struct obex_session *os, const char *filename)
+{
+       int err;
+       void *object;
+       size_t size = OBJECT_SIZE_UNKNOWN;
+
+       object = os->driver->open(filename, O_RDONLY, 0, os->service_data,
+                                                               &size, &err);
+       if (object == NULL) {
+               error("open(%s): %s (%d)", filename, strerror(-err), -err);
+               return err;
+       }
+
+       os->object = object;
+       os->offset = 0;
+       os->size = size;
+
+       err = driver_get_headers(os);
+       if (err != -EAGAIN)
+               return err;
+
+       g_obex_suspend(os->obex);
+       os->driver->set_io_watch(os->object, handle_async_io, os);
+       return 0;
+}
+
+int obex_put_stream_start(struct obex_session *os, const char *filename)
+{
+       int err;
+
+       os->object = os->driver->open(filename, O_WRONLY | O_CREAT | O_TRUNC,
+                                       0600, os->service_data,
+                                       os->size != OBJECT_SIZE_UNKNOWN ?
+                                       (size_t *) &os->size : NULL, &err);
+       if (os->object == NULL) {
+               error("open(%s): %s (%d)", filename, strerror(-err), -err);
+               return err;
+       }
+
+       os->path = g_strdup(filename);
+
+       return 0;
+}
+
+static void parse_length(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       guint32 size;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_LENGTH);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_uint32(hdr, &size))
+               return;
+
+       os->size = size;
+       DBG("LENGTH: %" PRIu64, os->size);
+}
+
+static void parse_time(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const guint8 *time;
+       gsize len;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TIME);
+       if (hdr == NULL)
+               return;
+
+
+       if (!g_obex_header_get_bytes(hdr, &time, &len))
+               return;
+
+       os->time = parse_iso8610((const char *) time, len);
+       DBG("TIME: %s", ctime(&os->time));
+}
+
+static gboolean check_put(GObex *obex, GObexPacket *req, void *user_data)
+{
+       struct obex_session *os = user_data;
+       int ret;
+
+       if (os->service->chkput == NULL)
+               goto done;
+
+       ret = os->service->chkput(os, os->service_data);
+       switch (ret) {
+       case 0:
+               break;
+       case -EAGAIN:
+               g_obex_suspend(os->obex);
+               os->driver->set_io_watch(os->object, handle_async_io, os);
+               return TRUE;
+       default:
+               os_set_response(os, ret);
+               return FALSE;
+       }
+
+       if (os->size == OBJECT_SIZE_DELETE || os->size == OBJECT_SIZE_UNKNOWN)
+               DBG("Got a PUT without a Length");
+
+done:
+       os->checked = TRUE;
+
+       return TRUE;
+}
+
+static void cmd_put(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+       int err;
+
+       DBG("");
+
+       print_event(G_OBEX_OP_PUT, -1);
+
+       if (os->service == NULL) {
+               os_set_response(os, -EPERM);
+               return;
+       }
+
+       parse_type(os, req);
+
+       if (os->driver == NULL) {
+               error("No driver found");
+               os_set_response(os, -ENOSYS);
+               return;
+       }
+
+       os->cmd = G_OBEX_OP_PUT;
+
+       parse_name(os, req);
+       parse_length(os, req);
+       parse_time(os, req);
+       parse_apparam(os, req);
+
+       if (!os->checked) {
+               if (!check_put(obex, req, user_data))
+                       return;
+       }
+
+       if (os->service->put == NULL) {
+               os_set_response(os, -ENOSYS);
+               return;
+       }
+
+       err = os->service->put(os, os->service_data);
+       if (err == 0) {
+               g_obex_put_rsp(obex, req, recv_data, transfer_complete, os,
+                                               NULL, G_OBEX_HDR_INVALID);
+               print_event(G_OBEX_OP_PUT, G_OBEX_RSP_CONTINUE);
+               return;
+       }
+
+       os_set_response(os, err);
+}
+
+static void parse_destname(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       const char *destname;
+
+       g_free(os->destname);
+       os->destname = NULL;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_DESTNAME);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_unicode(hdr, &destname))
+               return;
+
+       os->destname = g_strdup(destname);
+       DBG("DESTNAME: %s", os->destname);
+}
+
+static void parse_action(struct obex_session *os, GObexPacket *req)
+{
+       GObexHeader *hdr;
+       guint8 id;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_ACTION);
+       if (hdr == NULL)
+               return;
+
+       if (!g_obex_header_get_uint8(hdr, &id))
+               return;
+
+       os->action_id = id;
+       DBG("ACTION: 0x%02x", os->action_id);
+}
+
+static void cmd_action(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+       int err;
+
+       DBG("");
+
+       print_event(G_OBEX_OP_ACTION, -1);
+
+       if (os->service == NULL) {
+               err = -EPERM;
+               goto done;
+       }
+
+       if (os->service->action == NULL) {
+               err = -ENOSYS;
+               goto done;
+       }
+
+       os->cmd = G_OBEX_OP_ACTION;
+
+       parse_name(os, req);
+       parse_destname(os, req);
+       parse_action(os, req);
+
+       os->driver = obex_mime_type_driver_find(os->service->target,
+                                               os->service->target_size,
+                                               NULL,
+                                               os->service->who,
+                                               os->service->who_size);
+       if (os->driver == NULL) {
+               err = -ENOSYS;
+               goto done;
+       }
+
+       err = os->service->action(os, os->service_data);
+done:
+       os_set_response(os, err);
+}
+
+static void cmd_abort(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+
+       DBG("");
+
+       print_event(G_OBEX_OP_ABORT, -1);
+
+       os_reset_session(os);
+
+       os_set_response(os, 0);
+}
+
+static void obex_session_destroy(struct obex_session *os)
+{
+       DBG("");
+
+       os_reset_session(os);
+
+       if (os->service && os->service->disconnect)
+               os->service->disconnect(os, os->service_data);
+
+       obex_session_free(os);
+}
+
+static void disconn_func(GObex *obex, GError *err, gpointer user_data)
+{
+       struct obex_session *os = user_data;
+
+       error("disconnected: %s\n", err ? err->message : "<no err>");
+       obex_session_destroy(os);
+}
+
+int obex_session_start(GIOChannel *io, uint16_t tx_mtu, uint16_t rx_mtu,
+                               gboolean stream, struct obex_server *server)
+{
+       struct obex_session *os;
+       GObex *obex;
+       GObexTransportType type;
+       static uint32_t id = 0;
+
+       DBG("");
+
+       os = g_new0(struct obex_session, 1);
+       os->id = ++id;
+
+       os->service = obex_service_driver_find(server->drivers, NULL,
+                                                       0, NULL, 0);
+       os->server = server;
+       os->size = OBJECT_SIZE_DELETE;
+
+       type = stream ? G_OBEX_TRANSPORT_STREAM : G_OBEX_TRANSPORT_PACKET;
+
+       obex = g_obex_new(io, type, rx_mtu, tx_mtu);
+       if (!obex) {
+               obex_session_free(os);
+               return -EIO;
+       }
+
+       g_obex_set_disconnect_function(obex, disconn_func, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT, cmd_connect, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_DISCONNECT, cmd_disconnect,
+                                                                       os);
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, cmd_put, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, cmd_get, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_SETPATH, cmd_setpath, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_ACTION, cmd_action, os);
+       g_obex_add_request_function(obex, G_OBEX_OP_ABORT, cmd_abort, os);
+
+       os->obex = obex;
+       os->io = g_io_channel_ref(io);
+
+       obex_getsockname(os, &os->src);
+       obex_getpeername(os, &os->dst);
+
+       sessions = g_slist_prepend(sessions, os);
+
+       return 0;
+}
+
+const char *obex_get_name(struct obex_session *os)
+{
+       return os->name;
+}
+
+const char *obex_get_destname(struct obex_session *os)
+{
+       return os->destname;
+}
+
+void obex_set_name(struct obex_session *os, const char *name)
+{
+       g_free(os->name);
+       os->name = g_strdup(name);
+       DBG("Name changed: %s", os->name);
+}
+
+ssize_t obex_get_size(struct obex_session *os)
+{
+       return os->size;
+}
+
+const char *obex_get_type(struct obex_session *os)
+{
+       return os->type;
+}
+
+int obex_remove(struct obex_session *os, const char *path)
+{
+       if (os->driver == NULL)
+               return -ENOSYS;
+
+       return os->driver->remove(path);
+}
+
+int obex_copy(struct obex_session *os, const char *source,
+                                               const char *destination)
+{
+       if (os->driver == NULL || os->driver->copy == NULL)
+               return -ENOSYS;
+
+       DBG("%s %s", source, destination);
+
+       return os->driver->copy(source, destination);
+}
+
+int obex_move(struct obex_session *os, const char *source,
+                                               const char *destination)
+{
+       if (os->driver == NULL || os->driver->move == NULL)
+               return -ENOSYS;
+
+       DBG("%s %s", source, destination);
+
+       return os->driver->move(source, destination);
+}
+
+uint8_t obex_get_action_id(struct obex_session *os)
+{
+       return os->action_id;
+}
+
+ssize_t obex_get_apparam(struct obex_session *os, const uint8_t **buffer)
+{
+       *buffer = os->apparam;
+
+       return os->apparam_len;
+}
+
+ssize_t obex_get_non_header_data(struct obex_session *os,
+                                                       const uint8_t **data)
+{
+       *data = os->nonhdr;
+
+       return os->nonhdr_len;
+}
+
+int obex_getpeername(struct obex_session *os, char **name)
+{
+       struct obex_transport_driver *transport = os->server->transport;
+
+       if (transport == NULL || transport->getpeername == NULL)
+               return -ENOTSUP;
+
+       return transport->getpeername(os->io, name);
+}
+
+int obex_getsockname(struct obex_session *os, char **name)
+{
+       struct obex_transport_driver *transport = os->server->transport;
+
+       if (transport == NULL || transport->getsockname == NULL)
+               return -ENOTSUP;
+
+       return transport->getsockname(os->io, name);
+}
+
+int memncmp0(const void *a, size_t na, const void *b, size_t nb)
+{
+       if (na != nb)
+               return na - nb;
+
+       if (a == NULL)
+               return -(a != b);
+
+       if (b == NULL)
+               return a != b;
+
+       return memcmp(a, b, na);
+}
diff --git a/obexd/src/obex.h b/obexd/src/obex.h
new file mode 100644 (file)
index 0000000..fc16747
--- /dev/null
@@ -0,0 +1,52 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define OBJECT_SIZE_UNKNOWN -1
+#define OBJECT_SIZE_DELETE -2
+
+#define TARGET_SIZE 16
+
+struct obex_session;
+
+int obex_get_stream_start(struct obex_session *os, const char *filename);
+int obex_put_stream_start(struct obex_session *os, const char *filename);
+const char *obex_get_name(struct obex_session *os);
+const char *obex_get_destname(struct obex_session *os);
+void obex_set_name(struct obex_session *os, const char *name);
+ssize_t obex_get_size(struct obex_session *os);
+const char *obex_get_type(struct obex_session *os);
+int obex_remove(struct obex_session *os, const char *path);
+int obex_copy(struct obex_session *os, const char *source,
+                                               const char *destination);
+int obex_move(struct obex_session *os, const char *source,
+                                               const char *destination);
+uint8_t obex_get_action_id(struct obex_session *os);
+ssize_t obex_get_apparam(struct obex_session *os, const uint8_t **buffer);
+ssize_t obex_get_non_header_data(struct obex_session *os,
+                                                       const uint8_t **data);
+int obex_getpeername(struct obex_session *os, char **name);
+int obex_getsockname(struct obex_session *os, char **name);
+
+/* Just a thin wrapper around memcmp to deal with NULL values */
+int memncmp0(const void *a, size_t na, const void *b, size_t nb);
diff --git a/obexd/src/obex.service.in b/obexd/src/obex.service.in
new file mode 100644 (file)
index 0000000..bca3aef
--- /dev/null
@@ -0,0 +1,10 @@
+[Unit]
+Description=Bluetooth OBEX service
+
+[Service]
+Type=dbus
+BusName=org.bluez.obex
+ExecStart=@libexecdir@/obexd
+
+[Install]
+Alias=dbus-org.bluez.obex.service
similarity index 54%
rename from compat/pand.h
rename to obexd/src/obexd.h
index 08b5bdc..42c3c4d 100644 (file)
@@ -1,9 +1,8 @@
 /*
  *
- *  BlueZ - Bluetooth protocol stack for Linux
+ *  OBEX Server
  *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-int bnep_init(void);
-int bnep_cleanup(void);
+#define OBEX_OPP       (1 << 1)
+#define OBEX_FTP       (1 << 2)
+#define OBEX_BIP       (1 << 3)
+#define OBEX_PBAP      (1 << 4)
+#define OBEX_IRMC      (1 << 5)
+#define OBEX_PCSUITE   (1 << 6)
+#define OBEX_SYNCEVOLUTION     (1 << 7)
+#define OBEX_MAS       (1 << 8)
+#define OBEX_MNS       (1 << 9)
 
-int bnep_str2svc(char *svc, uint16_t *uuid);
-char *bnep_svc2str(uint16_t uuid);
+gboolean plugin_init(const char *pattern, const char *exclude);
+void plugin_cleanup(void);
 
-int bnep_show_connections(void);
-int bnep_kill_connection(uint8_t *dst);
-int bnep_kill_all_connections(void);
+gboolean manager_init(void);
+void manager_cleanup(void);
 
-int bnep_accept_connection(int sk, uint16_t role, char *dev);
-int bnep_create_connection(int sk, uint16_t role, uint16_t svc, char *dev);
+gboolean obex_option_auto_accept(void);
+const char *obex_option_root_folder(void);
+gboolean obex_option_symlinks(void);
+const char *obex_option_capability(void);
diff --git a/obexd/src/org.bluez.obex.service b/obexd/src/org.bluez.obex.service
new file mode 100644 (file)
index 0000000..a538088
--- /dev/null
@@ -0,0 +1,4 @@
+[D-BUS Service]
+Name=org.bluez.obex
+Exec=/bin/false
+SystemdService=dbus-org.bluez.obex.service
diff --git a/obexd/src/plugin.c b/obexd/src/plugin.c
new file mode 100644 (file)
index 0000000..7d971b6
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <dlfcn.h>
+#include <string.h>
+#include <sys/stat.h>
+
+#include <glib.h>
+
+#include "obexd.h"
+#include "plugin.h"
+#include "log.h"
+
+/*
+ * Plugins that are using libraries with threads and their own mainloop
+ * will crash on exit. This is a bug inside these libraries, but there is
+ * nothing much that can be done about it. One bad example is libebook.
+ */
+#ifdef NEED_THREADS
+#define PLUGINFLAG (RTLD_NOW | RTLD_NODELETE)
+#else
+#define PLUGINFLAG (RTLD_NOW)
+#endif
+
+static GSList *plugins = NULL;
+
+struct obex_plugin {
+       void *handle;
+       struct obex_plugin_desc *desc;
+};
+
+static gboolean add_plugin(void *handle, struct obex_plugin_desc *desc)
+{
+       struct obex_plugin *plugin;
+
+       if (desc->init == NULL)
+               return FALSE;
+
+       plugin = g_try_new0(struct obex_plugin, 1);
+       if (plugin == NULL)
+               return FALSE;
+
+       plugin->handle = handle;
+       plugin->desc = desc;
+
+       if (desc->init() < 0) {
+               g_free(plugin);
+               return FALSE;
+       }
+
+       plugins = g_slist_append(plugins, plugin);
+       DBG("Plugin %s loaded", desc->name);
+
+       return TRUE;
+}
+
+static gboolean check_plugin(struct obex_plugin_desc *desc,
+                               char **patterns, char **excludes)
+{
+       if (excludes) {
+               for (; *excludes; excludes++)
+                       if (g_pattern_match_simple(*excludes, desc->name))
+                               break;
+               if (*excludes) {
+                       info("Excluding %s", desc->name);
+                       return FALSE;
+               }
+       }
+
+       if (patterns) {
+               for (; *patterns; patterns++)
+                       if (g_pattern_match_simple(*patterns, desc->name))
+                               break;
+               if (*patterns == NULL) {
+                       info("Ignoring %s", desc->name);
+                       return FALSE;
+               }
+       }
+
+       return TRUE;
+}
+
+
+#include "builtin.h"
+
+gboolean plugin_init(const char *pattern, const char *exclude)
+{
+       char **patterns = NULL;
+       char **excludes = NULL;
+       GDir *dir;
+       const char *file;
+       unsigned int i;
+
+       if (strlen(PLUGINDIR) == 0)
+               return FALSE;
+
+       if (pattern)
+               patterns = g_strsplit_set(pattern, ":, ", -1);
+
+       if (exclude)
+               excludes = g_strsplit_set(exclude, ":, ", -1);
+
+       DBG("Loading builtin plugins");
+
+       for (i = 0; __obex_builtin[i]; i++) {
+               if (check_plugin(__obex_builtin[i],
+                                       patterns, excludes) == FALSE)
+                       continue;
+
+               add_plugin(NULL,  __obex_builtin[i]);
+       }
+
+       DBG("Loading plugins %s", PLUGINDIR);
+
+       dir = g_dir_open(PLUGINDIR, 0, NULL);
+       if (!dir)
+               return FALSE;
+
+       while ((file = g_dir_read_name(dir)) != NULL) {
+               struct obex_plugin_desc *desc;
+               void *handle;
+               char *filename;
+
+               if (g_str_has_prefix(file, "lib") == TRUE ||
+                               g_str_has_suffix(file, ".so") == FALSE)
+                       continue;
+
+               filename = g_build_filename(PLUGINDIR, file, NULL);
+
+               handle = dlopen(filename, PLUGINFLAG);
+               if (handle == NULL) {
+                       error("Can't load plugin %s: %s", filename,
+                                                               dlerror());
+                       g_free(filename);
+                       continue;
+               }
+
+               g_free(filename);
+
+               desc = dlsym(handle, "obex_plugin_desc");
+               if (desc == NULL) {
+                       error("Can't load plugin description: %s", dlerror());
+                       dlclose(handle);
+                       continue;
+               }
+
+               if (check_plugin(desc, patterns, excludes) == FALSE) {
+                       dlclose(handle);
+                       continue;
+               }
+
+               if (add_plugin(handle, desc) == FALSE)
+                       dlclose(handle);
+       }
+
+       g_dir_close(dir);
+       g_strfreev(patterns);
+       g_strfreev(excludes);
+
+       return TRUE;
+}
+
+void plugin_cleanup(void)
+{
+       GSList *list;
+
+       DBG("Cleanup plugins");
+
+       for (list = plugins; list; list = list->next) {
+               struct obex_plugin *plugin = list->data;
+
+               if (plugin->desc->exit)
+                       plugin->desc->exit();
+
+               if (plugin->handle != NULL)
+                       dlclose(plugin->handle);
+
+               g_free(plugin);
+       }
+
+       g_slist_free(plugins);
+}
similarity index 57%
rename from compat/dund.h
rename to obexd/src/plugin.h
index e3a4ef6..13d7769 100644 (file)
@@ -1,9 +1,8 @@
 /*
  *
- *  BlueZ - Bluetooth protocol stack for Linux
+ *  OBEX Server
  *
- *  Copyright (C) 2002-2003  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-#define DUN_CONFIG_DIR "/etc/bluetooth/dun"
+struct obex_plugin_desc {
+       const char *name;
+       int (*init) (void);
+       void (*exit) (void);
+};
 
-#define DUN_DEFAULT_CHANNEL    1
-
-#define DUN_MAX_PPP_OPTS       40
-
-int dun_init(void);
-int dun_cleanup(void);
-
-int dun_show_connections(void);
-int dun_kill_connection(uint8_t *dst);
-int dun_kill_all_connections(void);
-
-int dun_open_connection(int sk, char *pppd, char **pppd_opts, int wait);
-
-int ms_dun(int fd, int server, int timeo);
+#ifdef OBEX_PLUGIN_BUILTIN
+#define OBEX_PLUGIN_DEFINE(name, init, exit) \
+               struct obex_plugin_desc __obex_builtin_ ## name = { \
+                       #name, init, exit \
+               };
+#else
+#define OBEX_PLUGIN_DEFINE(name,init,exit) \
+               extern struct obex_plugin_desc obex_plugin_desc \
+                               __attribute__ ((visibility("default"))); \
+               struct obex_plugin_desc obex_plugin_desc = { \
+                       #name, init, exit \
+               };
+#endif
diff --git a/obexd/src/server.c b/obexd/src/server.c
new file mode 100644 (file)
index 0000000..007c27e
--- /dev/null
@@ -0,0 +1,127 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <glib.h>
+#include <gobex/gobex.h>
+
+#include "log.h"
+#include "obex.h"
+#include "obex-priv.h"
+#include "server.h"
+#include "service.h"
+#include "transport.h"
+
+static GSList *servers = NULL;
+
+static void init_server(uint16_t service, GSList *transports)
+{
+       GSList *l;
+
+       for (l = transports; l; l = l->next) {
+               struct obex_transport_driver *transport = l->data;
+               struct obex_server *server;
+               int err;
+
+               if (transport->service != 0 &&
+                               (transport->service & service) == FALSE)
+                       continue;
+
+               server = g_new0(struct obex_server, 1);
+               server->transport = transport;
+               server->drivers = obex_service_driver_list(service);
+
+               server->transport_data = transport->start(server, &err);
+               if (server->transport_data == NULL) {
+                       DBG("Unable to start %s transport: %s (%d)",
+                                       transport->name, strerror(err), err);
+                       g_free(server);
+                       continue;
+               }
+
+               servers = g_slist_prepend(servers, server);
+       }
+}
+
+int obex_server_init(void)
+{
+       GSList *drivers;
+       GSList *transports;
+       GSList *l;
+
+       drivers = obex_service_driver_list(0);
+       if (drivers == NULL) {
+               DBG("No service driver registered");
+               return -EINVAL;
+       }
+
+       transports = obex_transport_driver_list();
+       if (transports == NULL) {
+               DBG("No transport driver registered");
+               return -EINVAL;
+       }
+
+       for (l = drivers; l; l = l->next) {
+               struct obex_service_driver *driver = l->data;
+
+               init_server(driver->service, transports);
+       }
+
+       return 0;
+}
+
+void obex_server_exit(void)
+{
+       GSList *l;
+
+       for (l = servers; l; l = l->next) {
+               struct obex_server *server = l->data;
+
+               server->transport->stop(server->transport_data);
+               g_slist_free(server->drivers);
+               g_free(server);
+       }
+
+       g_slist_free(servers);
+
+       return;
+}
+
+int obex_server_new_connection(struct obex_server *server, GIOChannel *io,
+                                       uint16_t tx_mtu, uint16_t rx_mtu,
+                                       gboolean stream)
+{
+       return obex_session_start(io, tx_mtu, rx_mtu, stream, server);
+}
diff --git a/obexd/src/server.h b/obexd/src/server.h
new file mode 100644 (file)
index 0000000..278c35f
--- /dev/null
@@ -0,0 +1,37 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Nokia Corporation
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+struct obex_server {
+       struct obex_transport_driver *transport;
+       void *transport_data;
+       GSList *drivers;
+};
+
+int obex_server_init(void);
+
+void obex_server_exit(void);
+
+int obex_server_new_connection(struct obex_server *server, GIOChannel *io,
+                                       uint16_t tx_mtu, uint16_t rx_mtu,
+                                       gboolean stream);
diff --git a/obexd/src/service.c b/obexd/src/service.c
new file mode 100644 (file)
index 0000000..c088535
--- /dev/null
@@ -0,0 +1,132 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "obex.h"
+#include "service.h"
+#include "log.h"
+
+static GSList *drivers = NULL;
+
+struct obex_service_driver *obex_service_driver_find(GSList *drivers,
+                       const uint8_t *target, unsigned int target_size,
+                       const uint8_t *who, unsigned int who_size)
+{
+       GSList *l;
+
+       for (l = drivers; l; l = l->next) {
+               struct obex_service_driver *driver = l->data;
+
+               /* who is optional, so only check for it if not NULL */
+               if (who != NULL && memncmp0(who, who_size, driver->who,
+                                                       driver->who_size))
+                       continue;
+
+               if (memncmp0(target, target_size, driver->target,
+                                               driver->target_size) == 0)
+                       return driver;
+       }
+
+       return NULL;
+}
+
+GSList *obex_service_driver_list(uint16_t services)
+{
+       GSList *l;
+       GSList *list = NULL;
+
+       if (services == 0)
+               return drivers;
+
+       for (l = drivers; l && services; l = l->next) {
+               struct obex_service_driver *driver = l->data;
+
+               if (driver->service & services) {
+                       list = g_slist_append(list, driver);
+                       services &= ~driver->service;
+               }
+       }
+
+       return list;
+}
+
+static struct obex_service_driver *find_driver(uint16_t service)
+{
+       GSList *l;
+
+       for (l = drivers; l; l = l->next) {
+               struct obex_service_driver *driver = l->data;
+
+               if (driver->service == service)
+                       return driver;
+       }
+
+       return NULL;
+}
+
+int obex_service_driver_register(struct obex_service_driver *driver)
+{
+       if (!driver) {
+               error("Invalid driver");
+               return -EINVAL;
+       }
+
+       if (find_driver(driver->service)) {
+               error("Permission denied: service %s already registered",
+                       driver->name);
+               return -EPERM;
+       }
+
+       DBG("driver %p service %s registered", driver, driver->name);
+
+       /* Drivers that support who has priority */
+       if (driver->who)
+               drivers = g_slist_prepend(drivers, driver);
+       else
+               drivers = g_slist_append(drivers, driver);
+
+       return 0;
+}
+
+void obex_service_driver_unregister(struct obex_service_driver *driver)
+{
+       if (!g_slist_find(drivers, driver)) {
+               error("Unable to unregister: No such driver %p", driver);
+               return;
+       }
+
+       DBG("driver %p service %s unregistered", driver, driver->name);
+
+       drivers = g_slist_remove(drivers, driver);
+}
diff --git a/obexd/src/service.h b/obexd/src/service.h
new file mode 100644 (file)
index 0000000..5d9d325
--- /dev/null
@@ -0,0 +1,53 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define OBEX_PORT_RANDOM UINT16_MAX
+
+struct obex_service_driver {
+       const char *name;
+       uint16_t service;
+       uint8_t channel;
+       uint16_t port;
+       gboolean secure;
+       const uint8_t *target;
+       unsigned int target_size;
+       const uint8_t *who;
+       unsigned int who_size;
+       const char *record;
+       void *(*connect) (struct obex_session *os, int *err);
+       void (*progress) (struct obex_session *os, void *user_data);
+       int (*get) (struct obex_session *os, void *user_data);
+       int (*put) (struct obex_session *os, void *user_data);
+       int (*chkput) (struct obex_session *os, void *user_data);
+       int (*setpath) (struct obex_session *os, void *user_data);
+       int (*action) (struct obex_session *os, void *user_data);
+       void (*disconnect) (struct obex_session *os, void *user_data);
+       void (*reset) (struct obex_session *os, void *user_data);
+};
+
+int obex_service_driver_register(struct obex_service_driver *driver);
+void obex_service_driver_unregister(struct obex_service_driver *driver);
+GSList *obex_service_driver_list(uint16_t services);
+struct obex_service_driver *obex_service_driver_find(GSList *drivers,
+                       const uint8_t *target, unsigned int target_size,
+                       const uint8_t *who, unsigned int who_size);
diff --git a/obexd/src/transport.c b/obexd/src/transport.c
new file mode 100644 (file)
index 0000000..4984643
--- /dev/null
@@ -0,0 +1,93 @@
+/*
+ *
+ *  OBEX Server
+ *
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <string.h>
+#include <stdint.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "obex.h"
+#include "server.h"
+#include "transport.h"
+#include "log.h"
+
+static GSList *drivers = NULL;
+
+static struct obex_transport_driver *obex_transport_driver_find(
+                                                       const char *name)
+{
+       GSList *l;
+
+       for (l = drivers; l; l = l->next) {
+               struct obex_transport_driver *driver = l->data;
+
+               if (g_strcmp0(name, driver->name) == 0)
+                       return driver;
+       }
+
+       return NULL;
+}
+
+GSList *obex_transport_driver_list(void)
+{
+       return drivers;
+}
+
+int obex_transport_driver_register(struct obex_transport_driver *driver)
+{
+       if (!driver) {
+               error("Invalid driver");
+               return -EINVAL;
+       }
+
+       if (obex_transport_driver_find(driver->name) != NULL) {
+               error("Permission denied: transport %s already registered",
+                       driver->name);
+               return -EPERM;
+       }
+
+       DBG("driver %p transport %s registered", driver, driver->name);
+
+       drivers = g_slist_prepend(drivers, driver);
+
+       return 0;
+}
+
+void obex_transport_driver_unregister(struct obex_transport_driver *driver)
+{
+       if (!g_slist_find(drivers, driver)) {
+               error("Unable to unregister: No such driver %p", driver);
+               return;
+       }
+
+       DBG("driver %p transport %s unregistered", driver, driver->name);
+
+       drivers = g_slist_remove(drivers, driver);
+}
similarity index 58%
rename from tools/kword.h
rename to obexd/src/transport.h
index 81a2a88..97e10d0 100644 (file)
@@ -1,8 +1,8 @@
 /*
  *
- *  BlueZ - Bluetooth protocol stack for Linux
+ *  OBEX Server
  *
- *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
  *
  */
 
-extern int lineno;
-
-struct keyword_t {
-       char *string;
-       int type;
+struct obex_transport_driver {
+       const char *name;
+       uint16_t service;
+       void *(*start) (struct obex_server *server, int *err);
+       int (*getpeername) (GIOChannel *io, char **name);
+       int (*getsockname) (GIOChannel *io, char **name);
+       void (*stop) (void *data);
 };
 
-extern struct keyword_t rfcomm_keyword[];
-
-int rfcomm_find_keyword(struct keyword_t *keyword, char *string);
-
-#define MAXCOMMENTLEN  100
-
-struct rfcomm_opts {
-       int bind;
-       bdaddr_t bdaddr;
-       int channel;
-       char comment[MAXCOMMENTLEN + 1];
-};
-
-extern struct rfcomm_opts rfcomm_opts[RFCOMM_MAX_DEV];
-
-int rfcomm_read_config(char *filename);
+int obex_transport_driver_register(struct obex_transport_driver *driver);
+void obex_transport_driver_unregister(struct obex_transport_driver *driver);
+GSList *obex_transport_driver_list(void);
diff --git a/plugins/adaptername.c b/plugins/adaptername.c
deleted file mode 100644 (file)
index d3341b5..0000000
+++ /dev/null
@@ -1,327 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Red Hat, Inc.
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- *  Author: Bastien Nocera <hadess@hadess.net>
- *  Marcel Holtmann <marcel@holtmann.org> (for expand_name)
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
-
-#include <glib.h>
-#include <bluetooth/bluetooth.h>
-
-#include "plugin.h"
-#include "hcid.h" /* For main_opts */
-#include "adapter.h"
-#include "manager.h"
-#include "device.h" /* Needed for storage.h */
-#include "storage.h"
-#include "log.h"
-
-#include <sys/inotify.h>
-#define EVENT_SIZE  (sizeof (struct inotify_event))
-#define EVENT_BUF_LEN (1024 * (EVENT_SIZE + 16))
-
-#define MACHINE_INFO_DIR "/etc/"
-#define MACHINE_INFO_FILE "machine-info"
-
-static GIOChannel *inotify = NULL;
-static int watch_d = -1;
-
-/* This file is part of systemd's hostnamed functionality:
- * http://0pointer.de/public/systemd-man/machine-info.html
- * http://www.freedesktop.org/wiki/Software/systemd/hostnamed
- */
-static char *read_pretty_host_name(void)
-{
-       char *contents, *ret;
-       char **lines;
-       guint i;
-
-       if (g_file_get_contents(MACHINE_INFO_DIR MACHINE_INFO_FILE,
-                                       &contents, NULL, NULL) == FALSE)
-               return NULL;
-
-       lines = g_strsplit_set(contents, "\r\n", 0);
-       g_free(contents);
-
-       if (lines == NULL)
-               return NULL;
-
-       ret = NULL;
-       for (i = 0; lines[i] != NULL; i++) {
-               if (g_str_has_prefix(lines[i], "PRETTY_HOSTNAME=")) {
-                       ret = g_strdup(lines[i] + strlen("PRETTY_HOSTNAME="));
-                       break;
-               }
-       }
-
-       g_strfreev(lines);
-
-       return ret;
-}
-
-/*
- * Device name expansion
- *   %d - device id
- *   %h - hostname
- */
-static char *expand_name(char *dst, int size, char *str, int dev_id)
-{
-       register int sp, np, olen;
-       char *opt, buf[10];
-
-       if (!str || !dst)
-               return NULL;
-
-       sp = np = 0;
-       while (np < size - 1 && str[sp]) {
-               switch (str[sp]) {
-               case '%':
-                       opt = NULL;
-
-                       switch (str[sp+1]) {
-                       case 'd':
-                               sprintf(buf, "%d", dev_id);
-                               opt = buf;
-                               break;
-
-                       case 'h':
-                               opt = main_opts.host_name;
-                               break;
-
-                       case '%':
-                               dst[np++] = str[sp++];
-                               /* fall through */
-                       default:
-                               sp++;
-                               continue;
-                       }
-
-                       if (opt) {
-                               /* substitute */
-                               olen = strlen(opt);
-                               if (np + olen < size - 1)
-                                       memcpy(dst + np, opt, olen);
-                               np += olen;
-                       }
-                       sp += 2;
-                       continue;
-
-               case '\\':
-                       sp++;
-                       /* fall through */
-               default:
-                       dst[np++] = str[sp++];
-                       break;
-               }
-       }
-       dst[np] = '\0';
-       return dst;
-}
-
-static int get_default_adapter_id(void)
-{
-       struct btd_adapter *default_adapter;
-
-       default_adapter = manager_get_default_adapter();
-       if (default_adapter == NULL)
-               return -1;
-
-       return adapter_get_dev_id(default_adapter);
-}
-
-static void set_pretty_name(struct btd_adapter *adapter,
-                                               const char *pretty_hostname)
-{
-       int current_id;
-       int default_adapter;
-
-       default_adapter = get_default_adapter_id();
-       current_id = adapter_get_dev_id(adapter);
-
-       /* Allow us to change the name */
-       adapter_set_allow_name_changes(adapter, TRUE);
-
-       /* If it's the first device, let's assume it will be the
-        * default one, as we're not told when the default adapter
-        * changes */
-       if (default_adapter < 0)
-               default_adapter = current_id;
-
-       if (default_adapter != current_id) {
-               char *str;
-
-               /* +1 because we don't want an adapter called "Foobar's
-                * laptop #0" */
-               str = g_strdup_printf("%s #%d", pretty_hostname,
-                                                       current_id + 1);
-               DBG("Setting name '%s' for device 'hci%d'", str, current_id);
-
-               adapter_set_name(adapter, str);
-               g_free(str);
-       } else {
-               DBG("Setting name '%s' for device 'hci%d'", pretty_hostname,
-                                                               current_id);
-               adapter_set_name(adapter, pretty_hostname);
-       }
-
-       /* And disable the name change now */
-       adapter_set_allow_name_changes(adapter, FALSE);
-}
-
-static int adaptername_probe(struct btd_adapter *adapter)
-{
-       int current_id;
-       char name[MAX_NAME_LENGTH + 1];
-       char *pretty_hostname;
-       bdaddr_t bdaddr;
-
-       pretty_hostname = read_pretty_host_name();
-       if (pretty_hostname != NULL) {
-               set_pretty_name(adapter, pretty_hostname);
-               g_free(pretty_hostname);
-               return 0;
-       }
-
-       adapter_set_allow_name_changes(adapter, TRUE);
-       adapter_get_address(adapter, &bdaddr);
-       current_id = adapter_get_dev_id(adapter);
-
-       if (read_local_name(&bdaddr, name) < 0)
-               expand_name(name, MAX_NAME_LENGTH, main_opts.name, current_id);
-
-       DBG("Setting name '%s' for device 'hci%d'", name, current_id);
-       adapter_set_name(adapter, name);
-
-       return 0;
-}
-
-static gboolean handle_inotify_cb(GIOChannel *channel, GIOCondition cond,
-                                                               gpointer data)
-{
-       char buf[EVENT_BUF_LEN];
-       GIOStatus err;
-       gsize len, i;
-       gboolean changed;
-
-       changed = FALSE;
-
-       err = g_io_channel_read_chars(channel, buf, EVENT_BUF_LEN, &len, NULL);
-       if (err != G_IO_STATUS_NORMAL) {
-               error("Error reading inotify event: %d\n", err);
-               return FALSE;
-       }
-
-       i = 0;
-       while (i < len) {
-               struct inotify_event *pevent = (struct inotify_event *) &buf[i];
-
-               /* check that it's ours */
-               if (pevent->len && pevent->name != NULL &&
-                               strcmp(pevent->name, MACHINE_INFO_FILE) == 0)
-                       changed = TRUE;
-
-               i += EVENT_SIZE + pevent->len;
-       }
-
-       if (changed != FALSE) {
-               DBG(MACHINE_INFO_DIR MACHINE_INFO_FILE
-                               " changed, changing names for adapters");
-               manager_foreach_adapter((adapter_cb) adaptername_probe, NULL);
-       }
-
-       return TRUE;
-}
-
-static void adaptername_remove(struct btd_adapter *adapter)
-{
-}
-
-static struct btd_adapter_driver adaptername_driver = {
-       .name   = "adaptername",
-       .probe  = adaptername_probe,
-       .remove = adaptername_remove,
-};
-
-static int adaptername_init(void)
-{
-       int err;
-       int inot_fd;
-       guint32 mask;
-
-       err = btd_register_adapter_driver(&adaptername_driver);
-       if (err < 0)
-               return err;
-
-       inot_fd = inotify_init();
-       if (inot_fd < 0) {
-               error("Failed to setup inotify");
-               return 0;
-       }
-
-       mask = IN_CLOSE_WRITE;
-       mask |= IN_DELETE;
-       mask |= IN_CREATE;
-       mask |= IN_MOVED_FROM;
-       mask |= IN_MOVED_TO;
-
-       watch_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;
-       }
-
-       inotify = g_io_channel_unix_new(inot_fd);
-       g_io_channel_set_close_on_unref(inotify, TRUE);
-       g_io_channel_set_encoding(inotify, NULL, NULL);
-       g_io_channel_set_flags(inotify, G_IO_FLAG_NONBLOCK, NULL);
-       g_io_add_watch(inotify, G_IO_IN, handle_inotify_cb, NULL);
-
-       return 0;
-}
-
-static void adaptername_exit(void)
-{
-       if (watch_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);
-       }
-
-       btd_unregister_adapter_driver(&adaptername_driver);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(adaptername, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_LOW, adaptername_init, adaptername_exit)
diff --git a/plugins/autopair.c b/plugins/autopair.c
new file mode 100644 (file)
index 0000000..e6e5035
--- /dev/null
@@ -0,0 +1,177 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Google Inc.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  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 <stdbool.h>
+#include <stdlib.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <bluetooth/bluetooth.h>
+#include <glib.h>
+
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "log.h"
+#include "storage.h"
+
+/*
+ * Plugin to handle automatic pairing of devices with reduced user
+ * interaction, including implementing the recommendation of the HID spec
+ * for keyboard devices.
+ *
+ * The plugin works by intercepting the PIN request for devices; if the
+ * device is a keyboard a random six-digit numeric PIN is generated and
+ * returned, flagged for displaying using DisplayPinCode.
+ *
+ */
+
+static ssize_t autopair_pincb(struct btd_adapter *adapter,
+                                               struct btd_device *device,
+                                               char *pinbuf, bool *display,
+                                               unsigned int attempt)
+{
+       char addr[18];
+       char pinstr[7];
+       uint32_t class;
+
+       ba2str(device_get_address(device), addr);
+
+       class = btd_device_get_class(device);
+
+       DBG("device %s 0x%x", addr, class);
+
+       /* This is a class-based pincode guesser. Ignore devices with an
+        * unknown class.
+        */
+       if (class == 0)
+               return 0;
+
+       switch ((class & 0x1f00) >> 8) {
+       case 0x04:              /* Audio/Video */
+               switch ((class & 0xfc) >> 2) {
+               case 0x01:              /* Wearable Headset Device */
+               case 0x02:              /* Hands-free Device */
+               case 0x06:              /* Headphones */
+               case 0x07:              /* Portable Audio */
+               case 0x0a:              /* HiFi Audio Device */
+                       if (attempt > 1)
+                               return 0;
+                       memcpy(pinbuf, "0000", 4);
+                       return 4;
+               }
+               break;
+
+       case 0x05:              /* Peripheral */
+               switch ((class & 0xc0) >> 6) {
+               case 0x01:              /* Keyboard */
+               case 0x03:              /* Combo keyboard/pointing device */
+                       /* For keyboards rejecting the first random code
+                        * in less than 500ms, try a fixed code. */
+                       if (attempt > 1 &&
+                               device_bonding_last_duration(device) < 500) {
+                               /* Don't try more than one dumb code */
+                               if (attempt > 2)
+                                       return 0;
+                               /* Try "0000" as the code for the second
+                                * attempt. */
+                               memcpy(pinbuf, "0000", 4);
+                               return 4;
+                       }
+
+                       /* Never try more than 3 random pincodes. */
+                       if (attempt >= 4)
+                               return 0;
+
+                       snprintf(pinstr, sizeof(pinstr), "%06d",
+                                               rand() % 1000000);
+                       *display = true;
+                       memcpy(pinbuf, pinstr, 6);
+                       return 6;
+
+               case 0x02: /* Pointing device */
+                       if (attempt > 1)
+                               return 0;
+                       memcpy(pinbuf, "0000", 4);
+                       return 4;
+               }
+
+               break;
+       }
+
+       return 0;
+}
+
+
+static int autopair_probe(struct btd_adapter *adapter)
+{
+       btd_adapter_register_pin_cb(adapter, autopair_pincb);
+
+       return 0;
+}
+
+static void autopair_remove(struct btd_adapter *adapter)
+{
+       btd_adapter_unregister_pin_cb(adapter, autopair_pincb);
+}
+
+static struct btd_adapter_driver autopair_driver = {
+       .name = "autopair",
+       .probe = autopair_probe,
+       .remove = autopair_remove,
+};
+
+static int autopair_init(void)
+{
+       /* Initialize the random seed from /dev/urandom */
+       unsigned int seed;
+       int fd;
+
+       fd = open("/dev/urandom", O_RDONLY);
+       if (fd >= 0) {
+               ssize_t n;
+
+               n = read(fd, &seed, sizeof(seed));
+               if (n < (ssize_t) sizeof(seed))
+                       seed = time(NULL);
+
+               close(fd);
+       } else
+               seed = time(NULL);
+
+       srand(seed);
+
+       return btd_register_adapter_driver(&autopair_driver);
+}
+
+static void autopair_exit(void)
+{
+       btd_unregister_adapter_driver(&autopair_driver);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(autopair, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                               autopair_init, autopair_exit)
diff --git a/plugins/dbusoob.c b/plugins/dbusoob.c
deleted file mode 100644 (file)
index 1791342..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  ST-Ericsson SA
- *
- *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <gdbus.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
-
-#include "plugin.h"
-#include "log.h"
-#include "adapter.h"
-#include "device.h"
-#include "manager.h"
-#include "dbus-common.h"
-#include "event.h"
-#include "error.h"
-#include "oob.h"
-
-#define OOB_INTERFACE  "org.bluez.OutOfBand"
-
-struct oob_request {
-       struct btd_adapter *adapter;
-       DBusMessage *msg;
-};
-
-static GSList *oob_requests = NULL;
-static DBusConnection *connection = NULL;
-
-static gint oob_request_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct oob_request *data = a;
-       const struct btd_adapter *adapter = b;
-
-       return data->adapter != adapter;
-}
-
-static struct oob_request *find_oob_request(struct btd_adapter *adapter)
-{
-       GSList *match;
-
-       match = g_slist_find_custom(oob_requests, adapter, oob_request_cmp);
-
-       if (match)
-               return match->data;
-
-       return NULL;
-}
-
-static void read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-                               uint8_t *randomizer)
-{
-       struct DBusMessage *reply;
-       struct oob_request *oob_request;
-
-       oob_request = find_oob_request(adapter);
-       if (!oob_request)
-               return;
-
-       if (hash && randomizer)
-               reply = g_dbus_create_reply(oob_request->msg,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, 16,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, 16,
-                       DBUS_TYPE_INVALID);
-       else
-               reply = btd_error_failed(oob_request->msg,
-                                       "Failed to read local OOB data.");
-
-       oob_requests = g_slist_remove(oob_requests, oob_request);
-       dbus_message_unref(oob_request->msg);
-       g_free(oob_request);
-
-       if (!reply) {
-               error("Couldn't allocate D-Bus message");
-               return;
-       }
-
-       if (!g_dbus_send_message(connection, reply))
-               error("D-Bus send failed");
-}
-
-static DBusMessage *read_local_data(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct oob_request *oob_request;
-
-       if (find_oob_request(adapter))
-               return btd_error_in_progress(msg);
-
-       if (btd_adapter_read_local_oob_data(adapter))
-               return btd_error_failed(msg, "Request failed.");
-
-       oob_request = g_new(struct oob_request, 1);
-       oob_request->adapter = adapter;
-       oob_requests = g_slist_append(oob_requests, oob_request);
-       oob_request->msg = dbus_message_ref(msg);
-
-       return NULL;
-}
-
-static DBusMessage *add_remote_data(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct btd_adapter *adapter = data;
-       uint8_t *hash, *randomizer;
-       int32_t hlen, rlen;
-       const char *addr;
-       bdaddr_t bdaddr;
-
-       if (!dbus_message_get_args(msg, NULL,
-                       DBUS_TYPE_STRING, &addr,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &hash, &hlen,
-                       DBUS_TYPE_ARRAY, DBUS_TYPE_BYTE, &randomizer, &rlen,
-                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       if (hlen != 16 || rlen != 16 || bachk(addr))
-               return btd_error_invalid_args(msg);
-
-       str2ba(addr, &bdaddr);
-
-       if (btd_adapter_add_remote_oob_data(adapter, &bdaddr, hash, randomizer))
-               return btd_error_failed(msg, "Request failed");
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *remove_remote_data(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct btd_adapter *adapter = data;
-       const char *addr;
-       bdaddr_t bdaddr;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &addr,
-                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       if (bachk(addr))
-               return btd_error_invalid_args(msg);
-
-       str2ba(addr, &bdaddr);
-
-       if (btd_adapter_remove_remote_oob_data(adapter, &bdaddr))
-               return btd_error_failed(msg, "Request failed");
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-static 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)
-{
-       const char *path = adapter_get_path(adapter);
-
-       if (!g_dbus_register_interface(connection, path, OOB_INTERFACE,
-                               oob_methods, NULL, NULL, adapter, NULL)) {
-                       error("OOB interface init failed on path %s", path);
-                       return -EIO;
-               }
-
-       return 0;
-}
-
-static void oob_remove(struct btd_adapter *adapter)
-{
-       read_local_data_complete(adapter, NULL, NULL);
-
-       g_dbus_unregister_interface(connection, adapter_get_path(adapter),
-                                                       OOB_INTERFACE);
-}
-
-static struct btd_adapter_driver oob_driver = {
-       .name   = "oob",
-       .probe  = oob_probe,
-       .remove = oob_remove,
-};
-
-static int dbusoob_init(void)
-{
-       DBG("Setup dbusoob plugin");
-
-       connection = get_dbus_connection();
-
-       oob_register_cb(read_local_data_complete);
-
-       return btd_register_adapter_driver(&oob_driver);
-}
-
-static void dbusoob_exit(void)
-{
-       DBG("Cleanup dbusoob plugin");
-
-       manager_foreach_adapter((adapter_cb) oob_remove, NULL);
-
-       btd_unregister_adapter_driver(&oob_driver);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(dbusoob, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                                               dbusoob_init, dbusoob_exit)
diff --git a/plugins/formfactor.c b/plugins/formfactor.c
deleted file mode 100644 (file)
index 0e19ac6..0000000
+++ /dev/null
@@ -1,148 +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 <stdlib.h>
-#include <errno.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include "plugin.h"
-#include "adapter.h"
-#include "log.h"
-
-#define DMI_CHASSIS_FILE "/sys/class/dmi/id/chassis_type"
-#define DMI_CHASSIS_FILE_FALLBACK "/sys/devices/virtual/dmi/id/chassis_type"
-
-/* Map the chassis type from chassis_type to a sensible type used in hal
- *
- * See also 3.3.4.1 of the "System Management BIOS Reference Specification,
- * Version 2.6.1" (Preliminary Standard) document, available from
- * http://www.dmtf.org/standards/smbios.
- *
- * TODO: figure out WTF the mapping should be; "Lunch Box"? Give me a break :-)
- *
- * Copied from hal/hald/linux/osspec.c
- */
-static const char *chassis_map[] = {
-       "Other",                 "unknown", /* 0x01 */
-       "Unknown",               "unknown",
-       "Desktop",               "desktop",
-       "Low Profile Desktop",   "desktop",
-       "Pizza Box",             "server",
-       "Mini Tower",            "desktop",
-       "Tower",                 "desktop",
-       "Portable",              "laptop",
-       "Laptop",                "laptop",
-       "Notebook",              "laptop",
-       "Hand Held",             "handheld",
-       "Docking Station",       "laptop",
-       "All In One",            "unknown",
-       "Sub Notebook",          "laptop",
-       "Space-saving",          "desktop",
-       "Lunch Box",             "unknown",
-       "Main Server Chassis",   "server",
-       "Expansion Chassis",     "unknown",
-       "Sub Chassis",           "unknown",
-       "Bus Expansion Chassis", "unknown",
-       "Peripheral Chassis",    "unknown",
-       "RAID Chassis",          "unknown",
-       "Rack Mount Chassis",    "unknown",
-       "Sealed-case PC",        "unknown",
-       "Multi-system",          "unknown",
-       "CompactPCI",            "unknown",
-       "AdvancedTCA",           "unknown",
-       "Blade",                 "server",
-       "Blade Enclosure",       "unknown", /* 0x1D */
-       NULL
-};
-
-static int formfactor_probe(struct btd_adapter *adapter)
-{
-       int chassis_type;
-       uint8_t minor = 0;
-       const char *formfactor;
-       char *contents;
-
-       if (g_file_get_contents(DMI_CHASSIS_FILE,
-                               &contents, NULL, NULL) == FALSE) {
-               if (g_file_get_contents(DMI_CHASSIS_FILE_FALLBACK,
-                                       &contents, NULL, NULL) == FALSE) {
-                       error("Could not get the contents of DMI chassis type");
-                       return 0;
-               }
-       }
-
-       chassis_type = atoi(contents);
-       g_free (contents);
-
-       if (chassis_type > 0x1D || chassis_type <= 0) {
-               error ("Chassis type is not a known chassis type");
-               return 0;
-       }
-
-       formfactor = chassis_map[chassis_type * 2 - 1];
-       if (formfactor != NULL) {
-               if (g_str_equal(formfactor, "laptop") == TRUE)
-                       minor |= (1 << 2) | (1 << 3);
-               else if (g_str_equal(formfactor, "desktop") == TRUE)
-                       minor |= 1 << 2;
-               else if (g_str_equal(formfactor, "server") == TRUE)
-                       minor |= 1 << 3;
-               else if (g_str_equal(formfactor, "handheld") == TRUE)
-                       minor += 1 << 4;
-       }
-
-       /* Computer major class */
-       DBG("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
-
-       btd_adapter_set_class(adapter, 0x01, minor);
-
-       return 0;
-}
-
-static void formfactor_remove(struct btd_adapter *adapter)
-{
-}
-
-static struct btd_adapter_driver formfactor_driver = {
-       .name   = "formfactor",
-       .probe  = formfactor_probe,
-       .remove = formfactor_remove,
-};
-
-static int formfactor_init(void)
-{
-       return btd_register_adapter_driver(&formfactor_driver);
-}
-
-static void formfactor_exit(void)
-{
-       btd_unregister_adapter_driver(&formfactor_driver);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(formfactor, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_LOW, formfactor_init, formfactor_exit)
index cd2c481..9b4187a 100644 (file)
 #endif
 
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <errno.h>
 #include <adapter.h>
 
+#include "lib/uuid.h"
 #include "plugin.h"
 #include "hcid.h"
 #include "log.h"
-#include "gattrib.h"
-#include "gatt-service.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt-service.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/att-database.h"
 #include "attrib-server.h"
 
 /* FIXME: Not defined by SIG? UUID128? */
@@ -72,7 +72,7 @@ static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
        while (gadapter->sdp_handles != NULL) {
                uint32_t handle = GPOINTER_TO_UINT(gadapter->sdp_handles->data);
 
-               attrib_free_sdp(handle);
+               attrib_free_sdp(gadapter->adapter, handle);
                gadapter->sdp_handles = g_slist_remove(gadapter->sdp_handles,
                                                gadapter->sdp_handles->data);
        }
@@ -83,7 +83,7 @@ static void gatt_example_adapter_free(struct gatt_example_adapter *gadapter)
        g_free(gadapter);
 }
 
-static gint adapter_cmp(gconstpointer a, gconstpointer b)
+static int adapter_cmp(gconstpointer a, gconstpointer b)
 {
        const struct gatt_example_adapter *gatt_adapter = a;
        const struct btd_adapter *adapter = b;
@@ -114,7 +114,7 @@ static gboolean register_battery_service(struct btd_adapter *adapter)
 
        return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
                        /* battery state characteristic */
-                       GATT_OPT_CHR_UUID, BATTERY_STATE_UUID,
+                       GATT_OPT_CHR_UUID16, BATTERY_STATE_UUID,
                        GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
                                                        ATT_CHAR_PROPER_NOTIFY,
                        GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
@@ -563,19 +563,11 @@ static struct btd_adapter_driver gatt_example_adapter_driver = {
 
 static int gatt_example_init(void)
 {
-       if (!main_opts.gatt_enabled) {
-               DBG("GATT is disabled");
-               return -ENOTSUP;
-       }
-
        return btd_register_adapter_driver(&gatt_example_adapter_driver);
 }
 
 static void gatt_example_exit(void)
 {
-       if (!main_opts.gatt_enabled)
-               return;
-
        btd_unregister_adapter_driver(&gatt_example_adapter_driver);
 }
 
diff --git a/plugins/hal.c b/plugins/hal.c
deleted file mode 100644 (file)
index 21d7688..0000000
+++ /dev/null
@@ -1,144 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <dbus/dbus.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include "plugin.h"
-#include "adapter.h"
-#include "log.h"
-
-static void formfactor_reply(DBusPendingCall *call, void *user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       const char *formfactor = NULL;
-       DBusMessage *reply;
-       uint8_t minor = 0;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       if (dbus_set_error_from_message(NULL, reply) == TRUE) {
-               error("Failed to access HAL");
-               dbus_message_unref(reply);
-               return;
-       }
-
-       if (dbus_message_get_args(reply, NULL, DBUS_TYPE_STRING, &formfactor,
-                                               DBUS_TYPE_INVALID) == FALSE) {
-               error("Wrong formfactor arguments");
-               dbus_message_unref(reply);
-               return;
-       }
-
-       DBG("Computer is classified as %s", formfactor);
-
-       if (formfactor != NULL) {
-               if (g_str_equal(formfactor, "laptop") == TRUE)
-                       minor |= (1 << 2) | (1 << 3);
-               else if (g_str_equal(formfactor, "desktop") == TRUE)
-                       minor |= 1 << 2;
-               else if (g_str_equal(formfactor, "server") == TRUE)
-                       minor |= 1 << 3;
-               else if (g_str_equal(formfactor, "handheld") == TRUE)
-                       minor += 1 << 4;
-       }
-
-       dbus_message_unref(reply);
-
-       /* Computer major class */
-       DBG("Setting 0x%06x for major/minor device class", (1 << 8) | minor);
-
-       btd_adapter_set_class(adapter, 0x01, minor);
-}
-
-static DBusConnection *connection;
-
-static int hal_probe(struct btd_adapter *adapter)
-{
-       const char *property = "system.formfactor";
-       DBusMessage *message;
-       DBusPendingCall *call;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -ENOMEM;
-
-       message = dbus_message_new_method_call("org.freedesktop.Hal",
-                               "/org/freedesktop/Hal/devices/computer",
-                                               "org.freedesktop.Hal.Device",
-                                                       "GetPropertyString");
-       if (message == NULL) {
-               error("Failed to create formfactor request");
-               dbus_connection_unref(connection);
-               return -ENOMEM;
-       }
-
-       dbus_message_append_args(message, DBUS_TYPE_STRING, &property,
-                                                       DBUS_TYPE_INVALID);
-
-       if (dbus_connection_send_with_reply(connection, message,
-                                               &call, -1) == FALSE) {
-               error("Failed to send formfactor request");
-               dbus_message_unref(message);
-               dbus_connection_unref(connection);
-               return -EIO;
-       }
-
-       dbus_pending_call_set_notify(call, formfactor_reply, adapter, NULL);
-
-       dbus_pending_call_unref(call);
-
-       dbus_message_unref(message);
-
-       return 0;
-}
-
-static void hal_remove(struct btd_adapter *adapter)
-{
-       dbus_connection_unref(connection);
-}
-
-static struct btd_adapter_driver hal_driver = {
-       .name   = "hal",
-       .probe  = hal_probe,
-       .remove = hal_remove,
-};
-
-static int hal_init(void)
-{
-       return btd_register_adapter_driver(&hal_driver);
-}
-
-static void hal_exit(void)
-{
-       btd_unregister_adapter_driver(&hal_driver);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(hal, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_LOW, hal_init, hal_exit)
diff --git a/plugins/hciops.c b/plugins/hciops.c
deleted file mode 100644 (file)
index d74f2ea..0000000
+++ /dev/null
@@ -1,3943 +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 <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-
-#include "hcid.h"
-#include "sdpd.h"
-#include "btio.h"
-#include "adapter.h"
-#include "device.h"
-#include "plugin.h"
-#include "log.h"
-#include "storage.h"
-#include "event.h"
-#include "manager.h"
-#include "oob.h"
-#include "eir.h"
-
-#define DISCOV_HALTED 0
-#define DISCOV_INQ 1
-#define DISCOV_SCAN 2
-#define DISCOV_NAMES 3
-
-#define TIMEOUT_BR_LE_SCAN 5120 /* TGAP(100)/2 */
-#define TIMEOUT_LE_SCAN 10240 /* TGAP(gen_disc_scan_min) */
-
-#define LENGTH_BR_INQ 0x08
-#define LENGTH_BR_LE_INQ 0x04
-
-static int start_scanning(int index, int timeout);
-
-static int child_pipe[2] = { -1, -1 };
-
-static guint child_io_id = 0;
-static guint ctl_io_id = 0;
-
-enum adapter_type {
-       BR_EDR,
-       LE_ONLY,
-       BR_EDR_LE,
-       UNKNOWN,
-};
-
-/* Commands sent by kernel on starting an adapter */
-enum {
-       PENDING_BDADDR,
-       PENDING_VERSION,
-       PENDING_FEATURES,
-       PENDING_NAME,
-};
-
-struct bt_conn {
-       struct dev_info *dev;
-       bdaddr_t bdaddr;
-       uint16_t handle;
-       uint8_t loc_cap;
-       uint8_t loc_auth;
-       uint8_t rem_cap;
-       uint8_t rem_auth;
-       uint8_t rem_oob_data;
-       gboolean bonding_initiator;
-       gboolean secmode3;
-       GIOChannel *io; /* For raw L2CAP socket (bonding) */
-};
-
-struct oob_data {
-       bdaddr_t bdaddr;
-       uint8_t hash[16];
-       uint8_t randomizer[16];
-};
-
-enum name_state {
-       NAME_UNKNOWN,
-       NAME_NEEDED,
-       NAME_NOT_NEEDED,
-       NAME_PENDING,
-};
-
-struct found_dev {
-       bdaddr_t bdaddr;
-       int8_t rssi;
-       enum name_state name_state;
-};
-
-static int max_dev = -1;
-static struct dev_info {
-       int id;
-       int sk;
-       bdaddr_t bdaddr;
-       char name[249];
-       uint8_t eir[HCI_MAX_EIR_LENGTH];
-       uint8_t features[8];
-       uint8_t extfeatures[8];
-       uint8_t ssp_mode;
-
-       int8_t tx_power;
-
-       int discov_state;
-
-       uint32_t current_cod;
-       uint32_t wanted_cod;
-       uint32_t pending_cod;
-       gboolean cache_enable;
-       gboolean already_up;
-       gboolean registered;
-       gboolean pairable;
-
-       uint8_t io_capability;
-
-       struct hci_version ver;
-
-       uint16_t did_source;
-       uint16_t did_vendor;
-       uint16_t did_product;
-       uint16_t did_version;
-
-       gboolean up;
-       uint32_t pending;
-
-       GIOChannel *io;
-       guint watch_id;
-
-       gboolean debug_keys;
-       GSList *keys;
-       uint8_t pin_length;
-
-       GSList *oob_data;
-
-       GSList *uuids;
-
-       GSList *connections;
-
-       GSList *found_devs;
-       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)
-{
-       const struct found_dev *d1 = a, *d2 = b;
-       int rssi1, rssi2;
-
-       if (d2->name_state == NAME_NOT_NEEDED)
-               return -1;
-
-       rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
-       rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
-
-       return rssi1 - rssi2;
-}
-
-static int found_dev_bda_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct found_dev *d1 = a, *d2 = b;
-
-       return bacmp(&d1->bdaddr, &d2->bdaddr);
-}
-
-static void found_dev_cleanup(struct dev_info *info)
-{
-       g_slist_free_full(info->found_devs, g_free);
-       info->found_devs = NULL;
-
-       g_slist_free_full(info->need_name, g_free);
-       info->need_name = NULL;
-}
-
-static int resolve_name(struct dev_info *info, bdaddr_t *bdaddr)
-{
-       remote_name_req_cp cp;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", info->id, addr);
-
-       memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
-       cp.pscan_rep_mode = 0x02;
-
-       if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ,
-                                       REMOTE_NAME_REQ_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int resolve_names(struct dev_info *info, struct btd_adapter *adapter)
-{
-       struct found_dev *dev;
-
-       DBG("found_dev %u need_name %u", g_slist_length(info->found_devs),
-                                       g_slist_length(info->need_name));
-
-       if (g_slist_length(info->need_name) == 0)
-               return -ENOENT;
-
-       dev = info->need_name->data;
-       resolve_name(info, &dev->bdaddr);
-       dev->name_state = NAME_PENDING;
-
-       return 0;
-}
-
-static void set_state(int index, int state)
-{
-       struct btd_adapter *adapter;
-       struct dev_info *dev = &devs[index];
-
-       if (dev->discov_state == state)
-               return;
-
-       adapter = manager_find_adapter_by_id(index);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       dev->discov_state = state;
-
-       DBG("hci%d: new state %d", index, dev->discov_state);
-
-       switch (dev->discov_state) {
-       case DISCOV_HALTED:
-               found_dev_cleanup(dev);
-               adapter_set_discovering(adapter, FALSE);
-               break;
-       case DISCOV_INQ:
-       case DISCOV_SCAN:
-               adapter_set_discovering(adapter, TRUE);
-               break;
-       case DISCOV_NAMES:
-               if (resolve_names(dev, adapter) < 0)
-                       set_state(index, DISCOV_HALTED);
-               break;
-       }
-}
-
-static inline gboolean is_le_capable(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       return (dev->features[4] & LMP_LE &&
-                       dev->extfeatures[0] & LMP_HOST_LE) ? TRUE : FALSE;
-}
-
-static inline gboolean is_bredr_capable(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       return (dev->features[4] & LMP_NO_BREDR) == 0 ? TRUE : FALSE;
-}
-
-static int get_adapter_type(int index)
-{
-       if (is_le_capable(index) && is_bredr_capable(index))
-               return BR_EDR_LE;
-       else if (is_le_capable(index))
-               return LE_ONLY;
-       else if (is_bredr_capable(index))
-               return BR_EDR;
-
-       return UNKNOWN;
-}
-
-static int ignore_device(struct hci_dev_info *di)
-{
-       return hci_test_bit(HCI_RAW, &di->flags) || di->type >> 4 != HCI_BREDR;
-}
-
-static struct dev_info *init_dev_info(int index, int sk, gboolean registered,
-                                                       gboolean already_up)
-{
-       struct dev_info *dev = &devs[index];
-
-       memset(dev, 0, sizeof(*dev));
-
-       dev->id = index;
-       dev->sk = sk;
-       dev->cache_enable = TRUE;
-       dev->registered = registered;
-       dev->already_up = already_up;
-       dev->io_capability = 0x03; /* No Input No Output */
-       dev->discov_state = DISCOV_HALTED;
-
-       return dev;
-}
-
-/* Async HCI command handling with callback support */
-
-struct hci_cmd_data {
-       bt_hci_result_t         cb;
-       uint16_t                handle;
-       uint16_t                ocf;
-       gpointer                caller_data;
-};
-
-static gboolean hci_event_watch(GIOChannel *io,
-                       GIOCondition cond, gpointer user_data)
-{
-       unsigned char buf[HCI_MAX_EVENT_SIZE], *body;
-       struct hci_cmd_data *cmd = user_data;
-       evt_cmd_status *evt_status;
-       evt_auth_complete *evt_auth;
-       evt_encrypt_change *evt_enc;
-       hci_event_hdr *hdr;
-       set_conn_encrypt_cp cp;
-       int dd;
-       uint16_t ocf;
-       uint8_t status = HCI_OE_POWER_OFF;
-
-       if (cond & G_IO_NVAL) {
-               cmd->cb(status, cmd->caller_data);
-               return FALSE;
-       }
-
-       if (cond & (G_IO_ERR | G_IO_HUP))
-               goto failed;
-
-       dd = g_io_channel_unix_get_fd(io);
-
-       if (read(dd, buf, sizeof(buf)) < 0)
-               goto failed;
-
-       hdr = (hci_event_hdr *) (buf + 1);
-       body = buf + (1 + HCI_EVENT_HDR_SIZE);
-
-       switch (hdr->evt) {
-       case EVT_CMD_STATUS:
-               evt_status = (evt_cmd_status *) body;
-               ocf = cmd_opcode_ocf(evt_status->opcode);
-               if (ocf != cmd->ocf)
-                       return TRUE;
-               switch (ocf) {
-               case OCF_AUTH_REQUESTED:
-               case OCF_SET_CONN_ENCRYPT:
-                       if (evt_status->status != 0) {
-                               /* Baseband rejected command */
-                               status = evt_status->status;
-                               goto failed;
-                       }
-                       break;
-               default:
-                       return TRUE;
-               }
-               /* Wait for the next event */
-               return TRUE;
-       case EVT_AUTH_COMPLETE:
-               evt_auth = (evt_auth_complete *) body;
-               if (evt_auth->handle != cmd->handle) {
-                       /* Skipping */
-                       return TRUE;
-               }
-
-               if (evt_auth->status != 0x00) {
-                       status = evt_auth->status;
-                       /* Abort encryption */
-                       goto failed;
-               }
-
-               memset(&cp, 0, sizeof(cp));
-               cp.handle  = cmd->handle;
-               cp.encrypt = 1;
-
-               cmd->ocf = OCF_SET_CONN_ENCRYPT;
-
-               if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_SET_CONN_ENCRYPT,
-                                       SET_CONN_ENCRYPT_CP_SIZE, &cp) < 0) {
-                       status = HCI_COMMAND_DISALLOWED;
-                       goto failed;
-               }
-               /* Wait for encrypt change event */
-               return TRUE;
-       case EVT_ENCRYPT_CHANGE:
-               evt_enc = (evt_encrypt_change *) body;
-               if (evt_enc->handle != cmd->handle)
-                       return TRUE;
-
-               /* Procedure finished: reporting status */
-               status = evt_enc->status;
-               break;
-       default:
-               /* Skipping */
-               return TRUE;
-       }
-
-failed:
-       cmd->cb(status, cmd->caller_data);
-       g_io_channel_shutdown(io, TRUE, NULL);
-
-       return FALSE;
-}
-
-static int write_inq_mode(int index, uint8_t mode)
-{
-       struct dev_info *dev = &devs[index];
-       write_inquiry_mode_cp cp;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.mode = mode;
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_INQUIRY_MODE,
-                                       WRITE_INQUIRY_MODE_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static uint8_t get_inquiry_mode(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       if (dev->features[6] & LMP_EXT_INQ)
-               return 2;
-
-       if (dev->features[3] & LMP_RSSI_INQ)
-               return 1;
-
-       if (dev->ver.manufacturer == 11 && dev->ver.hci_rev == 0x00 &&
-                                       dev->ver.lmp_subver == 0x0757)
-               return 1;
-
-       if (dev->ver.manufacturer == 15) {
-               if (dev->ver.hci_rev == 0x03 &&
-                                       dev->ver.lmp_subver == 0x6963)
-                       return 1;
-               if (dev->ver.hci_rev == 0x09 &&
-                                       dev->ver.lmp_subver == 0x6963)
-                       return 1;
-               if (dev->ver.hci_rev == 0x00 &&
-                                       dev->ver.lmp_subver == 0x6965)
-                       return 1;
-       }
-
-       if (dev->ver.manufacturer == 31 && dev->ver.hci_rev == 0x2005 &&
-                                       dev->ver.lmp_subver == 0x1805)
-               return 1;
-
-       return 0;
-}
-
-static int init_ssp_mode(int index)
-{
-       struct dev_info *dev = &devs[index];
-       write_simple_pairing_mode_cp cp;
-
-       if (ioctl(dev->sk, HCIGETAUTHINFO, NULL) < 0 && errno == EINVAL)
-               return 0;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.mode = 0x01;
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                               OCF_WRITE_SIMPLE_PAIRING_MODE,
-                               WRITE_SIMPLE_PAIRING_MODE_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_set_discoverable(int index, gboolean discoverable,
-                                                       uint16_t timeout)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t mode;
-
-       if (discoverable)
-               mode = (SCAN_PAGE | SCAN_INQUIRY);
-       else
-               mode = SCAN_PAGE;
-
-       DBG("hci%d discoverable %d", index, discoverable);
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE,
-                                                               1, &mode) < 0)
-               return -errno;
-
-       dev->discoverable_timeout = timeout;
-
-       return 0;
-}
-
-static int hciops_set_pairable(int index, gboolean pairable)
-{
-       struct btd_adapter *adapter;
-
-       DBG("hci%d pairable %d", index, pairable);
-
-       adapter = manager_find_adapter(&devs[index].bdaddr);
-       if (adapter)
-               btd_adapter_pairable_changed(adapter, pairable);
-
-       devs[index].pairable = pairable;
-
-       return 0;
-}
-
-static int hciops_power_off(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       if (ioctl(dev->sk, HCIDEVDOWN, index) < 0 && errno != EALREADY)
-               return -errno;
-
-       return 0;
-}
-
-static void set_event_mask(int index)
-{
-       struct dev_info *dev = &devs[index];
-       /* The second byte is 0xff instead of 0x9f (two reserved bits
-        * disabled) since a Broadcom 1.2 dongle doesn't respond to the
-        * command otherwise */
-       uint8_t events[8] = { 0xff, 0xff, 0xfb, 0xff, 0x00, 0x00, 0x00, 0x00 };
-
-       /* Events for 1.2 and newer controllers */
-       if (dev->ver.lmp_ver > 1) {
-               events[4] |= 0x01; /* Flow Specification Complete */
-               events[4] |= 0x02; /* Inquiry Result with RSSI */
-               events[4] |= 0x04; /* Read Remote Extended Features Complete */
-               events[5] |= 0x08; /* Synchronous Connection Complete */
-               events[5] |= 0x10; /* Synchronous Connection Changed */
-       }
-
-       if (dev->features[3] & LMP_RSSI_INQ)
-               events[4] |= 0x02; /* Inquiry Result with RSSI */
-
-       if (dev->features[5] & LMP_SNIFF_SUBR)
-               events[5] |= 0x20; /* Sniff Subrating */
-
-       if (dev->features[5] & LMP_PAUSE_ENC)
-               events[5] |= 0x80; /* Encryption Key Refresh Complete */
-
-       if (dev->features[6] & LMP_EXT_INQ)
-               events[5] |= 0x40; /* Extended Inquiry Result */
-
-       if (dev->features[6] & LMP_NFLUSH_PKTS)
-               events[7] |= 0x01; /* Enhanced Flush Complete */
-
-       if (dev->features[7] & LMP_LSTO)
-               events[6] |= 0x80; /* Link Supervision Timeout Changed */
-
-       if (dev->features[6] & LMP_SIMPLE_PAIR) {
-               events[6] |= 0x01;      /* IO Capability Request */
-               events[6] |= 0x02;      /* IO Capability Response */
-               events[6] |= 0x04;      /* User Confirmation Request */
-               events[6] |= 0x08;      /* User Passkey Request */
-               events[6] |= 0x10;      /* Remote OOB Data Request */
-               events[6] |= 0x20;      /* Simple Pairing Complete */
-               events[7] |= 0x04;      /* User Passkey Notification */
-               events[7] |= 0x08;      /* Keypress Notification */
-               events[7] |= 0x10;      /* Remote Host Supported
-                                        * Features Notification */
-       }
-
-       if (dev->features[4] & LMP_LE)
-               events[7] |= 0x20;      /* LE Meta-Event */
-
-       hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_SET_EVENT_MASK,
-                                               sizeof(events), events);
-}
-
-static void start_adapter(int index)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t inqmode;
-       uint16_t link_policy;
-
-       set_event_mask(index);
-
-       if (dev->features[6] & LMP_SIMPLE_PAIR)
-               init_ssp_mode(index);
-
-       inqmode = get_inquiry_mode(index);
-       if (inqmode)
-               write_inq_mode(index, inqmode);
-
-       if (dev->features[7] & LMP_INQ_TX_PWR)
-               hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                               OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL, 0, NULL);
-
-       /* Set default link policy */
-       link_policy = main_opts.link_policy;
-
-       if (!(dev->features[0] & LMP_RSWITCH))
-               link_policy &= ~HCI_LP_RSWITCH;
-       if (!(dev->features[0] & LMP_HOLD))
-               link_policy &= ~HCI_LP_HOLD;
-       if (!(dev->features[0] & LMP_SNIFF))
-               link_policy &= ~HCI_LP_SNIFF;
-       if (!(dev->features[1] & LMP_PARK))
-               link_policy &= ~HCI_LP_PARK;
-
-       link_policy = htobs(link_policy);
-       hci_send_cmd(dev->sk, OGF_LINK_POLICY, OCF_WRITE_DEFAULT_LINK_POLICY,
-                                       sizeof(link_policy), &link_policy);
-
-       dev->current_cod = 0;
-       memset(dev->eir, 0, sizeof(dev->eir));
-}
-
-static int hciops_stop_inquiry(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_INQUIRY_CANCEL, 0, 0) < 0)
-               return -errno;
-
-       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, major, minor;
-       gboolean pairable, discoverable;
-       const char *name;
-       uint16_t discoverable_timeout;
-
-       if (!dev->registered) {
-               adapter = btd_manager_register_adapter(index, TRUE);
-               if (adapter)
-                       dev->registered = TRUE;
-       } else {
-               adapter = manager_find_adapter(&dev->bdaddr);
-               /* FIXME: manager_find_adapter should return a new ref */
-               btd_adapter_ref(adapter);
-       }
-
-       if (adapter == NULL)
-               return FALSE;
-
-       btd_adapter_get_mode(adapter, &mode, &on_mode,
-                                               &discoverable_timeout,
-                                               &pairable);
-
-       if (existing_adapter)
-               mode = on_mode;
-
-       if (mode == MODE_OFF) {
-               hciops_power_off(index);
-               goto done;
-       }
-
-       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, discoverable_timeout);
-       hciops_set_pairable(index, pairable);
-
-       if (dev->already_up)
-               hciops_stop_inquiry(index);
-
-done:
-       btd_adapter_unref(adapter);
-       return TRUE;
-}
-
-static int hciops_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
-                                                       gpointer user_data)
-{
-       GIOChannel *io;
-       struct hci_cmd_data *cmd;
-       struct hci_conn_info_req *cr;
-       auth_requested_cp cp;
-       struct hci_filter nf;
-       int dd, err;
-       uint32_t link_mode;
-       uint16_t handle;
-
-       dd = hci_open_dev(index);
-       if (dd < 0)
-               return -errno;
-
-       cr = g_malloc0(sizeof(*cr) + sizeof(struct hci_conn_info));
-       cr->type = ACL_LINK;
-       bacpy(&cr->bdaddr, dst);
-
-       err = ioctl(dd, HCIGETCONNINFO, cr);
-       link_mode = cr->conn_info->link_mode;
-       handle = cr->conn_info->handle;
-       g_free(cr);
-
-       if (err < 0) {
-               err = -errno;
-               goto fail;
-       }
-
-       if (link_mode & HCI_LM_ENCRYPT) {
-               err = -EALREADY;
-               goto fail;
-       }
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(handle);
-
-       if (hci_send_cmd(dd, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-                               AUTH_REQUESTED_CP_SIZE, &cp) < 0) {
-               err = -errno;
-               goto fail;
-       }
-
-       cmd = g_new0(struct hci_cmd_data, 1);
-       cmd->handle = handle;
-       cmd->ocf = OCF_AUTH_REQUESTED;
-       cmd->cb = cb;
-       cmd->caller_data = user_data;
-
-       hci_filter_clear(&nf);
-       hci_filter_set_ptype(HCI_EVENT_PKT, &nf);
-       hci_filter_set_event(EVT_CMD_STATUS, &nf);
-       hci_filter_set_event(EVT_AUTH_COMPLETE, &nf);
-       hci_filter_set_event(EVT_ENCRYPT_CHANGE, &nf);
-
-       if (setsockopt(dd, SOL_HCI, HCI_FILTER, &nf, sizeof(nf)) < 0) {
-               err = -errno;
-               g_free(cmd);
-               goto fail;
-       }
-
-       io = g_io_channel_unix_new(dd);
-       g_io_channel_set_close_on_unref(io, FALSE);
-       g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
-                       G_IO_HUP | G_IO_ERR | G_IO_NVAL | G_IO_IN,
-                       hci_event_watch, cmd, g_free);
-       g_io_channel_unref(io);
-
-       return 0;
-
-fail:
-       close(dd);
-       return err;
-}
-
-static int hciops_set_did(int index, uint16_t vendor, uint16_t product,
-                                       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;
-}
-
-/* End async HCI command handling */
-
-/* Start of HCI event callbacks */
-
-static gint conn_handle_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct bt_conn *conn = a;
-       uint16_t handle = *((const uint16_t *) b);
-
-       return (int) conn->handle - (int) handle;
-}
-
-static struct bt_conn *find_conn_by_handle(struct dev_info *dev,
-                                                       uint16_t handle)
-{
-       GSList *match;
-
-       match = g_slist_find_custom(dev->connections, &handle,
-                                                       conn_handle_cmp);
-       if (match)
-               return match->data;
-
-       return NULL;
-}
-
-static gint conn_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct bt_conn *conn = a;
-       const bdaddr_t *bdaddr = b;
-
-       return bacmp(&conn->bdaddr, bdaddr);
-}
-
-static struct bt_conn *find_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
-       GSList *match;
-
-       match = g_slist_find_custom(dev->connections, bdaddr, conn_bdaddr_cmp);
-       if (match)
-               return match->data;
-
-       return NULL;
-}
-
-static struct bt_conn *get_connection(struct dev_info *dev, bdaddr_t *bdaddr)
-{
-       struct bt_conn *conn;
-
-       conn = find_connection(dev, bdaddr);
-       if (conn)
-               return conn;
-
-       conn = g_new0(struct bt_conn, 1);
-
-       conn->dev = dev;
-       conn->loc_cap = dev->io_capability;
-       conn->loc_auth = 0xff;
-       conn->rem_auth = 0xff;
-       bacpy(&conn->bdaddr, bdaddr);
-
-       dev->connections = g_slist_append(dev->connections, conn);
-
-       return conn;
-}
-
-static int get_handle(int index, bdaddr_t *bdaddr, uint16_t *handle)
-{
-       struct dev_info *dev = &devs[index];
-       struct bt_conn *conn;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       conn = find_connection(dev, bdaddr);
-       if (conn == NULL)
-               return -ENOENT;
-
-       *handle = conn->handle;
-
-       return 0;
-}
-
-static int disconnect_addr(int index, bdaddr_t *dba, uint8_t reason)
-{
-       disconnect_cp cp;
-       uint16_t handle;
-       int err;
-
-       err = get_handle(index, dba, &handle);
-       if (err < 0)
-               return err;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(handle);
-       cp.reason = reason;
-
-       if (hci_send_cmd(devs[index].sk, OGF_LINK_CTL, OCF_DISCONNECT,
-                                               DISCONNECT_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static void bonding_complete(struct dev_info *dev, struct bt_conn *conn,
-                                                               uint8_t status)
-{
-       struct btd_adapter *adapter;
-
-       DBG("status 0x%02x", status);
-
-       if (conn->io != NULL) {
-               /* bonding_connect_cb takes care of the successul case */
-               if (status != 0)
-                       g_io_channel_shutdown(conn->io, TRUE, NULL);
-               g_io_channel_unref(conn->io);
-               conn->io = NULL;
-       }
-
-       conn->bonding_initiator = FALSE;
-
-       adapter = manager_find_adapter(&dev->bdaddr);
-       if (adapter)
-               adapter_bonding_complete(adapter, &conn->bdaddr, status);
-}
-
-static int get_auth_info(int index, bdaddr_t *bdaddr, uint8_t *auth)
-{
-       struct dev_info *dev = &devs[index];
-       struct hci_auth_info_req req;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       memset(&req, 0, sizeof(req));
-       bacpy(&req.bdaddr, bdaddr);
-
-       if (ioctl(dev->sk, HCIGETAUTHINFO, (unsigned long) &req) < 0)
-               return -errno;
-
-       if (auth)
-               *auth = req.type;
-
-       return 0;
-}
-
-/* Link Key handling */
-
-static void link_key_request(int index, bdaddr_t *dba)
-{
-       struct dev_info *dev = &devs[index];
-       struct link_key_info *key_info;
-       struct bt_conn *conn;
-       GSList *match;
-       char da[18];
-
-       ba2str(dba, da);
-       DBG("hci%d dba %s", index, da);
-
-       conn = get_connection(dev, dba);
-       if (conn->handle == 0)
-               conn->secmode3 = TRUE;
-
-       get_auth_info(index, dba, &conn->loc_auth);
-
-       DBG("kernel auth requirements = 0x%02x", conn->loc_auth);
-
-       match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
-       if (match)
-               key_info = match->data;
-       else
-               key_info = NULL;
-
-       DBG("Matching key %s", key_info ? "found" : "not found");
-
-       if (key_info == NULL || (!dev->debug_keys && key_info->type == 0x03)) {
-               /* Link key not found */
-               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
-                                                               6, dba);
-               return;
-       }
-
-       /* Link key found */
-
-       DBG("link key type 0x%02x", key_info->type);
-
-       /* Don't use unauthenticated combination keys if MITM is
-        * required */
-       if (key_info->type == 0x04 && conn->loc_auth != 0xff &&
-                                               (conn->loc_auth & 0x01))
-               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_NEG_REPLY,
-                                                               6, dba);
-       else {
-               link_key_reply_cp lr;
-
-               memcpy(lr.link_key, key_info->key, 16);
-               bacpy(&lr.bdaddr, dba);
-
-               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_LINK_KEY_REPLY,
-                                               LINK_KEY_REPLY_CP_SIZE, &lr);
-       }
-}
-
-static void link_key_notify(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_link_key_notify *evt = ptr;
-       bdaddr_t *dba = &evt->bdaddr;
-       struct link_key_info *key_info;
-       uint8_t old_key_type, key_type;
-       struct bt_conn *conn;
-       GSList *match;
-       char da[18];
-       uint8_t status = 0;
-
-       ba2str(dba, da);
-       DBG("hci%d dba %s type %d", index, da, evt->key_type);
-
-       conn = get_connection(dev, &evt->bdaddr);
-
-       match = g_slist_find_custom(dev->keys, dba, (GCompareFunc) bacmp);
-       if (match)
-               key_info = match->data;
-       else
-               key_info = NULL;
-
-       if (key_info == NULL) {
-               key_info = g_new0(struct link_key_info, 1);
-               bacpy(&key_info->bdaddr, &evt->bdaddr);
-               old_key_type = 0xff;
-       } else {
-               dev->keys = g_slist_remove(dev->keys, key_info);
-               old_key_type = key_info->type;
-       }
-
-       memcpy(key_info->key, evt->link_key, sizeof(evt->link_key));
-       key_info->type = evt->key_type;
-       key_info->pin_len = dev->pin_length;
-
-       key_type = evt->key_type;
-
-       DBG("key type 0x%02x old key type 0x%02x", key_type, old_key_type);
-       DBG("local auth 0x%02x and remote auth 0x%02x",
-                                       conn->loc_auth, conn->rem_auth);
-
-       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 = HCI_LK_COMBINATION;
-               else if (old_key_type != 0xff)
-                       key_type = old_key_type;
-               else
-                       /* This is Changed Combination Link Key for
-                        * a temporary link key.*/
-                       goto done;
-       }
-
-       key_info->type = key_type;
-
-       /* Skip the storage check if this is a debug key */
-       if (key_type == HCI_LK_DEBUG_COMBINATION)
-               goto done;
-
-       /* Store the link key persistently if one of the following is true:
-        * 1. this is a legacy link key
-        * 2. this is a changed combination key and there was a previously
-        *    stored one
-        * 3. neither local nor remote side had no-bonding as a requirement
-        * 4. the local side had dedicated bonding as a requirement
-        * 5. the remote side is using dedicated bonding since in that case
-        *    also the local requirements are set to dedicated bonding
-        * If none of the above match only keep the link key around for
-        * this connection and set the temporary flag for the device.
-        */
-       if (key_type < 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)) {
-               int err;
-
-               err = btd_event_link_key_notify(&dev->bdaddr, dba,
-                                               evt->link_key, key_type,
-                                               dev->pin_length);
-
-               if (err == -ENODEV)
-                       status = HCI_OE_LOW_RESOURCES;
-               else if (err < 0)
-                       status = HCI_MEMORY_FULL;
-
-               goto done;
-       }
-
-done:
-       dev->pin_length = 0;
-
-       if (status != 0) {
-               g_free(key_info);
-               bonding_complete(dev, conn, status);
-               disconnect_addr(index, dba, status);
-               return;
-       }
-
-       dev->keys = g_slist_prepend(dev->keys, key_info);
-
-       /* If we're connected and not dedicated bonding initiators we're
-        * done with the bonding process */
-       if (!conn->bonding_initiator && conn->handle != 0)
-               bonding_complete(dev, conn, 0);
-}
-
-static void return_link_keys(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_return_link_keys *evt = ptr;
-       uint8_t num = evt->num_keys;
-       unsigned char key[16];
-       char da[18];
-       bdaddr_t dba;
-       int i;
-
-       DBG("hci%d num_keys %u", index, num);
-
-       ptr++;
-
-       for (i = 0; i < num; i++) {
-               bacpy(&dba, ptr); ba2str(&dba, da);
-               memcpy(key, ptr + 6, 16);
-
-               DBG("hci%d returned key for %s", index, da);
-
-               btd_event_returned_link_key(&dev->bdaddr, &dba);
-
-               ptr += 22;
-       }
-}
-
-/* Simple Pairing handling */
-
-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;
-       char addr[18];
-       int err;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s success %d", index, addr, success);
-
-       memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
-
-       if (success)
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_USER_CONFIRM_REPLY,
-                                       USER_CONFIRM_REPLY_CP_SIZE, &cp);
-       else
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_USER_CONFIRM_NEG_REPLY,
-                                       USER_CONFIRM_REPLY_CP_SIZE, &cp);
-
-       if (err < 0)
-               err = -errno;
-
-       return err;
-}
-
-static void user_confirm_request(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_user_confirm_request *req = ptr;
-       gboolean loc_mitm, rem_mitm;
-       struct bt_conn *conn;
-
-       DBG("hci%d", index);
-
-       conn = find_connection(dev, &req->bdaddr);
-       if (conn == NULL)
-               return;
-
-       loc_mitm = (conn->loc_auth & 0x01) ? TRUE : FALSE;
-       rem_mitm = (conn->rem_auth & 0x01) ? TRUE : FALSE;
-
-       /* If we require MITM but the remote device can't provide that
-        * (it has NoInputNoOutput) then reject the confirmation
-        * request. The only exception is when we're dedicated bonding
-        * initiators since then we always have the MITM bit set. */
-       if (!conn->bonding_initiator && loc_mitm && conn->rem_cap == 0x03) {
-               error("Rejecting request: remote device can't provide MITM");
-               goto fail;
-       }
-
-       /* If no side requires MITM protection; auto-accept */
-       if ((conn->loc_auth == 0xff || !loc_mitm || conn->rem_cap == 0x03) &&
-                                       (!rem_mitm || conn->loc_cap == 0x03)) {
-               DBG("auto accept of confirmation");
-
-               /* Wait 5 milliseconds before doing auto-accept */
-               usleep(5000);
-
-               if (hciops_confirm_reply(index, &req->bdaddr,
-                                               BDADDR_BREDR, TRUE) < 0)
-                       goto fail;
-
-               return;
-       }
-
-       if (btd_event_user_confirm(&dev->bdaddr, &req->bdaddr,
-                                               btohl(req->passkey)) == 0)
-               return;
-
-fail:
-       hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_USER_CONFIRM_NEG_REPLY,
-                                                               6, ptr);
-}
-
-static void user_passkey_request(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_user_passkey_request *req = ptr;
-
-       DBG("hci%d", index);
-
-       if (btd_event_user_passkey(&dev->bdaddr, &req->bdaddr) < 0)
-               hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                               OCF_USER_PASSKEY_NEG_REPLY, 6, ptr);
-}
-
-static void user_passkey_notify(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_user_passkey_notify *req = ptr;
-
-       DBG("hci%d", index);
-
-       btd_event_user_notify(&dev->bdaddr, &req->bdaddr,
-                                               btohl(req->passkey));
-}
-
-static gint oob_bdaddr_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct oob_data *data = a;
-       const bdaddr_t *bdaddr = b;
-
-       return bacmp(&data->bdaddr, bdaddr);
-}
-
-static void remote_oob_data_request(int index, bdaddr_t *bdaddr)
-{
-       struct dev_info *dev = &devs[index];
-       GSList *match;
-
-       DBG("hci%d", index);
-
-       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-       if (match) {
-               struct oob_data *data;
-               remote_oob_data_reply_cp cp;
-
-               data = match->data;
-
-               bacpy(&cp.bdaddr, &data->bdaddr);
-               memcpy(cp.hash, data->hash, sizeof(cp.hash));
-               memcpy(cp.randomizer, data->randomizer, sizeof(cp.randomizer));
-
-               dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
-               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_REMOTE_OOB_DATA_REPLY,
-                               REMOTE_OOB_DATA_REPLY_CP_SIZE, &cp);
-
-       } else {
-               hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                               OCF_REMOTE_OOB_DATA_NEG_REPLY, 6, bdaddr);
-       }
-}
-
-static int get_io_cap(int index, bdaddr_t *bdaddr, uint8_t *cap, uint8_t *auth)
-{
-       struct dev_info *dev = &devs[index];
-       struct bt_conn *conn;
-       int err;
-
-       conn = find_connection(dev, bdaddr);
-       if (conn == NULL)
-               return -ENOENT;
-
-       err = get_auth_info(index, bdaddr, &conn->loc_auth);
-       if (err < 0)
-               return err;
-
-       DBG("initial authentication requirement is 0x%02x", conn->loc_auth);
-
-       if (!dev->pairable && !conn->bonding_initiator) {
-               if (conn->rem_auth < 0x02) {
-                       DBG("Allowing no bonding in non-bondable mode");
-                       /* Kernel defaults to general bonding and so
-                        * overwrite for this special case. Otherwise
-                        * non-pairable test cases will fail. */
-                       conn->loc_auth = conn->rem_auth;
-                       goto done;
-               }
-
-               return -EPERM;
-       }
-
-       /* If the kernel doesn't know the local requirement just mirror
-        * the remote one */
-       if (conn->loc_auth == 0xff)
-               conn->loc_auth = conn->rem_auth;
-
-       if (conn->loc_auth == 0x00 || conn->loc_auth == 0x04) {
-               /* If remote requests dedicated bonding follow that lead */
-               if (conn->rem_auth == 0x02 || conn->rem_auth == 0x03) {
-
-                       /* If both remote and local IO capabilities allow MITM
-                        * then require it, otherwise don't */
-                       if (conn->rem_cap == 0x03 || conn->loc_cap == 0x03)
-                               conn->loc_auth = 0x02;
-                       else
-                               conn->loc_auth = 0x03;
-               }
-
-               /* If remote indicates no bonding then follow that. This
-                * is important since the kernel might give general bonding
-                * as default. */
-               if (conn->rem_auth == 0x00 || conn->rem_auth == 0x01)
-                       conn->loc_auth = 0x00;
-
-               /* If remote requires MITM then also require it, unless
-                * our IO capability is NoInputNoOutput (so some
-                * just-works security cases can be tested) */
-               if (conn->rem_auth != 0xff && (conn->rem_auth & 0x01) &&
-                                                       conn->loc_cap != 0x03)
-                       conn->loc_auth |= 0x01;
-       }
-
-done:
-       *cap = conn->loc_cap;
-       *auth = conn->loc_auth;
-
-       DBG("final authentication requirement is 0x%02x", *auth);
-
-       return 0;
-}
-
-static void io_capa_request(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       bdaddr_t *dba = ptr;
-       uint8_t cap, auth = 0xff;
-       char da[18];
-       int err;
-
-       ba2str(dba, da);
-       DBG("hci%d IO capability request for %s", index, da);
-
-       err = get_io_cap(index, dba, &cap, &auth);
-       if (err < 0) {
-               io_capability_neg_reply_cp cp;
-
-               error("Getting IO capability failed: %s (%d)",
-                                               strerror(-err), -err);
-
-               memset(&cp, 0, sizeof(cp));
-               bacpy(&cp.bdaddr, dba);
-               cp.reason = HCI_PAIRING_NOT_ALLOWED;
-               hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_IO_CAPABILITY_NEG_REPLY,
-                                       IO_CAPABILITY_NEG_REPLY_CP_SIZE, &cp);
-       } else {
-               io_capability_reply_cp cp;
-               struct bt_conn *conn;
-               GSList *match;
-
-               memset(&cp, 0, sizeof(cp));
-               bacpy(&cp.bdaddr, dba);
-               cp.capability = cap;
-               cp.authentication = auth;
-
-               conn = find_connection(dev, dba);
-               match = g_slist_find_custom(dev->oob_data, dba, oob_bdaddr_cmp);
-
-               if ((conn->bonding_initiator || conn->rem_oob_data == 0x01) &&
-                               match)
-                       cp.oob_data = 0x01;
-               else
-                       cp.oob_data = 0x00;
-
-               hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_IO_CAPABILITY_REPLY,
-                                       IO_CAPABILITY_REPLY_CP_SIZE, &cp);
-       }
-}
-
-static void io_capa_response(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_io_capability_response *evt = ptr;
-       struct bt_conn *conn;
-       char da[18];
-
-       ba2str(&evt->bdaddr, da);
-       DBG("hci%d IO capability response from %s", index, da);
-
-       conn = find_connection(dev, &evt->bdaddr);
-       if (conn) {
-               conn->rem_cap = evt->capability;
-               conn->rem_auth = evt->authentication;
-               conn->rem_oob_data = evt->oob_data;
-       }
-}
-
-/* PIN code handling */
-
-static void pin_code_request(int index, bdaddr_t *dba)
-{
-       struct dev_info *dev = &devs[index];
-       struct bt_conn *conn;
-       char addr[18];
-       int err;
-
-       ba2str(dba, addr);
-       DBG("hci%d PIN request for %s", index, addr);
-
-       conn = get_connection(dev, dba);
-       if (conn->handle == 0)
-               conn->secmode3 = TRUE;
-
-       /* Check if the adapter is not pairable and if there isn't a bonding in
-        * progress */
-       if (!dev->pairable && !conn->bonding_initiator) {
-               DBG("Rejecting PIN request in non-pairable mode");
-               goto reject;
-       }
-
-       err = btd_event_request_pin(&dev->bdaddr, dba, FALSE);
-       if (err < 0) {
-               error("PIN code negative reply: %s", strerror(-err));
-               goto reject;
-       }
-
-       return;
-
-reject:
-       hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_PIN_CODE_NEG_REPLY, 6, dba);
-}
-
-static inline void remote_features_notify(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_remote_host_features_notify *evt = ptr;
-
-       if (evt->features[0] & 0x01)
-               btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
-                                                                       FALSE);
-       else
-               btd_event_set_legacy_pairing(&dev->bdaddr, &evt->bdaddr,
-                                                                       TRUE);
-
-       write_features_info(&dev->bdaddr, &evt->bdaddr, NULL, evt->features);
-}
-
-static void read_local_version_complete(int index,
-                               const read_local_version_rp *rp)
-{
-       struct dev_info *dev = &devs[index];
-
-       if (rp->status)
-               return;
-
-       dev->ver.manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
-       dev->ver.hci_ver = rp->hci_ver;
-       dev->ver.hci_rev = btohs(bt_get_unaligned(&rp->hci_rev));
-       dev->ver.lmp_ver = rp->lmp_ver;
-       dev->ver.lmp_subver = btohs(bt_get_unaligned(&rp->lmp_subver));
-
-       if (!dev->pending)
-               return;
-
-       hci_clear_bit(PENDING_VERSION, &dev->pending);
-
-       DBG("Got version for hci%d", index);
-
-       if (!dev->pending && dev->up)
-               init_adapter(index);
-}
-
-static void read_local_features_complete(int index,
-                               const read_local_features_rp *rp)
-{
-       struct dev_info *dev = &devs[index];
-
-       if (rp->status)
-               return;
-
-       memcpy(dev->features, rp->features, 8);
-
-       if (!dev->pending)
-               return;
-
-       hci_clear_bit(PENDING_FEATURES, &dev->pending);
-
-       DBG("Got features for hci%d", index);
-
-       if (!dev->pending && dev->up)
-               init_adapter(index);
-}
-
-static void update_name(int index, const char *name)
-{
-       struct btd_adapter *adapter;
-
-       adapter = manager_find_adapter_by_id(index);
-       if (adapter)
-               adapter_name_changed(adapter, name);
-
-       update_ext_inquiry_response(index);
-}
-
-static void read_local_name_complete(int index, read_local_name_rp *rp)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d status %u", index, rp->status);
-
-       if (rp->status)
-               return;
-
-       memcpy(dev->name, rp->name, 248);
-
-       if (!dev->pending) {
-               update_name(index, (char *) rp->name);
-               return;
-       }
-
-       hci_clear_bit(PENDING_NAME, &dev->pending);
-
-       DBG("Got name for hci%d", index);
-
-       if (!dev->pending && dev->up)
-               init_adapter(index);
-}
-
-static void read_tx_power_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-
-       read_inq_response_tx_power_level_rp *rp = ptr;
-
-       DBG("hci%d status %u", index, rp->status);
-
-       if (rp->status)
-               return;
-
-       dev->tx_power = rp->level;
-       update_ext_inquiry_response(index);
-}
-
-static void read_simple_pairing_mode_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       read_simple_pairing_mode_rp *rp = ptr;
-
-       DBG("hci%d status %u", index, rp->status);
-
-       if (rp->status)
-               return;
-
-       dev->ssp_mode = rp->mode;
-       update_ext_inquiry_response(index);
-}
-
-static void read_local_ext_features_complete(int index,
-                               const read_local_ext_features_rp *rp)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d status %u", index, rp->status);
-
-       if (rp->status)
-               return;
-
-       /* Local Extended feature page number is 1 */
-       if (rp->page_num != 1)
-               return;
-
-       memcpy(dev->extfeatures, rp->features, sizeof(dev->extfeatures));
-}
-
-static void read_bd_addr_complete(int index, read_bd_addr_rp *rp)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d status %u", index, rp->status);
-
-       if (rp->status)
-               return;
-
-       bacpy(&dev->bdaddr, &rp->bdaddr);
-
-       if (!dev->pending)
-               return;
-
-       hci_clear_bit(PENDING_BDADDR, &dev->pending);
-
-       DBG("Got bdaddr for hci%d", index);
-
-       if (!dev->pending && dev->up)
-               init_adapter(index);
-}
-
-static inline void cs_inquiry_evt(int index, uint8_t status)
-{
-       if (status) {
-               error("Inquiry Failed with status 0x%02x", status);
-               return;
-       }
-
-       set_state(index, DISCOV_INQ);
-}
-
-static inline void cmd_status(int index, void *ptr)
-{
-       evt_cmd_status *evt = ptr;
-       uint16_t opcode = btohs(evt->opcode);
-
-       if (opcode == cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY))
-               cs_inquiry_evt(index, evt->status);
-}
-
-static gboolean discoverable_timeout_handler(gpointer user_data)
-{
-       struct dev_info *dev = user_data;
-
-       hciops_set_discoverable(dev->id, FALSE, 0);
-
-       return FALSE;
-}
-
-/* Limited Discoverable bit mask in CoD */
-#define LIMITED_BIT                    0x002000
-
-static int hciops_set_limited_discoverable(int index, gboolean limited)
-{
-       struct dev_info *dev = &devs[index];
-       int num = (limited ? 2 : 1);
-       uint8_t lap[] = { 0x33, 0x8b, 0x9e, 0x00, 0x8b, 0x9e };
-       write_current_iac_lap_cp cp;
-
-       DBG("hci%d limited %d", index, limited);
-
-       /* Check if limited bit needs to be set/reset */
-       if (limited)
-               dev->wanted_cod |= LIMITED_BIT;
-       else
-               dev->wanted_cod &= ~LIMITED_BIT;
-
-       /* If we dont need the toggling, save an unnecessary CoD write */
-       if (dev->pending_cod || dev->wanted_cod == dev->current_cod)
-               return 0;
-
-       /*
-        * 1: giac
-        * 2: giac + liac
-        */
-       memset(&cp, 0, sizeof(cp));
-       cp.num_current_iac = num;
-       memcpy(&cp.lap, lap, num * 3);
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_CURRENT_IAC_LAP,
-                                               (num * 3 + 1), &cp) < 0)
-               return -errno;
-
-       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];
-       struct btd_adapter *adapter;
-
-       if (status)
-               return;
-
-       if (dev->pending_cod == 0)
-               return;
-
-       dev->current_cod = dev->pending_cod;
-       dev->pending_cod = 0;
-
-       adapter = manager_find_adapter(&dev->bdaddr);
-       if (adapter)
-               btd_adapter_class_changed(adapter, dev->current_cod);
-
-       update_ext_inquiry_response(index);
-
-       if (dev->wanted_cod == dev->current_cod)
-               return;
-
-       if (dev->wanted_cod & LIMITED_BIT &&
-                       !(dev->current_cod & LIMITED_BIT))
-               hciops_set_limited_discoverable(index, TRUE);
-       else if (!(dev->wanted_cod & LIMITED_BIT) &&
-                                       (dev->current_cod & LIMITED_BIT))
-               hciops_set_limited_discoverable(index, FALSE);
-       else
-               write_class(index, dev->wanted_cod);
-}
-
-static void read_local_oob_data_complete(int index, uint8_t status,
-                                               read_local_oob_data_rp *rp)
-{
-       struct btd_adapter *adapter = manager_find_adapter_by_id(index);
-
-       if (!adapter)
-               return;
-
-       if (status)
-               oob_read_local_data_complete(adapter, NULL, NULL);
-       else
-               oob_read_local_data_complete(adapter, rp->hash, rp->randomizer);
-}
-
-static inline void inquiry_complete_evt(int index, uint8_t status)
-{
-       int adapter_type;
-       struct btd_adapter *adapter;
-
-       if (status) {
-               error("Inquiry Failed with status 0x%02x", status);
-               return;
-       }
-
-       adapter = manager_find_adapter_by_id(index);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       adapter_type = get_adapter_type(index);
-
-       if (adapter_type == BR_EDR_LE &&
-                       start_scanning(index, TIMEOUT_BR_LE_SCAN) == 0)
-               return;
-
-       set_state(index, DISCOV_NAMES);
-}
-
-static inline void cc_inquiry_cancel(int index, uint8_t status)
-{
-       if (status) {
-               error("Inquiry Cancel Failed with status 0x%02x", status);
-               return;
-       }
-
-       set_state(index, DISCOV_HALTED);
-}
-
-static inline void cc_le_set_scan_enable(int index, uint8_t status)
-{
-       struct dev_info *info = &devs[index];
-
-       if (status) {
-               error("LE Set Scan Enable Failed with status 0x%02x", status);
-               return;
-       }
-
-       if (info->discov_state == DISCOV_SCAN)
-               set_state(index, DISCOV_HALTED);
-       else
-               set_state(index, DISCOV_SCAN);
-}
-
-static inline void cmd_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_cmd_complete *evt = ptr;
-       uint16_t opcode = btohs(evt->opcode);
-       uint8_t status = *((uint8_t *) ptr + EVT_CMD_COMPLETE_SIZE);
-
-       switch (opcode) {
-       case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION):
-               ptr += sizeof(evt_cmd_complete);
-               read_local_version_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_FEATURES):
-               ptr += sizeof(evt_cmd_complete);
-               read_local_features_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_EXT_FEATURES):
-               ptr += sizeof(evt_cmd_complete);
-               read_local_ext_features_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_BD_ADDR):
-               ptr += sizeof(evt_cmd_complete);
-               read_bd_addr_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_LINK_CTL, OCF_INQUIRY_CANCEL):
-               cc_inquiry_cancel(index, status);
-               break;
-       case cmd_opcode_pack(OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE):
-               cc_le_set_scan_enable(index, status);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_CHANGE_LOCAL_NAME):
-               if (!status)
-                       hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                                               OCF_READ_LOCAL_NAME, 0, 0);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SCAN_ENABLE):
-               hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_SCAN_ENABLE,
-                                                               0, NULL);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SCAN_ENABLE):
-               ptr += sizeof(evt_cmd_complete);
-               read_scan_complete(index, status, ptr);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_CLASS_OF_DEV):
-               write_class_complete(index, status);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_WRITE_SIMPLE_PAIRING_MODE):
-               if (!status)
-                       hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                                       OCF_READ_SIMPLE_PAIRING_MODE, 0, NULL);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_SIMPLE_PAIRING_MODE):
-               ptr += sizeof(evt_cmd_complete);
-               read_simple_pairing_mode_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_NAME):
-               ptr += sizeof(evt_cmd_complete);
-               read_local_name_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL,
-                                       OCF_READ_INQ_RESPONSE_TX_POWER_LEVEL):
-               ptr += sizeof(evt_cmd_complete);
-               read_tx_power_complete(index, ptr);
-               break;
-       case cmd_opcode_pack(OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA):
-               ptr += sizeof(evt_cmd_complete);
-               read_local_oob_data_complete(index, status, ptr);
-               break;
-       };
-}
-
-static inline void remote_name_information(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_remote_name_req_complete *evt = ptr;
-       struct btd_adapter *adapter;
-       char name[MAX_NAME_LENGTH + 1];
-       struct found_dev *found;
-
-       GSList *match;
-
-       DBG("hci%d status %u", index, evt->status);
-
-       memset(name, 0, sizeof(name));
-
-       if (evt->status == 0) {
-               memcpy(name, evt->name, MAX_NAME_LENGTH);
-               btd_event_remote_name(&dev->bdaddr, &evt->bdaddr, name);
-       }
-
-       adapter = manager_find_adapter_by_id(index);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       match = g_slist_find_custom(dev->need_name, &evt->bdaddr,
-                                                       found_dev_bda_cmp);
-       if (match == NULL)
-               return;
-
-       found = match->data;
-       found->name_state = NAME_NOT_NEEDED;
-
-       dev->need_name = g_slist_remove_link(dev->need_name, match);
-
-       match->next = dev->found_devs;
-       dev->found_devs = match;
-       dev->found_devs = g_slist_sort(dev->found_devs, found_dev_rssi_cmp);
-
-       if (resolve_names(dev, adapter) < 0)
-               set_state(index, DISCOV_HALTED);
-}
-
-static inline void remote_version_information(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_read_remote_version_complete *evt = ptr;
-       struct bt_conn *conn;
-
-       DBG("hci%d status %u", index, evt->status);
-
-       if (evt->status)
-               return;
-
-       conn = find_conn_by_handle(dev, btohs(evt->handle));
-       if (conn == NULL)
-               return;
-
-       write_version_info(&dev->bdaddr, &conn->bdaddr,
-                               btohs(evt->manufacturer), evt->lmp_ver,
-                               btohs(evt->lmp_subver));
-}
-
-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;
-
-       match = g_slist_find_custom(info->found_devs, dba, found_dev_bda_cmp);
-       if (match != NULL) {
-               cfm_name = 0;
-               goto event;
-       }
-
-       dev = g_new0(struct found_dev, 1);
-       bacpy(&dev->bdaddr, dba);
-       dev->rssi = rssi;
-       if (cfm_name)
-               dev->name_state = NAME_UNKNOWN;
-       else
-               dev->name_state = NAME_NOT_NEEDED;
-
-       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, bdaddr_type, rssi, cfm_name,
-                                                               eir, eir_len);
-}
-
-static inline void inquiry_result(int index, int plen, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t num = *(uint8_t *) ptr++;
-       int i;
-
-       for (i = 0; i < num; i++) {
-               inquiry_info *info = ptr;
-               uint8_t eir[5];
-
-               memset(eir, 0, sizeof(eir));
-               dev_found(dev, &info->bdaddr, BDADDR_BREDR, info->dev_class,
-                                                               0, 1, eir, 0);
-               ptr += INQUIRY_INFO_SIZE;
-       }
-}
-
-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)
-               return;
-
-       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;
-
-                       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;
-
-                       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;
-               }
-       }
-}
-
-static inline void extended_inquiry_result(int index, int plen, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t num = *(uint8_t *) ptr++;
-       int i;
-
-       for (i = 0; i < num; i++) {
-               extended_inquiry_info *info = ptr;
-               uint8_t eir[sizeof(info->data) + 5];
-               gboolean cfm_name;
-               size_t eir_len;
-
-               eir_len = eir_length(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, BDADDR_BREDR, info->dev_class,
-                                       info->rssi, cfm_name, eir, eir_len);
-               ptr += EXTENDED_INQUIRY_INFO_SIZE;
-       }
-}
-
-static inline void remote_features_information(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_read_remote_features_complete *evt = ptr;
-       struct bt_conn *conn;
-
-       DBG("hci%d status %u", index, evt->status);
-
-       if (evt->status)
-               return;
-
-       conn = find_conn_by_handle(dev, btohs(evt->handle));
-       if (conn == NULL)
-               return;
-
-       write_features_info(&dev->bdaddr, &conn->bdaddr, evt->features, NULL);
-}
-
-struct remote_version_req {
-       int index;
-       uint16_t handle;
-};
-
-static gboolean __get_remote_version(gpointer user_data)
-{
-       struct remote_version_req *req = user_data;
-       struct dev_info *dev = &devs[req->index];
-       read_remote_version_cp cp;
-
-       DBG("hci%d handle %u", req->index, req->handle);
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(req->handle);
-
-       hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_READ_REMOTE_VERSION,
-                                       READ_REMOTE_VERSION_CP_SIZE, &cp);
-
-       return FALSE;
-}
-
-static void get_remote_version(int index, uint16_t handle)
-{
-       struct remote_version_req *req;
-
-       req = g_new0(struct remote_version_req, 1);
-       req->handle = handle;
-       req->index = index;
-
-       g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, 1, __get_remote_version,
-                                                               req, g_free);
-}
-
-static void conn_free(struct bt_conn *conn)
-{
-       if (conn->io != NULL) {
-               g_io_channel_shutdown(conn->io, TRUE, NULL);
-               g_io_channel_unref(conn->io);
-       }
-
-       g_free(conn);
-}
-
-static inline void conn_failed(int index, bdaddr_t *bdaddr, uint8_t status)
-{
-       struct dev_info *dev = &devs[index];
-       struct bt_conn *conn;
-
-       btd_event_conn_failed(&dev->bdaddr, bdaddr, status);
-
-       conn = find_connection(dev, bdaddr);
-       if (conn == NULL)
-               return;
-
-       bonding_complete(dev, conn, status);
-
-       dev->connections = g_slist_remove(dev->connections, conn);
-       conn_free(conn);
-}
-
-static inline void conn_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_conn_complete *evt = ptr;
-       char filename[PATH_MAX];
-       char local_addr[18], peer_addr[18], *str;
-       struct bt_conn *conn;
-
-       if (evt->link_type != ACL_LINK)
-               return;
-
-       DBG("status 0x%02x", evt->status);
-
-       if (evt->status != 0) {
-               conn_failed(index, &evt->bdaddr, evt->status);
-               return;
-       }
-
-       conn = get_connection(dev, &evt->bdaddr);
-       conn->handle = btohs(evt->handle);
-
-       btd_event_conn_complete(&dev->bdaddr, &evt->bdaddr, BDADDR_BREDR,
-                                                               NULL, NULL);
-
-       if (conn->secmode3)
-               bonding_complete(dev, conn, 0);
-
-       /* check if the remote version needs be requested */
-       ba2str(&dev->bdaddr, local_addr);
-       ba2str(&evt->bdaddr, peer_addr);
-
-       create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
-                                                       "manufacturers");
-
-       str = textfile_get(filename, peer_addr);
-       if (!str)
-               get_remote_version(index, btohs(evt->handle));
-       else
-               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];
-       evt_le_connection_complete *evt = 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,
-                                                               evt->status);
-               return;
-       }
-
-       conn = get_connection(dev, &evt->peer_bdaddr);
-       conn->handle = btohs(evt->handle);
-
-       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);
-       ba2str(&evt->peer_bdaddr, peer_addr);
-
-       create_name(filename, sizeof(filename), STORAGEDIR, local_addr,
-                                                       "manufacturers");
-
-       str = textfile_get(filename, peer_addr);
-       if (!str)
-               get_remote_version(index, btohs(evt->handle));
-       else
-               free(str);
-}
-
-static inline void disconn_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_disconn_complete *evt = ptr;
-       struct bt_conn *conn;
-
-       DBG("handle %u status 0x%02x", btohs(evt->handle), evt->status);
-
-       if (evt->status != 0)
-               return;
-
-       conn = find_conn_by_handle(dev, btohs(evt->handle));
-       if (conn == NULL)
-               return;
-
-       dev->connections = g_slist_remove(dev->connections, conn);
-
-       btd_event_disconn_complete(&dev->bdaddr, &conn->bdaddr);
-
-       conn_free(conn);
-}
-
-static inline void auth_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_auth_complete *evt = ptr;
-       struct bt_conn *conn;
-
-       DBG("hci%d status %u", index, evt->status);
-
-       conn = find_conn_by_handle(dev, btohs(evt->handle));
-       if (conn == NULL)
-               return;
-
-       bonding_complete(dev, conn, evt->status);
-}
-
-static inline void simple_pairing_complete(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_simple_pairing_complete *evt = ptr;
-
-       DBG("hci%d status %u", index, evt->status);
-
-       btd_event_simple_pairing_complete(&dev->bdaddr, &evt->bdaddr,
-                                                               evt->status);
-}
-
-static inline void conn_request(int index, void *ptr)
-{
-       struct dev_info *dev = &devs[index];
-       evt_conn_request *evt = ptr;
-       uint32_t class = evt->dev_class[0] | (evt->dev_class[1] << 8)
-                               | (evt->dev_class[2] << 16);
-
-       btd_event_remote_class(&dev->bdaddr, &evt->bdaddr, class);
-}
-
-static inline void le_advertising_report(int index, evt_le_meta_event *meta)
-{
-       struct dev_info *dev = &devs[index];
-       le_advertising_info *info;
-       uint8_t num_reports, rssi;
-       const uint8_t RSSI_SIZE = 1;
-
-       num_reports = meta->data[0];
-
-       info = (le_advertising_info *) &meta->data[1];
-       rssi = *(info->data + info->length);
-
-       dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type), NULL,
-                                       rssi, 0, info->data, info->length);
-
-       num_reports--;
-
-       while (num_reports--) {
-               info = (le_advertising_info *) (info->data + info->length +
-                                                               RSSI_SIZE);
-               rssi = *(info->data + info->length);
-
-               dev_found(dev, &info->bdaddr, le_addr_type(info->bdaddr_type),
-                               NULL, rssi, 0, info->data, info->length);
-       }
-}
-
-static inline void le_metaevent(int index, void *ptr)
-{
-       evt_le_meta_event *meta = ptr;
-
-       DBG("hci%d LE Meta Event %u", index, meta->subevent);
-
-       switch (meta->subevent) {
-       case EVT_LE_ADVERTISING_REPORT:
-               le_advertising_report(index, meta);
-               break;
-
-       case EVT_LE_CONN_COMPLETE:
-               le_conn_complete(index, meta->data);
-               break;
-       }
-}
-
-static void stop_hci_dev(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       if (dev->sk < 0)
-               return;
-
-       info("Stopping hci%d event socket", index);
-
-       if (dev->watch_id > 0)
-               g_source_remove(dev->watch_id);
-
-       if (dev->stop_scan_id > 0)
-               g_source_remove(dev->stop_scan_id);
-
-       if (dev->io != NULL)
-               g_io_channel_unref(dev->io);
-
-       hci_close_dev(dev->sk);
-
-       g_slist_free_full(dev->keys, g_free);
-       g_slist_free_full(dev->uuids, g_free);
-       g_slist_free_full(dev->connections, g_free);
-
-       init_dev_info(index, -1, dev->registered, dev->already_up);
-}
-
-static gboolean io_security_event(GIOChannel *chan, GIOCondition cond,
-                                                               gpointer data)
-{
-       unsigned char buf[HCI_MAX_EVENT_SIZE], *ptr = buf;
-       int type, index = GPOINTER_TO_INT(data);
-       struct dev_info *dev = &devs[index];
-       struct hci_dev_info di;
-       ssize_t len;
-       hci_event_hdr *eh;
-       evt_cmd_status *evt;
-       int fd;
-
-       if (cond & (G_IO_NVAL | G_IO_HUP | G_IO_ERR)) {
-               stop_hci_dev(index);
-               return FALSE;
-       }
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       len = read(fd, buf, sizeof(buf));
-       if (len < 0) {
-               if (errno == EAGAIN)
-                       return TRUE;
-               stop_hci_dev(index);
-               return FALSE;
-       }
-
-       type = *ptr++;
-
-       if (type != HCI_EVENT_PKT)
-               return TRUE;
-
-       eh = (hci_event_hdr *) ptr;
-       ptr += HCI_EVENT_HDR_SIZE;
-
-       memset(&di, 0, sizeof(di));
-       if (hci_devinfo(index, &di) == 0) {
-               bacpy(&dev->bdaddr, &di.bdaddr);
-
-               if (ignore_device(&di))
-                       return TRUE;
-       }
-
-       switch (eh->evt) {
-       case EVT_CMD_STATUS:
-               cmd_status(index, ptr);
-               break;
-
-       case EVT_CMD_COMPLETE:
-               cmd_complete(index, ptr);
-               break;
-
-       case EVT_REMOTE_NAME_REQ_COMPLETE:
-               remote_name_information(index, ptr);
-               break;
-
-       case EVT_READ_REMOTE_VERSION_COMPLETE:
-               remote_version_information(index, ptr);
-               break;
-
-       case EVT_READ_REMOTE_FEATURES_COMPLETE:
-               remote_features_information(index, ptr);
-               break;
-
-       case EVT_REMOTE_HOST_FEATURES_NOTIFY:
-               remote_features_notify(index, ptr);
-               break;
-
-       case EVT_INQUIRY_COMPLETE:
-               evt = (evt_cmd_status *) ptr;
-               inquiry_complete_evt(index, evt->status);
-               break;
-
-       case EVT_INQUIRY_RESULT:
-               inquiry_result(index, eh->plen, ptr);
-               break;
-
-       case EVT_INQUIRY_RESULT_WITH_RSSI:
-               inquiry_result_with_rssi(index, eh->plen, ptr);
-               break;
-
-       case EVT_EXTENDED_INQUIRY_RESULT:
-               extended_inquiry_result(index, eh->plen, ptr);
-               break;
-
-       case EVT_CONN_COMPLETE:
-               conn_complete(index, ptr);
-               break;
-
-       case EVT_DISCONN_COMPLETE:
-               disconn_complete(index, ptr);
-               break;
-
-       case EVT_AUTH_COMPLETE:
-               auth_complete(index, ptr);
-               break;
-
-       case EVT_SIMPLE_PAIRING_COMPLETE:
-               simple_pairing_complete(index, ptr);
-               break;
-
-       case EVT_CONN_REQUEST:
-               conn_request(index, ptr);
-               break;
-       case EVT_LE_META_EVENT:
-               le_metaevent(index, ptr);
-               break;
-       case EVT_PIN_CODE_REQ:
-               pin_code_request(index, (bdaddr_t *) ptr);
-               break;
-
-       case EVT_LINK_KEY_REQ:
-               link_key_request(index, (bdaddr_t *) ptr);
-               break;
-
-       case EVT_LINK_KEY_NOTIFY:
-               link_key_notify(index, ptr);
-               break;
-
-       case EVT_RETURN_LINK_KEYS:
-               return_link_keys(index, ptr);
-               break;
-
-       case EVT_IO_CAPABILITY_REQUEST:
-               io_capa_request(index, ptr);
-               break;
-
-       case EVT_IO_CAPABILITY_RESPONSE:
-               io_capa_response(index, ptr);
-               break;
-
-       case EVT_USER_CONFIRM_REQUEST:
-               user_confirm_request(index, ptr);
-               break;
-
-       case EVT_USER_PASSKEY_REQUEST:
-               user_passkey_request(index, ptr);
-               break;
-
-       case EVT_USER_PASSKEY_NOTIFY:
-               user_passkey_notify(index, ptr);
-               break;
-
-       case EVT_REMOTE_OOB_DATA_REQUEST:
-               remote_oob_data_request(index, (bdaddr_t *) ptr);
-               break;
-       }
-
-       return TRUE;
-}
-
-static void start_hci_dev(int index)
-{
-       struct dev_info *dev = &devs[index];
-       GIOChannel *chan = dev->io;
-       GIOCondition cond;
-       struct hci_filter flt;
-
-       if (chan)
-               return;
-
-       info("Listening for HCI events on hci%d", index);
-
-       /* Set filter */
-       hci_filter_clear(&flt);
-       hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
-       hci_filter_set_event(EVT_CMD_STATUS, &flt);
-       hci_filter_set_event(EVT_CMD_COMPLETE, &flt);
-       hci_filter_set_event(EVT_PIN_CODE_REQ, &flt);
-       hci_filter_set_event(EVT_LINK_KEY_REQ, &flt);
-       hci_filter_set_event(EVT_LINK_KEY_NOTIFY, &flt);
-       hci_filter_set_event(EVT_RETURN_LINK_KEYS, &flt);
-       hci_filter_set_event(EVT_IO_CAPABILITY_REQUEST, &flt);
-       hci_filter_set_event(EVT_IO_CAPABILITY_RESPONSE, &flt);
-       hci_filter_set_event(EVT_USER_CONFIRM_REQUEST, &flt);
-       hci_filter_set_event(EVT_USER_PASSKEY_REQUEST, &flt);
-       hci_filter_set_event(EVT_REMOTE_OOB_DATA_REQUEST, &flt);
-       hci_filter_set_event(EVT_USER_PASSKEY_NOTIFY, &flt);
-       hci_filter_set_event(EVT_KEYPRESS_NOTIFY, &flt);
-       hci_filter_set_event(EVT_SIMPLE_PAIRING_COMPLETE, &flt);
-       hci_filter_set_event(EVT_AUTH_COMPLETE, &flt);
-       hci_filter_set_event(EVT_REMOTE_NAME_REQ_COMPLETE, &flt);
-       hci_filter_set_event(EVT_READ_REMOTE_VERSION_COMPLETE, &flt);
-       hci_filter_set_event(EVT_READ_REMOTE_FEATURES_COMPLETE, &flt);
-       hci_filter_set_event(EVT_REMOTE_HOST_FEATURES_NOTIFY, &flt);
-       hci_filter_set_event(EVT_INQUIRY_COMPLETE, &flt);
-       hci_filter_set_event(EVT_INQUIRY_RESULT, &flt);
-       hci_filter_set_event(EVT_INQUIRY_RESULT_WITH_RSSI, &flt);
-       hci_filter_set_event(EVT_EXTENDED_INQUIRY_RESULT, &flt);
-       hci_filter_set_event(EVT_CONN_REQUEST, &flt);
-       hci_filter_set_event(EVT_CONN_COMPLETE, &flt);
-       hci_filter_set_event(EVT_DISCONN_COMPLETE, &flt);
-       hci_filter_set_event(EVT_LE_META_EVENT, &flt);
-       if (setsockopt(dev->sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-               error("Can't set filter on hci%d: %s (%d)",
-                                               index, strerror(errno), errno);
-               return;
-       }
-
-       chan = g_io_channel_unix_new(dev->sk);
-       cond = G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR;
-       dev->watch_id = g_io_add_watch_full(chan, G_PRIORITY_LOW, cond,
-                                               io_security_event,
-                                               GINT_TO_POINTER(index), NULL);
-       dev->io = chan;
-       dev->pin_length = 0;
-
-}
-
-/* End of HCI event callbacks */
-
-static gboolean child_exit(GIOChannel *io, GIOCondition cond, void *user_data)
-{
-       int status, fd = g_io_channel_unix_get_fd(io);
-       pid_t child_pid;
-
-       if (read(fd, &child_pid, sizeof(child_pid)) != sizeof(child_pid)) {
-               error("child_exit: unable to read child pid from pipe");
-               return TRUE;
-       }
-
-       if (waitpid(child_pid, &status, 0) != child_pid)
-               error("waitpid(%d) failed", child_pid);
-       else
-               DBG("child %d exited", child_pid);
-
-       return TRUE;
-}
-
-static void at_child_exit(void)
-{
-       pid_t pid = getpid();
-
-       if (write(child_pipe[1], &pid, sizeof(pid)) != sizeof(pid))
-               error("unable to write to child pipe");
-}
-
-static void device_devup_setup(int index)
-{
-       struct dev_info *dev = &devs[index];
-       struct hci_dev_info di;
-       read_stored_link_key_cp cp;
-
-       DBG("hci%d", index);
-
-       if (hci_devinfo(index, &di) < 0)
-               return;
-
-       if (ignore_device(&di))
-               return;
-
-       bacpy(&dev->bdaddr, &di.bdaddr);
-       memcpy(dev->features, di.features, 8);
-
-       if (dev->features[7] & LMP_EXT_FEAT) {
-               uint8_t page_num = 0x01;
-
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                               OCF_READ_LOCAL_EXT_FEATURES, 1, &page_num);
-       }
-
-       /* Set page timeout */
-       if ((main_opts.flags & (1 << HCID_SET_PAGETO))) {
-               write_page_timeout_cp cp;
-
-               cp.timeout = htobs(main_opts.pageto);
-               hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_TIMEOUT,
-                                       WRITE_PAGE_TIMEOUT_CP_SIZE, &cp);
-       }
-
-       bacpy(&cp.bdaddr, BDADDR_ANY);
-       cp.read_all = 1;
-       hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_STORED_LINK_KEY,
-                                       READ_STORED_LINK_KEY_CP_SIZE, &cp);
-
-       if (!dev->pending) {
-               init_adapter(index);
-               return;
-       }
-
-       /* Even though it shouldn't happen (assuming the kernel behaves
-        * properly) it seems like we might miss the very first
-        * initialization commands that the kernel sends. So check for
-        * it here and resend the ones we haven't seen their results yet */
-
-       if (hci_test_bit(PENDING_FEATURES, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_LOCAL_FEATURES, 0, NULL);
-
-       if (hci_test_bit(PENDING_VERSION, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_LOCAL_VERSION, 0, NULL);
-
-       if (hci_test_bit(PENDING_NAME, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                                       OCF_READ_LOCAL_NAME, 0, 0);
-
-       if (hci_test_bit(PENDING_BDADDR, &dev->pending))
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_BD_ADDR, 0, NULL);
-}
-
-static void init_pending(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       hci_set_bit(PENDING_BDADDR, &dev->pending);
-       hci_set_bit(PENDING_VERSION, &dev->pending);
-       hci_set_bit(PENDING_FEATURES, &dev->pending);
-       hci_set_bit(PENDING_NAME, &dev->pending);
-}
-
-static struct dev_info *init_device(int index, gboolean already_up)
-{
-       struct dev_info *dev;
-       struct hci_dev_req dr;
-       int dd;
-       pid_t pid;
-
-       DBG("hci%d", index);
-
-       dd = hci_open_dev(index);
-       if (dd < 0) {
-               error("Unable to open hci%d: %s (%d)", index,
-                                               strerror(errno), errno);
-               return NULL;
-       }
-
-       if (index > max_dev) {
-               max_dev = index;
-               devs = g_realloc(devs, sizeof(devs[0]) * (max_dev + 1));
-       }
-
-       dev = init_dev_info(index, dd, FALSE, already_up);
-       init_pending(index);
-       start_hci_dev(index);
-
-       /* Avoid forking if nothing else has to be done */
-       if (already_up)
-               return dev;
-
-       /* Do initialization in the separate process */
-       pid = fork();
-       switch (pid) {
-               case 0:
-                       atexit(at_child_exit);
-                       break;
-               case -1:
-                       error("Fork failed. Can't init device hci%d: %s (%d)",
-                                       index, strerror(errno), errno);
-               default:
-                       DBG("child %d forked", pid);
-                       return dev;
-       }
-
-       memset(&dr, 0, sizeof(dr));
-       dr.dev_id = index;
-
-       /* Set link mode */
-       dr.dev_opt = main_opts.link_mode;
-       if (ioctl(dd, HCISETLINKMODE, (unsigned long) &dr) < 0)
-               error("Can't set link mode on hci%d: %s (%d)",
-                                               index, strerror(errno), errno);
-
-       /* Start HCI device */
-       if (ioctl(dd, HCIDEVUP, index) < 0 && errno != EALREADY) {
-               error("Can't init device hci%d: %s (%d)",
-                                       index, strerror(errno), errno);
-               goto fail;
-       }
-
-       hci_close_dev(dd);
-       exit(0);
-
-fail:
-       hci_close_dev(dd);
-       exit(1);
-}
-
-static void init_conn_list(int index)
-{
-       struct dev_info *dev = &devs[index];
-       struct hci_conn_list_req *cl;
-       struct hci_conn_info *ci;
-       int i;
-
-       DBG("hci%d", index);
-
-       cl = g_malloc0(10 * sizeof(*ci) + sizeof(*cl));
-
-       cl->dev_id = index;
-       cl->conn_num = 10;
-       ci = cl->conn_info;
-
-       if (ioctl(dev->sk, HCIGETCONNLIST, cl) < 0) {
-               error("Unable to get connection list: %s (%d)",
-                                               strerror(errno), errno);
-               goto failed;
-       }
-
-       for (i = 0; i < cl->conn_num; i++, ci++) {
-               struct bt_conn *conn;
-
-               if (ci->type != ACL_LINK)
-                       continue;
-
-               conn = get_connection(dev, &ci->bdaddr);
-               conn->handle = ci->handle;
-       }
-
-failed:
-       g_free(cl);
-}
-
-static void device_event(int event, int index)
-{
-       switch (event) {
-       case HCI_DEV_REG:
-               info("HCI dev %d registered", index);
-               init_device(index, FALSE);
-               break;
-
-       case HCI_DEV_UNREG:
-               info("HCI dev %d unregistered", index);
-               stop_hci_dev(index);
-               if (devs[index].registered)
-                       btd_manager_unregister_adapter(index);
-               break;
-
-       case HCI_DEV_UP:
-               info("HCI dev %d up", index);
-               devs[index].up = TRUE;
-               device_devup_setup(index);
-               break;
-
-       case HCI_DEV_DOWN:
-               info("HCI dev %d down", index);
-               devs[index].up = FALSE;
-               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;
-
-                       adapter = manager_find_adapter_by_id(index);
-                       if (adapter)
-                               btd_adapter_stop(adapter);
-
-                       init_pending(index);
-               }
-               break;
-       }
-}
-
-static gboolean init_known_adapters(gpointer user_data)
-{
-       struct hci_dev_list_req *dl;
-       struct hci_dev_req *dr;
-       int i, err, ctl = GPOINTER_TO_INT(user_data);
-       size_t req_size;
-
-       DBG("");
-
-       req_size = HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t);
-
-       dl = g_try_malloc0(req_size);
-       if (!dl) {
-               error("Can't allocate devlist buffer");
-               return FALSE;
-       }
-
-       dl->dev_num = HCI_MAX_DEV;
-       dr = dl->dev_req;
-
-       if (ioctl(ctl, HCIGETDEVLIST, dl) < 0) {
-               err = -errno;
-               error("Can't get device list: %s (%d)", strerror(-err), -err);
-               g_free(dl);
-               return FALSE;
-       }
-
-       for (i = 0; i < dl->dev_num; i++, dr++) {
-               struct dev_info *dev;
-               gboolean already_up;
-
-               already_up = hci_test_bit(HCI_UP, &dr->dev_opt);
-
-               dev = init_device(dr->dev_id, already_up);
-               if (dev == NULL)
-                       continue;
-
-               if (!dev->already_up)
-                       continue;
-
-               init_conn_list(dr->dev_id);
-
-               dev->pending = 0;
-               hci_set_bit(PENDING_VERSION, &dev->pending);
-               hci_send_cmd(dev->sk, OGF_INFO_PARAM,
-                                       OCF_READ_LOCAL_VERSION, 0, NULL);
-               device_event(HCI_DEV_UP, dr->dev_id);
-       }
-
-       g_free(dl);
-
-       return FALSE;
-}
-
-static gboolean io_stack_event(GIOChannel *chan, GIOCondition cond,
-                                                               gpointer data)
-{
-       unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
-       evt_stack_internal *si;
-       evt_si_device *sd;
-       hci_event_hdr *eh;
-       int type, fd;
-       ssize_t len;
-
-       ptr = buf;
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       len = read(fd, buf, sizeof(buf));
-       if (len < 0) {
-               if (errno == EAGAIN)
-                       return TRUE;
-
-               error("Read from control socket failed: %s (%d)",
-                                               strerror(errno), errno);
-               return FALSE;
-       }
-
-       type = *ptr++;
-
-       if (type != HCI_EVENT_PKT)
-               return TRUE;
-
-       eh = (hci_event_hdr *) ptr;
-       if (eh->evt != EVT_STACK_INTERNAL)
-               return TRUE;
-
-       ptr += HCI_EVENT_HDR_SIZE;
-
-       si = (evt_stack_internal *) ptr;
-       switch (si->type) {
-       case EVT_SI_DEVICE:
-               sd = (void *) &si->data;
-               device_event(sd->event, sd->dev_id);
-               break;
-       }
-
-       return TRUE;
-}
-
-static int hciops_setup(void)
-{
-       struct sockaddr_hci addr;
-       struct hci_filter flt;
-       GIOChannel *ctl_io, *child_io;
-       int sock, err;
-
-       DBG("");
-
-       if (child_pipe[0] != -1)
-               return -EALREADY;
-
-       if (pipe(child_pipe) < 0) {
-               err = -errno;
-               error("pipe(): %s (%d)", strerror(-err), -err);
-               return err;
-       }
-
-       child_io = g_io_channel_unix_new(child_pipe[0]);
-       g_io_channel_set_close_on_unref(child_io, TRUE);
-       child_io_id = g_io_add_watch(child_io,
-                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                               child_exit, NULL);
-       g_io_channel_unref(child_io);
-
-       /* Create and bind HCI socket */
-       sock = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-       if (sock < 0) {
-               err = -errno;
-               error("Can't open HCI socket: %s (%d)", strerror(-err),
-                                                               -err);
-               return err;
-       }
-
-       /* Set filter */
-       hci_filter_clear(&flt);
-       hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
-       hci_filter_set_event(EVT_STACK_INTERNAL, &flt);
-       if (setsockopt(sock, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
-               err = -errno;
-               error("Can't set filter: %s (%d)", strerror(-err), -err);
-               return err;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.hci_family = AF_BLUETOOTH;
-       addr.hci_dev = HCI_DEV_NONE;
-       if (bind(sock, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               error("Can't bind HCI socket: %s (%d)", strerror(-err), -err);
-               return err;
-       }
-
-       ctl_io = g_io_channel_unix_new(sock);
-       g_io_channel_set_close_on_unref(ctl_io, TRUE);
-
-       ctl_io_id = g_io_add_watch(ctl_io, G_IO_IN, io_stack_event, NULL);
-
-       g_io_channel_unref(ctl_io);
-
-       g_idle_add(init_known_adapters, GINT_TO_POINTER(sock));
-
-       return 0;
-}
-
-static void hciops_cleanup(void)
-{
-       int i;
-
-       DBG("");
-
-       for (i = 0; i <= max_dev; i++)
-               stop_hci_dev(i);
-
-       g_free(devs);
-       devs = NULL;
-       max_dev = -1;
-
-       if (child_io_id) {
-               g_source_remove(child_io_id);
-               child_io_id = 0;
-       }
-
-       if (ctl_io_id) {
-               g_source_remove(ctl_io_id);
-               ctl_io_id = 0;
-       }
-
-       if (child_pipe[0] >= 0) {
-               close(child_pipe[0]);
-               child_pipe[0] = -1;
-       }
-
-       if (child_pipe[1] >= 0) {
-               close(child_pipe[1]);
-               child_pipe[1] = -1;
-       }
-}
-
-static int hciops_set_powered(int index, gboolean powered)
-{
-       struct dev_info *dev = &devs[index];
-       int err;
-
-       DBG("hci%d powered %d", index, powered);
-
-       if (powered == FALSE)
-               return hciops_power_off(index);
-
-       if (ioctl(dev->sk, HCIDEVUP, index) == 0)
-               return 0;
-
-       if (errno == EALREADY)
-               return 0;
-
-       err = -errno;
-       error("Can't init device hci%d: %s (%d)",
-                                       index, strerror(-err), -err);
-
-       return err;
-}
-
-static int start_inquiry(int index, uint8_t length)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
-       inquiry_cp inq_cp;
-
-       DBG("hci%d length %u", index, length);
-
-       memset(&inq_cp, 0, sizeof(inq_cp));
-       memcpy(&inq_cp.lap, lap, 3);
-       inq_cp.length = length;
-       inq_cp.num_rsp = 0x00;
-
-       if (hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                       OCF_INQUIRY, INQUIRY_CP_SIZE, &inq_cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int le_set_scan_enable(int index, uint8_t enable)
-{
-       struct dev_info *dev = &devs[index];
-       le_set_scan_enable_cp cp;
-
-       DBG("hci%d enable %u", index, enable);
-
-       memset(&cp, 0, sizeof(cp));
-       cp.enable = enable;
-       cp.filter_dup = 0;
-
-       if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_ENABLE,
-                               LE_SET_SCAN_ENABLE_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static gboolean stop_le_scan_cb(gpointer user_data)
-{
-       struct dev_info *dev = user_data;
-       int err;
-
-       err = le_set_scan_enable(dev->id, 0);
-       if (err < 0)
-               return TRUE;
-
-       dev->stop_scan_id = 0;
-
-       return FALSE;
-}
-
-static int start_scanning(int index, int timeout)
-{
-       struct dev_info *dev = &devs[index];
-       le_set_scan_parameters_cp cp;
-       int err;
-
-       DBG("hci%d", index);
-
-       memset(&cp, 0, sizeof(cp));
-       cp.type = 0x01;                 /* Active scanning */
-       /* The recommended value for scan interval and window is 11.25 msec.
-        * It is calculated by: time = n * 0.625 msec */
-       cp.interval = htobs(0x0012);
-       cp.window = htobs(0x0012);
-       cp.own_bdaddr_type = 0;         /* Public address */
-       cp.filter = 0;                  /* Accept all adv packets */
-
-       if (hci_send_cmd(dev->sk, OGF_LE_CTL, OCF_LE_SET_SCAN_PARAMETERS,
-                               LE_SET_SCAN_PARAMETERS_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       err = le_set_scan_enable(index, 1);
-       if (err < 0)
-               return err;
-
-       /* Schedule a le scan disable in 'timeout' milliseconds */
-       dev->stop_scan_id = g_timeout_add(timeout, stop_le_scan_cb, dev);
-
-       return 0;
-}
-
-static int hciops_stop_scanning(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       if (dev->stop_scan_id > 0) {
-               g_source_remove(dev->stop_scan_id);
-               dev->stop_scan_id = 0;
-       }
-
-       return le_set_scan_enable(index, 0);
-}
-
-static int cancel_resolve_name(int index)
-{
-       struct dev_info *info = &devs[index];
-       struct found_dev *dev;
-       remote_name_req_cancel_cp cp;
-       struct btd_adapter *adapter;
-
-       DBG("hci%d", index);
-
-       if (g_slist_length(info->need_name) == 0)
-               return 0;
-
-       dev = info->need_name->data;
-       if (dev->name_state != NAME_PENDING)
-               return 0;
-
-       memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, &dev->bdaddr);
-
-       adapter = manager_find_adapter_by_id(index);
-       if (adapter)
-               adapter_set_discovering(adapter, FALSE);
-
-       found_dev_cleanup(info);
-
-       if (hci_send_cmd(info->sk, OGF_LINK_CTL, OCF_REMOTE_NAME_REQ_CANCEL,
-                               REMOTE_NAME_REQ_CANCEL_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_start_discovery(int index)
-{
-       int adapter_type = get_adapter_type(index);
-
-       DBG("hci%u", index);
-
-       switch (adapter_type) {
-       case BR_EDR_LE:
-               return start_inquiry(index, LENGTH_BR_LE_INQ);
-       case BR_EDR:
-               return start_inquiry(index, LENGTH_BR_INQ);
-       case LE_ONLY:
-               return start_scanning(index, TIMEOUT_LE_SCAN);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int hciops_stop_discovery(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("index %d", index);
-
-       switch (dev->discov_state) {
-       case DISCOV_INQ:
-               return hciops_stop_inquiry(index);
-       case DISCOV_SCAN:
-               return hciops_stop_scanning(index);
-       case DISCOV_NAMES:
-               cancel_resolve_name(index);
-       default:
-               return -EINVAL;
-       }
-}
-
-static int hciops_set_fast_connectable(int index, gboolean enable)
-{
-       struct dev_info *dev = &devs[index];
-       write_page_activity_cp cp;
-       uint8_t type;
-
-       DBG("hci%d enable %d", index, enable);
-
-       if (enable) {
-               type = PAGE_SCAN_TYPE_INTERLACED;
-               cp.interval = 0x0024;   /* 22.5 msec page scan interval */
-       } else {
-               type = PAGE_SCAN_TYPE_STANDARD; /* default */
-               cp.interval = 0x0800;   /* default 1.28 sec page scan */
-       }
-
-       cp.window = 0x0012;     /* default 11.25 msec page scan window */
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_WRITE_PAGE_ACTIVITY,
-                                       WRITE_PAGE_ACTIVITY_CP_SIZE, &cp) < 0)
-               return -errno;
-       else if (hci_send_cmd(dev->sk, OGF_HOST_CTL,
-                               OCF_WRITE_PAGE_SCAN_TYPE, 1, &type) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_read_clock(int index, bdaddr_t *bdaddr, int which,
-                                               int timeout, uint32_t *clock,
-                                               uint16_t *accuracy)
-{
-       struct dev_info *dev = &devs[index];
-       uint16_t handle = 0;
-       char addr[18];
-       int ret;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d addr %s which %d timeout %d", index, addr, which, timeout);
-
-       ret = get_handle(index, bdaddr, &handle);
-       if (ret < 0)
-               return ret;
-
-       if (hci_read_clock(dev->sk, htobs(handle), which, clock, accuracy,
-                                                               timeout) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_read_bdaddr(int index, bdaddr_t *bdaddr)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       bacpy(bdaddr, &dev->bdaddr);
-
-       return 0;
-}
-
-static int hciops_block_device(int index, bdaddr_t *bdaddr,
-                                               uint8_t bdaddr_type)
-{
-       struct dev_info *dev = &devs[index];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       if (ioctl(dev->sk, HCIBLOCKADDR, bdaddr) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_unblock_device(int index, bdaddr_t *bdaddr,
-                                               uint8_t bdaddr_type)
-{
-       struct dev_info *dev = &devs[index];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       if (ioctl(dev->sk, HCIUNBLOCKADDR, bdaddr) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_get_conn_list(int index, GSList **conns)
-{
-       struct dev_info *dev = &devs[index];
-       GSList *l;
-
-       DBG("hci%d", index);
-
-       *conns = NULL;
-
-       for (l = dev->connections; l != NULL; l = g_slist_next(l)) {
-               struct bt_conn *conn = l->data;
-
-               *conns = g_slist_append(*conns,
-                               g_memdup(&conn->bdaddr, sizeof(bdaddr_t)));
-       }
-
-       return 0;
-}
-
-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,
-                                                       uint8_t bdaddr_type)
-{
-       struct dev_info *dev = &devs[index];
-       delete_stored_link_key_cp cp;
-       GSList *match;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       match = g_slist_find_custom(dev->keys, bdaddr, (GCompareFunc) bacmp);
-       if (match) {
-               g_free(match->data);
-               dev->keys = g_slist_delete_link(dev->keys, match);
-       }
-
-       memset(&cp, 0, sizeof(cp));
-       bacpy(&cp.bdaddr, bdaddr);
-
-       /* Delete the link key from the Bluetooth chip */
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_DELETE_STORED_LINK_KEY,
-                               DELETE_STORED_LINK_KEY_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
-                                                               size_t pin_len)
-{
-       struct dev_info *dev = &devs[index];
-       char addr[18];
-       int err;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       if (pin) {
-               pin_code_reply_cp pr;
-
-               dev->pin_length = pin_len;
-
-               memset(&pr, 0, sizeof(pr));
-               bacpy(&pr.bdaddr, bdaddr);
-               memcpy(pr.pin_code, pin, pin_len);
-               pr.pin_len = pin_len;
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                               OCF_PIN_CODE_REPLY,
-                                               PIN_CODE_REPLY_CP_SIZE, &pr);
-       } else
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_PIN_CODE_NEG_REPLY, 6, bdaddr);
-
-       if (err < 0)
-               err = -errno;
-
-       return err;
-}
-
-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];
-       int err;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d dba %s", index, addr);
-
-       if (passkey != INVALID_PASSKEY) {
-               user_passkey_reply_cp cp;
-
-               memset(&cp, 0, sizeof(cp));
-               bacpy(&cp.bdaddr, bdaddr);
-               cp.passkey = passkey;
-
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_USER_PASSKEY_REPLY,
-                                       USER_PASSKEY_REPLY_CP_SIZE, &cp);
-       } else
-               err = hci_send_cmd(dev->sk, OGF_LINK_CTL,
-                                       OCF_USER_PASSKEY_NEG_REPLY, 6, bdaddr);
-
-       if (err < 0)
-               err = -errno;
-
-       return err;
-}
-
-static uint8_t generate_service_class(int index)
-{
-       struct dev_info *dev = &devs[index];
-       GSList *l;
-       uint8_t val = 0;
-
-       for (l = dev->uuids; l != NULL; l = g_slist_next(l)) {
-               struct uuid_info *uuid = l->data;
-
-               val |= uuid->svc_hint;
-       }
-
-       return val;
-}
-
-static int update_service_classes(int index)
-{
-       struct dev_info *dev = &devs[index];
-       uint8_t value;
-       int err;
-
-       value = generate_service_class(index);
-
-       DBG("hci%d value %u", index, value);
-
-       /* Update only the service class, keep the limited bit,
-        * major/minor class bits intact */
-       dev->wanted_cod &= 0x00ffff;
-       dev->wanted_cod |= (value << 16);
-
-       /* If the cache is enabled or an existing CoD write is in progress
-        * just bail out */
-       if (dev->cache_enable || dev->pending_cod)
-               return 0;
-
-       /* If we already have the CoD we want, update EIR and return */
-       if (dev->current_cod == dev->wanted_cod) {
-               update_ext_inquiry_response(index);
-               return 0;
-       }
-
-       DBG("Changing service classes 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 hciops_add_uuid(int index, uuid_t *uuid, uint8_t svc_hint)
-{
-       struct dev_info *dev = &devs[index];
-       struct uuid_info *info;
-
-       DBG("hci%d", index);
-
-       info = g_new0(struct uuid_info, 1);
-       memcpy(&info->uuid, uuid, sizeof(*uuid));
-       info->svc_hint = svc_hint;
-
-       dev->uuids = g_slist_append(dev->uuids, info);
-
-       return update_service_classes(index);
-}
-
-static int hciops_remove_uuid(int index, uuid_t *uuid)
-{
-       struct dev_info *dev = &devs[index];
-       GSList *match;
-
-       match = g_slist_find_custom(dev->uuids, uuid, sdp_uuid_cmp);
-       if (match) {
-               g_free(match->data);
-               dev->uuids = g_slist_delete_link(dev->uuids, match);
-       }
-
-       DBG("hci%d", index);
-
-       return update_service_classes(index);
-}
-
-static int hciops_disable_cod_cache(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d cache_enable %d", index, dev->cache_enable);
-
-       if (!dev->cache_enable)
-               return 0;
-
-       DBG("hci%d current_cod 0x%06x wanted_cod 0x%06x", index,
-                                       dev->current_cod, dev->wanted_cod);
-
-       /* Disable and flush svc cache. All successive service class
-        * updates * will be written to the device */
-       dev->cache_enable = FALSE;
-
-       if (dev->current_cod == dev->wanted_cod) {
-               update_ext_inquiry_response(index);
-               return 0;
-       }
-
-       return write_class(index, dev->wanted_cod);
-}
-
-static int hciops_restore_powered(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       if (!dev->already_up && dev->up)
-               return hciops_power_off(index);
-
-       return 0;
-}
-
-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);
-
-       if (dev->keys != NULL)
-               return -EEXIST;
-
-       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;
-}
-
-static int hciops_set_io_capability(int index, uint8_t io_capability)
-{
-       struct dev_info *dev = &devs[index];
-
-       /* 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;
-}
-
-static int request_authentication(int index, bdaddr_t *bdaddr)
-{
-       struct dev_info *dev = &devs[index];
-       auth_requested_cp cp;
-       uint16_t handle;
-       int err;
-
-       DBG("hci%d", index);
-
-       err = get_handle(index, bdaddr, &handle);
-       if (err < 0)
-               return err;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(handle);
-
-       if (hci_send_cmd(dev->sk, OGF_LINK_CTL, OCF_AUTH_REQUESTED,
-                                       AUTH_REQUESTED_CP_SIZE, &cp) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static void bonding_connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
-       struct bt_conn *conn = user_data;
-       struct dev_info *dev = conn->dev;
-
-       if (!conn->io) {
-               if (!err)
-                       g_io_channel_shutdown(io, TRUE, NULL);
-               return;
-       }
-
-       if (err)
-               /* Wait proper error to be propagated by bonding complete */
-               return;
-
-       if (request_authentication(dev->id, &conn->bdaddr) < 0)
-               goto failed;
-
-       return;
-
-failed:
-       bonding_complete(dev, conn, HCI_UNSPECIFIED_ERROR);
-}
-
-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;
-       struct bt_conn *conn;
-       GError *err = NULL;
-
-       conn = get_connection(dev, bdaddr);
-
-       if (conn->io != NULL)
-               return -EBUSY;
-
-       /* 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
-        * security level */
-       if (io_cap == 0x03)
-               sec_level = BT_IO_SEC_MEDIUM;
-       else
-               sec_level = BT_IO_SEC_HIGH;
-
-       conn->io = bt_io_connect(BT_IO_L2RAW, bonding_connect_cb, conn,
-                                       NULL, &err,
-                                       BT_IO_OPT_SOURCE_BDADDR, &dev->bdaddr,
-                                       BT_IO_OPT_DEST_BDADDR, bdaddr,
-                                       BT_IO_OPT_SEC_LEVEL, sec_level,
-                                       BT_IO_OPT_INVALID);
-       if (conn->io == NULL) {
-               error("bt_io_connect: %s", err->message);
-               g_error_free(err);
-               return -EIO;
-       }
-
-       conn->bonding_initiator = TRUE;
-
-       return 0;
-}
-
-static int hciops_cancel_bonding(int index, bdaddr_t *bdaddr)
-{
-       struct dev_info *dev = &devs[index];
-       struct bt_conn *conn;
-
-       DBG("hci%d", index);
-
-       conn = find_connection(dev, bdaddr);
-       if (conn == NULL || conn->io == NULL)
-               return -ENOTCONN;
-
-       g_io_channel_shutdown(conn->io, TRUE, NULL);
-       g_io_channel_unref(conn->io);
-       conn->io = NULL;
-
-       return 0;
-}
-
-static int hciops_read_local_oob_data(int index)
-{
-       struct dev_info *dev = &devs[index];
-
-       DBG("hci%d", index);
-
-       if (hci_send_cmd(dev->sk, OGF_HOST_CTL, OCF_READ_LOCAL_OOB_DATA, 0, 0)
-                                                                       < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int hciops_add_remote_oob_data(int index, bdaddr_t *bdaddr,
-                                       uint8_t *hash, uint8_t *randomizer)
-{
-       char addr[18];
-       struct dev_info *dev = &devs[index];
-       GSList *match;
-       struct oob_data *data;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s", index, addr);
-
-       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-       if (match) {
-               data = match->data;
-       } else {
-               data = g_new(struct oob_data, 1);
-               bacpy(&data->bdaddr, bdaddr);
-               dev->oob_data = g_slist_prepend(dev->oob_data, data);
-       }
-
-       memcpy(data->hash, hash, sizeof(data->hash));
-       memcpy(data->randomizer, randomizer, sizeof(data->randomizer));
-
-       return 0;
-}
-
-static int hciops_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
-{
-       char addr[18];
-       struct dev_info *dev = &devs[index];
-       GSList *match;
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s", index, addr);
-
-       match = g_slist_find_custom(dev->oob_data, bdaddr, oob_bdaddr_cmp);
-
-       if (!match)
-               return -ENOENT;
-
-       g_free(match->data);
-       dev->oob_data = g_slist_delete_link(dev->oob_data, match);
-
-       return 0;
-}
-
-static int hciops_confirm_name(int index, bdaddr_t *bdaddr,
-                               uint8_t bdaddr_type, gboolean name_known)
-{
-       struct dev_info *info = &devs[index];
-       struct found_dev *dev;
-       GSList *match;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%u %s name_known %u", index, addr, name_known);
-
-       match = g_slist_find_custom(info->found_devs, bdaddr,
-                                               found_dev_bda_cmp);
-       if (match == NULL)
-               return -ENOENT;
-
-       dev = match->data;
-
-       if (name_known) {
-               dev->name_state = NAME_NOT_NEEDED;
-               info->found_devs = g_slist_sort(info->found_devs,
-                                                       found_dev_rssi_cmp);
-               return 0;
-       }
-
-       dev->name_state = NAME_NEEDED;
-       info->found_devs = g_slist_remove_link(info->found_devs, match);
-
-       match->next = info->need_name;
-       info->need_name = match;
-       info->need_name = g_slist_sort(info->need_name, found_dev_rssi_cmp);
-
-       return 0;
-}
-
-static 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,
-       .start_discovery = hciops_start_discovery,
-       .stop_discovery = hciops_stop_discovery,
-       .set_name = hciops_set_name,
-       .set_dev_class = hciops_set_dev_class,
-       .set_fast_connectable = hciops_set_fast_connectable,
-       .read_clock = hciops_read_clock,
-       .read_bdaddr = hciops_read_bdaddr,
-       .block_device = hciops_block_device,
-       .unblock_device = hciops_unblock_device,
-       .get_conn_list = hciops_get_conn_list,
-       .disconnect = hciops_disconnect,
-       .remove_bonding = hciops_remove_bonding,
-       .pincode_reply = hciops_pincode_reply,
-       .confirm_reply = hciops_confirm_reply,
-       .passkey_reply = hciops_passkey_reply,
-       .encrypt_link = hciops_encrypt_link,
-       .set_did = hciops_set_did,
-       .add_uuid = hciops_add_uuid,
-       .remove_uuid = hciops_remove_uuid,
-       .disable_cod_cache = hciops_disable_cod_cache,
-       .restore_powered = hciops_restore_powered,
-       .load_keys = hciops_load_keys,
-       .set_io_capability = hciops_set_io_capability,
-       .create_bonding = hciops_create_bonding,
-       .cancel_bonding = hciops_cancel_bonding,
-       .read_local_oob_data = hciops_read_local_oob_data,
-       .add_remote_oob_data = hciops_add_remote_oob_data,
-       .remove_remote_oob_data = hciops_remove_remote_oob_data,
-       .confirm_name = hciops_confirm_name,
-       .load_ltks = hciops_load_ltks,
-};
-
-static int hciops_init(void)
-{
-       DBG("");
-       return btd_register_adapter_ops(&hci_ops, FALSE);
-}
-
-static void hciops_exit(void)
-{
-       DBG("");
-       btd_adapter_cleanup_ops(&hci_ops);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(hciops, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_LOW, hciops_init, hciops_exit)
diff --git a/plugins/hostname.c b/plugins/hostname.c
new file mode 100644 (file)
index 0000000..92a71e0
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <gdbus/gdbus.h>
+
+#include "dbus-common.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "log.h"
+
+/* http://www.bluetooth.org/Technical/AssignedNumbers/baseband.htm */
+
+#define MAJOR_CLASS_MISCELLANEOUS      0x00
+#define MAJOR_CLASS_COMPUTER           0x01
+
+#define MINOR_CLASS_UNCATEGORIZED      0x00
+#define MINOR_CLASS_DESKTOP            0x01
+#define MINOR_CLASS_SERVER             0x02
+#define MINOR_CLASS_LAPTOP             0x03
+#define MINOR_CLASS_HANDHELD           0x04
+#define MINOR_CLASS_PALM_SIZED         0x05
+#define MINOR_CLASS_WEARABLE           0x06
+#define MINOR_CLASS_TABLET             0x07
+
+static uint8_t major_class = MAJOR_CLASS_MISCELLANEOUS;
+static uint8_t minor_class = MINOR_CLASS_UNCATEGORIZED;
+
+static char *pretty_hostname = NULL;
+static char *static_hostname = NULL;
+
+/*
+ * Fallback to static hostname only if empty pretty hostname was already
+ * received.
+ */
+static const char *get_hostname(void)
+{
+       if (pretty_hostname) {
+               if (g_str_equal(pretty_hostname, "") == FALSE)
+                       return pretty_hostname;
+
+               if (static_hostname &&
+                               g_str_equal(static_hostname, "") == FALSE)
+                       return static_hostname;
+       }
+
+       return NULL;
+}
+
+static void update_name(struct btd_adapter *adapter, gpointer user_data)
+{
+       const char *hostname = get_hostname();
+
+       if (hostname == NULL)
+               return;
+
+       if (btd_adapter_is_default(adapter)) {
+               DBG("name: %s", hostname);
+
+               adapter_set_name(adapter, hostname);
+       } else {
+               uint16_t index = btd_adapter_get_index(adapter);
+               char *str;
+
+               /* Avoid "some device #0" names, start at #1 */
+               str = g_strdup_printf("%s #%u", hostname, index + 1);
+
+               DBG("name: %s", str);
+
+               adapter_set_name(adapter, str);
+
+               g_free(str);
+       }
+}
+
+static void update_class(struct btd_adapter *adapter, gpointer user_data)
+{
+       if (major_class == MAJOR_CLASS_MISCELLANEOUS)
+               return;
+
+       DBG("major: 0x%02x minor: 0x%02x", major_class, minor_class);
+
+       btd_adapter_set_class(adapter, major_class, minor_class);
+}
+
+static const struct {
+       const char *chassis;
+       uint8_t major_class;
+       uint8_t minor_class;
+} chassis_table[] = {
+       { "desktop",  MAJOR_CLASS_COMPUTER, MINOR_CLASS_DESKTOP  },
+       { "server",   MAJOR_CLASS_COMPUTER, MINOR_CLASS_SERVER   },
+       { "laptop",   MAJOR_CLASS_COMPUTER, MINOR_CLASS_LAPTOP   },
+       { "handset",  MAJOR_CLASS_COMPUTER, MINOR_CLASS_HANDHELD },
+       { "tablet",   MAJOR_CLASS_COMPUTER, MINOR_CLASS_TABLET   },
+       { }
+};
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       if (g_str_equal(name, "PrettyHostname") == TRUE) {
+               if (iter == NULL) {
+                       g_dbus_proxy_refresh_property(proxy, name);
+                       return;
+               }
+
+               if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+                       const char *str;
+
+                       dbus_message_iter_get_basic(iter, &str);
+
+                       DBG("pretty hostname: %s", str);
+
+                       g_free(pretty_hostname);
+                       pretty_hostname = g_strdup(str);
+
+                       adapter_foreach(update_name, NULL);
+               }
+       } else if (g_str_equal(name, "StaticHostname") == TRUE) {
+               if (iter == NULL) {
+                       g_dbus_proxy_refresh_property(proxy, name);
+                       return;
+               }
+
+               if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+                       const char *str;
+
+                       dbus_message_iter_get_basic(iter, &str);
+
+                       DBG("static hostname: %s", str);
+
+                       g_free(static_hostname);
+                       static_hostname = g_strdup(str);
+
+                       adapter_foreach(update_name, NULL);
+               }
+       } else if (g_str_equal(name, "Chassis") == TRUE) {
+               if (iter == NULL) {
+                       g_dbus_proxy_refresh_property(proxy, name);
+                       return;
+               }
+
+               if (dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING) {
+                       const char *str;
+                       int i;
+
+                       dbus_message_iter_get_basic(iter, &str);
+
+                       DBG("chassis: %s", str);
+
+                       for (i = 0; chassis_table[i].chassis; i++) {
+                               if (strcmp(chassis_table[i].chassis, str))
+                                       continue;
+
+                               major_class = chassis_table[i].major_class;
+                               minor_class = chassis_table[i].minor_class;
+
+                               adapter_foreach(update_class, NULL);
+                               break;
+                       }
+               }
+       }
+}
+
+static int hostname_probe(struct btd_adapter *adapter)
+{
+       DBG("");
+
+       update_name(adapter, NULL);
+       update_class(adapter, NULL);
+
+       return 0;
+}
+
+static void hostname_remove(struct btd_adapter *adapter)
+{
+       DBG("");
+}
+
+static struct btd_adapter_driver hostname_driver = {
+       .name   = "hostname",
+       .probe  = hostname_probe,
+       .remove = hostname_remove,
+};
+
+static void read_dmi_fallback(void)
+{
+       char *contents;
+       int i, type;
+       const char *str;
+
+       if (g_file_get_contents("/sys/class/dmi/id/chassis_type",
+                                       &contents, NULL, NULL) == FALSE)
+               return;
+
+       type = atoi(contents);
+       if (type < 0 || type > 0x1D)
+               return;
+
+       g_free(contents);
+
+       /* from systemd hostname chassis list */
+       switch (type) {
+       case 0x3:
+       case 0x4:
+       case 0x6:
+       case 0x7:
+               str = "desktop";
+               break;
+       case 0x8:
+       case 0x9:
+       case 0xA:
+       case 0xE:
+               str = "laptop";
+               break;
+       case 0xB:
+               str = "handset";
+               break;
+       case 0x11:
+       case 0x1C:
+               str = "server";
+               break;
+       default:
+               return;
+       }
+
+       DBG("chassis: %s", str);
+
+       for (i = 0; chassis_table[i].chassis; i++) {
+               if (!strcmp(chassis_table[i].chassis, str)) {
+                       major_class = chassis_table[i].major_class;
+                       minor_class = chassis_table[i].minor_class;
+                       break;
+               }
+       }
+
+       DBG("major: 0x%02x minor: 0x%02x", major_class, minor_class);
+}
+
+static GDBusClient *hostname_client = NULL;
+static GDBusProxy *hostname_proxy = NULL;
+
+static int hostname_init(void)
+{
+       DBusConnection *conn = btd_get_dbus_connection();
+       int err;
+
+       read_dmi_fallback();
+
+       hostname_client = g_dbus_client_new(conn, "org.freedesktop.hostname1",
+                                               "/org/freedesktop/hostname1");
+       if (!hostname_client)
+               return -EIO;
+
+       hostname_proxy = g_dbus_proxy_new(hostname_client,
+                                               "/org/freedesktop/hostname1",
+                                               "org.freedesktop.hostname1");
+       if (!hostname_proxy) {
+               g_dbus_client_unref(hostname_client);
+               hostname_client = NULL;
+               return -EIO;
+       }
+
+       g_dbus_proxy_set_property_watch(hostname_proxy, property_changed, NULL);
+
+       err = btd_register_adapter_driver(&hostname_driver);
+       if (err < 0) {
+               g_dbus_proxy_unref(hostname_proxy);
+               hostname_proxy = NULL;
+               g_dbus_client_unref(hostname_client);
+               hostname_client = NULL;
+       }
+
+       return err;
+}
+
+static void hostname_exit(void)
+{
+       btd_unregister_adapter_driver(&hostname_driver);
+
+       if (hostname_proxy) {
+               g_dbus_proxy_unref(hostname_proxy);
+               hostname_proxy = NULL;
+       }
+
+       if (hostname_client) {
+               g_dbus_client_unref(hostname_client);
+               hostname_client = NULL;
+       }
+
+       g_free(pretty_hostname);
+       g_free(static_hostname);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(hostname, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                               hostname_init, hostname_exit)
diff --git a/plugins/maemo6.c b/plugins/maemo6.c
deleted file mode 100644 (file)
index 4819af4..0000000
+++ /dev/null
@@ -1,283 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <dbus/dbus.h>
-
-#include "adapter.h"
-#include "plugin.h"
-#include "log.h"
-#include "gdbus.h"
-
-/* from mce/mode-names.h */
-#define MCE_RADIO_STATE_BLUETOOTH      (1 << 3)
-
-/* from mce/dbus-names.h */
-#define MCE_SERVICE                    "com.nokia.mce"
-#define MCE_REQUEST_IF                 "com.nokia.mce.request"
-#define MCE_SIGNAL_IF                  "com.nokia.mce.signal"
-#define MCE_REQUEST_PATH               "/com/nokia/mce/request"
-#define MCE_SIGNAL_PATH                        "/com/nokia/mce/signal"
-#define MCE_RADIO_STATES_CHANGE_REQ    "req_radio_states_change"
-#define MCE_RADIO_STATES_GET           "get_radio_states"
-#define MCE_RADIO_STATES_SIG           "radio_states_ind"
-#define MCE_TKLOCK_MODE_SIG            "tklock_mode_ind"
-
-static guint watch_id;
-static guint tklock_watch_id;
-static DBusConnection *conn = NULL;
-static gboolean mce_bt_set = FALSE;
-static gboolean mce_bt_on = FALSE;
-
-static gboolean mce_tklock_mode_cb(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       DBusMessageIter args;
-       const char *sigvalue;
-
-       if (!dbus_message_iter_init(message, &args)) {
-               error("message has no arguments");
-       } else if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_STRING) {
-               error("argument is not string");
-       } else {
-
-               dbus_message_iter_get_basic(&args, &sigvalue);
-               DBG("got signal with value %s", sigvalue);
-
-               if (g_strcmp0("unlocked", sigvalue) == 0 && mce_bt_on)
-                       btd_adapter_enable_auto_connect(adapter);
-       }
-
-       return TRUE;
-}
-
-static gboolean mce_signal_callback(DBusConnection *connection,
-                                       DBusMessage *message, void *user_data)
-{
-       DBusMessageIter args;
-       uint32_t sigvalue;
-       struct btd_adapter *adapter = user_data;
-       int err;
-
-       DBG("received mce signal");
-
-       if (!dbus_message_iter_init(message, &args))
-               error("message has no arguments");
-       else if (DBUS_TYPE_UINT32 != dbus_message_iter_get_arg_type(&args))
-               error("argument is not uint32");
-       else {
-               dbus_message_iter_get_basic(&args, &sigvalue);
-               DBG("got signal with value %u", sigvalue);
-
-               /* set the adapter according to the mce signal
-                  and remember the value */
-               mce_bt_on = sigvalue & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
-
-               if (mce_bt_on)
-                       err = btd_adapter_switch_online(adapter);
-               else
-                       err = btd_adapter_switch_offline(adapter);
-
-               if (err == 0)
-                       mce_bt_set = TRUE;
-
-       }
-
-       return TRUE;
-}
-
-static void read_radio_states_cb(DBusPendingCall *call, void *user_data)
-{
-       DBusError derr;
-       DBusMessage *reply;
-       dbus_uint32_t radio_states;
-       struct btd_adapter *adapter = user_data;
-       int err;
-
-       reply = dbus_pending_call_steal_reply(call);
-
-       dbus_error_init(&derr);
-       if (dbus_set_error_from_message(&derr, reply)) {
-               error("mce replied with an error: %s, %s",
-                               derr.name, derr.message);
-               dbus_error_free(&derr);
-               goto done;
-       }
-
-       if (dbus_message_get_args(reply, &derr,
-                               DBUS_TYPE_UINT32, &radio_states,
-                               DBUS_TYPE_INVALID) == FALSE) {
-               error("unable to parse get_radio_states reply: %s, %s",
-                                                       derr.name, derr.message);
-               dbus_error_free(&derr);
-               goto done;
-       }
-
-       DBG("radio_states: %d", radio_states);
-
-       mce_bt_on = radio_states & MCE_RADIO_STATE_BLUETOOTH ? TRUE : FALSE;
-
-       if (mce_bt_on)
-               err = btd_adapter_switch_online(adapter);
-       else
-               err = btd_adapter_switch_offline(adapter);
-
-       if (err == 0)
-               mce_bt_set = TRUE;
-
-done:
-       dbus_message_unref(reply);
-}
-
-static void adapter_powered(struct btd_adapter *adapter, gboolean powered)
-{
-       DBusMessage *msg;
-       static gboolean startup = TRUE;
-
-       DBG("adapter_powered called with %d", powered);
-
-       if (startup) {
-               DBusPendingCall *call;
-
-               /* Initialization: sync adapter state and MCE radio state */
-
-               DBG("Startup: reading MCE Bluetooth radio state...");
-               startup = FALSE;
-
-               msg = dbus_message_new_method_call(MCE_SERVICE,
-                                       MCE_REQUEST_PATH, MCE_REQUEST_IF,
-                                       MCE_RADIO_STATES_GET);
-
-               if (!dbus_connection_send_with_reply(conn, msg, &call, -1)) {
-                       error("calling %s failed", MCE_RADIO_STATES_GET);
-                       dbus_message_unref(msg);
-                       return;
-               }
-
-               dbus_pending_call_set_notify(call, read_radio_states_cb,
-                                                               adapter, NULL);
-               dbus_pending_call_unref(call);
-               dbus_message_unref(msg);
-               return;
-       }
-
-       /* MCE initiated operation */
-       if (mce_bt_set == TRUE) {
-               mce_bt_set = FALSE;
-               return;
-       }
-
-       /* Non MCE operation: set MCE according to adapter state */
-       if (mce_bt_on != powered) {
-               dbus_uint32_t radio_states;
-               dbus_uint32_t radio_mask = MCE_RADIO_STATE_BLUETOOTH;
-
-               msg = dbus_message_new_method_call(MCE_SERVICE,
-                                       MCE_REQUEST_PATH, MCE_REQUEST_IF,
-                                       MCE_RADIO_STATES_CHANGE_REQ);
-
-               radio_states = (powered ? MCE_RADIO_STATE_BLUETOOTH : 0);
-
-               DBG("Changing MCE Bluetooth radio state to: %d", radio_states);
-
-               dbus_message_append_args(msg, DBUS_TYPE_UINT32, &radio_states,
-                                       DBUS_TYPE_UINT32, &radio_mask,
-                                       DBUS_TYPE_INVALID);
-
-               if (dbus_connection_send(conn, msg, NULL))
-                       mce_bt_on = powered;
-               else
-                       error("calling %s failed", MCE_RADIO_STATES_CHANGE_REQ);
-
-               dbus_message_unref(msg);
-       }
-}
-
-static int mce_probe(struct btd_adapter *adapter)
-{
-
-       DBG("path %s", adapter_get_path(adapter));
-
-       watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
-                                       MCE_SIGNAL_IF, MCE_RADIO_STATES_SIG,
-                                       mce_signal_callback, adapter, NULL);
-
-       tklock_watch_id = g_dbus_add_signal_watch(conn, NULL, MCE_SIGNAL_PATH,
-                                       MCE_SIGNAL_IF, MCE_TKLOCK_MODE_SIG,
-                                       mce_tklock_mode_cb, adapter, NULL);
-
-       btd_adapter_register_powered_callback(adapter, adapter_powered);
-
-       return 0;
-}
-
-static void mce_remove(struct btd_adapter *adapter)
-{
-       DBG("path %s", adapter_get_path(adapter));
-
-       if (watch_id > 0)
-               g_dbus_remove_watch(conn, watch_id);
-
-       if (tklock_watch_id > 0)
-               g_dbus_remove_watch(conn, tklock_watch_id);
-
-       btd_adapter_unregister_powered_callback(adapter, adapter_powered);
-}
-
-static struct btd_adapter_driver mce_driver = {
-       .name   = "mce",
-       .probe  = mce_probe,
-       .remove = mce_remove,
-};
-
-static int maemo6_init(void)
-{
-       DBG("init maemo6 plugin");
-
-       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (conn == NULL) {
-               error("Unable to connect to D-Bus");
-               return -1;
-       }
-
-       return btd_register_adapter_driver(&mce_driver);
-}
-
-static void maemo6_exit(void)
-{
-       DBG("exit maemo6 plugin");
-
-       if (conn != NULL)
-               dbus_connection_unref(conn);
-
-       btd_unregister_adapter_driver(&mce_driver);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(maemo6, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, maemo6_init, maemo6_exit)
diff --git a/plugins/mgmtops.c b/plugins/mgmtops.c
deleted file mode 100644 (file)
index 16a97c9..0000000
+++ /dev/null
@@ -1,2523 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <sys/ioctl.h>
-#include <sys/wait.h>
-
-#include <glib.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/mgmt.h>
-
-#include "plugin.h"
-#include "log.h"
-#include "adapter.h"
-#include "manager.h"
-#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;
-       gboolean notified;
-       bdaddr_t bdaddr;
-       uint8_t version;
-       uint16_t manufacturer;
-       uint32_t supported_settings;
-       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;
-static guint mgmt_watch = 0;
-
-static uint8_t mgmt_version = 0;
-static uint16_t mgmt_revision = 0;
-
-static void read_version_complete(int sk, void *buf, size_t len)
-{
-       struct mgmt_hdr hdr;
-       struct mgmt_rp_read_version *rp = buf;
-
-       if (len < sizeof(*rp)) {
-               error("Too small read version complete event"
-                               " (probably an old kernel)");
-               abort();
-       }
-
-       mgmt_revision = btohs(bt_get_unaligned(&rp->revision));
-       mgmt_version = rp->version;
-
-       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);
-       if (write(sk, &hdr, sizeof(hdr)) < 0)
-               error("Unable to read controller index list: %s (%d)",
-                                               strerror(errno), errno);
-}
-
-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);
-       }
-
-       info = &controllers[index];
-
-       memset(info, 0, sizeof(*info));
-
-       info->valid = TRUE;
-
-       DBG("Added controller %u", index);
-}
-
-static void read_info(int sk, uint16_t index)
-{
-       struct mgmt_hdr hdr;
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.opcode = htobs(MGMT_OP_READ_INFO);
-       hdr.index = htobs(index);
-
-       if (write(sk, &hdr, sizeof(hdr)) < 0)
-               error("Unable to send read_info command: %s (%d)",
-                                               strerror(errno), errno);
-}
-
-static void get_connections(int sk, uint16_t index)
-{
-       struct mgmt_hdr hdr;
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.opcode = htobs(MGMT_OP_GET_CONNECTIONS);
-       hdr.index = htobs(index);
-
-       if (write(sk, &hdr, sizeof(hdr)) < 0)
-               error("Unable to send get_connections command: %s (%d)",
-                                               strerror(errno), errno);
-}
-
-static void mgmt_index_added(int sk, uint16_t index)
-{
-       add_controller(index);
-       read_info(sk, index);
-}
-
-static void remove_controller(uint16_t index)
-{
-       if (index > max_index)
-               return;
-
-       if (!controllers[index].valid)
-               return;
-
-       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);
-}
-
-static void mgmt_index_removed(int sk, uint16_t index)
-{
-       remove_controller(index);
-}
-
-static int mgmt_set_mode(int index, uint16_t opcode, uint8_t val)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)];
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(opcode);
-       hdr->index = htobs(index);
-       hdr->len = htobs(sizeof(*cp));
-
-       cp->val = val;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_set_connectable(int index, gboolean connectable)
-{
-       DBG("index %d connectable %d", index, connectable);
-       return mgmt_set_mode(index, MGMT_OP_SET_CONNECTABLE, connectable);
-}
-
-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;
-       struct mgmt_cp_set_discoverable *cp = (void *) &buf[sizeof(*hdr)];
-
-       DBG("index %d discoverable %d", index, discoverable);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_SET_DISCOVERABLE);
-       hdr->index = htobs(index);
-       hdr->len = htobs(sizeof(*cp));
-
-       cp->val = discoverable;
-       cp->timeout = timeout;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_set_pairable(int index, gboolean pairable)
-{
-       DBG("index %d pairable %d", index, pairable);
-       return mgmt_set_mode(index, MGMT_OP_SET_PAIRABLE, pairable);
-}
-
-static inline int mgmt_powered(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_POWERED) != 0;
-}
-
-static inline int mgmt_connectable(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_CONNECTABLE) != 0;
-}
-
-static inline int mgmt_fast_connectable(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_FAST_CONNECTABLE) != 0;
-}
-
-static inline int mgmt_discoverable(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_DISCOVERABLE) != 0;
-}
-
-static inline int mgmt_pairable(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_PAIRABLE) != 0;
-}
-
-static inline int mgmt_ssp(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_SSP) != 0;
-}
-
-static inline int mgmt_bredr(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_BREDR) != 0;
-}
-
-static inline int mgmt_high_speed(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_HS) != 0;
-}
-
-static inline int mgmt_low_energy(uint32_t settings)
-{
-       return (settings & MGMT_SETTING_LE) != 0;
-}
-
-static uint8_t create_mode(uint32_t settings)
-{
-       uint8_t mode = 0;
-
-       if (mgmt_connectable(settings))
-               mode |= SCAN_PAGE;
-
-       if (mgmt_discoverable(settings))
-               mode |= SCAN_INQUIRY;
-
-       return mode;
-}
-
-static void update_settings(struct btd_adapter *adapter, uint32_t settings)
-{
-       struct controller_info *info;
-       gboolean pairable;
-       uint8_t on_mode;
-       uint16_t index, discoverable_timeout;
-
-       DBG("new settings %x", settings);
-
-       btd_adapter_get_mode(adapter, NULL, &on_mode, &discoverable_timeout,
-                                                               &pairable);
-
-       index = adapter_get_dev_id(adapter);
-
-       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 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;
-}
-
-static int mode_changed(uint32_t s1, uint32_t s2)
-{
-       if (mgmt_connectable(s1) != mgmt_connectable(s2))
-               return 1;
-
-       if (mgmt_discoverable(s1) != mgmt_discoverable(s2))
-               return 1;
-
-       return 0;
-}
-
-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");
-               return;
-       }
-
-       DBG("hci%u new settings", index);
-
-       if (index > max_index) {
-               error("Unexpected index %u in new_settings event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter == NULL) {
-               DBG("Adapter not found");
-               return;
-       }
-
-       settings = bt_get_le32(ev);
-
-       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));
-
-       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;
-}
-
-static void bonding_complete(struct controller_info *info, bdaddr_t *bdaddr,
-                                                               uint8_t status)
-{
-       struct btd_adapter *adapter;
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter != NULL)
-               adapter_bonding_complete(adapter, bdaddr, status);
-}
-
-static void mgmt_new_link_key(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_ev_new_link_key *ev = buf;
-       struct controller_info *info;
-
-       if (len != sizeof(*ev)) {
-               error("mgmt_new_link_key event size mismatch (%zu != %zu)",
-                                                       len, sizeof(*ev));
-               return;
-       }
-
-       DBG("Controller %u new key of type %u pin_len %u", index,
-                                       ev->key.type, ev->key.pin_len);
-
-       if (index > max_index) {
-               error("Unexpected index %u in new_key event", index);
-               return;
-       }
-
-       if (ev->key.pin_len > 16) {
-               error("Invalid PIN length (%u) in new_key event",
-                                                       ev->key.pin_len);
-               return;
-       }
-
-       info = &controllers[index];
-
-       if (ev->store_hint)
-               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.addr.bdaddr, 0);
-}
-
-static void mgmt_device_connected(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_ev_device_connected *ev = buf;
-       struct eir_data eir_data;
-       struct controller_info *info;
-       uint16_t eir_len;
-       char addr[18];
-
-       if (len < sizeof(*ev)) {
-               error("Too small device_connected event");
-               return;
-       }
-
-       eir_len = bt_get_le16(&ev->eir_len);
-       if (len < sizeof(*ev) + eir_len) {
-               error("Too small device_connected event");
-               return;
-       }
-
-       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);
-               return;
-       }
-
-       info = &controllers[index];
-
-       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,
-                                                               size_t len)
-{
-       struct mgmt_addr_info *ev = buf;
-       struct controller_info *info;
-       char addr[18];
-
-       if (len < sizeof(*ev)) {
-               error("Too small device_disconnected event");
-               return;
-       }
-
-       ba2str(&ev->bdaddr, addr);
-
-       DBG("hci%u device %s disconnected", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in device_disconnected event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       btd_event_disconn_complete(&info->bdaddr, &ev->bdaddr);
-}
-
-static void mgmt_connect_failed(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_ev_connect_failed *ev = buf;
-       struct controller_info *info;
-       char addr[18];
-
-       if (len < sizeof(*ev)) {
-               error("Too small connect_failed event");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-
-       DBG("hci%u %s status %u", index, addr, ev->status);
-
-       if (index > max_index) {
-               error("Unexpected index %u in connect_failed event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       btd_event_conn_failed(&info->bdaddr, &ev->addr.bdaddr, ev->status);
-
-       /* In the case of security mode 3 devices */
-       bonding_complete(info, &ev->addr.bdaddr, ev->status);
-}
-
-static int mgmt_pincode_reply(int index, bdaddr_t *bdaddr, const char *pin,
-                                                               size_t pin_len)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_pin_code_reply)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       size_t buf_len;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s pinlen %zu", index, addr, pin_len);
-
-       memset(buf, 0, sizeof(buf));
-
-       if (pin == NULL) {
-               struct mgmt_cp_pin_code_neg_reply *cp;
-
-               hdr->opcode = htobs(MGMT_OP_PIN_CODE_NEG_REPLY);
-               hdr->len = htobs(sizeof(*cp));
-               hdr->index = htobs(index);
-
-               cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->addr.bdaddr, bdaddr);
-               cp->addr.type = BDADDR_BREDR;
-
-               buf_len = sizeof(*hdr) + sizeof(*cp);
-       } else {
-               struct mgmt_cp_pin_code_reply *cp;
-
-               if (pin_len > 16)
-                       return -EINVAL;
-
-               hdr->opcode = htobs(MGMT_OP_PIN_CODE_REPLY);
-               hdr->len = htobs(sizeof(*cp));
-               hdr->index = htobs(index);
-
-               cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->addr.bdaddr, bdaddr);
-               cp->addr.type = BDADDR_BREDR;
-               cp->pin_len = pin_len;
-               memcpy(cp->pin_code, pin, pin_len);
-
-               buf_len = sizeof(*hdr) + sizeof(*cp);
-       }
-
-       if (write(mgmt_sock, buf, buf_len) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static void mgmt_pin_code_request(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_ev_pin_code_request *ev = buf;
-       struct controller_info *info;
-       char addr[18];
-       int err;
-
-       if (len < sizeof(*ev)) {
-               error("Too small pin_code_request event");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-
-       DBG("hci%u %s", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in pin_code_request event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       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->addr.bdaddr, NULL, 0);
-       }
-}
-
-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;
-       struct mgmt_cp_user_confirm_reply *cp;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s success %d", index, addr, success);
-
-       memset(buf, 0, sizeof(buf));
-
-       if (success)
-               hdr->opcode = htobs(MGMT_OP_USER_CONFIRM_REPLY);
-       else
-               hdr->opcode = htobs(MGMT_OP_USER_CONFIRM_NEG_REPLY);
-
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       cp->addr.type = bdaddr_type;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-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;
-       size_t buf_len;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s passkey %06u", index, addr, passkey);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->index = htobs(index);
-       if (passkey == INVALID_PASSKEY) {
-               struct mgmt_cp_user_passkey_neg_reply *cp;
-
-               hdr->opcode = htobs(MGMT_OP_USER_PASSKEY_NEG_REPLY);
-               hdr->len = htobs(sizeof(*cp));
-
-               cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->addr.bdaddr, bdaddr);
-               cp->addr.type = bdaddr_type;
-
-               buf_len = sizeof(*hdr) + sizeof(*cp);
-       } else {
-               struct mgmt_cp_user_passkey_reply *cp;
-
-               hdr->opcode = htobs(MGMT_OP_USER_PASSKEY_REPLY);
-               hdr->len = htobs(sizeof(*cp));
-
-               cp = (void *) &buf[sizeof(*hdr)];
-               bacpy(&cp->addr.bdaddr, bdaddr);
-               cp->addr.type = bdaddr_type;
-               cp->passkey = htobl(passkey);
-
-               buf_len = sizeof(*hdr) + sizeof(*cp);
-       }
-
-       if (write(mgmt_sock, buf, buf_len) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static void mgmt_passkey_request(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_ev_user_passkey_request *ev = buf;
-       struct controller_info *info;
-       char addr[18];
-       int err;
-
-       if (len < sizeof(*ev)) {
-               error("Too small passkey_request event");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-
-       DBG("hci%u %s", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in passkey_request event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       err = btd_event_user_passkey(&info->bdaddr, &ev->addr.bdaddr);
-       if (err < 0) {
-               error("btd_event_user_passkey: %s", strerror(-err));
-               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)
-{
-       struct confirm_data *data = user_data;
-       struct controller_info *info = &controllers[data->index];
-
-       DBG("auto-accepting incoming pairing request");
-
-       if (data->index > max_index || !info->valid)
-               return FALSE;
-
-       mgmt_confirm_reply(data->index, &data->bdaddr, data->type, TRUE);
-
-       return FALSE;
-}
-
-static void mgmt_user_confirm_request(int sk, uint16_t index, void *buf,
-                                                               size_t len)
-{
-       struct mgmt_ev_user_confirm_request *ev = buf;
-       struct controller_info *info;
-       char addr[18];
-       int err;
-
-       if (len < sizeof(*ev)) {
-               error("Too small user_confirm_request event");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-
-       DBG("hci%u %s confirm_hint %u", index, addr, ev->confirm_hint);
-
-       if (index > max_index) {
-               error("Unexpected index %u in user_confirm_request event",
-                                                                       index);
-               return;
-       }
-
-       if (ev->confirm_hint) {
-               struct confirm_data *data;
-
-               data = g_new0(struct confirm_data, 1);
-               data->index = index;
-               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);
-               return;
-       }
-
-       info = &controllers[index];
-
-       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->addr.bdaddr, ev->addr.type,
-                                                                       FALSE);
-       }
-}
-
-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 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));
-       hdr->opcode = htobs(MGMT_OP_ADD_UUID);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
-       htob128(&uint128, (uint128_t *) cp->uuid);
-
-       cp->svc_hint = svc_hint;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       info->pending_uuid = TRUE;
-
-       return 0;
-}
-
-static int mgmt_remove_uuid(int index, uuid_t *uuid)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_uuid)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_remove_uuid *cp = (void *) &buf[sizeof(*hdr)];
-       uuid_t uuid128;
-       uint128_t uint128;
-
-       DBG("index %d", index);
-
-       uuid_to_uuid128(&uuid128, uuid);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_REMOVE_UUID);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
-       htob128(&uint128, (uint128_t *) cp->uuid);
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int clear_uuids(int index)
-{
-       uuid_t uuid_any;
-
-       memset(&uuid_any, 0, sizeof(uuid_any));
-       uuid_any.type = SDP_UUID128;
-
-       return mgmt_remove_uuid(index, &uuid_any);
-}
-
-static void read_index_list_complete(int sk, void *buf, size_t len)
-{
-       struct mgmt_rp_read_index_list *rp = buf;
-       uint16_t num;
-       int i;
-
-       if (len < sizeof(*rp)) {
-               error("Too small read index list complete event");
-               return;
-       }
-
-       num = btohs(bt_get_unaligned(&rp->num_controllers));
-
-       if (num * sizeof(uint16_t) + sizeof(*rp) != len) {
-               error("Incorrect packet size for index list event");
-               return;
-       }
-
-       for (i = 0; i < num; i++) {
-               uint16_t index;
-
-               index = btohs(bt_get_unaligned(&rp->index[i]));
-
-               add_controller(index);
-               read_info(sk, index);
-       }
-}
-
-static int mgmt_set_powered(int index, gboolean 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;
-       const char *name;
-       uint8_t mode, major, minor;
-       char addr[18];
-
-       if (len < sizeof(*rp)) {
-               error("Too small read info complete event");
-               return;
-       }
-
-       if (index > max_index) {
-               error("Unexpected index %u in read info complete", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       bacpy(&info->bdaddr, &rp->bdaddr);
-       info->version = rp->version;
-       info->manufacturer = btohs(bt_get_unaligned(&rp->manufacturer));
-
-       memcpy(&info->supported_settings, &rp->supported_settings,
-                                       sizeof(info->supported_settings));
-       memcpy(&info->current_settings, &rp->current_settings,
-                                       sizeof(info->current_settings));
-
-       memcpy(info->dev_class, rp->dev_class, sizeof(info->dev_class));
-
-       ba2str(&info->bdaddr, addr);
-       DBG("hci%u addr %s version %u manufacturer %u class 0x%02x%02x%02x\n",
-               index, addr, info->version, info->manufacturer,
-               info->dev_class[2], info->dev_class[1], info->dev_class[0]);
-       DBG("hci%u settings", index);
-       DBG("hci%u name %s", index, (char *) rp->name);
-       DBG("hci%u short name %s", index, (char *) rp->short_name);
-
-       clear_uuids(index);
-
-       adapter = btd_manager_register_adapter(index,
-                                       mgmt_powered(info->current_settings));
-       if (adapter == NULL) {
-               error("mgmtops: unable to register adapter");
-               return;
-       }
-
-       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 (mode != MODE_OFF && !mgmt_powered(info->current_settings))
-               mgmt_set_powered(index, TRUE);
-       else {
-               get_connections(sk, index);
-               btd_adapter_start(adapter);
-       }
-
-       btd_adapter_unref(adapter);
-}
-
-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;
-       char addr[18];
-
-       if (len < sizeof(*rp)) {
-               error("Too small disconnect complete event");
-               return;
-       }
-
-       ba2str(&rp->addr.bdaddr, addr);
-
-       if (status != 0) {
-               error("Disconnecting %s failed with status %u", addr, status);
-               return;
-       }
-
-       DBG("hci%d %s disconnected", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in disconnect complete", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       btd_event_disconn_complete(&info->bdaddr, &rp->addr.bdaddr);
-
-       bonding_complete(info, &rp->addr.bdaddr, HCI_CONNECTION_TERMINATED);
-}
-
-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;
-       char addr[18];
-
-       if (len < sizeof(*rp)) {
-               error("Too small pair_device complete event");
-               return;
-       }
-
-       ba2str(&rp->addr.bdaddr, addr);
-
-       DBG("hci%d %s pairing complete status %u", index, addr, status);
-
-       if (index > max_index) {
-               error("Unexpected index %u in pair_device complete", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       bonding_complete(info, &rp->addr.bdaddr, status);
-}
-
-static void get_connections_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
-{
-       struct mgmt_rp_get_connections *rp = buf;
-       struct controller_info *info;
-       int i;
-
-       if (len < sizeof(*rp)) {
-               error("Too small get_connections complete event");
-               return;
-       }
-
-       if (len < (sizeof(*rp) + (rp->conn_count * sizeof(bdaddr_t)))) {
-               error("Too small get_connections complete event");
-               return;
-       }
-
-       if (index > max_index) {
-               error("Unexpected index %u in get_connections complete",
-                                                               index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       for (i = 0; i < rp->conn_count; i++) {
-               bdaddr_t *bdaddr = g_memdup(&rp->addr[i], sizeof(bdaddr_t));
-               info->connections = g_slist_append(info->connections, bdaddr);
-       }
-}
-
-static void set_local_name_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
-{
-       struct mgmt_cp_set_local_name *rp = buf;
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-
-       if (len < sizeof(*rp)) {
-               error("Too small set_local_name complete event");
-               return;
-       }
-
-       DBG("hci%d name %s", index, (char *) rp->name);
-
-       if (index > max_index) {
-               error("Unexpected index %u in set_local_name complete", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter == NULL) {
-               DBG("Adapter not found");
-               return;
-       }
-
-       adapter_name_changed(adapter, (char *) rp->name);
-}
-
-static void read_local_oob_data_complete(int sk, uint16_t index, void *buf,
-                                                               size_t len)
-{
-       struct mgmt_rp_read_local_oob_data *rp = buf;
-       struct btd_adapter *adapter;
-
-       if (len != sizeof(*rp)) {
-               error("read_local_oob_data_complete event size mismatch "
-                                       "(%zu != %zu)", len, sizeof(*rp));
-               return;
-       }
-
-       if (index > max_index) {
-               error("Unexpected index %u in read_local_oob_data_complete",
-                                                               index);
-               return;
-       }
-
-       DBG("hci%u", index);
-
-       adapter = manager_find_adapter_by_id(index);
-
-       if (adapter)
-               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;
-
-       if (index > max_index) {
-               error("Unexpected index %u in read_local_oob_data_failed",
-                                                               index);
-               return;
-       }
-
-       DBG("hci%u", index);
-
-       adapter = manager_find_adapter_by_id(index);
-
-       if (adapter)
-               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;
-       uint16_t opcode;
-
-       DBG("");
-
-       if (len < sizeof(*ev)) {
-               error("Too small management command complete event packet");
-               return;
-       }
-
-       opcode = btohs(bt_get_unaligned(&ev->opcode));
-
-       len -= sizeof(*ev);
-
-       switch (opcode) {
-       case MGMT_OP_READ_VERSION:
-               read_version_complete(sk, ev->data, len);
-               break;
-       case MGMT_OP_READ_INDEX_LIST:
-               read_index_list_complete(sk, ev->data, len);
-               break;
-       case MGMT_OP_READ_INFO:
-               read_info_complete(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_SET_POWERED:
-               mgmt_new_settings(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_SET_DISCOVERABLE:
-               mgmt_new_settings(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_SET_CONNECTABLE:
-               mgmt_new_settings(sk, index, ev->data, len);
-               break;
-       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:
-               mgmt_add_uuid_complete(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_REMOVE_UUID:
-               DBG("remove_uuid complete");
-               break;
-       case MGMT_OP_SET_DEV_CLASS:
-               DBG("set_dev_class complete");
-               break;
-       case MGMT_OP_LOAD_LINK_KEYS:
-               DBG("load_link_keys complete");
-               break;
-       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->status, ev->data, len);
-               break;
-       case MGMT_OP_GET_CONNECTIONS:
-               get_connections_complete(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_PIN_CODE_REPLY:
-               DBG("pin_code_reply complete");
-               break;
-       case MGMT_OP_PIN_CODE_NEG_REPLY:
-               DBG("pin_code_neg_reply complete");
-               break;
-       case MGMT_OP_SET_IO_CAPABILITY:
-               DBG("set_io_capability complete");
-               break;
-       case MGMT_OP_PAIR_DEVICE:
-               pair_device_complete(sk, index, ev->status, ev->data, len);
-               break;
-       case MGMT_OP_USER_CONFIRM_REPLY:
-               DBG("user_confirm_reply complete");
-               break;
-       case MGMT_OP_USER_CONFIRM_NEG_REPLY:
-               DBG("user_confirm_net_reply complete");
-               break;
-       case MGMT_OP_SET_LOCAL_NAME:
-               set_local_name_complete(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_READ_LOCAL_OOB_DATA:
-               read_local_oob_data_complete(sk, index, ev->data, len);
-               break;
-       case MGMT_OP_ADD_REMOTE_OOB_DATA:
-               DBG("add_remote_oob_data complete");
-               break;
-       case MGMT_OP_REMOVE_REMOTE_OOB_DATA:
-               DBG("remove_remote_oob_data complete");
-               break;
-       case MGMT_OP_BLOCK_DEVICE:
-               DBG("block_device complete");
-               break;
-       case MGMT_OP_UNBLOCK_DEVICE:
-               DBG("unblock_device complete");
-               break;
-       case MGMT_OP_SET_FAST_CONNECTABLE:
-               DBG("set_fast_connectable complete");
-               break;
-       case MGMT_OP_START_DISCOVERY:
-               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;
-       uint16_t opcode;
-
-       if (len < sizeof(*ev)) {
-               error("Too small management command status event packet");
-               return;
-       }
-
-       opcode = btohs(bt_get_unaligned(&ev->opcode));
-
-       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)
-{
-       struct mgmt_ev_controller_error *ev = buf;
-
-       if (len < sizeof(*ev)) {
-               error("Too small management controller error event packet");
-               return;
-       }
-
-       DBG("index %u error_code %u", index, ev->error_code);
-}
-
-static void mgmt_auth_failed(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct controller_info *info;
-       struct mgmt_ev_auth_failed *ev = buf;
-
-       if (len < sizeof(*ev)) {
-               error("Too small mgmt_auth_failed event packet");
-               return;
-       }
-
-       DBG("hci%u auth failed status %u", index, ev->status);
-
-       if (index > max_index) {
-               error("Unexpected index %u in auth_failed event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       bonding_complete(info, &ev->addr.bdaddr, ev->status);
-}
-
-static void mgmt_local_name_changed(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct mgmt_cp_set_local_name *ev = buf;
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-
-       if (len < sizeof(*ev)) {
-               error("Too small mgmt_local_name_changed event packet");
-               return;
-       }
-
-       DBG("hci%u local name changed: %s", index, (char *) ev->name);
-
-       if (index > max_index) {
-               error("Unexpected index %u in name_changed event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (adapter)
-               adapter_name_changed(adapter, (char *) ev->name);
-}
-
-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;
-       gboolean confirm_name;
-
-       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;
-       }
-
-       if (index > max_index) {
-               error("Unexpected index %u in device_found event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       if (eir_len == 0)
-               eir = NULL;
-       else
-               eir = ev->eir;
-
-       flags = btohl(ev->flags);
-
-       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 (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);
-
-       confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_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_ev_discovering *ev = buf;
-       struct controller_info *info;
-       struct btd_adapter *adapter;
-
-       if (len < sizeof(*ev)) {
-               error("Too small discovering event");
-               return;
-       }
-
-       DBG("Controller %u type %u discovering %u", index,
-                                       ev->type, ev->discovering);
-
-       if (index > max_index) {
-               error("Unexpected index %u in discovering event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       adapter = manager_find_adapter(&info->bdaddr);
-       if (!adapter)
-               return;
-
-       adapter_set_discovering(adapter, ev->discovering);
-}
-
-static void mgmt_device_blocked(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct controller_info *info;
-       struct mgmt_ev_device_blocked *ev = buf;
-       char addr[18];
-
-       if (len < sizeof(*ev)) {
-               error("Too small mgmt_device_blocked event packet");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-       DBG("Device blocked, index %u, addr %s", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in device_blocked event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       btd_event_device_blocked(&info->bdaddr, &ev->addr.bdaddr);
-}
-
-static void mgmt_device_unblocked(int sk, uint16_t index, void *buf, size_t len)
-{
-       struct controller_info *info;
-       struct mgmt_ev_device_unblocked *ev = buf;
-       char addr[18];
-
-       if (len < sizeof(*ev)) {
-               error("Too small mgmt_device_unblocked event packet");
-               return;
-       }
-
-       ba2str(&ev->addr.bdaddr, addr);
-       DBG("Device unblocked, index %u, addr %s", index, addr);
-
-       if (index > max_index) {
-               error("Unexpected index %u in device_unblocked event", index);
-               return;
-       }
-
-       info = &controllers[index];
-
-       btd_event_device_unblocked(&info->bdaddr, &ev->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)
-{
-       char buf[MGMT_BUF_SIZE];
-       struct mgmt_hdr *hdr = (void *) buf;
-       int sk;
-       ssize_t ret;
-       uint16_t len, opcode, index;
-
-       DBG("cond %d", cond);
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       sk = g_io_channel_unix_get_fd(io);
-
-       if (cond & (G_IO_ERR | G_IO_HUP)) {
-               error("Error on management socket");
-               return FALSE;
-       }
-
-       ret = read(sk, buf, sizeof(buf));
-       if (ret < 0) {
-               error("Unable to read from management socket: %s (%d)",
-                                               strerror(errno), errno);
-               return TRUE;
-       }
-
-       DBG("Received %zd bytes from management socket", ret);
-
-       if (ret < MGMT_HDR_SIZE) {
-               error("Too small Management packet");
-               return TRUE;
-       }
-
-       opcode = btohs(bt_get_unaligned(&hdr->opcode));
-       len = btohs(bt_get_unaligned(&hdr->len));
-       index = btohs(bt_get_unaligned(&hdr->index));
-
-       if (ret != MGMT_HDR_SIZE + len) {
-               error("Packet length mismatch. ret %zd len %u", ret, len);
-               return TRUE;
-       }
-
-       switch (opcode) {
-       case MGMT_EV_CMD_COMPLETE:
-               mgmt_cmd_complete(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_CMD_STATUS:
-               mgmt_cmd_status(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_CONTROLLER_ERROR:
-               mgmt_controller_error(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_INDEX_ADDED:
-               mgmt_index_added(sk, index);
-               break;
-       case MGMT_EV_INDEX_REMOVED:
-               mgmt_index_removed(sk, index);
-               break;
-       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;
-       case MGMT_EV_DEVICE_CONNECTED:
-               mgmt_device_connected(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DEVICE_DISCONNECTED:
-               mgmt_device_disconnected(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_CONNECT_FAILED:
-               mgmt_connect_failed(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_PIN_CODE_REQUEST:
-               mgmt_pin_code_request(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_USER_CONFIRM_REQUEST:
-               mgmt_user_confirm_request(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_AUTH_FAILED:
-               mgmt_auth_failed(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_LOCAL_NAME_CHANGED:
-               mgmt_local_name_changed(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DEVICE_FOUND:
-               mgmt_device_found(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DISCOVERING:
-               mgmt_discovering(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DEVICE_BLOCKED:
-               mgmt_device_blocked(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_DEVICE_UNBLOCKED:
-               mgmt_device_unblocked(sk, index, buf + MGMT_HDR_SIZE, len);
-               break;
-       case MGMT_EV_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;
-       }
-
-       return TRUE;
-}
-
-static int mgmt_setup(void)
-{
-       struct mgmt_hdr hdr;
-       struct sockaddr_hci addr;
-       GIOChannel *io;
-       GIOCondition condition;
-       int dd, err;
-
-       dd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-       if (dd < 0)
-               return -errno;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.hci_family = AF_BLUETOOTH;
-       addr.hci_dev = HCI_DEV_NONE;
-       addr.hci_channel = HCI_CHANNEL_CONTROL;
-
-       if (bind(dd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               goto fail;
-       }
-
-       memset(&hdr, 0, sizeof(hdr));
-       hdr.opcode = htobs(MGMT_OP_READ_VERSION);
-       hdr.index = htobs(MGMT_INDEX_NONE);
-       if (write(dd, &hdr, sizeof(hdr)) < 0) {
-               err = -errno;
-               goto fail;
-       }
-
-       io = g_io_channel_unix_new(dd);
-       condition = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
-       mgmt_watch = g_io_add_watch(io, condition, mgmt_event, NULL);
-       g_io_channel_unref(io);
-
-       mgmt_sock = dd;
-
-       info("Bluetooth Management interface initialized");
-
-       return 0;
-
-fail:
-       close(dd);
-       return err;
-}
-
-static void mgmt_cleanup(void)
-{
-       g_free(controllers);
-       controllers = NULL;
-       max_index = -1;
-
-       if (mgmt_sock >= 0) {
-               close(mgmt_sock);
-               mgmt_sock = -1;
-       }
-
-       if (mgmt_watch > 0) {
-               g_source_remove(mgmt_watch);
-               mgmt_watch = 0;
-       }
-}
-
-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);
-
-       cp->type = info->discov_type;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_stop_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);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_STOP_DISCOVERY);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp->type = info->discov_type;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_set_fast_connectable(int index, gboolean enable)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_mode)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_mode *cp = (void *) &buf[sizeof(*hdr)];
-
-       DBG("index %d enable %d", index, enable);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_SET_FAST_CONNECTABLE);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp->val = enable;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_read_clock(int index, bdaddr_t *bdaddr, int which, int timeout,
-                                       uint32_t *clock, uint16_t *accuracy)
-{
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s which %d timeout %d", index, addr, which,
-                                                               timeout);
-
-       return -ENOSYS;
-}
-
-static int mgmt_read_bdaddr(int index, bdaddr_t *bdaddr)
-{
-       char addr[18];
-       struct controller_info *info = &controllers[index];
-
-       ba2str(&info->bdaddr, addr);
-       DBG("index %d addr %s", index, addr);
-
-       if (!info->valid)
-               return -ENODEV;
-
-       bacpy(bdaddr, &info->bdaddr);
-
-       return 0;
-}
-
-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;
-       struct mgmt_cp_block_device *cp;
-       size_t buf_len;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s", index, addr);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->opcode = htobs(MGMT_OP_BLOCK_DEVICE);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       cp->addr.type = bdaddr_type;
-
-       buf_len = sizeof(*hdr) + sizeof(*cp);
-
-       if (write(mgmt_sock, buf, buf_len) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_unblock_device(int index, bdaddr_t *bdaddr,
-                                                       uint8_t bdaddr_type)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unblock_device)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_unblock_device *cp;
-       size_t buf_len;
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d addr %s", index, addr);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->opcode = htobs(MGMT_OP_UNBLOCK_DEVICE);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp = (void *) &buf[sizeof(*hdr)];
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       cp->addr.type = bdaddr_type;
-
-       buf_len = sizeof(*hdr) + sizeof(*cp);
-
-       if (write(mgmt_sock, buf, buf_len) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_get_conn_list(int index, GSList **conns)
-{
-       struct controller_info *info = &controllers[index];
-
-       DBG("index %d", index);
-
-       *conns = info->connections;
-       info->connections = NULL;
-
-       return 0;
-}
-
-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;
-       struct mgmt_cp_disconnect *cp = (void *) &buf[sizeof(*hdr)];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("index %d %s", index, addr);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_DISCONNECT);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       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);
-
-       return 0;
-}
-
-static int mgmt_unpair_device(int index, bdaddr_t *bdaddr, uint8_t bdaddr_type)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_unpair_device)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       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_UNPAIR_DEVICE);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       cp->addr.type = bdaddr_type;
-       cp->disconnect = 1;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_encrypt_link(int index, bdaddr_t *dst, bt_hci_result_t cb,
-                                                       gpointer user_data)
-{
-       char addr[18];
-
-       ba2str(dst, addr);
-       DBG("index %d addr %s", index, addr);
-
-       return -ENOSYS;
-}
-
-static int mgmt_set_did(int index, uint16_t vendor, uint16_t product,
-                                       uint16_t version, uint16_t source)
-{
-       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)
-{
-       DBG("index %d", index);
-
-       /* The cache control is handled automatically for mgmt */
-       return 0;
-}
-
-static int mgmt_restore_powered(int index)
-{
-       DBG("index %d", index);
-       return -ENOSYS;
-}
-
-static int mgmt_load_link_keys(int index, GSList *keys, gboolean debug_keys)
-{
-       char *buf;
-       struct mgmt_hdr *hdr;
-       struct mgmt_cp_load_link_keys *cp;
-       struct mgmt_link_key_info *key;
-       size_t key_count, cp_size;
-       GSList *l;
-       int err;
-
-       key_count = g_slist_length(keys);
-
-       DBG("index %d keys %zu debug_keys %d", index, key_count, debug_keys);
-
-       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_LINK_KEYS);
-       hdr->len = htobs(cp_size);
-       hdr->index = htobs(index);
-
-       cp = (void *) (buf + sizeof(*hdr));
-       cp->debug_keys = debug_keys;
-       cp->key_count = htobs(key_count);
-
-       for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
-               struct link_key_info *info = l->data;
-
-               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;
-       }
-
-       if (write(mgmt_sock, buf, sizeof(*hdr) + cp_size) < 0)
-               err = -errno;
-       else
-               err = 0;
-
-       g_free(buf);
-
-       return err;
-}
-
-static int mgmt_set_io_capability(int index, uint8_t io_capability)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_set_io_capability)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_set_io_capability *cp = (void *) &buf[sizeof(*hdr)];
-
-       DBG("hci%d io_capability 0x%02x", index, io_capability);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_SET_IO_CAPABILITY);
-       hdr->len = htobs(sizeof(*cp));
-       hdr->index = htobs(index);
-
-       cp->io_capability = io_capability;
-
-       if (write(mgmt_sock, buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-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;
-       struct mgmt_cp_pair_device *cp = (void *) &buf[sizeof(*hdr)];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s io_cap 0x%02x", index, addr, io_cap);
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(MGMT_OP_PAIR_DEVICE);
-       hdr->len = htobs(sizeof(*cp));
-       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)
-               return -errno;
-
-       return 0;
-}
-
-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);
-
-       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)
-{
-       struct mgmt_hdr hdr;
-
-       DBG("hci%d", index);
-
-       hdr.opcode = htobs(MGMT_OP_READ_LOCAL_OOB_DATA);
-       hdr.len = 0;
-       hdr.index = htobs(index);
-
-       if (write(mgmt_sock, &hdr, sizeof(hdr)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_add_remote_oob_data(int index, bdaddr_t *bdaddr,
-                                       uint8_t *hash, uint8_t *randomizer)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_add_remote_oob_data)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_add_remote_oob_data *cp = (void *) &buf[sizeof(*hdr)];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s", index, addr);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->opcode = htobs(MGMT_OP_ADD_REMOTE_OOB_DATA);
-       hdr->index = htobs(index);
-       hdr->len = htobs(sizeof(*cp));
-
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       memcpy(cp->hash, hash, 16);
-       memcpy(cp->randomizer, randomizer, 16);
-
-       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static int mgmt_remove_remote_oob_data(int index, bdaddr_t *bdaddr)
-{
-       char buf[MGMT_HDR_SIZE + sizeof(struct mgmt_cp_remove_remote_oob_data)];
-       struct mgmt_hdr *hdr = (void *) buf;
-       struct mgmt_cp_remove_remote_oob_data *cp = (void *) &buf[sizeof(*hdr)];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s", index, addr);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->opcode = htobs(MGMT_OP_REMOVE_REMOTE_OOB_DATA);
-       hdr->index = htobs(index);
-       hdr->len = htobs(sizeof(*cp));
-
-       bacpy(&cp->addr.bdaddr, bdaddr);
-
-       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
-               return -errno;
-
-       return 0;
-}
-
-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;
-       struct mgmt_cp_confirm_name *cp = (void *) &buf[sizeof(*hdr)];
-       char addr[18];
-
-       ba2str(bdaddr, addr);
-       DBG("hci%d bdaddr %s name_known %u", index, addr, name_known);
-
-       memset(buf, 0, sizeof(buf));
-
-       hdr->opcode = htobs(MGMT_OP_CONFIRM_NAME);
-       hdr->index = htobs(index);
-       hdr->len = htobs(sizeof(*cp));
-
-       bacpy(&cp->addr.bdaddr, bdaddr);
-       cp->addr.type = bdaddr_type;
-       cp->name_known = name_known;
-
-       if (write(mgmt_sock, &buf, sizeof(buf)) < 0)
-               return -errno;
-
-       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,
-       .start_discovery = mgmt_start_discovery,
-       .stop_discovery = mgmt_stop_discovery,
-       .set_name = mgmt_set_name,
-       .set_dev_class = mgmt_set_dev_class,
-       .set_fast_connectable = mgmt_set_fast_connectable,
-       .read_clock = mgmt_read_clock,
-       .read_bdaddr = mgmt_read_bdaddr,
-       .block_device = mgmt_block_device,
-       .unblock_device = mgmt_unblock_device,
-       .get_conn_list = mgmt_get_conn_list,
-       .disconnect = mgmt_disconnect,
-       .remove_bonding = mgmt_unpair_device,
-       .pincode_reply = mgmt_pincode_reply,
-       .confirm_reply = mgmt_confirm_reply,
-       .passkey_reply = mgmt_passkey_reply,
-       .encrypt_link = mgmt_encrypt_link,
-       .set_did = mgmt_set_did,
-       .add_uuid = mgmt_add_uuid,
-       .remove_uuid = mgmt_remove_uuid,
-       .disable_cod_cache = mgmt_disable_cod_cache,
-       .restore_powered = mgmt_restore_powered,
-       .load_keys = mgmt_load_link_keys,
-       .set_io_capability = mgmt_set_io_capability,
-       .create_bonding = mgmt_create_bonding,
-       .cancel_bonding = mgmt_cancel_bonding,
-       .read_local_oob_data = mgmt_read_local_oob_data,
-       .add_remote_oob_data = mgmt_add_remote_oob_data,
-       .remove_remote_oob_data = mgmt_remove_remote_oob_data,
-       .confirm_name = mgmt_confirm_name,
-       .load_ltks = mgmtops_load_ltks,
-};
-
-static int mgmt_init(void)
-{
-       return btd_register_adapter_ops(&mgmt_ops, TRUE);
-}
-
-static void mgmt_exit(void)
-{
-       btd_adapter_cleanup_ops(&mgmt_ops);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(mgmtops, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_LOW, mgmt_init, mgmt_exit)
diff --git a/plugins/neard.c b/plugins/neard.c
new file mode 100644 (file)
index 0000000..ea91c4d
--- /dev/null
@@ -0,0 +1,908 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012-2013  Tieto Poland
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <gdbus/gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/sdp.h>
+
+#include "plugin.h"
+#include "log.h"
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "eir.h"
+#include "agent.h"
+#include "hcid.h"
+
+#define NEARD_NAME "org.neard"
+#define NEARD_PATH "/"
+#define NEARD_MANAGER_INTERFACE "org.neard.Manager"
+#define AGENT_INTERFACE "org.neard.HandoverAgent"
+#define AGENT_PATH "/org/bluez/neard_handover_agent"
+#define AGENT_CARRIER_TYPE "bluetooth"
+#define ERROR_INTERFACE "org.neard.HandoverAgent.Error"
+
+static guint watcher_id = 0;
+static char *neard_service = NULL;
+static bool agent_register_postpone = false;
+
+/* For NFC mimetype limits max OOB EIR size */
+#define NFC_OOB_EIR_MAX UINT8_MAX
+
+enum cps {
+       CPS_ACTIVE,
+       CPS_INACTIVE,
+       CPS_ACTIVATING,
+       CPS_UNKNOWN,
+};
+
+struct oob_params {
+       bdaddr_t address;
+       uint32_t class;
+       char *name;
+       GSList *services;
+       uint8_t *hash;
+       uint8_t *randomizer;
+       uint8_t *pin;
+       int pin_len;
+       enum cps power_state;
+};
+
+static void free_oob_params(struct oob_params *params)
+{
+       g_slist_free_full(params->services, g_free);
+       g_free(params->name);
+       g_free(params->hash);
+       g_free(params->randomizer);
+       g_free(params->pin);
+}
+
+static DBusMessage *error_reply(DBusMessage *msg, int error)
+{
+       const char *name;
+
+       if (error == EINPROGRESS)
+               name = ERROR_INTERFACE ".InProgress";
+       else
+               name = ERROR_INTERFACE ".Failed";
+
+       return g_dbus_create_error(msg, name , "%s", strerror(error));
+}
+
+static void register_agent(bool append_carrier);
+
+static void register_agent_cb(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *reply;
+       DBusError err;
+       static bool try_fallback = true;
+
+       reply = dbus_pending_call_steal_reply(call);
+
+       dbus_error_init(&err);
+       if (dbus_set_error_from_message(&err, reply)) {
+               if (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err.name) &&
+                               try_fallback) {
+                       DBG("Register to neard failed, trying legacy way");
+
+                       register_agent(false);
+                       try_fallback = false;
+               } else {
+                       error("neard manager replied with an error: %s, %s",
+                                                       err.name, err.message);
+
+                       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               AGENT_PATH, AGENT_INTERFACE);
+                       try_fallback = true;
+               }
+
+               dbus_error_free(&err);
+               dbus_message_unref(reply);
+
+               return;
+       }
+
+       dbus_message_unref(reply);
+       neard_service = g_strdup(dbus_message_get_sender(reply));
+
+       try_fallback = true;
+
+       info("Registered as neard handover agent");
+}
+
+static void register_agent(bool append_carrier)
+{
+       DBusMessage *message;
+       DBusPendingCall *call;
+       const char *path = AGENT_PATH;
+       const char *carrier = AGENT_CARRIER_TYPE;
+
+       message = dbus_message_new_method_call(NEARD_NAME, NEARD_PATH,
+                       NEARD_MANAGER_INTERFACE, "RegisterHandoverAgent");
+       if (!message) {
+               error("Couldn't allocate D-Bus message");
+               return;
+       }
+
+       dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID);
+
+       if (append_carrier)
+               dbus_message_append_args(message, DBUS_TYPE_STRING, &carrier,
+                                                       DBUS_TYPE_INVALID);
+
+       if (!g_dbus_send_message_with_reply(btd_get_dbus_connection(),
+                                                       message, &call, -1)) {
+               dbus_message_unref(message);
+               error("D-Bus send failed");
+               return;
+       }
+
+       dbus_pending_call_set_notify(call, register_agent_cb, NULL, NULL);
+       dbus_pending_call_unref(call);
+
+       dbus_message_unref(message);
+}
+
+static void unregister_agent(void)
+{
+       DBusMessage *message;
+       const char *path = AGENT_PATH;
+       const char *carrier = AGENT_CARRIER_TYPE;
+
+       g_free(neard_service);
+       neard_service = NULL;
+
+       message = dbus_message_new_method_call(NEARD_NAME, NEARD_PATH,
+                       NEARD_MANAGER_INTERFACE, "UnregisterHandoverAgent");
+
+       if (!message) {
+               error("Couldn't allocate D-Bus message");
+               goto unregister;
+       }
+
+       dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID);
+
+       dbus_message_append_args(message, DBUS_TYPE_STRING, &carrier,
+                                                       DBUS_TYPE_INVALID);
+
+       if (!g_dbus_send_message(btd_get_dbus_connection(), message))
+               error("D-Bus send failed");
+
+unregister:
+       g_dbus_unregister_interface(btd_get_dbus_connection(), AGENT_PATH,
+                                                       AGENT_INTERFACE);
+}
+
+static void add_power_state(DBusMessageIter *dict, struct btd_adapter *adapter)
+{
+       const char *state;
+
+       if (btd_adapter_get_powered(adapter) &&
+                                       btd_adapter_get_connectable(adapter))
+               state = "active";
+       else
+               state = "inactive";
+
+       dict_append_entry(dict, "State", DBUS_TYPE_STRING, &state);
+}
+
+static DBusMessage *create_request_oob_reply(struct btd_adapter *adapter,
+                                               const uint8_t *hash,
+                                               const uint8_t *randomizer,
+                                               DBusMessage *msg)
+{
+       DBusMessage *reply;
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       uint8_t eir[NFC_OOB_EIR_MAX];
+       uint8_t *peir = eir;
+       int len;
+
+       len = eir_create_oob(adapter_get_address(adapter),
+                               btd_adapter_get_name(adapter),
+                               btd_adapter_get_class(adapter), hash,
+                               randomizer, main_opts.did_vendor,
+                               main_opts.did_product, main_opts.did_version,
+                               main_opts.did_source,
+                               btd_adapter_get_services(adapter), eir);
+
+       reply = dbus_message_new_method_return(msg);
+       if (!reply)
+               return NULL;
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                               &dict);
+
+       dict_append_array(&dict, "EIR", DBUS_TYPE_BYTE, &peir, len);
+
+       add_power_state(&dict, adapter);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       return reply;
+}
+
+static void read_local_complete(struct btd_adapter *adapter,
+                               const uint8_t *hash, const uint8_t *randomizer,
+                               void *user_data)
+{
+       DBusMessage *msg = user_data;
+       DBusMessage *reply;
+
+       DBG("");
+
+       if (neard_service == NULL) {
+               dbus_message_unref(msg);
+
+               if (agent_register_postpone) {
+                       agent_register_postpone = false;
+                       register_agent(true);
+               }
+
+               return;
+       }
+
+       if (hash && randomizer)
+               reply = create_request_oob_reply(adapter, hash, randomizer,
+                                                                       msg);
+       else
+               reply = error_reply(msg, EIO);
+
+       dbus_message_unref(msg);
+
+       if (!g_dbus_send_message(btd_get_dbus_connection(), reply))
+               error("D-Bus send failed");
+}
+
+static void bonding_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr, uint8_t status,
+                                       void *user_data)
+{
+       DBusMessage *msg = user_data;
+       DBusMessage *reply;
+
+       DBG("");
+
+       if (neard_service == NULL) {
+               dbus_message_unref(msg);
+
+               if (agent_register_postpone) {
+                       agent_register_postpone = false;
+                       register_agent(true);
+               }
+
+               return;
+       }
+
+       if (status)
+               reply = error_reply(msg, EIO);
+       else
+               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+       dbus_message_unref(msg);
+
+       if (!g_dbus_send_message(btd_get_dbus_connection(), reply))
+               error("D-Bus send failed");
+}
+
+static int check_device(struct btd_device *device)
+{
+       if (!device)
+               return -ENOENT;
+
+       /* If already paired */
+       if (device_is_paired(device)) {
+               DBG("already paired");
+               return -EALREADY;
+       }
+
+       /* Pairing in progress... */
+       if (device_is_bonding(device, NULL)) {
+               DBG("pairing in progress");
+               return -EINPROGRESS;
+       }
+
+       return 0;
+}
+
+static int process_eir(uint8_t *eir, size_t size, struct oob_params *remote)
+{
+       struct eir_data eir_data;
+
+       DBG("size %zu", size);
+
+       memset(&eir_data, 0, sizeof(eir_data));
+
+       if (eir_parse_oob(&eir_data, eir, size) < 0)
+               return -EINVAL;
+
+       bacpy(&remote->address, &eir_data.addr);
+
+       remote->class = eir_data.class;
+
+       remote->name = eir_data.name;
+       eir_data.name = NULL;
+
+       remote->services = eir_data.services;
+       eir_data.services = NULL;
+
+       remote->hash = eir_data.hash;
+       eir_data.hash = NULL;
+
+       remote->randomizer = eir_data.randomizer;
+       eir_data.randomizer = NULL;
+
+       eir_data_free(&eir_data);
+
+       return 0;
+}
+
+/*
+ * This is (barely documented) Nokia extension format, most work was done by
+ * reverse engineering.
+ *
+ * Binary format varies among different devices, type depends on first byte
+ * 0x00 - BT address not reversed, 16 bytes authentication data (all zeros)
+ * 0x01 - BT address not reversed, 16 bytes authentication data (4 digit PIN,
+ *        padded with zeros)
+ * 0x02 - BT address not reversed, 16 bytes authentication data (not sure if
+ *        16 digit PIN or link key?, Nokia refers to it as ' Public Key')
+ * 0x10 - BT address reversed, no authentication data
+ * 0x24 - BT address not reversed, 4 bytes authentication data (4 digit PIN)
+ *
+ * General structure:
+ * 1 byte  - marker
+ * 6 bytes - BT address (reversed or not, depends on marker)
+ * 3 bytes - Class of Device
+ * 0, 4 or 16 bytes - authentication data, interpretation depends on marker
+ * 1 bytes - name length
+ * N bytes - name
+ */
+
+static int process_nokia_long (void *data, size_t size, uint8_t marker,
+                                               struct oob_params *remote)
+{
+       struct {
+               bdaddr_t address;
+               uint8_t class[3];
+               uint8_t authentication[16];
+               uint8_t name_len;
+               uint8_t name[0];
+       } __attribute__((packed)) *n = data;
+
+       if (size != sizeof(*n) + n->name_len)
+               return -EINVAL;
+
+       /* address is not reverted */
+       baswap(&remote->address, &n->address);
+
+       remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16);
+
+       if (n->name_len > 0)
+               remote->name = g_strndup((char *)n->name, n->name_len);
+
+       if (marker == 0x01) {
+               remote->pin = g_memdup(n->authentication, 4);
+               remote->pin_len = 4;
+       } else if (marker == 0x02) {
+               remote->pin = g_memdup(n->authentication, 16);
+               remote->pin_len = 16;
+       }
+
+       return 0;
+}
+
+static int process_nokia_short (void *data, size_t size,
+                                               struct oob_params *remote)
+{
+       struct {
+               bdaddr_t address;
+               uint8_t class[3];
+               uint8_t authentication[4];
+               uint8_t name_len;
+               uint8_t name[0];
+       } __attribute__((packed)) *n = data;
+
+       if (size != sizeof(*n) + n->name_len)
+               return -EINVAL;
+
+       /* address is not reverted */
+       baswap(&remote->address, &n->address);
+
+       remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16);
+
+       if (n->name_len > 0)
+               remote->name = g_strndup((char *)n->name, n->name_len);
+
+       remote->pin = g_memdup(n->authentication, 4);
+       remote->pin_len = 4;
+
+       return 0;
+}
+
+static int process_nokia_extra_short (void *data, size_t size,
+                                               struct oob_params *remote)
+{
+       struct {
+               bdaddr_t address;
+               uint8_t class[3];
+               uint8_t name_len;
+               uint8_t name[0];
+       } __attribute__((packed)) *n = data;
+
+       if (size != sizeof(*n) + n->name_len)
+               return -EINVAL;
+
+       bacpy(&remote->address, &n->address);
+
+       remote->class = n->class[0] | (n->class[1] << 8) | (n->class[2] << 16);
+
+       if (n->name_len > 0)
+               remote->name = g_strndup((char *)n->name, n->name_len);
+
+       return 0;
+}
+
+static int process_nokia_com_bt(uint8_t *data, size_t size,
+                                               struct oob_params *remote)
+{
+       uint8_t marker;
+
+       marker = *data++;
+       size--;
+
+       DBG("marker: 0x%.2x  size: %zu", marker, size);
+
+       switch (marker) {
+       case 0x00:
+       case 0x01:
+       case 0x02:
+               return process_nokia_long(data, size, marker, remote);
+       case 0x10:
+               return process_nokia_extra_short(data, size, remote);
+       case 0x24:
+               return process_nokia_short(data, size, remote);
+       default:
+               warn("Not supported Nokia NFC extension (0x%.2x)", marker);
+               return -EPROTONOSUPPORT;
+       }
+}
+
+static enum cps process_state(const char *state)
+{
+       if (strcasecmp(state, "active") == 0)
+               return CPS_ACTIVE;
+
+       if (strcasecmp(state, "activating") == 0)
+               return CPS_ACTIVATING;
+
+       if (strcasecmp(state, "inactive") == 0)
+               return CPS_INACTIVE;
+
+       return CPS_UNKNOWN;
+}
+
+static int process_message(DBusMessage *msg, struct oob_params *remote)
+{
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+
+       dbus_message_iter_init(msg, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return -EINVAL;
+
+       /* set CPS to unknown in case State was not provided */
+       remote->power_state = CPS_UNKNOWN;
+
+       dbus_message_iter_recurse(&iter, &dict);
+
+       while (dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter value;
+               DBusMessageIter entry;
+               const char *key;
+
+               dbus_message_iter_recurse(&dict, &entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       goto error;
+
+               dbus_message_iter_get_basic(&entry, &key);
+               dbus_message_iter_next(&entry);
+
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (strcasecmp(key, "EIR") == 0) {
+                       DBusMessageIter array;
+                       uint8_t *eir;
+                       int size;
+
+                       /* nokia.com:bt and EIR should not be passed together */
+                       if (bacmp(&remote->address, BDADDR_ANY) != 0)
+                               goto error;
+
+                       if (dbus_message_iter_get_arg_type(&value) !=
+                                       DBUS_TYPE_ARRAY)
+                               goto error;
+
+                       dbus_message_iter_recurse(&value, &array);
+                       dbus_message_iter_get_fixed_array(&array, &eir, &size);
+
+                       if (process_eir(eir, size, remote) < 0)
+                               goto error;
+               } else if (strcasecmp(key, "nokia.com:bt") == 0) {
+                       DBusMessageIter array;
+                       uint8_t *data;
+                       int size;
+
+                       /* nokia.com:bt and EIR should not be passed together */
+                       if (bacmp(&remote->address, BDADDR_ANY) != 0)
+                               goto error;
+
+                       if (dbus_message_iter_get_arg_type(&value) !=
+                                       DBUS_TYPE_ARRAY)
+                               goto error;
+
+                       dbus_message_iter_recurse(&value, &array);
+                       dbus_message_iter_get_fixed_array(&array, &data, &size);
+
+                       if (process_nokia_com_bt(data, size, remote))
+                               goto error;
+               } else if (strcasecmp(key, "State") == 0) {
+                       DBusMessageIter array;
+                       const char *state;
+
+                       if (dbus_message_iter_get_arg_type(&value) !=
+                                       DBUS_TYPE_STRING)
+                               goto error;
+
+                       dbus_message_iter_recurse(&value, &array);
+                       dbus_message_iter_get_basic(&value, &state);
+
+                       remote->power_state = process_state(state);
+                       if (remote->power_state == CPS_UNKNOWN)
+                               goto error;
+               }
+
+               dbus_message_iter_next(&dict);
+       }
+
+       /* Check if 'State' was passed along with one of other fields */
+       if (remote->power_state != CPS_UNKNOWN
+                       && bacmp(&remote->address, BDADDR_ANY) == 0)
+               return -EINVAL;
+
+       return 0;
+
+error:
+       if (bacmp(&remote->address, BDADDR_ANY) != 0) {
+               free_oob_params(remote);
+               memset(remote, 0, sizeof(*remote));
+       }
+
+       return -EINVAL;
+}
+
+static int check_adapter(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return -ENOENT;
+
+       if (btd_adapter_check_oob_handler(adapter))
+               return -EINPROGRESS;
+
+       if (!btd_adapter_ssp_enabled(adapter))
+               return -ENOTSUP;
+
+       return 0;
+}
+
+static void store_params(struct btd_adapter *adapter, struct btd_device *device,
+                                               struct oob_params *params)
+{
+       if (params->class != 0)
+               device_set_class(device, params->class);
+
+       if (params->name) {
+               device_store_cached_name(device, params->name);
+               device_set_name(device, params->name);
+       }
+
+       /* TODO handle UUIDs? */
+
+       if (params->hash) {
+               btd_adapter_add_remote_oob_data(adapter, &params->address,
+                                                       params->hash,
+                                                       params->randomizer);
+       } else if (params->pin_len) {
+               /* TODO
+                * Handle PIN, for now only discovery mode and 'common' PINs
+                * that might be provided by agent will work correctly.
+                */
+       }
+}
+
+static DBusMessage *push_oob(DBusConnection *conn, DBusMessage *msg, void *data)
+{
+       struct btd_adapter *adapter;
+       struct agent *agent;
+       struct oob_handler *handler;
+       struct oob_params remote;
+       struct btd_device *device;
+       uint8_t io_cap;
+       int err;
+
+       if (neard_service == NULL ||
+                       !g_str_equal(neard_service, dbus_message_get_sender(msg)))
+               return error_reply(msg, EPERM);
+
+       DBG("");
+
+       adapter = btd_adapter_get_default();
+
+       err = check_adapter(adapter);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       if (!btd_adapter_get_powered(adapter))
+               return error_reply(msg, ENONET);
+
+       agent = adapter_get_agent(adapter);
+       if (!agent)
+               return error_reply(msg, ENONET);
+
+       io_cap = agent_get_io_capability(agent);
+       agent_unref(agent);
+
+       memset(&remote, 0, sizeof(remote));
+
+       err = process_message(msg, &remote);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       if (bacmp(&remote.address, BDADDR_ANY) == 0) {
+               free_oob_params(&remote);
+
+               return error_reply(msg, EINVAL);
+       }
+
+       device = adapter_get_device(adapter, &remote.address, BDADDR_BREDR);
+
+       err = check_device(device);
+       if (err < 0) {
+               free_oob_params(&remote);
+
+               /* already paired, reply immediately */
+               if (err == -EALREADY)
+                       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+               return error_reply(msg, -err);
+       }
+
+       if (!btd_adapter_get_pairable(adapter)) {
+               free_oob_params(&remote);
+
+               return error_reply(msg, ENONET);
+       }
+
+       store_params(adapter, device, &remote);
+
+       free_oob_params(&remote);
+
+       err = adapter_create_bonding(adapter, device_get_address(device),
+                                                       BDADDR_BREDR, io_cap);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       handler = g_new0(struct oob_handler, 1);
+       handler->bonding_cb = bonding_complete;
+       bacpy(&handler->remote_addr, device_get_address(device));
+       handler->user_data = dbus_message_ref(msg);
+
+       btd_adapter_set_oob_handler(adapter, handler);
+
+       return NULL;
+}
+
+static DBusMessage *request_oob(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct btd_adapter *adapter;
+       struct oob_handler *handler;
+       struct oob_params remote;
+       struct btd_device *device;
+       int err;
+
+       if (neard_service == NULL ||
+                       !g_str_equal(neard_service, dbus_message_get_sender(msg)))
+               return error_reply(msg, EPERM);
+
+       DBG("");
+
+       adapter = btd_adapter_get_default();
+
+       err = check_adapter(adapter);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       memset(&remote, 0, sizeof(remote));
+
+       err = process_message(msg, &remote);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       if (bacmp(&remote.address, BDADDR_ANY) == 0)
+               goto read_local;
+
+       device = adapter_get_device(adapter, &remote.address, BDADDR_BREDR);
+
+       err = check_device(device);
+       if (err < 0) {
+               free_oob_params(&remote);
+
+               if (err == -EALREADY)
+                       return create_request_oob_reply(adapter, NULL, NULL,
+                                                                       msg);
+
+               return error_reply(msg, -err);
+       }
+
+       if (!btd_adapter_get_pairable(adapter)) {
+               free_oob_params(&remote);
+
+               return error_reply(msg, ENONET);
+       }
+
+       store_params(adapter, device, &remote);
+
+       if (!remote.hash || !btd_adapter_get_powered(adapter)) {
+               free_oob_params(&remote);
+               return create_request_oob_reply(adapter, NULL, NULL, msg);
+       }
+
+read_local:
+       free_oob_params(&remote);
+
+       if (!btd_adapter_get_powered(adapter))
+               return create_request_oob_reply(adapter, NULL, NULL, msg);
+
+       err = btd_adapter_read_local_oob_data(adapter);
+       if (err < 0)
+               return error_reply(msg, -err);
+
+       handler = g_new0(struct oob_handler, 1);
+       handler->read_local_cb = read_local_complete;
+       handler->user_data = dbus_message_ref(msg);
+
+       btd_adapter_set_oob_handler(adapter, handler);
+
+       return NULL;
+}
+
+static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       if (neard_service == NULL ||
+                       !g_str_equal(neard_service, dbus_message_get_sender(msg)))
+               return error_reply(msg, EPERM);
+
+       DBG("");
+
+       g_free(neard_service);
+       neard_service = NULL;
+
+       g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static const GDBusMethodTable neard_methods[] = {
+       { GDBUS_ASYNC_METHOD("RequestOOB",
+                       GDBUS_ARGS({ "data", "a{sv}" }),
+                       GDBUS_ARGS({ "data", "a{sv}" }), request_oob) },
+       { GDBUS_ASYNC_METHOD("PushOOB",
+                       GDBUS_ARGS({ "data", "a{sv}"}), NULL, push_oob) },
+       { GDBUS_METHOD("Release", NULL, NULL, release) },
+       { }
+};
+
+static void neard_appeared(DBusConnection *conn, void *user_data)
+{
+       struct btd_adapter *adapter;
+
+       DBG("");
+
+       if (!g_dbus_register_interface(conn, AGENT_PATH, AGENT_INTERFACE,
+                                               neard_methods,
+                                               NULL, NULL, NULL, NULL)) {
+               error("neard interface init failed on path " AGENT_PATH);
+               return;
+       }
+
+       /*
+        * If there is pending action ongoing when neard appeared, possibly
+        * due to neard crash or release before action was completed, postpone
+        * register until action is finished.
+        */
+       adapter = btd_adapter_get_default();
+
+       if (adapter && btd_adapter_check_oob_handler(adapter))
+               agent_register_postpone = true;
+       else
+               register_agent(true);
+}
+
+static void neard_vanished(DBusConnection *conn, void *user_data)
+{
+       DBG("");
+
+       /* neard existed without unregistering agent */
+       if (neard_service != NULL) {
+               g_free(neard_service);
+               neard_service = NULL;
+
+               g_dbus_unregister_interface(conn, AGENT_PATH, AGENT_INTERFACE);
+       }
+}
+
+static int neard_init(void)
+{
+       DBG("Setup neard plugin");
+
+       watcher_id = g_dbus_add_service_watch(btd_get_dbus_connection(),
+                                               NEARD_NAME, neard_appeared,
+                                               neard_vanished, NULL, NULL);
+       if (watcher_id == 0)
+               return -ENOMEM;
+
+       return 0;
+}
+
+static void neard_exit(void)
+{
+       DBG("Cleanup neard plugin");
+
+       g_dbus_remove_watch(btd_get_dbus_connection(), watcher_id);
+       watcher_id = 0;
+
+       if (neard_service != NULL)
+               unregister_agent();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(neard, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                               neard_init, neard_exit)
diff --git a/plugins/pnat.c b/plugins/pnat.c
deleted file mode 100644 (file)
index 3c611a9..0000000
+++ /dev/null
@@ -1,526 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010  Nokia Corporation
- *  Copyright (C) 2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <unistd.h>
-#include <sys/socket.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <sys/wait.h>
-#include <fcntl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-
-#include <gdbus.h>
-
-#include "plugin.h"
-#include "sdpd.h"
-#include "btio.h"
-#include "adapter.h"
-#include "log.h"
-
-/* FIXME: This location should be build-time configurable */
-#define PNATD "/usr/bin/phonet-at"
-
-#define DUN_CHANNEL 1
-
-#define TTY_TIMEOUT 100
-#define TTY_TRIES 10
-
-struct dun_client {
-       bdaddr_t bda;
-
-       GIOChannel *io; /* Client socket */
-       guint io_watch; /* Client IO watch id */
-
-       guint tty_timer;
-       int tty_tries;
-       gboolean tty_open;
-       int tty_id;
-       char tty_name[PATH_MAX];
-
-       GPid pnatd_pid;
-};
-
-struct dun_server {
-       bdaddr_t bda;           /* Local adapter address */
-
-       uint32_t record_handle; /* Local SDP record handle */
-       GIOChannel *server;     /* Server socket */
-
-       int rfcomm_ctl;
-
-       struct dun_client client;
-};
-
-static GSList *servers = NULL;
-
-static void disconnect(struct dun_server *server)
-{
-       struct dun_client *client = &server->client;
-
-       if (!client->io)
-               return;
-
-       if (client->io_watch > 0) {
-               g_source_remove(client->io_watch);
-               client->io_watch = 0;
-       }
-
-       g_io_channel_shutdown(client->io, TRUE, NULL);
-       g_io_channel_unref(client->io);
-       client->io = NULL;
-
-       if (client->pnatd_pid > 0) {
-               kill(client->pnatd_pid, SIGTERM);
-               client->pnatd_pid = 0;
-       }
-
-       if (client->tty_timer > 0) {
-               g_source_remove(client->tty_timer);
-               client->tty_timer = 0;
-       }
-
-       if (client->tty_id >= 0) {
-               struct rfcomm_dev_req req;
-
-               memset(&req, 0, sizeof(req));
-               req.dev_id = client->tty_id;
-               req.flags = (1 << RFCOMM_HANGUP_NOW);
-               ioctl(server->rfcomm_ctl, RFCOMMRELEASEDEV, &req);
-
-               client->tty_name[0] = '\0';
-               client->tty_open = FALSE;
-               client->tty_id = -1;
-       }
-}
-
-static gboolean client_event(GIOChannel *chan,
-                                       GIOCondition cond, gpointer data)
-{
-       struct dun_server *server = data;
-       struct dun_client *client = &server->client;
-       char addr[18];
-
-       ba2str(&client->bda, addr);
-
-       DBG("Disconnected DUN from %s (%s)", addr, client->tty_name);
-
-       client->io_watch = 0;
-       disconnect(server);
-
-       return FALSE;
-}
-
-static void pnatd_exit(GPid pid, gint status, gpointer user_data)
-{
-       struct dun_server *server = user_data;
-       struct dun_client *client = &server->client;
-
-        if (WIFEXITED(status))
-                DBG("pnatd (%d) exited with status %d", pid,
-                                                       WEXITSTATUS(status));
-        else
-                DBG("pnatd (%d) was killed by signal %d", pid,
-                                                       WTERMSIG(status));
-       g_spawn_close_pid(pid);
-
-       if (pid != client->pnatd_pid)
-               return;
-
-       /* So disconnect() doesn't send SIGTERM to a non-existing process */
-       client->pnatd_pid = 0;
-
-       disconnect(server);
-}
-
-static gboolean start_pnatd(struct dun_server *server)
-{
-       struct dun_client *client = &server->client;
-       GSpawnFlags flags = G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH;
-       char *argv[] = { PNATD, client->tty_name, NULL };
-       GError *err = NULL;
-       GPid pid;
-
-       g_spawn_async(NULL, argv, NULL, flags, NULL, NULL, &pid, &err);
-       if (err != NULL) {
-               error("Unable to spawn pnatd: %s", err->message);
-               g_error_free(err);
-               return FALSE;
-       }
-
-       DBG("pnatd started for %s with pid %d", client->tty_name, pid);
-
-       client->pnatd_pid = pid;
-
-       /* We do not store the GSource id since g_remove_source doesn't
-        * make sense for a child watch. If the callback gets removed
-        * waitpid won't be called and the child remains as a zombie)
-        */
-       g_child_watch_add(pid, pnatd_exit, server);
-
-       return TRUE;
-}
-
-static gboolean tty_try_open(gpointer user_data)
-{
-       struct dun_server *server = user_data;
-       struct dun_client *client = &server->client;
-       int tty_fd;
-
-       tty_fd = open(client->tty_name, O_RDONLY | O_NOCTTY);
-       if (tty_fd < 0) {
-               if (errno == EACCES)
-                       goto disconnect;
-
-               client->tty_tries--;
-
-               if (client->tty_tries <= 0)
-                       goto disconnect;
-
-               return TRUE;
-       }
-
-       DBG("%s created for DUN", client->tty_name);
-
-       client->tty_open = TRUE;
-       client->tty_timer = 0;
-
-       g_io_channel_unref(client->io);
-       g_source_remove(client->io_watch);
-
-       client->io = g_io_channel_unix_new(tty_fd);
-       client->io_watch = g_io_add_watch(client->io,
-                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                                       client_event, server);
-
-       if (!start_pnatd(server))
-               goto disconnect;
-
-       return FALSE;
-
-disconnect:
-       client->tty_timer = 0;
-       disconnect(server);
-       return FALSE;
-}
-
-static gboolean create_tty(struct dun_server *server)
-{
-       struct dun_client *client = &server->client;
-       struct rfcomm_dev_req req;
-       int sk = g_io_channel_unix_get_fd(client->io);
-
-       memset(&req, 0, sizeof(req));
-       req.dev_id = -1;
-       req.flags = (1 << RFCOMM_REUSE_DLC) | (1 << RFCOMM_RELEASE_ONHUP);
-
-       bacpy(&req.src, &server->bda);
-       bacpy(&req.dst, &client->bda);
-
-       bt_io_get(client->io, BT_IO_RFCOMM, NULL,
-                       BT_IO_OPT_DEST_CHANNEL, &req.channel,
-                       BT_IO_OPT_INVALID);
-
-       client->tty_id = ioctl(sk, RFCOMMCREATEDEV, &req);
-       if (client->tty_id < 0) {
-               error("Can't create RFCOMM TTY: %s", strerror(errno));
-               return FALSE;
-       }
-
-       snprintf(client->tty_name, PATH_MAX - 1, "/dev/rfcomm%d",
-                                                       client->tty_id);
-
-       client->tty_tries = TTY_TRIES;
-
-       tty_try_open(server);
-       if (!client->tty_open && client->tty_tries > 0)
-               client->tty_timer = g_timeout_add(TTY_TIMEOUT,
-                                                       tty_try_open, server);
-
-       return TRUE;
-}
-
-static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
-{
-       struct dun_server *server = user_data;
-
-       if (err) {
-               error("Accepting DUN connection failed: %s", err->message);
-               disconnect(server);
-               return;
-       }
-
-       if (!create_tty(server)) {
-               error("Device creation failed");
-               disconnect(server);
-       }
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct dun_server *server = user_data;
-       struct dun_client *client = &server->client;
-       GError *err = NULL;
-
-       if (derr && dbus_error_is_set(derr)) {
-               error("DUN access denied: %s", derr->message);
-               goto drop;
-       }
-
-       if (!bt_io_accept(client->io, connect_cb, server, NULL, &err)) {
-               error("bt_io_accept: %s", err->message);
-               g_error_free(err);
-               goto drop;
-       }
-
-       return;
-
-drop:
-       disconnect(server);
-}
-
-static gboolean auth_watch(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       struct dun_server *server = data;
-       struct dun_client *client = &server->client;
-
-       error("DUN client disconnected while waiting for authorization");
-
-       btd_cancel_authorization(&server->bda, &client->bda);
-
-       disconnect(server);
-
-       return FALSE;
-}
-
-static void confirm_cb(GIOChannel *io, gpointer user_data)
-{
-       struct dun_server *server = user_data;
-       struct dun_client *client = &server->client;
-       GError *err = NULL;
-
-       if (client->io) {
-               error("Rejecting DUN connection since one already exists");
-               return;
-       }
-
-       bt_io_get(io, BT_IO_RFCOMM, &err,
-                       BT_IO_OPT_DEST_BDADDR, &client->bda,
-                       BT_IO_OPT_INVALID);
-       if (err != NULL) {
-               error("Unable to get DUN source and dest address: %s",
-                                                               err->message);
-               g_error_free(err);
-               return;
-       }
-
-       if (btd_request_authorization(&server->bda, &client->bda, DUN_GW_UUID,
-                                               auth_cb, user_data) < 0) {
-               error("Requesting DUN authorization failed");
-               return;
-       }
-
-       client->io_watch = g_io_add_watch(io, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                                               (GIOFunc) auth_watch, server);
-       client->io = g_io_channel_ref(io);
-}
-
-static sdp_record_t *dun_record(uint8_t ch)
-{
-       sdp_list_t *svclass_id, *pfseq, *apseq, *root, *aproto;
-       uuid_t root_uuid, dun, gn, l2cap, rfcomm;
-       sdp_profile_desc_t profile;
-       sdp_list_t *proto[2];
-       sdp_record_t *record;
-       sdp_data_t *channel;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(NULL, &root_uuid);
-       sdp_set_browse_groups(record, root);
-
-       sdp_uuid16_create(&dun, DIALUP_NET_SVCLASS_ID);
-       svclass_id = sdp_list_append(NULL, &dun);
-       sdp_uuid16_create(&gn,  GENERIC_NETWORKING_SVCLASS_ID);
-       svclass_id = sdp_list_append(svclass_id, &gn);
-       sdp_set_service_classes(record, svclass_id);
-
-       sdp_uuid16_create(&profile.uuid, DIALUP_NET_PROFILE_ID);
-       profile.version = 0x0100;
-       pfseq = sdp_list_append(NULL, &profile);
-       sdp_set_profile_descs(record, pfseq);
-
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(NULL, &l2cap);
-       apseq = sdp_list_append(NULL, proto[0]);
-
-       sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-       proto[1] = sdp_list_append(NULL, &rfcomm);
-       channel = sdp_data_alloc(SDP_UINT8, &ch);
-       proto[1] = sdp_list_append(proto[1], channel);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(0, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_set_info_attr(record, "Dial-Up Networking", 0, 0);
-
-       sdp_data_free(channel);
-       sdp_list_free(root, NULL);
-       sdp_list_free(svclass_id, NULL);
-       sdp_list_free(proto[0], NULL);
-       sdp_list_free(proto[1], NULL);
-       sdp_list_free(pfseq, NULL);
-       sdp_list_free(apseq, NULL);
-       sdp_list_free(aproto, NULL);
-
-       return record;
-}
-
-static gint server_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct dun_server *server = a;
-       const bdaddr_t *src = b;
-
-       return bacmp(src, &server->bda);
-}
-
-static int pnat_probe(struct btd_adapter *adapter)
-{
-       struct dun_server *server;
-       GIOChannel *io;
-       GError *err = NULL;
-       sdp_record_t *record;
-       bdaddr_t src;
-
-       adapter_get_address(adapter, &src);
-
-       server = g_new0(struct dun_server, 1);
-
-       io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_cb, server, NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
-                               BT_IO_OPT_CHANNEL, DUN_CHANNEL,
-                               BT_IO_OPT_INVALID);
-       if (err != NULL) {
-               error("Failed to start DUN server: %s", err->message);
-               g_error_free(err);
-               goto fail;
-       }
-
-       record = dun_record(DUN_CHANNEL);
-       if (!record) {
-               error("Unable to allocate new service record");
-               goto fail;
-       }
-
-       if (add_record_to_server(&src, record) < 0) {
-               error("Unable to register DUN service record");
-               goto fail;
-       }
-
-       server->rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
-       if (server->rfcomm_ctl < 0) {
-               error("Unable to create RFCOMM control socket: %s (%d)",
-                                               strerror(errno), errno);
-               goto fail;
-       }
-
-       server->server = io;
-       server->record_handle = record->handle;
-       bacpy(&server->bda, &src);
-
-       servers = g_slist_append(servers, server);
-
-       return 0;
-
-fail:
-       if (io != NULL)
-               g_io_channel_unref(io);
-       g_free(server);
-       return -EIO;
-}
-
-static void pnat_remove(struct btd_adapter *adapter)
-{
-       struct dun_server *server;
-       GSList *match;
-       bdaddr_t src;
-
-       adapter_get_address(adapter, &src);
-
-       match = g_slist_find_custom(servers, &src, server_cmp);
-       if (match == NULL)
-               return;
-
-       server = match->data;
-
-       servers = g_slist_delete_link(servers, match);
-
-       disconnect(server);
-
-       remove_record_from_server(server->record_handle);
-       close(server->rfcomm_ctl);
-       g_io_channel_shutdown(server->server, TRUE, NULL);
-       g_io_channel_unref(server->server);
-       g_free(server);
-}
-
-static struct btd_adapter_driver pnat_server = {
-       .name   = "pnat-server",
-       .probe  = pnat_probe,
-       .remove = pnat_remove,
-};
-
-static int pnat_init(void)
-{
-       DBG("Setup Phonet AT (DUN) plugin");
-
-       return btd_register_adapter_driver(&pnat_server);
-}
-
-static void pnat_exit(void)
-{
-       DBG("Cleanup Phonet AT (DUN) plugin");
-
-       btd_unregister_adapter_driver(&pnat_server);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(pnat, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                       pnat_init, pnat_exit)
diff --git a/plugins/policy.c b/plugins/policy.c
new file mode 100644 (file)
index 0000000..0292482
--- /dev/null
@@ -0,0 +1,437 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "lib/uuid.h"
+#include "src/log.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/service.h"
+#include "src/profile.h"
+
+#define CONTROL_CONNECT_TIMEOUT 2
+#define SOURCE_RETRY_TIMEOUT 2
+#define SINK_RETRY_TIMEOUT SOURCE_RETRY_TIMEOUT
+#define SOURCE_RETRIES 1
+#define SINK_RETRIES SOURCE_RETRIES
+
+static unsigned int service_id = 0;
+static GSList *devices = NULL;
+
+struct policy_data {
+       struct btd_device *dev;
+
+       guint source_timer;
+       uint8_t source_retries;
+       guint sink_timer;
+       uint8_t sink_retries;
+       guint ct_timer;
+       guint tg_timer;
+};
+
+static void policy_connect(struct policy_data *data,
+                                               struct btd_service *service)
+{
+       struct btd_profile *profile = btd_service_get_profile(service);
+
+       DBG("%s profile %s", device_get_path(data->dev), profile->name);
+
+       btd_service_connect(service);
+}
+
+static void policy_disconnect(struct policy_data *data,
+                                               struct btd_service *service)
+{
+       struct btd_profile *profile = btd_service_get_profile(service);
+
+       DBG("%s profile %s", device_get_path(data->dev), profile->name);
+
+       btd_service_disconnect(service);
+}
+
+static gboolean policy_connect_ct(gpointer user_data)
+{
+       struct policy_data *data = user_data;
+       struct btd_service *service;
+
+       data->ct_timer = 0;
+
+       service = btd_device_get_service(data->dev, AVRCP_REMOTE_UUID);
+       if (service != NULL)
+               policy_connect(data, service);
+
+       return FALSE;
+}
+
+static void policy_set_ct_timer(struct policy_data *data)
+{
+       if (data->ct_timer > 0)
+               g_source_remove(data->ct_timer);
+
+       data->ct_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
+                                               policy_connect_ct, data);
+}
+
+static struct policy_data *find_data(struct btd_device *dev)
+{
+       GSList *l;
+
+       for (l = devices; l; l = l->next) {
+               struct policy_data *data = l->data;
+
+               if (data->dev == dev)
+                       return data;
+       }
+
+       return NULL;
+}
+
+static void policy_remove(void *user_data)
+{
+       struct policy_data *data = user_data;
+
+       if (data->source_timer > 0)
+               g_source_remove(data->source_timer);
+
+       if (data->sink_timer > 0)
+               g_source_remove(data->sink_timer);
+
+       if (data->ct_timer > 0)
+               g_source_remove(data->ct_timer);
+
+       if (data->tg_timer > 0)
+               g_source_remove(data->tg_timer);
+
+       g_free(data);
+}
+
+static struct policy_data *policy_get_data(struct btd_device *dev)
+{
+       struct policy_data *data;
+
+       data = find_data(dev);
+       if (data != NULL)
+               return data;
+
+       data = g_new0(struct policy_data, 1);
+       data->dev = dev;
+
+       devices = g_slist_prepend(devices, data);
+
+       return data;
+}
+
+static gboolean policy_connect_sink(gpointer user_data)
+{
+       struct policy_data *data = user_data;
+       struct btd_service *service;
+
+       data->source_timer = 0;
+       data->sink_retries++;
+
+       service = btd_device_get_service(data->dev, A2DP_SINK_UUID);
+       if (service != NULL)
+               policy_connect(data, service);
+
+       return FALSE;
+}
+
+static void policy_set_sink_timer(struct policy_data *data)
+{
+       if (data->sink_timer > 0)
+               g_source_remove(data->sink_timer);
+
+       data->sink_timer = g_timeout_add_seconds(SINK_RETRY_TIMEOUT,
+                                                       policy_connect_sink,
+                                                       data);
+}
+
+static void sink_cb(struct btd_service *service, btd_service_state_t old_state,
+                                               btd_service_state_t new_state)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct policy_data *data;
+       struct btd_service *controller;
+
+       controller = btd_device_get_service(dev, AVRCP_REMOTE_UUID);
+       if (controller == NULL)
+               return;
+
+       data = policy_get_data(dev);
+
+       switch (new_state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               if (old_state == BTD_SERVICE_STATE_CONNECTING) {
+                       int err = btd_service_get_error(service);
+
+                       if (err == -EAGAIN) {
+                               if (data->sink_retries < SINK_RETRIES)
+                                       policy_set_sink_timer(data);
+                               else
+                                       data->sink_retries = 0;
+                               break;
+                       } else if (data->sink_timer > 0) {
+                               g_source_remove(data->sink_timer);
+                               data->sink_timer = 0;
+                       }
+               }
+
+               if (data->ct_timer > 0) {
+                       g_source_remove(data->ct_timer);
+                       data->ct_timer = 0;
+               } else if (btd_service_get_state(controller) !=
+                                               BTD_SERVICE_STATE_DISCONNECTED)
+                       policy_disconnect(data, controller);
+               break;
+       case BTD_SERVICE_STATE_CONNECTING:
+               break;
+       case BTD_SERVICE_STATE_CONNECTED:
+               if (data->sink_timer > 0) {
+                       g_source_remove(data->sink_timer);
+                       data->sink_timer = 0;
+               }
+
+               /* Check if service initiate the connection then proceed
+                * immediatelly otherwise set timer
+                */
+               if (old_state == BTD_SERVICE_STATE_CONNECTING)
+                       policy_connect(data, controller);
+               else if (btd_service_get_state(controller) !=
+                                               BTD_SERVICE_STATE_CONNECTED)
+                       policy_set_ct_timer(data);
+               break;
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               break;
+       }
+}
+
+static gboolean policy_connect_tg(gpointer user_data)
+{
+       struct policy_data *data = user_data;
+       struct btd_service *service;
+
+       data->tg_timer = 0;
+
+       service = btd_device_get_service(data->dev, AVRCP_TARGET_UUID);
+       if (service != NULL)
+               policy_connect(data, service);
+
+       return FALSE;
+}
+
+static void policy_set_tg_timer(struct policy_data *data)
+{
+       if (data->tg_timer > 0)
+               g_source_remove(data->tg_timer);
+
+       data->tg_timer = g_timeout_add_seconds(CONTROL_CONNECT_TIMEOUT,
+                                                       policy_connect_tg,
+                                                       data);
+}
+
+static gboolean policy_connect_source(gpointer user_data)
+{
+       struct policy_data *data = user_data;
+       struct btd_service *service;
+
+       data->source_timer = 0;
+       data->source_retries++;
+
+       service = btd_device_get_service(data->dev, A2DP_SOURCE_UUID);
+       if (service != NULL)
+               policy_connect(data, service);
+
+       return FALSE;
+}
+
+static void policy_set_source_timer(struct policy_data *data)
+{
+       if (data->source_timer > 0)
+               g_source_remove(data->source_timer);
+
+       data->source_timer = g_timeout_add_seconds(SOURCE_RETRY_TIMEOUT,
+                                                       policy_connect_source,
+                                                       data);
+}
+
+static void source_cb(struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct policy_data *data;
+       struct btd_service *target;
+
+       target = btd_device_get_service(dev, AVRCP_TARGET_UUID);
+       if (target == NULL)
+               return;
+
+       data = policy_get_data(dev);
+
+       switch (new_state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               if (old_state == BTD_SERVICE_STATE_CONNECTING) {
+                       int err = btd_service_get_error(service);
+
+                       if (err == -EAGAIN) {
+                               if (data->source_retries < SOURCE_RETRIES)
+                                       policy_set_source_timer(data);
+                               else
+                                       data->source_retries = 0;
+                               break;
+                       } else if (data->source_timer > 0) {
+                               g_source_remove(data->source_timer);
+                               data->source_timer = 0;
+                       }
+               }
+
+               if (data->tg_timer > 0) {
+                       g_source_remove(data->tg_timer);
+                       data->tg_timer = 0;
+               } else if (btd_service_get_state(target) !=
+                                               BTD_SERVICE_STATE_DISCONNECTED)
+                       policy_disconnect(data, target);
+               break;
+       case BTD_SERVICE_STATE_CONNECTING:
+               break;
+       case BTD_SERVICE_STATE_CONNECTED:
+               if (data->source_timer > 0) {
+                       g_source_remove(data->source_timer);
+                       data->source_timer = 0;
+               }
+
+               /* Check if service initiate the connection then proceed
+                * immediatelly otherwise set timer
+                */
+               if (old_state == BTD_SERVICE_STATE_CONNECTING)
+                       policy_connect(data, target);
+               else if (btd_service_get_state(target) !=
+                                               BTD_SERVICE_STATE_CONNECTED)
+                       policy_set_tg_timer(data);
+               break;
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               break;
+       }
+}
+
+static void controller_cb(struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct policy_data *data;
+
+       data = find_data(dev);
+       if (data == NULL)
+               return;
+
+       switch (new_state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               break;
+       case BTD_SERVICE_STATE_CONNECTING:
+               break;
+       case BTD_SERVICE_STATE_CONNECTED:
+               if (data->ct_timer > 0) {
+                       g_source_remove(data->ct_timer);
+                       data->ct_timer = 0;
+               }
+               break;
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               break;
+       }
+}
+
+static void target_cb(struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct policy_data *data;
+
+       data = find_data(dev);
+       if (data == NULL)
+               return;
+
+       switch (new_state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               break;
+       case BTD_SERVICE_STATE_CONNECTING:
+               break;
+       case BTD_SERVICE_STATE_CONNECTED:
+               if (data->tg_timer > 0) {
+                       g_source_remove(data->tg_timer);
+                       data->tg_timer = 0;
+               }
+               break;
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               break;
+       }
+}
+
+static void service_cb(struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state,
+                                               void *user_data)
+{
+       struct btd_profile *profile = btd_service_get_profile(service);
+
+       if (g_str_equal(profile->remote_uuid, A2DP_SINK_UUID))
+               sink_cb(service, old_state, new_state);
+       else if (g_str_equal(profile->remote_uuid, A2DP_SOURCE_UUID))
+               source_cb(service, old_state, new_state);
+       else if (g_str_equal(profile->remote_uuid, AVRCP_REMOTE_UUID))
+               controller_cb(service, old_state, new_state);
+       else if (g_str_equal(profile->remote_uuid, AVRCP_TARGET_UUID))
+               target_cb(service, old_state, new_state);
+}
+
+static int policy_init(void)
+{
+       service_id = btd_service_add_state_cb(service_cb, NULL);
+
+       return 0;
+}
+
+static void policy_exit(void)
+{
+       g_slist_free_full(devices, policy_remove);
+
+       btd_service_remove_state_cb(service_id);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(policy, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                               policy_init, policy_exit)
diff --git a/plugins/service.c b/plugins/service.c
deleted file mode 100644 (file)
index 288f849..0000000
+++ /dev/null
@@ -1,832 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <gdbus.h>
-
-#include "sdpd.h"
-#include "sdp-xml.h"
-#include "plugin.h"
-#include "adapter.h"
-#include "error.h"
-#include "log.h"
-
-#define SERVICE_INTERFACE "org.bluez.Service"
-
-static DBusConnection *connection;
-
-struct record_data {
-       uint32_t handle;
-       char *sender;
-       guint listener_id;
-       struct service_adapter *serv_adapter;
-};
-
-struct context_data {
-       sdp_record_t *record;
-       sdp_data_t attr_data;
-       struct sdp_xml_data *stack_head;
-       uint16_t attr_id;
-};
-
-struct pending_auth {
-       DBusConnection *conn;
-       DBusMessage *msg;
-       char *sender;
-       bdaddr_t dst;
-       char uuid[MAX_LEN_UUID_STR];
-};
-
-struct service_adapter {
-       struct btd_adapter *adapter;
-       GSList *pending_list;
-       GSList *records;
-};
-
-static struct service_adapter *serv_adapter_any = NULL;
-
-static int compute_seq_size(sdp_data_t *data)
-{
-       int unit_size = data->unitSize;
-       sdp_data_t *seq = data->val.dataseq;
-
-       for (; seq; seq = seq->next)
-               unit_size += seq->unitSize;
-
-       return unit_size;
-}
-
-static void element_start(GMarkupParseContext *context,
-               const gchar *element_name, const gchar **attribute_names,
-               const gchar **attribute_values, gpointer user_data, GError **err)
-{
-       struct context_data *ctx_data = user_data;
-
-       if (!strcmp(element_name, "record"))
-               return;
-
-       if (!strcmp(element_name, "attribute")) {
-               int i;
-               for (i = 0; attribute_names[i]; i++) {
-                       if (!strcmp(attribute_names[i], "id")) {
-                               ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
-                               break;
-                       }
-               }
-               DBG("New attribute 0x%04x", ctx_data->attr_id);
-               return;
-       }
-
-       if (ctx_data->stack_head) {
-               struct sdp_xml_data *newelem = sdp_xml_data_alloc();
-               newelem->next = ctx_data->stack_head;
-               ctx_data->stack_head = newelem;
-       } else {
-               ctx_data->stack_head = sdp_xml_data_alloc();
-               ctx_data->stack_head->next = NULL;
-       }
-
-       if (!strcmp(element_name, "sequence"))
-               ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
-       else if (!strcmp(element_name, "alternate"))
-               ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
-       else {
-               int i;
-               /* Parse value, name, encoding */
-               for (i = 0; attribute_names[i]; i++) {
-                       if (!strcmp(attribute_names[i], "value")) {
-                               int curlen = strlen(ctx_data->stack_head->text);
-                               int attrlen = strlen(attribute_values[i]);
-
-                               /* Ensure we're big enough */
-                               while ((curlen + 1 + attrlen) > ctx_data->stack_head->size) {
-                                       sdp_xml_data_expand(ctx_data->stack_head);
-                               }
-
-                               memcpy(ctx_data->stack_head->text + curlen,
-                                               attribute_values[i], attrlen);
-                               ctx_data->stack_head->text[curlen + attrlen] = '\0';
-                       }
-
-                       if (!strcmp(attribute_names[i], "encoding")) {
-                               if (!strcmp(attribute_values[i], "hex"))
-                                       ctx_data->stack_head->type = 1;
-                       }
-
-                       if (!strcmp(attribute_names[i], "name")) {
-                               ctx_data->stack_head->name = strdup(attribute_values[i]);
-                       }
-               }
-
-               ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
-                               ctx_data->stack_head, ctx_data->record);
-
-               if (ctx_data->stack_head->data == NULL)
-                       error("Can't parse element %s", element_name);
-       }
-}
-
-static void element_end(GMarkupParseContext *context,
-               const gchar *element_name, gpointer user_data, GError **err)
-{
-       struct context_data *ctx_data = user_data;
-       struct sdp_xml_data *elem;
-
-       if (!strcmp(element_name, "record"))
-               return;
-
-       if (!strcmp(element_name, "attribute")) {
-               if (ctx_data->stack_head && ctx_data->stack_head->data) {
-                       int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
-                                                       ctx_data->stack_head->data);
-                       if (ret == -1)
-                               DBG("Could not add attribute 0x%04x",
-                                                       ctx_data->attr_id);
-
-                       ctx_data->stack_head->data = NULL;
-                       sdp_xml_data_free(ctx_data->stack_head);
-                       ctx_data->stack_head = NULL;
-               } else {
-                       DBG("No data for attribute 0x%04x", ctx_data->attr_id);
-               }
-               return;
-       }
-
-       if (!strcmp(element_name, "sequence")) {
-               ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
-
-               if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
-                       ctx_data->stack_head->data->dtd = SDP_SEQ32;
-               } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
-                       ctx_data->stack_head->data->dtd = SDP_SEQ16;
-               } else {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
-               }
-       } else if (!strcmp(element_name, "alternate")) {
-               ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
-
-               if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
-                       ctx_data->stack_head->data->dtd = SDP_ALT32;
-               } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
-                       ctx_data->stack_head->data->dtd = SDP_ALT16;
-               } else {
-                       ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
-               }
-       }
-
-       if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
-                                       ctx_data->stack_head->next->data) {
-               switch (ctx_data->stack_head->next->data->dtd) {
-               case SDP_SEQ8:
-               case SDP_SEQ16:
-               case SDP_SEQ32:
-               case SDP_ALT8:
-               case SDP_ALT16:
-               case SDP_ALT32:
-                       ctx_data->stack_head->next->data->val.dataseq =
-                               sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
-                                                               ctx_data->stack_head->data);
-                       ctx_data->stack_head->data = NULL;
-                       break;
-               }
-
-               elem = ctx_data->stack_head;
-               ctx_data->stack_head = ctx_data->stack_head->next;
-
-               sdp_xml_data_free(elem);
-       }
-}
-
-static GMarkupParser parser = {
-       element_start, element_end, NULL, NULL, NULL
-};
-
-static sdp_record_t *sdp_xml_parse_record(const char *data, int size)
-{
-       GMarkupParseContext *ctx;
-       struct context_data *ctx_data;
-       sdp_record_t *record;
-
-       ctx_data = malloc(sizeof(*ctx_data));
-       if (!ctx_data)
-               return NULL;
-
-       record = sdp_record_alloc();
-       if (!record) {
-               free(ctx_data);
-               return NULL;
-       }
-
-       memset(ctx_data, 0, sizeof(*ctx_data));
-       ctx_data->record = record;
-
-       ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
-
-       if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
-               error("XML parsing error");
-               g_markup_parse_context_free(ctx);
-               sdp_record_free(record);
-               free(ctx_data);
-               return NULL;
-       }
-
-       g_markup_parse_context_free(ctx);
-
-       free(ctx_data);
-
-       return record;
-}
-
-static struct record_data *find_record(struct service_adapter *serv_adapter,
-                                       uint32_t handle, const char *sender)
-{
-       GSList *list;
-
-       for (list = serv_adapter->records; list; list = list->next) {
-               struct record_data *data = list->data;
-               if (handle == data->handle && !strcmp(sender, data->sender))
-                       return data;
-       }
-
-       return NULL;
-}
-
-static struct pending_auth *next_pending(struct service_adapter *serv_adapter)
-{
-       GSList *l = serv_adapter->pending_list;
-
-       if (l) {
-               struct pending_auth *auth = l->data;
-               return auth;
-       }
-
-       return NULL;
-}
-
-static struct pending_auth *find_pending_by_sender(
-                       struct service_adapter *serv_adapter,
-                       const char *sender)
-{
-       GSList *l = serv_adapter->pending_list;
-
-       for (; l; l = l->next) {
-               struct pending_auth *auth = l->data;
-               if (g_str_equal(auth->sender, sender))
-                       return auth;
-       }
-
-       return NULL;
-}
-
-static void exit_callback(DBusConnection *conn, void *user_data)
-{
-       struct record_data *user_record = user_data;
-       struct service_adapter *serv_adapter = user_record->serv_adapter;
-       struct pending_auth *auth;
-
-       DBG("remove record");
-
-       serv_adapter->records = g_slist_remove(serv_adapter->records,
-                                               user_record);
-
-       auth = find_pending_by_sender(serv_adapter, user_record->sender);
-       if (auth) {
-               serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
-                                                       auth);
-               g_free(auth);
-       }
-
-       remove_record_from_server(user_record->handle);
-
-       g_free(user_record->sender);
-       g_free(user_record);
-}
-
-static int add_xml_record(DBusConnection *conn, const char *sender,
-                       struct service_adapter *serv_adapter,
-                       const char *record, dbus_uint32_t *handle)
-{
-       struct record_data *user_record;
-       sdp_record_t *sdp_record;
-       bdaddr_t src;
-
-       sdp_record = sdp_xml_parse_record(record, strlen(record));
-       if (!sdp_record) {
-               error("Parsing of XML service record failed");
-               return -EIO;
-       }
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       if (add_record_to_server(&src, sdp_record) < 0) {
-               error("Failed to register service record");
-               sdp_record_free(sdp_record);
-               return -EIO;
-       }
-
-       user_record = g_new0(struct record_data, 1);
-       user_record->handle = sdp_record->handle;
-       user_record->sender = g_strdup(sender);
-       user_record->serv_adapter = serv_adapter;
-       user_record->listener_id = g_dbus_add_disconnect_watch(conn, sender,
-                                       exit_callback, user_record, NULL);
-
-       serv_adapter->records = g_slist_append(serv_adapter->records,
-                                                               user_record);
-
-       DBG("listener_id %d", user_record->listener_id);
-
-       *handle = user_record->handle;
-
-       return 0;
-}
-
-static DBusMessage *update_record(DBusConnection *conn, DBusMessage *msg,
-               struct service_adapter *serv_adapter,
-               dbus_uint32_t handle, sdp_record_t *sdp_record)
-{
-       bdaddr_t src;
-       int err;
-
-       if (remove_record_from_server(handle) < 0) {
-               sdp_record_free(sdp_record);
-               return btd_error_not_available(msg);
-       }
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       sdp_record->handle = handle;
-       err = add_record_to_server(&src, sdp_record);
-       if (err < 0) {
-               sdp_record_free(sdp_record);
-               error("Failed to update the service record");
-               return btd_error_failed(msg, strerror(-err));
-       }
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *update_xml_record(DBusConnection *conn,
-                               DBusMessage *msg,
-                               struct service_adapter *serv_adapter)
-{
-       struct record_data *user_record;
-       sdp_record_t *sdp_record;
-       const char *record;
-       dbus_uint32_t handle;
-       int len;
-
-       if (dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_UINT32, &handle,
-                               DBUS_TYPE_STRING, &record,
-                               DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       len = (record ? strlen(record) : 0);
-       if (len == 0)
-               return btd_error_invalid_args(msg);
-
-       user_record = find_record(serv_adapter, handle,
-                               dbus_message_get_sender(msg));
-       if (!user_record)
-               return btd_error_not_available(msg);
-
-       sdp_record = sdp_xml_parse_record(record, len);
-       if (!sdp_record) {
-               error("Parsing of XML service record failed");
-               return btd_error_failed(msg,
-                                       "Parsing of XML service record failed");
-       }
-
-       return update_record(conn, msg, serv_adapter, handle, sdp_record);
-}
-
-static int remove_record(DBusConnection *conn, const char *sender,
-                       struct service_adapter *serv_adapter,
-                       dbus_uint32_t handle)
-{
-       struct record_data *user_record;
-
-       DBG("remove record 0x%x", handle);
-
-       user_record = find_record(serv_adapter, handle, sender);
-       if (!user_record)
-               return -1;
-
-       DBG("listner_id %d", user_record->listener_id);
-
-       g_dbus_remove_watch(conn, user_record->listener_id);
-
-       exit_callback(conn, user_record);
-
-       return 0;
-}
-
-static DBusMessage *add_service_record(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct service_adapter *serv_adapter = data;
-       DBusMessage *reply;
-       const char *sender, *record;
-       dbus_uint32_t handle;
-       int err;
-
-       if (dbus_message_get_args(msg, NULL,
-                       DBUS_TYPE_STRING, &record, DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       sender = dbus_message_get_sender(msg);
-       err = add_xml_record(conn, sender, serv_adapter, record, &handle);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_append_args(reply, DBUS_TYPE_UINT32, &handle,
-                                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *update_service_record(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct service_adapter *serv_adapter = data;
-
-       return update_xml_record(conn, msg, serv_adapter);
-}
-
-static DBusMessage *remove_service_record(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       struct service_adapter *serv_adapter = data;
-       dbus_uint32_t handle;
-       const char *sender;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &handle,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       sender = dbus_message_get_sender(msg);
-
-       if (remove_record(conn, sender, serv_adapter, handle) < 0)
-               return btd_error_not_available(msg);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct service_adapter *serv_adapter = user_data;
-       DBusMessage *reply;
-       struct pending_auth *auth;
-       bdaddr_t src;
-
-       auth = next_pending(serv_adapter);
-       if (auth == NULL) {
-               info("Authorization cancelled: Client exited");
-               return;
-       }
-
-       if (derr) {
-               error("Access denied: %s", derr->message);
-
-               reply = btd_error_not_authorized(auth->msg);
-               dbus_message_unref(auth->msg);
-               g_dbus_send_message(auth->conn, reply);
-               goto done;
-       }
-
-       g_dbus_send_reply(auth->conn, auth->msg,
-                       DBUS_TYPE_INVALID);
-
-done:
-       dbus_connection_unref(auth->conn);
-
-       serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
-                                                                       auth);
-       g_free(auth);
-
-       auth = next_pending(serv_adapter);
-       if (auth == NULL)
-               return;
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       btd_request_authorization(&src, &auth->dst,
-                                       auth->uuid, auth_cb, serv_adapter);
-}
-
-static DBusMessage *request_authorization(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct record_data *user_record;
-       struct service_adapter *serv_adapter = data;
-       sdp_record_t *record;
-       sdp_list_t *services;
-       const char *sender;
-       dbus_uint32_t handle;
-       const char *address;
-       struct pending_auth *auth;
-       char uuid_str[MAX_LEN_UUID_STR];
-       uuid_t *uuid, *uuid128;
-       bdaddr_t src;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_UINT32, &handle,
-                                       DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       sender = dbus_message_get_sender(msg);
-       if (find_pending_by_sender(serv_adapter, sender))
-               return btd_error_does_not_exist(msg);
-
-       user_record = find_record(serv_adapter, handle, sender);
-       if (!user_record) {
-               user_record = find_record(serv_adapter_any, handle, sender);
-               if (!user_record)
-                       return btd_error_not_authorized(msg);
-       }
-
-       record = sdp_record_find(user_record->handle);
-       if (record == NULL)
-               return btd_error_not_authorized(msg);
-
-       if (sdp_get_service_classes(record, &services) < 0) {
-               sdp_record_free(record);
-               return btd_error_not_authorized(msg);
-       }
-
-       if (services == NULL)
-               return btd_error_not_authorized(msg);
-
-       uuid = services->data;
-       uuid128 = sdp_uuid_to_uuid128(uuid);
-
-       sdp_list_free(services, bt_free);
-
-       if (sdp_uuid2strn(uuid128, uuid_str, MAX_LEN_UUID_STR) < 0) {
-               bt_free(uuid128);
-               return btd_error_not_authorized(msg);
-       }
-       bt_free(uuid128);
-
-       auth = g_new0(struct pending_auth, 1);
-       auth->msg = dbus_message_ref(msg);
-       auth->conn = dbus_connection_ref(connection);
-       auth->sender = user_record->sender;
-       memcpy(auth->uuid, uuid_str, MAX_LEN_UUID_STR);
-       str2ba(address, &auth->dst);
-
-       serv_adapter->pending_list = g_slist_append(serv_adapter->pending_list,
-                                                                       auth);
-
-       auth = next_pending(serv_adapter);
-       if (auth == NULL)
-               return btd_error_does_not_exist(msg);
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       if (btd_request_authorization(&src, &auth->dst, auth->uuid, auth_cb,
-                                                       serv_adapter) < 0) {
-               serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
-                                                                       auth);
-               g_free(auth);
-               return btd_error_not_authorized(msg);
-       }
-
-       return NULL;
-}
-
-static DBusMessage *cancel_authorization(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       struct service_adapter *serv_adapter = data;
-       struct pending_auth *auth;
-       const gchar *sender;
-       bdaddr_t src;
-
-       sender = dbus_message_get_sender(msg);
-
-       auth = find_pending_by_sender(serv_adapter, sender);
-       if (auth == NULL)
-               return btd_error_does_not_exist(msg);
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       btd_cancel_authorization(&src, &auth->dst);
-
-       reply = btd_error_not_authorized(auth->msg);
-       dbus_message_unref(auth->msg);
-       g_dbus_send_message(auth->conn, reply);
-
-       dbus_connection_unref(auth->conn);
-
-       serv_adapter->pending_list = g_slist_remove(serv_adapter->pending_list,
-                                                                       auth);
-       g_free(auth);
-
-       auth = next_pending(serv_adapter);
-       if (auth == NULL)
-               goto done;
-
-       if (serv_adapter->adapter)
-               adapter_get_address(serv_adapter->adapter, &src);
-       else
-               bacpy(&src, BDADDR_ANY);
-
-       btd_request_authorization(&src, &auth->dst,
-                                       auth->uuid, auth_cb, serv_adapter);
-
-done:
-       return dbus_message_new_method_return(msg);
-}
-
-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) },
-       { }
-};
-
-static void path_unregister(void *data)
-{
-       struct service_adapter *serv_adapter = data;
-       GSList *l, *next = NULL;
-
-       for (l = serv_adapter->records; l != NULL; l = next) {
-               struct record_data *user_record = l->data;
-
-               next = l->next;
-
-               g_dbus_remove_watch(connection, user_record->listener_id);
-               exit_callback(connection, user_record);
-       }
-
-       g_free(serv_adapter);
-}
-
-static int register_interface(const char *path, struct btd_adapter *adapter)
-{
-       struct service_adapter *serv_adapter;
-
-       DBG("path %s", path);
-
-       serv_adapter = g_try_new0(struct service_adapter, 1);
-       if (serv_adapter == NULL)
-               return -ENOMEM;
-
-       serv_adapter->adapter = adapter;
-       serv_adapter->pending_list = NULL;
-
-       if (g_dbus_register_interface(connection, path, SERVICE_INTERFACE,
-                               service_methods, NULL, NULL, serv_adapter,
-                                               path_unregister) == FALSE) {
-               error("D-Bus failed to register %s interface",
-                                                       SERVICE_INTERFACE);
-               g_free(serv_adapter);
-               return -EIO;
-       }
-
-       DBG("Registered interface %s on path %s", SERVICE_INTERFACE, path);
-
-       if (serv_adapter->adapter == NULL)
-               serv_adapter_any = serv_adapter;
-
-       return 0;
-}
-
-static void unregister_interface(const char *path)
-{
-       DBG("path %s", path);
-
-       g_dbus_unregister_interface(connection, path, SERVICE_INTERFACE);
-}
-
-static int service_probe(struct btd_adapter *adapter)
-{
-       register_interface(adapter_get_path(adapter), adapter);
-
-       return 0;
-}
-
-static void service_remove(struct btd_adapter *adapter)
-{
-       unregister_interface(adapter_get_path(adapter));
-}
-
-static struct btd_adapter_driver service_driver = {
-       .name   = "service",
-       .probe  = service_probe,
-       .remove = service_remove,
-};
-
-static const char *any_path;
-
-static int service_init(void)
-{
-       int err;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
-
-       any_path = btd_adapter_any_request_path();
-       if (any_path != NULL) {
-               if (register_interface(any_path, NULL) < 0) {
-                       btd_adapter_any_release_path();
-                       any_path = NULL;
-               }
-       }
-
-       err = btd_register_adapter_driver(&service_driver);
-       if (err < 0) {
-               dbus_connection_unref(connection);
-               return err;
-       }
-
-       return 0;
-}
-
-static void service_exit(void)
-{
-       btd_unregister_adapter_driver(&service_driver);
-
-       if (any_path != NULL) {
-               unregister_interface(any_path);
-
-               btd_adapter_any_release_path();
-               any_path = NULL;
-       }
-
-       dbus_connection_unref(connection);
-}
-
-BLUETOOTH_PLUGIN_DEFINE(service, VERSION,
-               BLUETOOTH_PLUGIN_PRIORITY_HIGH, service_init, service_exit)
index 9c69c6d..beda307 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2011  David Herrmann <dh.herrmann@googlemail.com>
+ *  Copyright (C) 2011-2012 David Herrmann <dh.herrmann@googlemail.com>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -25,6 +25,8 @@
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
 #include <bluetooth/bluetooth.h>
 #include <glib.h>
 
  * is pressed.
  */
 
+static uint16_t wii_ids[][2] = {
+       { 0x057e, 0x0306 },
+       { 0x057e, 0x0330 },
+};
+
+static const char *wii_names[] = {
+       "Nintendo RVL-CNT-01",
+       "Nintendo RVL-CNT-01-TR",
+       "Nintendo RVL-WBC-01",
+};
+
 static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
-                                               char *pinbuf, gboolean *display)
+                                               char *pinbuf, bool *display,
+                                               unsigned int attempt)
 {
        uint16_t vendor, product;
-       bdaddr_t sba, dba;
        char addr[18], name[25];
+       unsigned int i;
 
-       adapter_get_address(adapter, &sba);
-       device_get_address(device, &dba, NULL);
-       ba2str(&dba, addr);
+       /* Only try the pin code once per device. If it's not correct then it's
+        * an unknown device. */
+       if (attempt > 1)
+               return 0;
+
+       ba2str(device_get_address(device), addr);
 
        vendor = btd_device_get_vendor(device);
        product = btd_device_get_product(device);
@@ -73,14 +90,22 @@ static ssize_t wii_pincb(struct btd_adapter *adapter, struct btd_device *device,
        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;
+       for (i = 0; i < G_N_ELEMENTS(wii_ids); ++i) {
+               if (vendor == wii_ids[i][0] && product == wii_ids[i][1])
+                       goto found;
+       }
+
+       for (i = 0; i < G_N_ELEMENTS(wii_names); ++i) {
+               if (g_str_equal(name, wii_names[i]))
+                       goto found;
        }
 
        return 0;
+
+found:
+       DBG("Forcing fixed pin on detected wiimote %s", addr);
+       memcpy(pinbuf, adapter_get_address(adapter), 6);
+       return 6;
 }
 
 static int wii_probe(struct btd_adapter *adapter)
diff --git a/profiles/alert/server.c b/profiles/alert/server.c
new file mode 100644 (file)
index 0000000..4565470
--- /dev/null
@@ -0,0 +1,1017 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+#include <gdbus/gdbus.h>
+#include <glib.h>
+#include <stdlib.h>
+
+#include "lib/uuid.h"
+#include "plugin.h"
+#include "dbus-common.h"
+#include "attrib/att.h"
+#include "adapter.h"
+#include "device.h"
+#include "attrib/att-database.h"
+#include "log.h"
+#include "attrib/gatt-service.h"
+#include "attrib/gattrib.h"
+#include "attrib-server.h"
+#include "attrib/gatt.h"
+#include "profile.h"
+#include "error.h"
+#include "textfile.h"
+#include "attio.h"
+
+#define PHONE_ALERT_STATUS_SVC_UUID    0x180E
+#define ALERT_NOTIF_SVC_UUID           0x1811
+
+#define ALERT_STATUS_CHR_UUID          0x2A3F
+#define RINGER_CP_CHR_UUID             0x2A40
+#define RINGER_SETTING_CHR_UUID                0x2A41
+
+#define ALERT_NOTIF_CP_CHR_UUID                0x2A44
+#define UNREAD_ALERT_CHR_UUID          0x2A45
+#define NEW_ALERT_CHR_UUID             0x2A46
+#define SUPP_NEW_ALERT_CAT_CHR_UUID    0x2A47
+#define SUPP_UNREAD_ALERT_CAT_CHR_UUID 0x2A48
+
+#define ALERT_OBJECT_PATH              "/org/bluez"
+#define ALERT_INTERFACE                        "org.bluez.Alert1"
+#define ALERT_AGENT_INTERFACE          "org.bluez.AlertAgent1"
+
+/* Maximum length for "Text String Information" */
+#define NEW_ALERT_MAX_INFO_SIZE                18
+/* Maximum length for New Alert Characteristic Value */
+#define NEW_ALERT_CHR_MAX_VALUE_SIZE   (NEW_ALERT_MAX_INFO_SIZE + 2)
+
+enum {
+       ENABLE_NEW_INCOMING,
+       ENABLE_UNREAD_CAT,
+       DISABLE_NEW_INCOMING,
+       DISABLE_UNREAD_CAT,
+       NOTIFY_NEW_INCOMING,
+       NOTIFY_UNREAD_CAT,
+};
+
+enum {
+       RINGER_SILENT_MODE = 1,
+       RINGER_MUTE_ONCE,
+       RINGER_CANCEL_SILENT_MODE,
+};
+
+/* Ringer Setting characteristic values */
+enum {
+       RINGER_SILENT,
+       RINGER_NORMAL,
+};
+
+enum notify_type {
+       NOTIFY_RINGER_SETTING = 0,
+       NOTIFY_ALERT_STATUS,
+       NOTIFY_NEW_ALERT,
+       NOTIFY_UNREAD_ALERT,
+       NOTIFY_SIZE,
+};
+
+struct alert_data {
+       const char *category;
+       char *srv;
+       char *path;
+       guint watcher;
+};
+
+struct alert_adapter {
+       struct btd_adapter *adapter;
+       uint16_t supp_new_alert_cat_handle;
+       uint16_t supp_unread_alert_cat_handle;
+       uint16_t hnd_ccc[NOTIFY_SIZE];
+       uint16_t hnd_value[NOTIFY_SIZE];
+};
+
+struct notify_data {
+       struct alert_adapter *al_adapter;
+       enum notify_type type;
+       uint8_t *value;
+       size_t len;
+};
+
+struct notify_callback {
+       struct notify_data *notify_data;
+       struct btd_device *device;
+       guint id;
+};
+
+static GSList *registered_alerts = NULL;
+static GSList *alert_adapters = NULL;
+static uint8_t ringer_setting = RINGER_NORMAL;
+static uint8_t alert_status = 0;
+
+static const char * const anp_categories[] = {
+       "simple",
+       "email",
+       "news",
+       "call",
+       "missed-call",
+       "sms-mms",
+       "voice-mail",
+       "schedule",
+       "high-priority",
+       "instant-message",
+};
+
+static const char * const pasp_categories[] = {
+       "ringer",
+       "vibrate",
+       "display",
+};
+
+static int adapter_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct alert_adapter *al_adapter = a;
+       const struct btd_adapter *adapter = b;
+
+       return al_adapter->adapter == adapter ? 0 : -1;
+}
+
+static struct alert_adapter *find_alert_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(alert_adapters, adapter, adapter_cmp);
+
+       return l ? l->data : NULL;
+}
+
+static void alert_data_destroy(gpointer user_data)
+{
+       struct alert_data *alert = user_data;
+
+       if (alert->watcher)
+               g_dbus_remove_watch(btd_get_dbus_connection(), alert->watcher);
+
+       g_free(alert->srv);
+       g_free(alert->path);
+       g_free(alert);
+}
+
+static void alert_release(gpointer user_data)
+{
+       struct alert_data *alert = user_data;
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(alert->srv, alert->path,
+                                                       ALERT_AGENT_INTERFACE,
+                                                       "Release");
+       if (msg)
+               g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+       alert_data_destroy(alert);
+}
+
+static void alert_destroy(gpointer user_data)
+{
+       DBG("");
+
+       g_slist_free_full(registered_alerts, alert_release);
+       registered_alerts = NULL;
+}
+
+static const char *valid_category(const char *category)
+{
+       unsigned i;
+
+       for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+               if (g_str_equal(anp_categories[i], category))
+                       return anp_categories[i];
+       }
+
+       for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) {
+               if (g_str_equal(pasp_categories[i], category))
+                       return pasp_categories[i];
+       }
+
+       return NULL;
+}
+
+static struct alert_data *get_alert_data_by_category(const char *category)
+{
+       GSList *l;
+       struct alert_data *alert;
+
+       for (l = registered_alerts; l; l = g_slist_next(l)) {
+               alert = l->data;
+               if (g_str_equal(alert->category, category))
+                       return alert;
+       }
+
+       return NULL;
+}
+
+static gboolean registered_category(const char *category)
+{
+       struct alert_data *alert;
+
+       alert = get_alert_data_by_category(category);
+       if (alert)
+               return TRUE;
+
+       return FALSE;
+}
+
+static gboolean pasp_category(const char *category)
+{
+       unsigned i;
+
+       for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++)
+               if (g_str_equal(category, pasp_categories[i]))
+                       return TRUE;
+
+       return FALSE;
+}
+
+static gboolean valid_description(const char *category,
+                                               const char *description)
+{
+       if (!pasp_category(category)) {
+               if (strlen(description) >= NEW_ALERT_MAX_INFO_SIZE)
+                       return FALSE;
+
+               return TRUE;
+       }
+
+       if (g_str_equal(description, "active") ||
+                                       g_str_equal(description, "not active"))
+               return TRUE;
+
+       if (g_str_equal(category, "ringer"))
+               if (g_str_equal(description, "enabled") ||
+                                       g_str_equal(description, "disabled"))
+                       return TRUE;
+
+       return FALSE;
+}
+
+static gboolean valid_count(const char *category, uint16_t count)
+{
+       if (!pasp_category(category) && count > 0 && count <= 255)
+               return TRUE;
+
+       if (pasp_category(category) && count == 1)
+               return TRUE;
+
+       return FALSE;
+}
+
+static void update_supported_categories(gpointer data, gpointer user_data)
+{
+       struct alert_adapter *al_adapter = data;
+       struct btd_adapter *adapter = al_adapter->adapter;
+       uint8_t value[2];
+       unsigned int i;
+
+       memset(value, 0, sizeof(value));
+
+       for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+               if (registered_category(anp_categories[i]))
+                       hci_set_bit(i, value);
+       }
+
+       attrib_db_update(adapter, al_adapter->supp_new_alert_cat_handle, NULL,
+                                               value, sizeof(value), NULL);
+
+       /* FIXME: For now report all registered categories as supporting unread
+        * status, until it is known which ones should be supported */
+       attrib_db_update(adapter, al_adapter->supp_unread_alert_cat_handle,
+                                       NULL, value, sizeof(value), NULL);
+}
+
+static void watcher_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct alert_data *alert = user_data;
+
+       DBG("Category %s was disconnected", alert->category);
+
+       registered_alerts = g_slist_remove(registered_alerts, alert);
+       alert_data_destroy(alert);
+
+       g_slist_foreach(alert_adapters, update_supported_categories, NULL);
+}
+
+static gboolean is_notifiable_device(struct btd_device *device, uint16_t ccc)
+{
+       char *filename;
+       GKeyFile *key_file;
+       char handle[6];
+       char *str;
+       uint16_t val;
+       gboolean result;
+
+       sprintf(handle, "%hu", ccc);
+
+       filename = btd_device_get_storage_path(device, "ccc");
+       if (!filename) {
+               warn("Unable to get ccc storage path for device");
+               return FALSE;
+       }
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       str = g_key_file_get_string(key_file, handle, "Value", NULL);
+       if (!str) {
+               result = FALSE;
+               goto end;
+       }
+
+       val = strtol(str, NULL, 16);
+       if (!(val & 0x0001)) {
+               result = FALSE;
+               goto end;
+       }
+
+       result = TRUE;
+end:
+       g_free(str);
+       g_free(filename);
+       g_key_file_free(key_file);
+
+       return result;
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct notify_callback *cb = user_data;
+       struct notify_data *nd = cb->notify_data;
+       enum notify_type type = nd->type;
+       struct alert_adapter *al_adapter = nd->al_adapter;
+       size_t len;
+       uint8_t *pdu = g_attrib_get_buffer(attrib, &len);
+
+
+       switch (type) {
+       case NOTIFY_RINGER_SETTING:
+               len = enc_notification(al_adapter->hnd_value[type],
+                               &ringer_setting, sizeof(ringer_setting),
+                               pdu, len);
+               break;
+       case NOTIFY_ALERT_STATUS:
+               len = enc_notification(al_adapter->hnd_value[type],
+                               &alert_status, sizeof(alert_status),
+                               pdu, len);
+               break;
+       case NOTIFY_NEW_ALERT:
+       case NOTIFY_UNREAD_ALERT:
+               len = enc_notification(al_adapter->hnd_value[type],
+                                       nd->value, nd->len, pdu, len);
+               break;
+       default:
+               DBG("Unknown type, could not send notification");
+               goto end;
+       }
+
+       DBG("Send notification for handle: 0x%04x, ccc: 0x%04x",
+                                       al_adapter->hnd_value[type],
+                                       al_adapter->hnd_ccc[type]);
+
+       g_attrib_send(attrib, 0, pdu, len, NULL, NULL, NULL);
+
+end:
+       btd_device_remove_attio_callback(cb->device, cb->id);
+       btd_device_unref(cb->device);
+       g_free(cb->notify_data->value);
+       g_free(cb->notify_data);
+       g_free(cb);
+}
+
+static void filter_devices_notify(struct btd_device *device, void *user_data)
+{
+       struct notify_data *notify_data = user_data;
+       struct alert_adapter *al_adapter = notify_data->al_adapter;
+       enum notify_type type = notify_data->type;
+       struct notify_callback *cb;
+
+       if (!is_notifiable_device(device, al_adapter->hnd_ccc[type]))
+               return;
+
+       cb = g_new0(struct notify_callback, 1);
+       cb->notify_data = notify_data;
+       cb->device = btd_device_ref(device);
+       cb->id = btd_device_add_attio_callback(device,
+                                               attio_connected_cb, NULL, cb);
+}
+
+static void notify_devices(struct alert_adapter *al_adapter,
+                       enum notify_type type, uint8_t *value, size_t len)
+{
+       struct notify_data *notify_data;
+
+       notify_data = g_new0(struct notify_data, 1);
+       notify_data->al_adapter = al_adapter;
+       notify_data->type = type;
+       notify_data->value = g_memdup(value, len);
+       notify_data->len = len;
+
+       btd_adapter_for_each_device(al_adapter->adapter, filter_devices_notify,
+                                       notify_data);
+}
+
+static void pasp_notification(enum notify_type type)
+{
+       GSList *it;
+       struct alert_adapter *al_adapter;
+
+       for (it = alert_adapters; it; it = g_slist_next(it)) {
+               al_adapter = it->data;
+
+               notify_devices(al_adapter, type, NULL, 0);
+       }
+}
+
+static DBusMessage *register_alert(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       char *path;
+       const char *category;
+       const char *c;
+       struct alert_data *alert;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &c,
+                       DBUS_TYPE_OBJECT_PATH, &path, DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       category = valid_category(c);
+       if (!category) {
+               DBG("Invalid category: %s", c);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (registered_category(category)) {
+               DBG("Category %s already registered", category);
+               return dbus_message_new_method_return(msg);
+       }
+
+       alert = g_new0(struct alert_data, 1);
+       alert->srv = g_strdup(sender);
+       alert->path = g_strdup(path);
+       alert->category = category;
+       alert->watcher = g_dbus_add_disconnect_watch(conn, alert->srv,
+                                       watcher_disconnect, alert, NULL);
+
+       if (alert->watcher == 0) {
+               alert_data_destroy(alert);
+               DBG("Could not register disconnect watcher");
+               return btd_error_failed(msg,
+                               "Could not register disconnect watcher");
+       }
+
+       registered_alerts = g_slist_append(registered_alerts, alert);
+
+       g_slist_foreach(alert_adapters, update_supported_categories, NULL);
+
+       DBG("RegisterAlert(\"%s\", \"%s\")", alert->category, alert->path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static void update_new_alert(gpointer data, gpointer user_data)
+{
+       struct alert_adapter *al_adapter = data;
+       struct btd_adapter *adapter = al_adapter->adapter;
+       uint8_t *value = user_data;
+
+       attrib_db_update(adapter, al_adapter->hnd_value[NOTIFY_NEW_ALERT], NULL,
+                                               &value[1], value[0], NULL);
+
+       notify_devices(al_adapter, NOTIFY_NEW_ALERT, &value[1], value[0]);
+}
+
+static void update_phone_alerts(const char *category, const char *description)
+{
+       unsigned int i;
+
+       if (g_str_equal(category, "ringer")) {
+               if (g_str_equal(description, "enabled")) {
+                       ringer_setting = RINGER_NORMAL;
+                       pasp_notification(NOTIFY_RINGER_SETTING);
+                       return;
+               } else if (g_str_equal(description, "disabled")) {
+                       ringer_setting = RINGER_SILENT;
+                       pasp_notification(NOTIFY_RINGER_SETTING);
+                       return;
+               }
+       }
+
+       for (i = 0; i < G_N_ELEMENTS(pasp_categories); i++) {
+               if (g_str_equal(pasp_categories[i], category)) {
+                       if (g_str_equal(description, "active")) {
+                               alert_status |= (1 << i);
+                               pasp_notification(NOTIFY_ALERT_STATUS);
+                       } else if (g_str_equal(description, "not active")) {
+                               alert_status &= ~(1 << i);
+                               pasp_notification(NOTIFY_ALERT_STATUS);
+                       }
+                       break;
+               }
+       }
+}
+
+static DBusMessage *new_alert(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       const char *category, *description;
+       struct alert_data *alert;
+       uint16_t count;
+       unsigned int i;
+       size_t dlen;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
+                       DBUS_TYPE_UINT16, &count, DBUS_TYPE_STRING,
+                       &description, DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       alert = get_alert_data_by_category(category);
+       if (!alert) {
+               DBG("Category %s not registered", category);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (!g_str_equal(alert->srv, sender)) {
+               DBG("Sender %s is not registered in category %s", sender,
+                                                               category);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (!valid_description(category, description)) {
+               DBG("Description %s is invalid for %s category",
+                                                       description, category);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (!valid_count(category, count)) {
+               DBG("Count %d is invalid for %s category", count, category);
+               return btd_error_invalid_args(msg);
+       }
+
+       dlen = strlen(description);
+
+       for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+               uint8_t value[NEW_ALERT_CHR_MAX_VALUE_SIZE + 1];
+               uint8_t *ptr = value;
+
+               if (!g_str_equal(anp_categories[i], category))
+                       continue;
+
+               memset(value, 0, sizeof(value));
+
+               *ptr++ = 2; /* Attribute value size */
+               *ptr++ = i; /* Category ID (mandatory) */
+               *ptr++ = count; /* Number of New Alert (mandatory) */
+               /* Text String Information (optional) */
+               strncpy((char *) ptr, description,
+                                               NEW_ALERT_MAX_INFO_SIZE - 1);
+
+               if (dlen > 0)
+                       *value += dlen + 1;
+
+               g_slist_foreach(alert_adapters, update_new_alert, value);
+       }
+
+       if (pasp_category(category))
+               update_phone_alerts(category, description);
+
+       DBG("NewAlert(\"%s\", %d, \"%s\")", category, count, description);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static int agent_ringer_mute_once(void)
+{
+       struct alert_data *alert;
+       DBusMessage *msg;
+
+       alert = get_alert_data_by_category("ringer");
+       if (!alert) {
+               DBG("Category ringer is not registered");
+               return -EINVAL;
+       }
+
+       msg = dbus_message_new_method_call(alert->srv, alert->path,
+                                       ALERT_AGENT_INTERFACE, "MuteOnce");
+       if (!msg)
+               return -ENOMEM;
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+       return 0;
+}
+
+static int agent_ringer_set_ringer(const char *mode)
+{
+       struct alert_data *alert;
+       DBusMessage *msg;
+
+       alert = get_alert_data_by_category("ringer");
+       if (!alert) {
+               DBG("Category ringer is not registered");
+               return -EINVAL;
+       }
+
+       msg = dbus_message_new_method_call(alert->srv, alert->path,
+                                       ALERT_AGENT_INTERFACE, "SetRinger");
+       if (!msg)
+               return -ENOMEM;
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &mode,
+                                                       DBUS_TYPE_INVALID);
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+       return 0;
+}
+
+static void update_unread_alert(gpointer data, gpointer user_data)
+{
+       struct alert_adapter *al_adapter = data;
+       struct btd_adapter *adapter = al_adapter->adapter;
+       uint8_t *value = user_data;
+
+       attrib_db_update(adapter,
+                       al_adapter->hnd_value[NOTIFY_UNREAD_ALERT], NULL, value,
+                       2, NULL);
+
+       notify_devices(al_adapter, NOTIFY_UNREAD_ALERT, value, 2);
+}
+
+static DBusMessage *unread_alert(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct alert_data *alert;
+       const char *category;
+       unsigned int i;
+       uint16_t count;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &category,
+                                               DBUS_TYPE_UINT16, &count,
+                                               DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       alert = get_alert_data_by_category(category);
+       if (!alert) {
+               DBG("Category %s not registered", category);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (!valid_count(category, count)) {
+               DBG("Count %d is invalid for %s category", count, category);
+               return btd_error_invalid_args(msg);
+       }
+
+       if (!g_str_equal(alert->srv, sender)) {
+               DBG("Sender %s is not registered in category %s", sender,
+                                                               category);
+               return btd_error_invalid_args(msg);
+       }
+
+       for (i = 0; i < G_N_ELEMENTS(anp_categories); i++) {
+               if (g_str_equal(anp_categories[i], category)) {
+                       uint8_t value[2];
+
+                       value[0] = i; /* Category ID */
+                       value[1] = count; /* Unread count */
+
+                       g_slist_foreach(alert_adapters, update_unread_alert,
+                                                                       value);
+               }
+       }
+
+       DBG("category %s, count %d", category, count);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static uint8_t ringer_cp_write(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       DBG("a = %p", a);
+
+       if (a->len > 1) {
+               DBG("Invalid command size (%zu)", a->len);
+               return 0;
+       }
+
+       switch (a->data[0]) {
+       case RINGER_SILENT_MODE:
+               DBG("Silent Mode");
+               agent_ringer_set_ringer("disabled");
+               break;
+       case RINGER_MUTE_ONCE:
+               DBG("Mute Once");
+               agent_ringer_mute_once();
+               break;
+       case RINGER_CANCEL_SILENT_MODE:
+               DBG("Cancel Silent Mode");
+               agent_ringer_set_ringer("enabled");
+               break;
+       default:
+               DBG("Invalid command (0x%02x)", a->data[0]);
+       }
+
+       return 0;
+}
+
+static uint8_t alert_status_read(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("a = %p", a);
+
+       if (a->data == NULL || a->data[0] != alert_status)
+               attrib_db_update(adapter, a->handle, NULL, &alert_status,
+                                               sizeof(alert_status), NULL);
+
+       return 0;
+}
+
+static uint8_t ringer_setting_read(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       DBG("a = %p", a);
+
+       if (a->data == NULL || a->data[0] != ringer_setting)
+               attrib_db_update(adapter, a->handle, NULL, &ringer_setting,
+                                               sizeof(ringer_setting), NULL);
+
+       return 0;
+}
+
+static void register_phone_alert_service(struct alert_adapter *al_adapter)
+{
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, PHONE_ALERT_STATUS_SVC_UUID);
+
+       /* Phone Alert Status Service */
+       gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid,
+                       /* Alert Status characteristic */
+                       GATT_OPT_CHR_UUID16, ALERT_STATUS_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+                                                       ATT_CHAR_PROPER_NOTIFY,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                       alert_status_read, al_adapter->adapter,
+                       GATT_OPT_CCC_GET_HANDLE,
+                       &al_adapter->hnd_ccc[NOTIFY_ALERT_STATUS],
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->hnd_value[NOTIFY_ALERT_STATUS],
+                       /* Ringer Control Point characteristic */
+                       GATT_OPT_CHR_UUID16, RINGER_CP_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+                       ringer_cp_write, NULL,
+                       /* Ringer Setting characteristic */
+                       GATT_OPT_CHR_UUID16, RINGER_SETTING_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+                                                       ATT_CHAR_PROPER_NOTIFY,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                       ringer_setting_read, al_adapter->adapter,
+                       GATT_OPT_CCC_GET_HANDLE,
+                       &al_adapter->hnd_ccc[NOTIFY_RINGER_SETTING],
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->hnd_value[NOTIFY_RINGER_SETTING],
+                       GATT_OPT_INVALID);
+}
+
+static uint8_t supp_new_alert_cat_read(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value[] = { 0x00, 0x00 };
+
+       DBG("a = %p", a);
+
+       if (a->data == NULL)
+               attrib_db_update(adapter, a->handle, NULL, value, sizeof(value),
+                                                                       NULL);
+
+       return 0;
+}
+
+static uint8_t supp_unread_alert_cat_read(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value[] = { 0x00, 0x00 };
+
+       DBG("a = %p", a);
+
+       if (a->data == NULL)
+               attrib_db_update(adapter, a->handle, NULL, value, sizeof(value),
+                                                                       NULL);
+
+       return 0;
+}
+
+static uint8_t alert_notif_cp_write(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       DBG("a = %p", a);
+
+       if (a->len < 2)
+               return 0;
+
+       switch (a->data[0]) {
+       case ENABLE_NEW_INCOMING:
+               DBG("ENABLE_NEW_INCOMING: 0x%02x", a->data[1]);
+               break;
+       case ENABLE_UNREAD_CAT:
+               DBG("ENABLE_UNREAD_CAT: 0x%02x", a->data[1]);
+               break;
+       case DISABLE_NEW_INCOMING:
+               DBG("DISABLE_NEW_INCOMING: 0x%02x", a->data[1]);
+               break;
+       case DISABLE_UNREAD_CAT:
+               DBG("DISABLE_UNREAD_CAT: 0x%02x", a->data[1]);
+               break;
+       case NOTIFY_NEW_INCOMING:
+               DBG("NOTIFY_NEW_INCOMING: 0x%02x", a->data[1]);
+               break;
+       case NOTIFY_UNREAD_CAT:
+               DBG("NOTIFY_UNREAD_CAT: 0x%02x", a->data[1]);
+               break;
+       default:
+               DBG("0x%02x 0x%02x", a->data[0], a->data[1]);
+       }
+
+       return 0;
+}
+
+static void register_alert_notif_service(struct alert_adapter *al_adapter)
+{
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, ALERT_NOTIF_SVC_UUID);
+
+       /* Alert Notification Service */
+       gatt_service_add(al_adapter->adapter, GATT_PRIM_SVC_UUID, &uuid,
+                       /* Supported New Alert Category */
+                       GATT_OPT_CHR_UUID16, SUPP_NEW_ALERT_CAT_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                       supp_new_alert_cat_read, al_adapter->adapter,
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->supp_new_alert_cat_handle,
+                       /* New Alert */
+                       GATT_OPT_CHR_UUID16, NEW_ALERT_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+                       GATT_OPT_CCC_GET_HANDLE,
+                       &al_adapter->hnd_ccc[NOTIFY_NEW_ALERT],
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->hnd_value[NOTIFY_NEW_ALERT],
+                       /* Supported Unread Alert Category */
+                       GATT_OPT_CHR_UUID16, SUPP_UNREAD_ALERT_CAT_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                       supp_unread_alert_cat_read, al_adapter->adapter,
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->supp_unread_alert_cat_handle,
+                       /* Unread Alert Status */
+                       GATT_OPT_CHR_UUID16, UNREAD_ALERT_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_NOTIFY,
+                       GATT_OPT_CCC_GET_HANDLE,
+                       &al_adapter->hnd_ccc[NOTIFY_UNREAD_ALERT],
+                       GATT_OPT_CHR_VALUE_GET_HANDLE,
+                       &al_adapter->hnd_value[NOTIFY_UNREAD_ALERT],
+                       /* Alert Notification Control Point */
+                       GATT_OPT_CHR_UUID16, ALERT_NOTIF_CP_CHR_UUID,
+                       GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_WRITE,
+                       GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+                       alert_notif_cp_write, NULL,
+                       GATT_OPT_INVALID);
+}
+
+static int alert_server_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct alert_adapter *al_adapter;
+
+       al_adapter = g_new0(struct alert_adapter, 1);
+       al_adapter->adapter = btd_adapter_ref(adapter);
+
+       alert_adapters = g_slist_append(alert_adapters, al_adapter);
+
+       register_phone_alert_service(al_adapter);
+       register_alert_notif_service(al_adapter);
+
+       return 0;
+}
+
+static void alert_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct alert_adapter *al_adapter;
+
+       al_adapter = find_alert_adapter(adapter);
+       if (!al_adapter)
+               return;
+
+       alert_adapters = g_slist_remove(alert_adapters, al_adapter);
+       btd_adapter_unref(al_adapter->adapter);
+
+       g_free(al_adapter);
+}
+
+static struct btd_profile alert_profile = {
+       .name = "gatt-alert-server",
+       .adapter_probe = alert_server_probe,
+       .adapter_remove = alert_server_remove,
+};
+
+static const GDBusMethodTable alert_methods[] = {
+       { GDBUS_METHOD("RegisterAlert",
+                       GDBUS_ARGS({ "category", "s" },
+                                  { "agent", "o" }), NULL,
+                       register_alert) },
+       { GDBUS_METHOD("NewAlert",
+                       GDBUS_ARGS({ "category", "s" },
+                                  { "count", "q" },
+                                  { "description", "s" }), NULL,
+                       new_alert) },
+       { GDBUS_METHOD("UnreadAlert",
+                       GDBUS_ARGS({ "category", "s" }, { "count", "q" }), NULL,
+                       unread_alert) },
+       { }
+};
+
+static int alert_server_init(void)
+{
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       ALERT_OBJECT_PATH, ALERT_INTERFACE,
+                                       alert_methods, NULL, NULL, NULL,
+                                       alert_destroy)) {
+               error("D-Bus failed to register %s interface",
+                                                       ALERT_INTERFACE);
+               return -EIO;
+       }
+
+       return btd_profile_register(&alert_profile);
+}
+
+static void alert_server_exit(void)
+{
+       btd_profile_unregister(&alert_profile);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       ALERT_OBJECT_PATH, ALERT_INTERFACE);
+}
+
+static int alert_init(void)
+{
+       return alert_server_init();
+}
+
+static void alert_exit(void)
+{
+       alert_server_exit();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(alert, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       alert_init, alert_exit)
similarity index 81%
rename from audio/a2dp-codecs.h
rename to profiles/audio/a2dp-codecs.h
index 51c796a..3dc31cb 100644 (file)
@@ -26,6 +26,7 @@
 #define A2DP_CODEC_MPEG12              0x01
 #define A2DP_CODEC_MPEG24              0x02
 #define A2DP_CODEC_ATRAC               0x03
+#define A2DP_CODEC_VENDOR              0xFF
 
 #define SBC_SAMPLING_FREQ_16000                (1 << 3)
 #define SBC_SAMPLING_FREQ_32000                (1 << 2)
@@ -48,6 +49,9 @@
 #define SBC_ALLOCATION_SNR             (1 << 1)
 #define SBC_ALLOCATION_LOUDNESS                1
 
+#define MAX_BITPOOL 64
+#define MIN_BITPOOL 2
+
 #define MPEG_CHANNEL_MODE_MONO         (1 << 3)
 #define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
 #define MPEG_CHANNEL_MODE_STEREO       (1 << 1)
 #define MPEG_SAMPLING_FREQ_44100       (1 << 1)
 #define MPEG_SAMPLING_FREQ_48000       1
 
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
+#define MPEG_BIT_RATE_VBR              0x8000
+#define MPEG_BIT_RATE_320000           0x4000
+#define MPEG_BIT_RATE_256000           0x2000
+#define MPEG_BIT_RATE_224000           0x1000
+#define MPEG_BIT_RATE_192000           0x0800
+#define MPEG_BIT_RATE_160000           0x0400
+#define MPEG_BIT_RATE_128000           0x0200
+#define MPEG_BIT_RATE_112000           0x0100
+#define MPEG_BIT_RATE_96000            0x0080
+#define MPEG_BIT_RATE_80000            0x0040
+#define MPEG_BIT_RATE_64000            0x0020
+#define MPEG_BIT_RATE_56000            0x0010
+#define MPEG_BIT_RATE_48000            0x0008
+#define MPEG_BIT_RATE_40000            0x0004
+#define MPEG_BIT_RATE_32000            0x0002
+#define MPEG_BIT_RATE_FREE             0x0001
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 
@@ -114,3 +132,8 @@ typedef struct {
 #else
 #error "Unknown byte order"
 #endif
+
+typedef struct {
+       uint8_t vendor_id[4];
+       uint8_t codec_id[2];
+} __attribute__ ((packed)) a2dp_vendor_codec_t;
similarity index 65%
rename from audio/a2dp.c
rename to profiles/audio/a2dp.c
index 404be53..8477b5d 100644 (file)
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include "lib/uuid.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+
 #include "log.h"
-#include "device.h"
-#include "manager.h"
 #include "avdtp.h"
 #include "sink.h"
 #include "source.h"
-#include "unix.h"
 #include "a2dp.h"
+#include "a2dp-codecs.h"
 #include "sdpd.h"
+#include "media.h"
 
 /* The duration that streams without users are allowed to stay in
  * STREAMING state. */
 #define SUSPEND_TIMEOUT 5
 #define RECONFIGURE_TIMEOUT 500
 
-#ifndef MIN
-# define MIN(x, y) ((x) < (y) ? (x) : (y))
-#endif
-
-#ifndef MAX
-# define MAX(x, y) ((x) > (y) ? (x) : (y))
-#endif
-
 struct a2dp_sep {
        struct a2dp_server *server;
        struct a2dp_endpoint *endpoint;
@@ -89,7 +87,6 @@ struct a2dp_setup_cb {
 };
 
 struct a2dp_setup {
-       struct audio_device *dev;
        struct avdtp *session;
        struct a2dp_sep *sep;
        struct avdtp_remote_sep *rsep;
@@ -103,15 +100,12 @@ struct a2dp_setup {
        int ref;
 };
 
-static DBusConnection *connection = NULL;
-
 struct a2dp_server {
-       bdaddr_t src;
+       struct btd_adapter *adapter;
        GSList *sinks;
        GSList *sources;
        uint32_t source_record_id;
        uint32_t sink_record_id;
-       uint16_t version;
        gboolean sink_enabled;
        gboolean source_enabled;
 };
@@ -129,29 +123,12 @@ static struct a2dp_setup *setup_ref(struct a2dp_setup *setup)
        return setup;
 }
 
-static struct audio_device *a2dp_get_dev(struct avdtp *session)
-{
-       bdaddr_t src, dst;
-
-       avdtp_get_peers(session, &src, &dst);
-
-       return manager_find_device(NULL, &src, &dst, NULL, FALSE);
-}
-
 static struct a2dp_setup *setup_new(struct avdtp *session)
 {
-       struct audio_device *dev;
        struct a2dp_setup *setup;
 
-       dev = a2dp_get_dev(session);
-       if (!dev) {
-               error("Unable to create setup");
-               return NULL;
-       }
-
        setup = g_new0(struct a2dp_setup, 1);
        setup->session = avdtp_ref(session);
-       setup->dev = a2dp_get_dev(session);
        setups = g_slist_append(setups, setup);
 
        return setup;
@@ -335,14 +312,14 @@ static struct a2dp_setup *a2dp_setup_get(struct avdtp *session)
        return setup_ref(setup);
 }
 
-static struct a2dp_setup *find_setup_by_dev(struct audio_device *dev)
+static struct a2dp_setup *find_setup_by_stream(struct avdtp_stream *stream)
 {
        GSList *l;
 
        for (l = setups; l != NULL; l = l->next) {
                struct a2dp_setup *setup = l->data;
 
-               if (setup->dev == dev)
+               if (setup->stream == stream)
                        return setup;
        }
 
@@ -357,6 +334,29 @@ static void stream_state_changed(struct avdtp_stream *stream,
 {
        struct a2dp_sep *sep = user_data;
 
+       if (new_state == AVDTP_STATE_OPEN) {
+               struct a2dp_setup *setup;
+               int err;
+
+               setup = find_setup_by_stream(stream);
+               if (!setup || !setup->start)
+                       return;
+
+               setup->start = FALSE;
+
+               err = avdtp_start(setup->session, stream);
+               if (err < 0 && err != -EINPROGRESS) {
+                       error("avdtp_start: %s (%d)", strerror(-err), -err);
+                       finalize_setup_errno(setup, err, finalize_resume,
+                                                                       NULL);
+                       return;
+               }
+
+               sep->starting = TRUE;
+
+               return;
+       }
+
        if (new_state != AVDTP_STATE_IDLE)
                return;
 
@@ -379,24 +379,26 @@ static void stream_state_changed(struct avdtp_stream *stream,
 static gboolean auto_config(gpointer data)
 {
        struct a2dp_setup *setup = data;
-       struct avdtp_error *err = NULL;
+       struct btd_device *dev = avdtp_get_device(setup->session);
+       struct btd_service *service;
 
        /* Check if configuration was aborted */
        if (setup->sep->stream == NULL)
                return FALSE;
 
-       if (setup->err != NULL) {
-               err = setup->err;
+       if (setup->err != NULL)
                goto done;
-       }
 
        avdtp_stream_add_cb(setup->session, setup->stream,
                                stream_state_changed, setup->sep);
 
-       if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE)
-               sink_new_stream(setup->dev, setup->session, setup->stream);
-       else
-               source_new_stream(setup->dev, setup->session, setup->stream);
+       if (setup->sep->type == AVDTP_SEP_TYPE_SOURCE) {
+               service = btd_device_get_service(dev, A2DP_SINK_UUID);
+               sink_new_stream(service, setup->session, setup->stream);
+       } else {
+               service = btd_device_get_service(dev, A2DP_SOURCE_UUID);
+               source_new_stream(service, setup->session, setup->stream);
+       }
 
 done:
        if (setup->setconf_cb)
@@ -404,241 +406,16 @@ done:
 
        finalize_config(setup);
 
-       if (err)
-               g_free(err);
+       if (setup->err) {
+               g_free(setup->err);
+               setup->err = NULL;
+       }
 
        setup_unref(setup);
 
        return FALSE;
 }
 
-static gboolean sbc_setconf_ind(struct avdtp *session,
-                                       struct avdtp_local_sep *sep,
-                                       struct avdtp_stream *stream,
-                                       GSList *caps,
-                                       avdtp_set_configuration_cb cb,
-                                       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: Set_Configuration_Ind", sep);
-       else
-               DBG("Source %p: Set_Configuration_Ind", sep);
-
-       setup = a2dp_setup_get(session);
-       if (!setup)
-               return FALSE;
-
-       a2dp_sep->stream = stream;
-       setup->sep = a2dp_sep;
-       setup->stream = stream;
-       setup->setconf_cb = cb;
-
-       /* Check valid settings */
-       for (; caps != NULL; caps = g_slist_next(caps)) {
-               struct avdtp_service_capability *cap = caps->data;
-               struct avdtp_media_codec_capability *codec_cap;
-               struct sbc_codec_cap *sbc_cap;
-
-               if (cap->category == AVDTP_DELAY_REPORTING &&
-                                       !a2dp_sep->delay_reporting) {
-                       setup->err = g_new(struct avdtp_error, 1);
-                       avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-                                               AVDTP_UNSUPPORTED_CONFIGURATION);
-                       goto done;
-               }
-
-               if (cap->category != AVDTP_MEDIA_CODEC)
-                       continue;
-
-               if (cap->length < sizeof(struct sbc_codec_cap))
-                       continue;
-
-               codec_cap = (void *) cap->data;
-
-               if (codec_cap->media_codec_type != A2DP_CODEC_SBC)
-                       continue;
-
-               sbc_cap = (void *) codec_cap;
-
-               if (sbc_cap->min_bitpool < MIN_BITPOOL ||
-                                       sbc_cap->max_bitpool > MAX_BITPOOL) {
-                       setup->err = g_new(struct avdtp_error, 1);
-                       avdtp_error_init(setup->err, AVDTP_MEDIA_CODEC,
-                                       AVDTP_UNSUPPORTED_CONFIGURATION);
-                       goto done;
-               }
-       }
-
-done:
-       g_idle_add(auto_config, setup);
-       return TRUE;
-}
-
-static gboolean sbc_getcap_ind(struct avdtp *session, struct avdtp_local_sep *sep,
-                               gboolean get_all, GSList **caps, uint8_t *err,
-                               void *user_data)
-{
-       struct a2dp_sep *a2dp_sep = user_data;
-       struct avdtp_service_capability *media_transport, *media_codec;
-       struct sbc_codec_cap sbc_cap;
-
-       if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-               DBG("Sink %p: Get_Capability_Ind", sep);
-       else
-               DBG("Source %p: Get_Capability_Ind", sep);
-
-       *caps = NULL;
-
-       media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-                                               NULL, 0);
-
-       *caps = g_slist_append(*caps, media_transport);
-
-       memset(&sbc_cap, 0, sizeof(struct sbc_codec_cap));
-
-       sbc_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-       sbc_cap.cap.media_codec_type = A2DP_CODEC_SBC;
-
-       sbc_cap.frequency = ( SBC_SAMPLING_FREQ_48000 |
-                               SBC_SAMPLING_FREQ_44100 |
-                               SBC_SAMPLING_FREQ_32000 |
-                               SBC_SAMPLING_FREQ_16000 );
-
-       sbc_cap.channel_mode = ( SBC_CHANNEL_MODE_JOINT_STEREO |
-                                       SBC_CHANNEL_MODE_STEREO |
-                                       SBC_CHANNEL_MODE_DUAL_CHANNEL |
-                                       SBC_CHANNEL_MODE_MONO );
-
-       sbc_cap.block_length = ( SBC_BLOCK_LENGTH_16 |
-                                       SBC_BLOCK_LENGTH_12 |
-                                       SBC_BLOCK_LENGTH_8 |
-                                       SBC_BLOCK_LENGTH_4 );
-
-       sbc_cap.subbands = ( SBC_SUBBANDS_8 | SBC_SUBBANDS_4 );
-
-       sbc_cap.allocation_method = ( SBC_ALLOCATION_LOUDNESS |
-                                       SBC_ALLOCATION_SNR );
-
-       sbc_cap.min_bitpool = MIN_BITPOOL;
-       sbc_cap.max_bitpool = MAX_BITPOOL;
-
-       media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-                                               sizeof(sbc_cap));
-
-       *caps = g_slist_append(*caps, media_codec);
-
-       if (get_all) {
-               struct avdtp_service_capability *delay_reporting;
-               delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-                                                               NULL, 0);
-               *caps = g_slist_append(*caps, delay_reporting);
-       }
-
-       return TRUE;
-}
-
-static gboolean mpeg_setconf_ind(struct avdtp *session,
-                                       struct avdtp_local_sep *sep,
-                                       struct avdtp_stream *stream,
-                                       GSList *caps,
-                                       avdtp_set_configuration_cb cb,
-                                       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: Set_Configuration_Ind", sep);
-       else
-               DBG("Source %p: Set_Configuration_Ind", sep);
-
-       setup = a2dp_setup_get(session);
-       if (!setup)
-               return FALSE;
-
-       a2dp_sep->stream = stream;
-       setup->sep = a2dp_sep;
-       setup->stream = stream;
-       setup->setconf_cb = cb;
-
-       for (; caps != NULL; caps = g_slist_next(caps)) {
-               struct avdtp_service_capability *cap = caps->data;
-
-               if (cap->category == AVDTP_DELAY_REPORTING &&
-                                       !a2dp_sep->delay_reporting) {
-                       setup->err = g_new(struct avdtp_error, 1);
-                       avdtp_error_init(setup->err, AVDTP_DELAY_REPORTING,
-                                       AVDTP_UNSUPPORTED_CONFIGURATION);
-                       goto done;
-               }
-       }
-
-done:
-       g_idle_add(auto_config, setup);
-       return TRUE;
-}
-
-static gboolean mpeg_getcap_ind(struct avdtp *session,
-                               struct avdtp_local_sep *sep,
-                               gboolean get_all,
-                               GSList **caps, uint8_t *err, void *user_data)
-{
-       struct a2dp_sep *a2dp_sep = user_data;
-       struct avdtp_service_capability *media_transport, *media_codec;
-       struct mpeg_codec_cap mpeg_cap;
-
-       if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-               DBG("Sink %p: Get_Capability_Ind", sep);
-       else
-               DBG("Source %p: Get_Capability_Ind", sep);
-
-       *caps = NULL;
-
-       media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-                                               NULL, 0);
-
-       *caps = g_slist_append(*caps, media_transport);
-
-       memset(&mpeg_cap, 0, sizeof(struct mpeg_codec_cap));
-
-       mpeg_cap.cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-       mpeg_cap.cap.media_codec_type = A2DP_CODEC_MPEG12;
-
-       mpeg_cap.frequency = ( MPEG_SAMPLING_FREQ_48000 |
-                               MPEG_SAMPLING_FREQ_44100 |
-                               MPEG_SAMPLING_FREQ_32000 |
-                               MPEG_SAMPLING_FREQ_24000 |
-                               MPEG_SAMPLING_FREQ_22050 |
-                               MPEG_SAMPLING_FREQ_16000 );
-
-       mpeg_cap.channel_mode = ( MPEG_CHANNEL_MODE_JOINT_STEREO |
-                                       MPEG_CHANNEL_MODE_STEREO |
-                                       MPEG_CHANNEL_MODE_DUAL_CHANNEL |
-                                       MPEG_CHANNEL_MODE_MONO );
-
-       mpeg_cap.layer = ( MPEG_LAYER_MP3 | MPEG_LAYER_MP2 | MPEG_LAYER_MP1 );
-
-       mpeg_cap.bitrate = 0xFFFF;
-
-       media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &mpeg_cap,
-                                               sizeof(mpeg_cap));
-
-       *caps = g_slist_append(*caps, media_codec);
-
-       if (get_all) {
-               struct avdtp_service_capability *delay_reporting;
-               delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-                                                               NULL, 0);
-               *caps = g_slist_append(*caps, delay_reporting);
-       }
-
-       return TRUE;
-}
-
-
 static void endpoint_setconf_cb(struct a2dp_setup *setup, gboolean ret)
 {
        if (ret == FALSE) {
@@ -700,7 +477,7 @@ static gboolean endpoint_setconf_ind(struct avdtp *session,
                }
 
                ret = a2dp_sep->endpoint->set_configuration(a2dp_sep,
-                                               setup->dev, codec->data,
+                                               codec->data,
                                                cap->length - sizeof(*codec),
                                                setup,
                                                endpoint_setconf_cb,
@@ -791,7 +568,8 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
 {
        struct a2dp_sep *a2dp_sep = user_data;
        struct a2dp_setup *setup;
-       struct audio_device *dev;
+       struct btd_device *dev;
+       struct btd_service *service;
        int ret;
 
        if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
@@ -803,8 +581,11 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
 
        if (err) {
                if (setup) {
+                       setup_ref(setup);
                        setup->err = err;
                        finalize_config(setup);
+                       setup->err = NULL;
+                       setup_unref(setup);
                }
                return;
        }
@@ -815,13 +596,16 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        if (!setup)
                return;
 
-       dev = a2dp_get_dev(session);
+       dev = avdtp_get_device(session);
 
        /* Notify D-Bus interface of the new stream */
-       if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE)
-               sink_new_stream(dev, session, setup->stream);
-       else
-               source_new_stream(dev, session, setup->stream);
+       if (a2dp_sep->type == AVDTP_SEP_TYPE_SOURCE) {
+               service = btd_device_get_service(dev, A2DP_SINK_UUID);
+               sink_new_stream(service, session, setup->stream);
+       } else {
+               service = btd_device_get_service(dev, A2DP_SOURCE_UUID);
+               source_new_stream(service, session, setup->stream);
+       }
 
        /* Notify Endpoint */
        if (a2dp_sep->endpoint) {
@@ -832,7 +616,7 @@ static void setconf_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
                service = avdtp_stream_get_codec(stream);
                codec = (struct avdtp_media_codec_capability *) service->data;
 
-               err = a2dp_sep->endpoint->set_configuration(a2dp_sep, dev,
+               err = a2dp_sep->endpoint->set_configuration(a2dp_sep,
                                                codec->data, service->length -
                                                sizeof(*codec),
                                                setup,
@@ -924,9 +708,13 @@ static void open_cfm(struct avdtp *session, struct avdtp_local_sep *sep,
        if (err) {
                setup->stream = NULL;
                setup->err = err;
+               if (setup->start)
+                       finalize_resume(setup);
        }
 
        finalize_config(setup);
+
+       return;
 }
 
 static gboolean suspend_timeout(struct a2dp_sep *sep)
@@ -1041,7 +829,7 @@ static gboolean suspend_ind(struct avdtp *session, struct avdtp_local_sep *sep,
        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);
+               finalize_setup_errno(setup, start_err, finalize_resume, NULL);
        }
 
        return TRUE;
@@ -1197,7 +985,7 @@ static void abort_ind(struct avdtp *session, struct avdtp_local_sep *sep,
 
        finalize_setup_errno(setup, -ECONNRESET, finalize_suspend,
                                                        finalize_resume,
-                                                       finalize_config);
+                                                       finalize_config, NULL);
 
        return;
 }
@@ -1234,24 +1022,6 @@ static gboolean reconf_ind(struct avdtp *session, struct avdtp_local_sep *sep,
        return TRUE;
 }
 
-static gboolean delayreport_ind(struct avdtp *session,
-                               struct avdtp_local_sep *sep,
-                               uint8_t rseid, uint16_t delay,
-                               uint8_t *err, void *user_data)
-{
-       struct a2dp_sep *a2dp_sep = user_data;
-       struct audio_device *dev = a2dp_get_dev(session);
-
-       if (a2dp_sep->type == AVDTP_SEP_TYPE_SINK)
-               DBG("Sink %p: DelayReport_Ind", sep);
-       else
-               DBG("Source %p: DelayReport_Ind", sep);
-
-       unix_delay_report(dev, rseid, delay);
-
-       return TRUE;
-}
-
 static gboolean endpoint_delayreport_ind(struct avdtp *session,
                                                struct avdtp_local_sep *sep,
                                                uint8_t rseid, uint16_t delay,
@@ -1321,32 +1091,6 @@ static struct avdtp_sep_cfm cfm = {
        .delay_report           = delay_report_cfm,
 };
 
-static struct avdtp_sep_ind sbc_ind = {
-       .get_capability         = sbc_getcap_ind,
-       .set_configuration      = sbc_setconf_ind,
-       .get_configuration      = getconf_ind,
-       .open                   = open_ind,
-       .start                  = start_ind,
-       .suspend                = suspend_ind,
-       .close                  = close_ind,
-       .abort                  = abort_ind,
-       .reconfigure            = reconf_ind,
-       .delayreport            = delayreport_ind,
-};
-
-static struct avdtp_sep_ind mpeg_ind = {
-       .get_capability         = mpeg_getcap_ind,
-       .set_configuration      = mpeg_setconf_ind,
-       .get_configuration      = getconf_ind,
-       .open                   = open_ind,
-       .start                  = start_ind,
-       .suspend                = suspend_ind,
-       .close                  = close_ind,
-       .abort                  = abort_ind,
-       .reconfigure            = reconf_ind,
-       .delayreport            = delayreport_ind,
-};
-
 static struct avdtp_sep_ind endpoint_ind = {
        .get_capability         = endpoint_getcap_ind,
        .set_configuration      = endpoint_setconf_ind,
@@ -1360,7 +1104,7 @@ static struct avdtp_sep_ind endpoint_ind = {
        .delayreport            = endpoint_delayreport_ind,
 };
 
-static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver)
+static sdp_record_t *a2dp_record(uint8_t type)
 {
        sdp_list_t *svclass_id, *pfseq, *apseq, *root;
        uuid_t root_uuid, l2cap_uuid, avdtp_uuid, a2dp_uuid;
@@ -1369,7 +1113,7 @@ static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver)
        sdp_record_t *record;
        sdp_data_t *psm, *version, *features;
        uint16_t lp = AVDTP_UUID;
-       uint16_t a2dp_ver = 0x0102, feat = 0x000f;
+       uint16_t a2dp_ver = 0x0103, avdtp_ver = 0x0103, feat = 0x000f;
 
        record = sdp_record_alloc();
        if (!record)
@@ -1427,207 +1171,60 @@ static sdp_record_t *a2dp_record(uint8_t type, uint16_t avdtp_ver)
        return record;
 }
 
-static struct a2dp_server *find_server(GSList *list, const bdaddr_t *src)
+static struct a2dp_server *find_server(GSList *list, struct btd_adapter *a)
 {
 
        for (; list; list = list->next) {
                struct a2dp_server *server = list->data;
 
-               if (bacmp(&server->src, src) == 0)
+               if (server->adapter == a)
                        return server;
        }
 
        return NULL;
 }
 
-int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config)
+static struct a2dp_server *a2dp_server_register(struct btd_adapter *adapter)
 {
-       int sbc_srcs = 0, sbc_sinks = 0;
-       int mpeg12_srcs = 0, mpeg12_sinks = 0;
-       gboolean source = TRUE, sink = FALSE, socket = FALSE;
-       gboolean delay_reporting = FALSE;
-       char *str;
-       GError *err = NULL;
-       int i;
        struct a2dp_server *server;
+       int av_err;
 
-       if (!config)
-               goto proceed;
+       server = g_new0(struct a2dp_server, 1);
 
-       str = g_key_file_get_string(config, "General", "Enable", &err);
-
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               if (strstr(str, "Sink"))
-                       source = TRUE;
-               if (strstr(str, "Source"))
-                       sink = TRUE;
-               if (strstr(str, "Socket"))
-                       socket = TRUE;
-               g_free(str);
+       av_err = avdtp_init(adapter);
+       if (av_err < 0) {
+               DBG("AVDTP not registered");
+               g_free(server);
+               return NULL;
        }
 
-       str = g_key_file_get_string(config, "General", "Disable", &err);
-
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               if (strstr(str, "Sink"))
-                       source = FALSE;
-               if (strstr(str, "Source"))
-                       sink = FALSE;
-               if (strstr(str, "Socket"))
-                       socket = FALSE;
-               g_free(str);
-       }
+       server->adapter = btd_adapter_ref(adapter);
+       servers = g_slist_append(servers, server);
 
-       /* Don't register any local sep if Socket is disabled */
-       if (socket == FALSE)
-               goto proceed;
+       return server;
+}
 
-       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);
+static void a2dp_unregister_sep(struct a2dp_sep *sep)
+{
+       if (sep->destroy) {
+               sep->destroy(sep->user_data);
+               sep->endpoint = NULL;
        }
 
-       str = g_key_file_get_string(config, "A2DP", "MPEG12Sources", &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               mpeg12_srcs = atoi(str);
-               g_free(str);
-       }
+       avdtp_unregister_sep(sep->lsep);
+       g_free(sep);
+}
 
-       str = g_key_file_get_string(config, "A2DP", "SBCSinks", &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-               sbc_sinks = 1;
-       } else {
-               sbc_sinks = atoi(str);
-               g_free(str);
-       }
-
-       str = g_key_file_get_string(config, "A2DP", "MPEG12Sinks", &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else {
-               mpeg12_sinks = atoi(str);
-               g_free(str);
-       }
-
-proceed:
-       if (!connection)
-               connection = dbus_connection_ref(conn);
-
-       server = find_server(servers, src);
-       if (!server) {
-               int av_err;
-
-               server = g_new0(struct a2dp_server, 1);
-               if (!server)
-                       return -ENOMEM;
-
-               av_err = avdtp_init(src, config, &server->version);
-               if (av_err < 0) {
-                       g_free(server);
-                       return av_err;
-               }
-
-               bacpy(&server->src, src);
-               servers = g_slist_append(servers, server);
-       }
-
-       if (config)
-               delay_reporting = g_key_file_get_boolean(config, "A2DP",
-                                               "DelayReporting", NULL);
-
-       if (delay_reporting)
-               server->version = 0x0103;
-       else
-               server->version = 0x0102;
-
-       server->source_enabled = source;
-       if (source) {
-               for (i = 0; i < sbc_srcs; i++)
-                       a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
-                                       A2DP_CODEC_SBC, delay_reporting,
-                                       NULL, NULL, NULL, NULL);
-
-               for (i = 0; i < mpeg12_srcs; i++)
-                       a2dp_add_sep(src, AVDTP_SEP_TYPE_SOURCE,
-                                       A2DP_CODEC_MPEG12, delay_reporting,
-                                       NULL, NULL, NULL, NULL);
-       }
-       server->sink_enabled = sink;
-       if (sink) {
-               for (i = 0; i < sbc_sinks; i++)
-                       a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
-                                       A2DP_CODEC_SBC, delay_reporting,
-                                       NULL, NULL, NULL, NULL);
-
-               for (i = 0; i < mpeg12_sinks; i++)
-                       a2dp_add_sep(src, AVDTP_SEP_TYPE_SINK,
-                                       A2DP_CODEC_MPEG12, delay_reporting,
-                                       NULL, NULL, NULL, NULL);
-       }
-
-       return 0;
-}
-
-static void a2dp_unregister_sep(struct a2dp_sep *sep)
-{
-       if (sep->destroy) {
-               sep->destroy(sep->user_data);
-               sep->endpoint = NULL;
-       }
-
-       avdtp_unregister_sep(sep->lsep);
-       g_free(sep);
-}
-
-void a2dp_unregister(const bdaddr_t *src)
+static void a2dp_server_unregister(struct a2dp_server *server)
 {
-       struct a2dp_server *server;
-
-       server = find_server(servers, src);
-       if (!server)
-               return;
-
-       g_slist_free_full(server->sinks, (GDestroyNotify) a2dp_unregister_sep);
-       g_slist_free_full(server->sources,
-                                       (GDestroyNotify) a2dp_unregister_sep);
-
-       avdtp_exit(src);
+       avdtp_exit(server->adapter);
 
        servers = g_slist_remove(servers, server);
-
-       if (server->source_record_id)
-               remove_record_from_server(server->source_record_id);
-
-       if (server->sink_record_id)
-               remove_record_from_server(server->sink_record_id);
-
+       btd_adapter_unref(server->adapter);
        g_free(server);
-
-       if (servers)
-               return;
-
-       dbus_connection_unref(connection);
-       connection = NULL;
 }
 
-struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
+struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
                                uint8_t codec, gboolean delay_reporting,
                                struct a2dp_endpoint *endpoint,
                                void *user_data, GDestroyNotify destroy,
@@ -1638,9 +1235,8 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
        GSList **l;
        uint32_t *record_id;
        sdp_record_t *record;
-       struct avdtp_sep_ind *ind;
 
-       server = find_server(servers, src);
+       server = find_server(servers, adapter);
        if (server == NULL) {
                if (err)
                        *err = -EPROTONOSUPPORT;
@@ -1661,17 +1257,11 @@ struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
 
        sep = g_new0(struct a2dp_sep, 1);
 
-       if (endpoint) {
-               ind = &endpoint_ind;
-               goto proceed;
-       }
-
-       ind = (codec == A2DP_CODEC_MPEG12) ? &mpeg_ind : &sbc_ind;
-
-proceed:
-       sep->lsep = avdtp_register_sep(&server->src, type,
+       sep->lsep = avdtp_register_sep(adapter, type,
                                        AVDTP_MEDIA_TYPE_AUDIO, codec,
-                                       delay_reporting, ind, &cfm, sep);
+                                       delay_reporting, &endpoint_ind,
+                                       &cfm, sep);
+
        if (sep->lsep == NULL) {
                g_free(sep);
                if (err)
@@ -1698,7 +1288,7 @@ proceed:
        if (*record_id != 0)
                goto add;
 
-       record = a2dp_record(type, server->version);
+       record = a2dp_record(type);
        if (!record) {
                error("Unable to allocate new service record");
                avdtp_unregister_sep(sep->lsep);
@@ -1708,8 +1298,8 @@ proceed:
                return NULL;
        }
 
-       if (add_record_to_server(&server->src, record) < 0) {
-               error("Unable to register A2DP service record");\
+       if (adapter_service_add(server->adapter, record) < 0) {
+               error("Unable to register A2DP service record");
                sdp_record_free(record);
                avdtp_unregister_sep(sep->lsep);
                g_free(sep);
@@ -1736,7 +1326,8 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
                        return;
                server->sources = g_slist_remove(server->sources, sep);
                if (server->sources == NULL && server->source_record_id) {
-                       remove_record_from_server(server->source_record_id);
+                       adapter_service_remove(server->adapter,
+                                               server->source_record_id);
                        server->source_record_id = 0;
                }
        } else {
@@ -1744,7 +1335,8 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
                        return;
                server->sinks = g_slist_remove(server->sinks, sep);
                if (server->sinks == NULL && server->sink_record_id) {
-                       remove_record_from_server(server->sink_record_id);
+                       adapter_service_remove(server->adapter,
+                                               server->sink_record_id);
                        server->sink_record_id = 0;
                }
        }
@@ -1755,186 +1347,6 @@ void a2dp_remove_sep(struct a2dp_sep *sep)
        a2dp_unregister_sep(sep);
 }
 
-struct a2dp_sep *a2dp_get(struct avdtp *session,
-                               struct avdtp_remote_sep *rsep)
-{
-       GSList *l;
-       struct a2dp_server *server;
-       struct avdtp_service_capability *cap;
-       struct avdtp_media_codec_capability *codec_cap = NULL;
-       bdaddr_t src;
-
-       avdtp_get_peers(session, &src, NULL);
-       server = find_server(servers, &src);
-       if (!server)
-               return NULL;
-
-       cap = avdtp_get_codec(rsep);
-       codec_cap = (void *) cap->data;
-
-       if (avdtp_get_type(rsep) == AVDTP_SEP_TYPE_SINK)
-               l = server->sources;
-       else
-               l = server->sinks;
-
-       for (; l != NULL; l = l->next) {
-               struct a2dp_sep *sep = l->data;
-
-               if (sep->locked)
-                       continue;
-
-               if (sep->codec != codec_cap->media_codec_type)
-                       continue;
-
-               if (!sep->stream || avdtp_has_stream(session, sep->stream))
-                       return sep;
-       }
-
-       return NULL;
-}
-
-static uint8_t default_bitpool(uint8_t freq, uint8_t mode)
-{
-       switch (freq) {
-       case SBC_SAMPLING_FREQ_16000:
-       case SBC_SAMPLING_FREQ_32000:
-               return 53;
-       case SBC_SAMPLING_FREQ_44100:
-               switch (mode) {
-               case SBC_CHANNEL_MODE_MONO:
-               case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 31;
-               case SBC_CHANNEL_MODE_STEREO:
-               case SBC_CHANNEL_MODE_JOINT_STEREO:
-                       return 53;
-               default:
-                       error("Invalid channel mode %u", mode);
-                       return 53;
-               }
-       case SBC_SAMPLING_FREQ_48000:
-               switch (mode) {
-               case SBC_CHANNEL_MODE_MONO:
-               case SBC_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 29;
-               case SBC_CHANNEL_MODE_STEREO:
-               case SBC_CHANNEL_MODE_JOINT_STEREO:
-                       return 51;
-               default:
-                       error("Invalid channel mode %u", mode);
-                       return 51;
-               }
-       default:
-               error("Invalid sampling freq %u", freq);
-               return 53;
-       }
-}
-
-static gboolean select_sbc_params(struct sbc_codec_cap *cap,
-                                       struct sbc_codec_cap *supported)
-{
-       unsigned int max_bitpool, min_bitpool;
-
-       memset(cap, 0, sizeof(struct sbc_codec_cap));
-
-       cap->cap.media_type = AVDTP_MEDIA_TYPE_AUDIO;
-       cap->cap.media_codec_type = A2DP_CODEC_SBC;
-
-       if (supported->frequency & SBC_SAMPLING_FREQ_44100)
-               cap->frequency = SBC_SAMPLING_FREQ_44100;
-       else if (supported->frequency & SBC_SAMPLING_FREQ_48000)
-               cap->frequency = SBC_SAMPLING_FREQ_48000;
-       else if (supported->frequency & SBC_SAMPLING_FREQ_32000)
-               cap->frequency = SBC_SAMPLING_FREQ_32000;
-       else if (supported->frequency & SBC_SAMPLING_FREQ_16000)
-               cap->frequency = SBC_SAMPLING_FREQ_16000;
-       else {
-               error("No supported frequencies");
-               return FALSE;
-       }
-
-       if (supported->channel_mode & SBC_CHANNEL_MODE_JOINT_STEREO)
-               cap->channel_mode = SBC_CHANNEL_MODE_JOINT_STEREO;
-       else if (supported->channel_mode & SBC_CHANNEL_MODE_STEREO)
-               cap->channel_mode = SBC_CHANNEL_MODE_STEREO;
-       else if (supported->channel_mode & SBC_CHANNEL_MODE_DUAL_CHANNEL)
-               cap->channel_mode = SBC_CHANNEL_MODE_DUAL_CHANNEL;
-       else if (supported->channel_mode & SBC_CHANNEL_MODE_MONO)
-               cap->channel_mode = SBC_CHANNEL_MODE_MONO;
-       else {
-               error("No supported channel modes");
-               return FALSE;
-       }
-
-       if (supported->block_length & SBC_BLOCK_LENGTH_16)
-               cap->block_length = SBC_BLOCK_LENGTH_16;
-       else if (supported->block_length & SBC_BLOCK_LENGTH_12)
-               cap->block_length = SBC_BLOCK_LENGTH_12;
-       else if (supported->block_length & SBC_BLOCK_LENGTH_8)
-               cap->block_length = SBC_BLOCK_LENGTH_8;
-       else if (supported->block_length & SBC_BLOCK_LENGTH_4)
-               cap->block_length = SBC_BLOCK_LENGTH_4;
-       else {
-               error("No supported block lengths");
-               return FALSE;
-       }
-
-       if (supported->subbands & SBC_SUBBANDS_8)
-               cap->subbands = SBC_SUBBANDS_8;
-       else if (supported->subbands & SBC_SUBBANDS_4)
-               cap->subbands = SBC_SUBBANDS_4;
-       else {
-               error("No supported subbands");
-               return FALSE;
-       }
-
-       if (supported->allocation_method & SBC_ALLOCATION_LOUDNESS)
-               cap->allocation_method = SBC_ALLOCATION_LOUDNESS;
-       else if (supported->allocation_method & SBC_ALLOCATION_SNR)
-               cap->allocation_method = SBC_ALLOCATION_SNR;
-
-       min_bitpool = MAX(MIN_BITPOOL, supported->min_bitpool);
-       max_bitpool = MIN(default_bitpool(cap->frequency, cap->channel_mode),
-                                                       supported->max_bitpool);
-
-       cap->min_bitpool = min_bitpool;
-       cap->max_bitpool = max_bitpool;
-
-       return TRUE;
-}
-
-static gboolean select_capabilities(struct avdtp *session,
-                                       struct avdtp_remote_sep *rsep,
-                                       GSList **caps)
-{
-       struct avdtp_service_capability *media_transport, *media_codec;
-       struct sbc_codec_cap sbc_cap;
-
-       media_codec = avdtp_get_codec(rsep);
-       if (!media_codec)
-               return FALSE;
-
-       select_sbc_params(&sbc_cap, (struct sbc_codec_cap *) media_codec->data);
-
-       media_transport = avdtp_service_cap_new(AVDTP_MEDIA_TRANSPORT,
-                                               NULL, 0);
-
-       *caps = g_slist_append(*caps, media_transport);
-
-       media_codec = avdtp_service_cap_new(AVDTP_MEDIA_CODEC, &sbc_cap,
-                                               sizeof(sbc_cap));
-
-       *caps = g_slist_append(*caps, media_codec);
-
-       if (avdtp_get_delay_reporting(rsep)) {
-               struct avdtp_service_capability *delay_reporting;
-               delay_reporting = avdtp_service_cap_new(AVDTP_DELAY_REPORTING,
-                                                               NULL, 0);
-               *caps = g_slist_append(*caps, delay_reporting);
-       }
-
-       return TRUE;
-}
-
 static void select_cb(struct a2dp_setup *setup, void *ret, int size)
 {
        struct avdtp_service_capability *media_transport, *media_codec;
@@ -1965,13 +1377,44 @@ done:
        finalize_select(setup);
 }
 
-static gboolean auto_select(gpointer data)
+static gboolean check_vendor_codec(struct a2dp_sep *sep, uint8_t *cap,
+                                                               size_t len)
 {
-       struct a2dp_setup *setup = data;
+       uint8_t *capabilities;
+       size_t length;
+       a2dp_vendor_codec_t *local_codec;
+       a2dp_vendor_codec_t *remote_codec;
 
-       finalize_select(setup);
+       if (len < sizeof(a2dp_vendor_codec_t))
+               return FALSE;
 
-       return FALSE;
+       remote_codec = (a2dp_vendor_codec_t *) cap;
+
+       if (sep->endpoint == NULL)
+               return FALSE;
+
+       length = sep->endpoint->get_capabilities(sep,
+                               &capabilities, sep->user_data);
+
+       if (length < sizeof(a2dp_vendor_codec_t))
+               return FALSE;
+
+       local_codec = (a2dp_vendor_codec_t *) capabilities;
+
+       if (memcmp(remote_codec->vendor_id, local_codec->vendor_id,
+                                       sizeof(local_codec->vendor_id)))
+               return FALSE;
+
+       if (memcmp(remote_codec->codec_id, local_codec->codec_id,
+                                       sizeof(local_codec->codec_id)))
+               return FALSE;
+
+       DBG("vendor 0x%02x%02x%02x%02x codec 0x%02x%02x",
+                       remote_codec->vendor_id[0], remote_codec->vendor_id[1],
+                       remote_codec->vendor_id[2], remote_codec->vendor_id[3],
+                       remote_codec->codec_id[0], remote_codec->codec_id[1]);
+
+       return TRUE;
 }
 
 static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
@@ -1979,6 +1422,9 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
 {
        for (; list; list = list->next) {
                struct a2dp_sep *sep = list->data;
+               struct avdtp_remote_sep *rsep;
+               struct avdtp_media_codec_capability *cap;
+               struct avdtp_service_capability *service;
 
                /* Use sender's endpoint if available */
                if (sender) {
@@ -1992,10 +1438,19 @@ static struct a2dp_sep *a2dp_find_sep(struct avdtp *session, GSList *list,
                                continue;
                }
 
-               if (avdtp_find_remote_sep(session, sep->lsep) == NULL)
+               rsep = avdtp_find_remote_sep(session, sep->lsep);
+               if (rsep == NULL)
                        continue;
 
-               return sep;
+               service = avdtp_get_codec(rsep);
+               cap = (struct avdtp_media_codec_capability *) service->data;
+
+               if (cap->media_codec_type != A2DP_CODEC_VENDOR)
+                       return sep;
+
+               if (check_vendor_codec(sep, cap->data,
+                                       service->length - sizeof(*cap)))
+                       return sep;
        }
 
        return NULL;
@@ -2007,10 +1462,8 @@ static struct a2dp_sep *a2dp_select_sep(struct avdtp *session, uint8_t type,
        struct a2dp_server *server;
        struct a2dp_sep *sep;
        GSList *l;
-       bdaddr_t src;
 
-       avdtp_get_peers(session, &src, NULL);
-       server = find_server(servers, &src);
+       server = find_server(servers, avdtp_get_adapter(session));
        if (!server)
                return NULL;
 
@@ -2058,20 +1511,6 @@ unsigned int a2dp_select_capabilities(struct avdtp *session,
                goto fail;
        }
 
-       /* FIXME: Remove auto select when it is not longer possible to register
-       endpoint in the configuration file */
-       if (sep->endpoint == NULL) {
-               if (!select_capabilities(session, setup->rsep,
-                                       &setup->caps)) {
-                       error("Unable to auto select remote SEP capabilities");
-                       goto fail;
-               }
-
-               g_idle_add(auto_select, setup);
-
-               return cb_data->id;
-       }
-
        service = avdtp_get_codec(setup->rsep);
        codec = (struct avdtp_media_codec_capability *) service->data;
 
@@ -2100,10 +1539,8 @@ unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep,
        struct avdtp_service_capability *cap;
        struct avdtp_media_codec_capability *codec_cap = NULL;
        int posix_err;
-       bdaddr_t src;
 
-       avdtp_get_peers(session, &src, NULL);
-       server = find_server(servers, &src);
+       server = find_server(servers, avdtp_get_adapter(session));
        if (!server)
                return 0;
 
@@ -2156,7 +1593,7 @@ unsigned int a2dp_config(struct avdtp *session, struct a2dp_sep *sep,
                }
 
                if (l != NULL) {
-                       if (a2dp_sep_get_lock(tmp))
+                       if (tmp->locked)
                                goto failed;
                        setup->reconfigure = TRUE;
                        if (avdtp_close(session, tmp->stream, FALSE) < 0) {
@@ -2228,6 +1665,9 @@ unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep,
        case AVDTP_STATE_IDLE:
                goto failed;
                break;
+       case AVDTP_STATE_CONFIGURED:
+               setup->start = TRUE;
+               break;
        case AVDTP_STATE_OPEN:
                if (avdtp_start(session, sep->stream) < 0) {
                        error("avdtp_start failed");
@@ -2304,32 +1744,31 @@ failed:
        return 0;
 }
 
-gboolean a2dp_cancel(struct audio_device *dev, unsigned int id)
+gboolean a2dp_cancel(unsigned int id)
 {
-       struct a2dp_setup *setup;
-       GSList *l;
+       GSList *ls;
 
-       setup = find_setup_by_dev(dev);
-       if (!setup)
-               return FALSE;
+       for (ls = setups; ls != NULL; ls = g_slist_next(ls)) {
+               struct a2dp_setup *setup = ls->data;
+               GSList *l;
+               for (l = setup->cb; l != NULL; l = g_slist_next(l)) {
+                       struct a2dp_setup_cb *cb = l->data;
 
-       for (l = setup->cb; l != NULL; l = g_slist_next(l)) {
-               struct a2dp_setup_cb *cb = l->data;
+                       if (cb->id != id)
+                               continue;
 
-               if (cb->id != id)
-                       continue;
+                       setup_ref(setup);
+                       setup_cb_free(cb);
 
-               setup_ref(setup);
-               setup_cb_free(cb);
+                       if (!setup->cb) {
+                               DBG("aborting setup %p", setup);
+                               avdtp_abort(setup->session, setup->stream);
+                               return TRUE;
+                       }
 
-               if (!setup->cb) {
-                       DBG("aborting setup %p", setup);
-                       avdtp_abort(setup->session, setup->stream);
+                       setup_unref(setup);
                        return TRUE;
                }
-
-               setup_unref(setup);
-               return TRUE;
        }
 
        return FALSE;
@@ -2387,50 +1826,248 @@ gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session)
        return TRUE;
 }
 
-gboolean a2dp_sep_get_lock(struct a2dp_sep *sep)
+struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep)
+{
+       return sep->stream;
+}
+
+struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup)
 {
-       return sep->locked;
+       if (setup->session == NULL)
+               return NULL;
+
+       return avdtp_get_device(setup->session);
 }
 
-static int stream_cmp(gconstpointer data, gconstpointer user_data)
+static int a2dp_source_probe(struct btd_service *service)
 {
-       const struct a2dp_sep *sep = data;
-       const struct avdtp_stream *stream = user_data;
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("path %s", device_get_path(dev));
 
-       return (sep->stream != stream);
+       source_init(service);
+
+       return 0;
 }
 
-struct a2dp_sep *a2dp_get_sep(struct avdtp *session,
-                               struct avdtp_stream *stream)
+static void a2dp_source_remove(struct btd_service *service)
+{
+       source_unregister(service);
+}
+
+static int a2dp_sink_probe(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("path %s", device_get_path(dev));
+
+       return sink_init(service);
+}
+
+static void a2dp_sink_remove(struct btd_service *service)
+{
+       sink_unregister(service);
+}
+
+static int a2dp_source_connect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return source_connect(service);
+}
+
+static int a2dp_source_disconnect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return source_disconnect(service, FALSE);
+}
+
+static int a2dp_sink_connect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return sink_connect(service);
+}
+
+static int a2dp_sink_disconnect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return sink_disconnect(service, FALSE);
+}
+
+static int a2dp_source_server_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
 {
        struct a2dp_server *server;
-       bdaddr_t src, dst;
-       GSList *l;
 
-       avdtp_get_peers(session, &src, &dst);
+       DBG("path %s", adapter_get_path(adapter));
 
-       for (l = servers; l; l = l->next) {
-               server = l->data;
+       server = find_server(servers, adapter);
+       if (server != NULL)
+               goto done;
 
-               if (bacmp(&src, &server->src) == 0)
-                       break;
+       server = a2dp_server_register(adapter);
+       if (server == NULL)
+               return -EPROTONOSUPPORT;
+
+done:
+       server->source_enabled = TRUE;
+
+       return 0;
+}
+
+static void a2dp_source_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct a2dp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return;
+
+       g_slist_free_full(server->sources,
+                                       (GDestroyNotify) a2dp_unregister_sep);
+
+       if (server->source_record_id) {
+               adapter_service_remove(server->adapter,
+                                       server->source_record_id);
+               server->source_record_id = 0;
        }
 
-       if (!l)
-               return NULL;
+       if (server->sink_record_id)
+               return;
+
+       a2dp_server_unregister(server);
+}
 
-       l = g_slist_find_custom(server->sources, stream, stream_cmp);
-       if (l)
-               return l->data;
+static int a2dp_sink_server_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct a2dp_server *server;
 
-       l = g_slist_find_custom(server->sinks, stream, stream_cmp);
-       if (l)
-               return l->data;
+       DBG("path %s", adapter_get_path(adapter));
 
-       return NULL;
+       server = find_server(servers, adapter);
+       if (server != NULL)
+               goto done;
+
+       server = a2dp_server_register(adapter);
+       if (server == NULL)
+               return -EPROTONOSUPPORT;
+
+done:
+       server->sink_enabled = TRUE;
+
+       return 0;
 }
 
-struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep)
+static void a2dp_sink_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
 {
-       return sep->stream;
+       struct a2dp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return;
+
+       g_slist_free_full(server->sinks, (GDestroyNotify) a2dp_unregister_sep);
+
+       if (server->sink_record_id) {
+               adapter_service_remove(server->adapter, server->sink_record_id);
+               server->sink_record_id = 0;
+       }
+
+       if (server->source_record_id)
+               return;
+
+       a2dp_server_unregister(server);
+}
+
+static int media_server_probe(struct btd_adapter *adapter)
+{
+       DBG("path %s", adapter_get_path(adapter));
+
+       return media_register(adapter);
+}
+
+static void media_server_remove(struct btd_adapter *adapter)
+{
+       DBG("path %s", adapter_get_path(adapter));
+
+       media_unregister(adapter);
+}
+
+static struct btd_profile a2dp_source_profile = {
+       .name           = "a2dp-source",
+       .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
+
+       .remote_uuid    = A2DP_SOURCE_UUID,
+       .device_probe   = a2dp_source_probe,
+       .device_remove  = a2dp_source_remove,
+
+       .auto_connect   = true,
+       .connect        = a2dp_source_connect,
+       .disconnect     = a2dp_source_disconnect,
+
+       .adapter_probe  = a2dp_sink_server_probe,
+       .adapter_remove = a2dp_sink_server_remove,
+};
+
+static struct btd_profile a2dp_sink_profile = {
+       .name           = "a2dp-sink",
+       .priority       = BTD_PROFILE_PRIORITY_MEDIUM,
+
+       .remote_uuid    = A2DP_SINK_UUID,
+       .device_probe   = a2dp_sink_probe,
+       .device_remove  = a2dp_sink_remove,
+
+       .auto_connect   = true,
+       .connect        = a2dp_sink_connect,
+       .disconnect     = a2dp_sink_disconnect,
+
+       .adapter_probe  = a2dp_source_server_probe,
+       .adapter_remove = a2dp_source_server_remove,
+};
+
+static struct btd_adapter_driver media_driver = {
+       .name           = "media",
+       .probe          = media_server_probe,
+       .remove         = media_server_remove,
+};
+
+static int a2dp_init(void)
+{
+       btd_register_adapter_driver(&media_driver);
+       btd_profile_register(&a2dp_source_profile);
+       btd_profile_register(&a2dp_sink_profile);
+
+       return 0;
 }
+
+static void a2dp_exit(void)
+{
+       btd_unregister_adapter_driver(&media_driver);
+       btd_profile_unregister(&a2dp_source_profile);
+       btd_profile_unregister(&a2dp_sink_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(a2dp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                                       a2dp_init, a2dp_exit)
similarity index 52%
rename from audio/a2dp.h
rename to profiles/audio/a2dp.h
index 887c5ac..ef3be5c 100644 (file)
  *
  */
 
-#define A2DP_CODEC_SBC                 0x00
-#define A2DP_CODEC_MPEG12              0x01
-#define A2DP_CODEC_MPEG24              0x02
-#define A2DP_CODEC_ATRAC               0x03
-
-#define SBC_SAMPLING_FREQ_16000                (1 << 3)
-#define SBC_SAMPLING_FREQ_32000                (1 << 2)
-#define SBC_SAMPLING_FREQ_44100                (1 << 1)
-#define SBC_SAMPLING_FREQ_48000                1
-
-#define SBC_CHANNEL_MODE_MONO          (1 << 3)
-#define SBC_CHANNEL_MODE_DUAL_CHANNEL  (1 << 2)
-#define SBC_CHANNEL_MODE_STEREO                (1 << 1)
-#define SBC_CHANNEL_MODE_JOINT_STEREO  1
-
-#define SBC_BLOCK_LENGTH_4             (1 << 3)
-#define SBC_BLOCK_LENGTH_8             (1 << 2)
-#define SBC_BLOCK_LENGTH_12            (1 << 1)
-#define SBC_BLOCK_LENGTH_16            1
-
-#define SBC_SUBBANDS_4                 (1 << 1)
-#define SBC_SUBBANDS_8                 1
-
-#define SBC_ALLOCATION_SNR             (1 << 1)
-#define SBC_ALLOCATION_LOUDNESS                1
-
-#define MPEG_CHANNEL_MODE_MONO         (1 << 3)
-#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
-#define MPEG_CHANNEL_MODE_STEREO       (1 << 1)
-#define MPEG_CHANNEL_MODE_JOINT_STEREO 1
-
-#define MPEG_LAYER_MP1                 (1 << 2)
-#define MPEG_LAYER_MP2                 (1 << 1)
-#define MPEG_LAYER_MP3                 1
-
-#define MPEG_SAMPLING_FREQ_16000       (1 << 5)
-#define MPEG_SAMPLING_FREQ_22050       (1 << 4)
-#define MPEG_SAMPLING_FREQ_24000       (1 << 3)
-#define MPEG_SAMPLING_FREQ_32000       (1 << 2)
-#define MPEG_SAMPLING_FREQ_44100       (1 << 1)
-#define MPEG_SAMPLING_FREQ_48000       1
-
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-
-struct sbc_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t channel_mode:4;
-       uint8_t frequency:4;
-       uint8_t allocation_method:2;
-       uint8_t subbands:2;
-       uint8_t block_length:4;
-       uint8_t min_bitpool;
-       uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t channel_mode:4;
-       uint8_t crc:1;
-       uint8_t layer:3;
-       uint8_t frequency:6;
-       uint8_t mpf:1;
-       uint8_t rfa:1;
-       uint16_t bitrate;
-} __attribute__ ((packed));
-
-#elif __BYTE_ORDER == __BIG_ENDIAN
-
-struct sbc_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t frequency:4;
-       uint8_t channel_mode:4;
-       uint8_t block_length:4;
-       uint8_t subbands:2;
-       uint8_t allocation_method:2;
-       uint8_t min_bitpool;
-       uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t layer:3;
-       uint8_t crc:1;
-       uint8_t channel_mode:4;
-       uint8_t rfa:1;
-       uint8_t mpf:1;
-       uint8_t frequency:6;
-       uint16_t bitrate;
-} __attribute__ ((packed));
-
-#else
-#error "Unknown byte order"
-#endif
-
 struct a2dp_sep;
 struct a2dp_setup;
 
@@ -139,7 +42,6 @@ struct a2dp_endpoint {
                                                a2dp_endpoint_select_t cb,
                                                void *user_data);
        int (*set_configuration) (struct a2dp_sep *sep,
-                                               struct audio_device *dev,
                                                uint8_t *configuration,
                                                size_t length,
                                                struct a2dp_setup *setup,
@@ -161,18 +63,13 @@ typedef void (*a2dp_stream_cb_t) (struct avdtp *session,
                                        struct avdtp_error *err,
                                        void *user_data);
 
-int a2dp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
-void a2dp_unregister(const bdaddr_t *src);
-
-struct a2dp_sep *a2dp_add_sep(const bdaddr_t *src, uint8_t type,
+struct a2dp_sep *a2dp_add_sep(struct btd_adapter *adapter, uint8_t type,
                                uint8_t codec, gboolean delay_reporting,
                                struct a2dp_endpoint *endpoint,
                                void *user_data, GDestroyNotify destroy,
                                int *err);
 void a2dp_remove_sep(struct a2dp_sep *sep);
 
-struct a2dp_sep *a2dp_get(struct avdtp *session, struct avdtp_remote_sep *sep);
-
 unsigned int a2dp_select_capabilities(struct avdtp *session,
                                        uint8_t type, const char *sender,
                                        a2dp_select_cb_t cb,
@@ -184,11 +81,9 @@ unsigned int a2dp_resume(struct avdtp *session, struct a2dp_sep *sep,
                                a2dp_stream_cb_t cb, void *user_data);
 unsigned int a2dp_suspend(struct avdtp *session, struct a2dp_sep *sep,
                                a2dp_stream_cb_t cb, void *user_data);
-gboolean a2dp_cancel(struct audio_device *dev, unsigned int id);
+gboolean a2dp_cancel(unsigned int id);
 
 gboolean a2dp_sep_lock(struct a2dp_sep *sep, struct avdtp *session);
 gboolean a2dp_sep_unlock(struct a2dp_sep *sep, struct avdtp *session);
-gboolean a2dp_sep_get_lock(struct a2dp_sep *sep);
 struct avdtp_stream *a2dp_sep_get_stream(struct a2dp_sep *sep);
-struct a2dp_sep *a2dp_get_sep(struct avdtp *session,
-                               struct avdtp_stream *stream);
+struct btd_device *a2dp_setup_get_device(struct a2dp_setup *setup);
diff --git a/profiles/audio/avctp.c b/profiles/audio/avctp.c
new file mode 100644 (file)
index 0000000..dac7a66
--- /dev/null
@@ -0,0 +1,2023 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  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 <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <netinet/in.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/l2cap.h>
+
+#include <glib.h>
+#include <btio/btio.h>
+
+#include "lib/uuid.h"
+#include "src/adapter.h"
+#include "src/device.h"
+
+#include "log.h"
+#include "error.h"
+#include "uinput.h"
+#include "avctp.h"
+#include "avrcp.h"
+
+/* AV/C Panel 1.23, page 76:
+ * command with the pressed value is valid for two seconds
+ */
+#define AVC_PRESS_TIMEOUT      2
+
+#define QUIRK_NO_RELEASE 1 << 0
+
+/* Message types */
+#define AVCTP_COMMAND          0
+#define AVCTP_RESPONSE         1
+
+/* Packet types */
+#define AVCTP_PACKET_SINGLE    0
+#define AVCTP_PACKET_START     1
+#define AVCTP_PACKET_CONTINUE  2
+#define AVCTP_PACKET_END       3
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avctp_header {
+       uint8_t ipid:1;
+       uint8_t cr:1;
+       uint8_t packet_type:2;
+       uint8_t transaction:4;
+       uint16_t pid;
+} __attribute__ ((packed));
+#define AVCTP_HEADER_LENGTH 3
+
+struct avc_header {
+       uint8_t code:4;
+       uint8_t _hdr0:4;
+       uint8_t subunit_id:3;
+       uint8_t subunit_type:5;
+       uint8_t opcode;
+} __attribute__ ((packed));
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avctp_header {
+       uint8_t transaction:4;
+       uint8_t packet_type:2;
+       uint8_t cr:1;
+       uint8_t ipid:1;
+       uint16_t pid;
+} __attribute__ ((packed));
+#define AVCTP_HEADER_LENGTH 3
+
+struct avc_header {
+       uint8_t _hdr0:4;
+       uint8_t code:4;
+       uint8_t subunit_type:5;
+       uint8_t subunit_id:3;
+       uint8_t opcode;
+} __attribute__ ((packed));
+
+#else
+#error "Unknown byte order"
+#endif
+
+struct avctp_state_callback {
+       avctp_state_cb cb;
+       struct btd_device *dev;
+       unsigned int id;
+       void *user_data;
+};
+
+struct avctp_server {
+       struct btd_adapter *adapter;
+       GIOChannel *control_io;
+       GIOChannel *browsing_io;
+       GSList *sessions;
+};
+
+struct avctp_control_req {
+       struct avctp_pending_req *p;
+       uint8_t code;
+       uint8_t subunit;
+       uint8_t op;
+       uint8_t *operands;
+       uint16_t operand_count;
+       avctp_rsp_cb func;
+       void *user_data;
+};
+
+struct avctp_browsing_req {
+       struct avctp_pending_req *p;
+       uint8_t *operands;
+       uint16_t operand_count;
+       avctp_browsing_rsp_cb func;
+       void *user_data;
+};
+
+typedef int (*avctp_process_cb) (void *data);
+
+struct avctp_pending_req {
+       struct avctp_channel *chan;
+       uint8_t transaction;
+       guint timeout;
+       int err;
+       avctp_process_cb process;
+       void *data;
+       GDestroyNotify destroy;
+};
+
+struct avctp_channel {
+       struct avctp *session;
+       GIOChannel *io;
+       uint8_t transaction;
+       guint watch;
+       uint16_t imtu;
+       uint16_t omtu;
+       uint8_t *buffer;
+       GSList *handlers;
+       struct avctp_pending_req *p;
+       GQueue *queue;
+       GSList *processed;
+       guint process_id;
+       GDestroyNotify destroy;
+};
+
+struct key_pressed {
+       uint8_t op;
+       guint timer;
+};
+
+struct avctp {
+       struct avctp_server *server;
+       struct btd_device *device;
+
+       avctp_state_t state;
+
+       int uinput;
+
+       guint auth_id;
+       unsigned int passthrough_id;
+       unsigned int unit_id;
+       unsigned int subunit_id;
+
+       struct avctp_channel *control;
+       struct avctp_channel *browsing;
+
+       struct avctp_passthrough_handler *handler;
+
+       uint8_t key_quirks[256];
+       struct key_pressed key;
+       bool initiator;
+};
+
+struct avctp_passthrough_handler {
+       avctp_passthrough_cb cb;
+       void *user_data;
+       unsigned int id;
+};
+
+struct avctp_pdu_handler {
+       uint8_t opcode;
+       avctp_control_pdu_cb cb;
+       void *user_data;
+       unsigned int id;
+};
+
+struct avctp_browsing_pdu_handler {
+       avctp_browsing_pdu_cb cb;
+       void *user_data;
+       unsigned int id;
+       GDestroyNotify destroy;
+};
+
+static struct {
+       const char *name;
+       uint8_t avc;
+       uint16_t uinput;
+} key_map[] = {
+       { "SELECT",             AVC_SELECT,             KEY_SELECT },
+       { "UP",                 AVC_UP,                 KEY_UP },
+       { "DOWN",               AVC_DOWN,               KEY_DOWN },
+       { "LEFT",               AVC_LEFT,               KEY_LEFT },
+       { "RIGHT",              AVC_RIGHT,              KEY_RIGHT },
+       { "ROOT MENU",          AVC_ROOT_MENU,          KEY_MENU },
+       { "CONTENTS MENU",      AVC_CONTENTS_MENU,      KEY_PROGRAM },
+       { "FAVORITE MENU",      AVC_FAVORITE_MENU,      KEY_FAVORITES },
+       { "ENTER",              AVC_ENTER,              KEY_ENTER },
+       { "CHANNEL UP",         AVC_CHANNEL_UP,         KEY_CHANNELUP },
+       { "CHANNEL DOWN",       AVC_CHANNEL_DOWN,       KEY_CHANNELDOWN },
+       { "INPUT SELECT",       AVC_INPUT_SELECT,       KEY_CONFIG },
+       { "HELP",               AVC_HELP,               KEY_HELP },
+       { "POWER",              AVC_POWER,              KEY_POWER2 },
+       { "VOLUME UP",          AVC_VOLUME_UP,          KEY_VOLUMEUP },
+       { "VOLUME DOWN",        AVC_VOLUME_DOWN,        KEY_VOLUMEDOWN },
+       { "PLAY",               AVC_PLAY,               KEY_PLAYCD },
+       { "STOP",               AVC_STOP,               KEY_STOPCD },
+       { "PAUSE",              AVC_PAUSE,              KEY_PAUSECD },
+       { "FORWARD",            AVC_FORWARD,            KEY_NEXTSONG },
+       { "BACKWARD",           AVC_BACKWARD,           KEY_PREVIOUSSONG },
+       { "REWIND",             AVC_REWIND,             KEY_REWIND },
+       { "FAST FORWARD",       AVC_FAST_FORWARD,       KEY_FASTFORWARD },
+       { "F1",                 AVC_F1,                 KEY_F1 },
+       { "F2",                 AVC_F2,                 KEY_F2 },
+       { "F3",                 AVC_F3,                 KEY_F3 },
+       { "F4",                 AVC_F4,                 KEY_F4 },
+       { NULL }
+};
+
+static GSList *callbacks = NULL;
+static GSList *servers = NULL;
+
+static void auth_cb(DBusError *derr, void *user_data);
+static gboolean process_queue(gpointer user_data);
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+                                       uint8_t subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data);
+
+static int send_event(int fd, uint16_t type, uint16_t code, int32_t value)
+{
+       struct uinput_event event;
+
+       memset(&event, 0, sizeof(event));
+       event.type      = type;
+       event.code      = code;
+       event.value     = value;
+
+       return write(fd, &event, sizeof(event));
+}
+
+static void send_key(int fd, uint16_t key, int pressed)
+{
+       if (fd < 0)
+               return;
+
+       send_event(fd, EV_KEY, key, pressed);
+       send_event(fd, EV_SYN, SYN_REPORT, 0);
+}
+
+static gboolean auto_release(gpointer user_data)
+{
+       struct avctp *session = user_data;
+
+       session->key.timer = 0;
+
+       DBG("AV/C: key press timeout");
+
+       send_key(session->uinput, session->key.op, 0);
+
+       return FALSE;
+}
+
+static size_t handle_panel_passthrough(struct avctp *session,
+                                       uint8_t transaction, uint8_t *code,
+                                       uint8_t *subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       struct avctp_passthrough_handler *handler = session->handler;
+       const char *status;
+       int pressed, i;
+
+       if (*code != AVC_CTYPE_CONTROL || *subunit != AVC_SUBUNIT_PANEL) {
+               *code = AVC_CTYPE_REJECTED;
+               return 0;
+       }
+
+       if (operand_count == 0)
+               goto done;
+
+       if (operands[0] & 0x80) {
+               status = "released";
+               pressed = 0;
+       } else {
+               status = "pressed";
+               pressed = 1;
+       }
+
+       if (session->key.timer == 0 && handler != NULL) {
+               if (handler->cb(session, operands[0] & 0x7F,
+                                               pressed, handler->user_data))
+                       goto done;
+       }
+
+       for (i = 0; key_map[i].name != NULL; i++) {
+               uint8_t key_quirks;
+
+               if ((operands[0] & 0x7F) != key_map[i].avc)
+                       continue;
+
+               DBG("AV/C: %s %s", key_map[i].name, status);
+
+               key_quirks = session->key_quirks[key_map[i].avc];
+
+               if (key_quirks & QUIRK_NO_RELEASE) {
+                       if (!pressed) {
+                               DBG("AV/C: Ignoring release");
+                               break;
+                       }
+
+                       DBG("AV/C: treating key press as press + release");
+                       send_key(session->uinput, key_map[i].uinput, 1);
+                       send_key(session->uinput, key_map[i].uinput, 0);
+                       break;
+               }
+
+               if (pressed) {
+                       if (session->key.timer > 0) {
+                               g_source_remove(session->key.timer);
+                               send_key(session->uinput, session->key.op, 0);
+                       }
+
+                       session->key.op = key_map[i].uinput;
+                       session->key.timer = g_timeout_add_seconds(
+                                                       AVC_PRESS_TIMEOUT,
+                                                       auto_release,
+                                                       session);
+               } else if (session->key.timer > 0) {
+                       g_source_remove(session->key.timer);
+                       session->key.timer = 0;
+               }
+
+               send_key(session->uinput, key_map[i].uinput, pressed);
+               break;
+       }
+
+       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;
+       return operand_count;
+}
+
+static size_t handle_unit_info(struct avctp *session,
+                                       uint8_t transaction, uint8_t *code,
+                                       uint8_t *subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       if (*code != AVC_CTYPE_STATUS) {
+               *code = AVC_CTYPE_REJECTED;
+               return 0;
+       }
+
+       *code = AVC_CTYPE_STABLE;
+
+       /* The first operand should be 0x07 for the UNITINFO response.
+        * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+        * Interface Command Set (section 9.2.1, page 45) specs
+        * explain this value but both use it */
+       if (operand_count >= 1)
+               operands[0] = 0x07;
+       if (operand_count >= 2)
+               operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+       DBG("reply to AVC_OP_UNITINFO");
+
+       return operand_count;
+}
+
+static size_t handle_subunit_info(struct avctp *session,
+                                       uint8_t transaction, uint8_t *code,
+                                       uint8_t *subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       if (*code != AVC_CTYPE_STATUS) {
+               *code = AVC_CTYPE_REJECTED;
+               return 0;
+       }
+
+       *code = AVC_CTYPE_STABLE;
+
+       /* The first operand should be 0x07 for the UNITINFO response.
+        * Neither AVRCP (section 22.1, page 117) nor AVC Digital
+        * Interface Command Set (section 9.2.1, page 45) specs
+        * explain this value but both use it */
+       if (operand_count >= 2)
+               operands[1] = AVC_SUBUNIT_PANEL << 3;
+
+       DBG("reply to AVC_OP_SUBUNITINFO");
+
+       return operand_count;
+}
+
+static struct avctp_pdu_handler *find_handler(GSList *list, uint8_t opcode)
+{
+       for (; list; list = list->next) {
+               struct avctp_pdu_handler *handler = list->data;
+
+               if (handler->opcode == opcode)
+                       return handler;
+       }
+
+       return NULL;
+}
+
+static void pending_destroy(gpointer data, gpointer user_data)
+{
+       struct avctp_pending_req *req = data;
+
+       if (req->destroy)
+               req->destroy(req->data);
+
+       if (req->timeout > 0)
+               g_source_remove(req->timeout);
+
+       g_free(req);
+}
+
+static void avctp_channel_destroy(struct avctp_channel *chan)
+{
+       g_io_channel_shutdown(chan->io, TRUE, NULL);
+       g_io_channel_unref(chan->io);
+
+       if (chan->watch)
+               g_source_remove(chan->watch);
+
+       if (chan->p)
+               pending_destroy(chan->p, NULL);
+
+       if (chan->process_id > 0)
+               g_source_remove(chan->process_id);
+
+       if (chan->destroy)
+               chan->destroy(chan);
+
+       g_free(chan->buffer);
+       g_queue_foreach(chan->queue, pending_destroy, NULL);
+       g_queue_free(chan->queue);
+       g_slist_foreach(chan->processed, pending_destroy, NULL);
+       g_slist_free(chan->processed);
+       g_slist_free_full(chan->handlers, g_free);
+       g_free(chan);
+}
+
+static void avctp_disconnected(struct avctp *session)
+{
+       struct avctp_server *server;
+
+       if (!session)
+               return;
+
+       if (session->browsing)
+               avctp_channel_destroy(session->browsing);
+
+       if (session->control)
+               avctp_channel_destroy(session->control);
+
+       if (session->auth_id != 0) {
+               btd_cancel_authorization(session->auth_id);
+               session->auth_id = 0;
+       }
+
+       if (session->key.timer > 0)
+               g_source_remove(session->key.timer);
+
+       if (session->uinput >= 0) {
+               char address[18];
+
+               ba2str(device_get_address(session->device), address);
+               DBG("AVCTP: closing uinput for %s", address);
+
+               ioctl(session->uinput, UI_DEV_DESTROY);
+               close(session->uinput);
+               session->uinput = -1;
+       }
+
+       server = session->server;
+       server->sessions = g_slist_remove(server->sessions, session);
+       btd_device_unref(session->device);
+       g_free(session);
+}
+
+static void avctp_set_state(struct avctp *session, avctp_state_t new_state)
+{
+       GSList *l;
+       avctp_state_t old_state = session->state;
+
+       session->state = new_state;
+
+       for (l = callbacks; l != NULL; l = l->next) {
+               struct avctp_state_callback *cb = l->data;
+
+               if (cb->dev && cb->dev != session->device)
+                       continue;
+
+               cb->cb(session->device, old_state, new_state, cb->user_data);
+       }
+
+       switch (new_state) {
+       case AVCTP_STATE_DISCONNECTED:
+               DBG("AVCTP Disconnected");
+               avctp_disconnected(session);
+               break;
+       case AVCTP_STATE_CONNECTING:
+               DBG("AVCTP Connecting");
+               break;
+       case AVCTP_STATE_CONNECTED:
+               DBG("AVCTP Connected");
+               break;
+       case AVCTP_STATE_BROWSING_CONNECTING:
+               DBG("AVCTP Browsing Connecting");
+               break;
+       case AVCTP_STATE_BROWSING_CONNECTED:
+               DBG("AVCTP Browsing Connected");
+               break;
+       default:
+               error("Invalid AVCTP state %d", new_state);
+               return;
+       }
+}
+
+static int avctp_send(struct avctp_channel *control, uint8_t transaction,
+                               uint8_t cr, uint8_t code,
+                               uint8_t subunit, uint8_t opcode,
+                               uint8_t *operands, size_t operand_count)
+{
+       struct avctp_header *avctp;
+       struct avc_header *avc;
+       struct msghdr msg;
+       struct iovec iov[2];
+       int sk, err = 0;
+
+       iov[0].iov_base = control->buffer;
+       iov[0].iov_len  = sizeof(*avctp) + sizeof(*avc);
+       iov[1].iov_base = operands;
+       iov[1].iov_len  = operand_count;
+
+       if (control->omtu < (iov[0].iov_len + iov[1].iov_len))
+               return -EOVERFLOW;
+
+       sk = g_io_channel_unix_get_fd(control->io);
+
+       memset(control->buffer, 0, iov[0].iov_len);
+
+       avctp = (void *) control->buffer;
+       avc = (void *) avctp + sizeof(*avctp);
+
+       avctp->transaction = transaction;
+       avctp->packet_type = AVCTP_PACKET_SINGLE;
+       avctp->cr = cr;
+       avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
+
+       avc->code = code;
+       avc->subunit_type = subunit;
+       avc->opcode = opcode;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 2;
+
+       if (sendmsg(sk, &msg, 0) < 0)
+               err = -errno;
+
+       return err;
+}
+
+static int avctp_browsing_send(struct avctp_channel *browsing,
+                               uint8_t transaction, uint8_t cr,
+                               uint8_t *operands, size_t operand_count)
+{
+       struct avctp_header *avctp;
+       struct msghdr msg;
+       struct iovec iov[2];
+       int sk, err = 0;
+
+       iov[0].iov_base = browsing->buffer;
+       iov[0].iov_len  = sizeof(*avctp);
+       iov[1].iov_base = operands;
+       iov[1].iov_len  = operand_count;
+
+       if (browsing->omtu < (iov[0].iov_len + iov[1].iov_len))
+               return -EOVERFLOW;
+
+       sk = g_io_channel_unix_get_fd(browsing->io);
+
+       memset(browsing->buffer, 0, iov[0].iov_len);
+
+       avctp = (void *) browsing->buffer;
+
+       avctp->transaction = transaction;
+       avctp->packet_type = AVCTP_PACKET_SINGLE;
+       avctp->cr = cr;
+       avctp->pid = htons(AV_REMOTE_SVCLASS_ID);
+
+       memset(&msg, 0, sizeof(msg));
+       msg.msg_iov = iov;
+       msg.msg_iovlen = 2;
+
+       if (sendmsg(sk, &msg, 0) < 0)
+               err = -errno;
+
+       return err;
+}
+
+static void control_req_destroy(void *data)
+{
+       struct avctp_control_req *req = data;
+       struct avctp_pending_req *p = req->p;
+       struct avctp *session = p->chan->session;
+
+       if (p->err == 0 || req->func == NULL)
+               goto done;
+
+       req->func(session, AVC_CTYPE_REJECTED, req->subunit, NULL, 0,
+                                                       req->user_data);
+
+done:
+       g_free(req->operands);
+       g_free(req);
+}
+
+static void browsing_req_destroy(void *data)
+{
+       struct avctp_browsing_req *req = data;
+       struct avctp_pending_req *p = req->p;
+       struct avctp *session = p->chan->session;
+
+       if (p->err == 0 || req->func == NULL)
+               goto done;
+
+       req->func(session, NULL, 0, req->user_data);
+
+done:
+       g_free(req->operands);
+       g_free(req);
+}
+
+static gboolean req_timeout(gpointer user_data)
+{
+       struct avctp_channel *chan = user_data;
+       struct avctp_pending_req *p = chan->p;
+
+       DBG("transaction %u", p->transaction);
+
+       p->timeout = 0;
+       p->err = -ETIMEDOUT;
+
+       pending_destroy(p, NULL);
+       chan->p = NULL;
+
+       if (chan->process_id == 0)
+               chan->process_id = g_idle_add(process_queue, chan);
+
+       return FALSE;
+}
+
+static int process_control(void *data)
+{
+       struct avctp_control_req *req = data;
+       struct avctp_pending_req *p = req->p;
+
+       return avctp_send(p->chan, p->transaction, AVCTP_COMMAND, req->code,
+                                       req->subunit, req->op,
+                                       req->operands, req->operand_count);
+}
+
+static int process_browsing(void *data)
+{
+       struct avctp_browsing_req *req = data;
+       struct avctp_pending_req *p = req->p;
+
+       return avctp_browsing_send(p->chan, p->transaction, AVCTP_COMMAND,
+                                       req->operands, req->operand_count);
+}
+
+static gboolean process_queue(void *user_data)
+{
+       struct avctp_channel *chan = user_data;
+       struct avctp_pending_req *p = chan->p;
+
+       chan->process_id = 0;
+
+       if (p != NULL)
+               return FALSE;
+
+       while ((p = g_queue_pop_head(chan->queue))) {
+
+               if (p->process(p->data) == 0)
+                       break;
+
+               pending_destroy(p, NULL);
+       }
+
+       if (p == NULL)
+               return FALSE;
+
+       chan->p = p;
+       p->timeout = g_timeout_add_seconds(2, req_timeout, chan);
+
+       return FALSE;
+
+}
+
+static void control_response(struct avctp_channel *control,
+                                       struct avctp_header *avctp,
+                                       struct avc_header *avc,
+                                       uint8_t *operands,
+                                       size_t operand_count)
+{
+       struct avctp_pending_req *p = control->p;
+       struct avctp_control_req *req;
+       GSList *l;
+
+       if (p && p->transaction == avctp->transaction) {
+               control->processed = g_slist_prepend(control->processed, p);
+
+               if (p->timeout > 0) {
+                       g_source_remove(p->timeout);
+                       p->timeout = 0;
+               }
+
+               control->p = NULL;
+
+               if (control->process_id == 0)
+                       control->process_id = g_idle_add(process_queue,
+                                                               control);
+       }
+
+       for (l = control->processed; l; l = l->next) {
+               p = l->data;
+               req = p->data;
+
+               if (p->transaction != avctp->transaction)
+                       continue;
+
+               if (req->func && req->func(control->session, avc->code,
+                                               avc->subunit_type,
+                                               operands, operand_count,
+                                               req->user_data))
+                       return;
+
+               control->processed = g_slist_remove(control->processed, p);
+               pending_destroy(p, NULL);
+
+               return;
+       }
+}
+
+static void browsing_response(struct avctp_channel *browsing,
+                                       struct avctp_header *avctp,
+                                       uint8_t *operands,
+                                       size_t operand_count)
+{
+       struct avctp_pending_req *p = browsing->p;
+       struct avctp_browsing_req *req;
+       GSList *l;
+
+       if (p && p->transaction == avctp->transaction) {
+               browsing->processed = g_slist_prepend(browsing->processed, p);
+
+               if (p->timeout > 0) {
+                       g_source_remove(p->timeout);
+                       p->timeout = 0;
+               }
+
+               browsing->p = NULL;
+
+               if (browsing->process_id == 0)
+                       browsing->process_id = g_idle_add(process_queue,
+                                                               browsing);
+       }
+
+       for (l = browsing->processed; l; l = l->next) {
+               p = l->data;
+               req = p->data;
+
+               if (p->transaction != avctp->transaction)
+                       continue;
+
+               if (req->func && req->func(browsing->session, operands,
+                                               operand_count, req->user_data))
+                       return;
+
+               browsing->processed = g_slist_remove(browsing->processed, p);
+               pending_destroy(p, NULL);
+
+               return;
+       }
+}
+
+static gboolean session_browsing_cb(GIOChannel *chan, GIOCondition cond,
+                               gpointer data)
+{
+       struct avctp *session = data;
+       struct avctp_channel *browsing = session->browsing;
+       uint8_t *buf = browsing->buffer;
+       uint8_t *operands;
+       struct avctp_header *avctp;
+       int sock, ret, packet_size, operand_count;
+       struct avctp_browsing_pdu_handler *handler;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+               goto failed;
+
+       sock = g_io_channel_unix_get_fd(chan);
+
+       ret = read(sock, buf, browsing->imtu);
+       if (ret <= 0)
+               goto failed;
+
+       avctp = (struct avctp_header *) buf;
+
+       if (avctp->packet_type != AVCTP_PACKET_SINGLE)
+               goto failed;
+
+       operands = buf + AVCTP_HEADER_LENGTH;
+       ret -= AVCTP_HEADER_LENGTH;
+       operand_count = ret;
+
+       if (avctp->cr == AVCTP_RESPONSE) {
+               browsing_response(browsing, avctp, operands, operand_count);
+               return TRUE;
+       }
+
+       packet_size = AVCTP_HEADER_LENGTH;
+       avctp->cr = AVCTP_RESPONSE;
+
+       handler = g_slist_nth_data(browsing->handlers, 0);
+       if (handler == NULL) {
+               DBG("handler not found");
+               packet_size += avrcp_browsing_general_reject(operands);
+               goto send;
+       }
+
+       packet_size += handler->cb(session, avctp->transaction,
+                                               operands, operand_count,
+                                               handler->user_data);
+
+send:
+       if (packet_size != 0) {
+               ret = write(sock, buf, packet_size);
+               if (ret != packet_size)
+                       goto failed;
+       }
+
+       return TRUE;
+
+failed:
+       DBG("AVCTP Browsing: disconnected");
+       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+
+       if (session->browsing) {
+               avctp_channel_destroy(session->browsing);
+               session->browsing = NULL;
+       }
+
+       return FALSE;
+}
+
+static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
+                               gpointer data)
+{
+       struct avctp *session = data;
+       struct avctp_channel *control = session->control;
+       uint8_t *buf = control->buffer;
+       uint8_t *operands, code, subunit;
+       struct avctp_header *avctp;
+       struct avc_header *avc;
+       int ret, packet_size, operand_count, sock;
+       struct avctp_pdu_handler *handler;
+
+       if (cond & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+               goto failed;
+
+       sock = g_io_channel_unix_get_fd(chan);
+
+       ret = read(sock, buf, control->imtu);
+       if (ret <= 0)
+               goto failed;
+
+       if ((unsigned int) ret < sizeof(struct avctp_header)) {
+               error("Too small AVCTP packet");
+               goto failed;
+       }
+
+       avctp = (struct avctp_header *) buf;
+
+       ret -= sizeof(struct avctp_header);
+       if ((unsigned int) ret < sizeof(struct avc_header)) {
+               error("Too small AVCTP packet");
+               goto failed;
+       }
+
+       avc = (struct avc_header *) (buf + sizeof(struct avctp_header));
+
+       ret -= sizeof(struct avc_header);
+
+       operands = buf + sizeof(struct avctp_header) + sizeof(struct avc_header);
+       operand_count = ret;
+
+       if (avctp->cr == AVCTP_RESPONSE) {
+               control_response(control, avctp, avc, operands, operand_count);
+               return TRUE;
+       }
+
+       packet_size = AVCTP_HEADER_LENGTH + AVC_HEADER_LENGTH;
+       avctp->cr = AVCTP_RESPONSE;
+
+       if (avctp->packet_type != AVCTP_PACKET_SINGLE) {
+               avc->code = AVC_CTYPE_NOT_IMPLEMENTED;
+               goto done;
+       }
+
+       if (avctp->pid != htons(AV_REMOTE_SVCLASS_ID)) {
+               avctp->ipid = 1;
+               packet_size = AVCTP_HEADER_LENGTH;
+               goto done;
+       }
+
+       handler = find_handler(control->handlers, avc->opcode);
+       if (!handler) {
+               DBG("handler not found for 0x%02x", avc->opcode);
+               packet_size += avrcp_handle_vendor_reject(&code, operands);
+               avc->code = code;
+               goto done;
+       }
+
+       code = avc->code;
+       subunit = avc->subunit_type;
+
+       packet_size += handler->cb(session, avctp->transaction, &code,
+                                       &subunit, operands, operand_count,
+                                       handler->user_data);
+
+       avc->code = code;
+       avc->subunit_type = subunit;
+
+done:
+       ret = write(sock, buf, packet_size);
+       if (ret != packet_size)
+               goto failed;
+
+       return TRUE;
+
+failed:
+       DBG("AVCTP session %p got disconnected", session);
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+       return FALSE;
+}
+
+static int uinput_create(char *name)
+{
+       struct uinput_dev dev;
+       int fd, err, i;
+
+       fd = open("/dev/uinput", O_RDWR);
+       if (fd < 0) {
+               fd = open("/dev/input/uinput", O_RDWR);
+               if (fd < 0) {
+                       fd = open("/dev/misc/uinput", O_RDWR);
+                       if (fd < 0) {
+                               err = -errno;
+                               error("Can't open input device: %s (%d)",
+                                                       strerror(-err), -err);
+                               return err;
+                       }
+               }
+       }
+
+       memset(&dev, 0, sizeof(dev));
+       if (name)
+               strncpy(dev.name, name, UINPUT_MAX_NAME_SIZE - 1);
+
+       dev.id.bustype = BUS_BLUETOOTH;
+       dev.id.vendor  = 0x0000;
+       dev.id.product = 0x0000;
+       dev.id.version = 0x0000;
+
+       if (write(fd, &dev, sizeof(dev)) < 0) {
+               err = -errno;
+               error("Can't write device information: %s (%d)",
+                                               strerror(-err), -err);
+               close(fd);
+               return err;
+       }
+
+       ioctl(fd, UI_SET_EVBIT, EV_KEY);
+       ioctl(fd, UI_SET_EVBIT, EV_REL);
+       ioctl(fd, UI_SET_EVBIT, EV_REP);
+       ioctl(fd, UI_SET_EVBIT, EV_SYN);
+
+       for (i = 0; key_map[i].name != NULL; i++)
+               ioctl(fd, UI_SET_KEYBIT, key_map[i].uinput);
+
+       if (ioctl(fd, UI_DEV_CREATE, NULL) < 0) {
+               err = -errno;
+               error("Can't create uinput device: %s (%d)",
+                                               strerror(-err), -err);
+               close(fd);
+               return err;
+       }
+
+       return fd;
+}
+
+static void init_uinput(struct avctp *session)
+{
+       char address[18], name[248 + 1];
+
+       device_get_name(session->device, name, sizeof(name));
+       if (g_str_equal(name, "Nokia CK-20W")) {
+               session->key_quirks[AVC_FORWARD] |= QUIRK_NO_RELEASE;
+               session->key_quirks[AVC_BACKWARD] |= QUIRK_NO_RELEASE;
+               session->key_quirks[AVC_PLAY] |= QUIRK_NO_RELEASE;
+               session->key_quirks[AVC_PAUSE] |= QUIRK_NO_RELEASE;
+       }
+
+       ba2str(device_get_address(session->device), address);
+       session->uinput = uinput_create(address);
+       if (session->uinput < 0)
+               error("AVRCP: failed to init uinput for %s", address);
+       else
+               DBG("AVRCP: uinput initialized for %s", address);
+}
+
+static struct avctp_channel *avctp_channel_create(struct avctp *session,
+                                                       GIOChannel *io,
+                                                       GDestroyNotify destroy)
+{
+       struct avctp_channel *chan;
+
+       chan = g_new0(struct avctp_channel, 1);
+       chan->session = session;
+       chan->io = g_io_channel_ref(io);
+       chan->queue = g_queue_new();
+       chan->destroy = destroy;
+
+       return chan;
+}
+
+static void handler_free(void *data)
+{
+       struct avctp_browsing_pdu_handler *handler = data;
+
+       if (handler->destroy)
+               handler->destroy(handler->user_data);
+
+       g_free(data);
+}
+
+static void avctp_destroy_browsing(void *data)
+{
+       struct avctp_channel *chan = data;
+
+       g_slist_free_full(chan->handlers, handler_free);
+
+       chan->handlers = NULL;
+}
+
+static void avctp_connect_browsing_cb(GIOChannel *chan, GError *err,
+                                                       gpointer data)
+{
+       struct avctp *session = data;
+       struct avctp_channel *browsing = session->browsing;
+       char address[18];
+       uint16_t imtu, omtu;
+       GError *gerr = NULL;
+
+       if (err) {
+               error("Browsing: %s", err->message);
+               goto fail;
+       }
+
+       bt_io_get(chan, &gerr,
+                       BT_IO_OPT_DEST, &address,
+                       BT_IO_OPT_IMTU, &imtu,
+                       BT_IO_OPT_OMTU, &omtu,
+                       BT_IO_OPT_INVALID);
+       if (gerr) {
+               error("%s", gerr->message);
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               g_io_channel_unref(chan);
+               g_error_free(gerr);
+               goto fail;
+       }
+
+       DBG("AVCTP Browsing: connected to %s", address);
+
+       if (browsing == NULL) {
+               browsing = avctp_channel_create(session, chan,
+                                               avctp_destroy_browsing);
+               session->browsing = browsing;
+       }
+
+       browsing->imtu = imtu;
+       browsing->omtu = omtu;
+       browsing->buffer = g_malloc0(MAX(imtu, omtu));
+       browsing->watch = g_io_add_watch(session->browsing->io,
+                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                               (GIOFunc) session_browsing_cb, session);
+
+       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTED);
+
+       /* Process any request that was pending the connection to complete */
+       if (browsing->process_id == 0 && !g_queue_is_empty(browsing->queue))
+               browsing->process_id = g_idle_add(process_queue, browsing);
+
+       return;
+
+fail:
+       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+
+       if (session->browsing) {
+               avctp_channel_destroy(session->browsing);
+               session->browsing = NULL;
+       }
+}
+
+static void avctp_connect_cb(GIOChannel *chan, GError *err, gpointer data)
+{
+       struct avctp *session = data;
+       char address[18];
+       uint16_t imtu, omtu;
+       GError *gerr = NULL;
+
+       if (err) {
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               error("%s", err->message);
+               return;
+       }
+
+       bt_io_get(chan, &gerr,
+                       BT_IO_OPT_DEST, &address,
+                       BT_IO_OPT_IMTU, &imtu,
+                       BT_IO_OPT_IMTU, &omtu,
+                       BT_IO_OPT_INVALID);
+       if (gerr) {
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               error("%s", gerr->message);
+               g_error_free(gerr);
+               return;
+       }
+
+       DBG("AVCTP: connected to %s", address);
+
+       if (session->control == NULL)
+               session->control = avctp_channel_create(session, chan, NULL);
+
+       session->control->imtu = imtu;
+       session->control->omtu = omtu;
+       session->control->buffer = g_malloc0(MAX(imtu, omtu));
+       session->control->watch = g_io_add_watch(session->control->io,
+                               G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
+                               (GIOFunc) session_cb, session);
+
+       session->passthrough_id = avctp_register_pdu_handler(session,
+                                               AVC_OP_PASSTHROUGH,
+                                               handle_panel_passthrough,
+                                               NULL);
+       session->unit_id = avctp_register_pdu_handler(session,
+                                               AVC_OP_UNITINFO,
+                                               handle_unit_info,
+                                               NULL);
+       session->subunit_id = avctp_register_pdu_handler(session,
+                                               AVC_OP_SUBUNITINFO,
+                                               handle_subunit_info,
+                                               NULL);
+
+       init_uinput(session);
+
+       avctp_set_state(session, AVCTP_STATE_CONNECTED);
+}
+
+static void auth_cb(DBusError *derr, void *user_data)
+{
+       struct avctp *session = user_data;
+       GError *err = NULL;
+
+       session->auth_id = 0;
+
+       if (session->control->watch > 0) {
+               g_source_remove(session->control->watch);
+               session->control->watch = 0;
+       }
+
+       if (derr && dbus_error_is_set(derr)) {
+               error("Access denied: %s", derr->message);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               return;
+       }
+
+       if (!bt_io_accept(session->control->io, avctp_connect_cb, session,
+                                                               NULL, &err)) {
+               error("bt_io_accept: %s", err->message);
+               g_error_free(err);
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+       }
+}
+
+static struct avctp_server *find_server(GSList *list, struct btd_adapter *a)
+{
+       for (; list; list = list->next) {
+               struct avctp_server *server = list->data;
+
+               if (server->adapter == a)
+                       return server;
+       }
+
+       return NULL;
+}
+
+static struct avctp *find_session(GSList *list, struct btd_device *device)
+{
+       for (; list != NULL; list = g_slist_next(list)) {
+               struct avctp *s = list->data;
+
+               if (s->device == device)
+                       return s;
+       }
+
+       return NULL;
+}
+
+static struct avctp *avctp_get_internal(struct btd_device *device)
+{
+       struct avctp_server *server;
+       struct avctp *session;
+
+       server = find_server(servers, device_get_adapter(device));
+       if (server == NULL)
+               return NULL;
+
+       session = find_session(server->sessions, device);
+       if (session)
+               return session;
+
+       session = g_new0(struct avctp, 1);
+
+       session->server = server;
+       session->device = btd_device_ref(device);
+       session->state = AVCTP_STATE_DISCONNECTED;
+       session->uinput = -1;
+
+       server->sessions = g_slist_append(server->sessions, session);
+
+       return session;
+}
+
+static void avctp_control_confirm(struct avctp *session, GIOChannel *chan,
+                                               struct btd_device *dev)
+{
+       const bdaddr_t *src;
+       const bdaddr_t *dst;
+
+       if (session->control != NULL) {
+               error("Control: Refusing unexpected connect");
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               return;
+       }
+
+       avctp_set_state(session, AVCTP_STATE_CONNECTING);
+       session->control = avctp_channel_create(session, chan, NULL);
+
+       src = adapter_get_address(device_get_adapter(dev));
+       dst = device_get_address(dev);
+
+       session->auth_id = btd_request_authorization(src, dst,
+                                                       AVRCP_TARGET_UUID,
+                                                       auth_cb, session);
+       if (session->auth_id == 0)
+               goto drop;
+
+       session->control->watch = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP |
+                                               G_IO_NVAL, session_cb, session);
+       return;
+
+drop:
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+}
+
+static void avctp_browsing_confirm(struct avctp *session, GIOChannel *chan,
+                                               struct btd_device *dev)
+{
+       GError *err = NULL;
+
+       if (session->control == NULL || session->browsing != NULL) {
+               error("Browsing: Refusing unexpected connect");
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               return;
+       }
+
+       if (bt_io_accept(chan, avctp_connect_browsing_cb, session, NULL,
+                                                               &err)) {
+               avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
+               return;
+       }
+
+       error("Browsing: %s", err->message);
+       g_error_free(err);
+
+       return;
+}
+
+static void avctp_confirm_cb(GIOChannel *chan, gpointer data)
+{
+       struct avctp *session;
+       char address[18];
+       bdaddr_t src, dst;
+       GError *err = NULL;
+       uint16_t psm;
+       struct btd_device *device;
+
+       bt_io_get(chan, &err,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_DEST, address,
+                       BT_IO_OPT_PSM, &psm,
+                       BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               return;
+       }
+
+       DBG("AVCTP: incoming connect from %s", address);
+
+       device = adapter_find_device(adapter_find(&src), &dst);
+       if (!device)
+               return;
+
+       session = avctp_get_internal(device);
+       if (session == NULL)
+               return;
+
+       if (btd_device_get_service(device, AVRCP_REMOTE_UUID) == NULL)
+               btd_device_add_uuid(device, AVRCP_REMOTE_UUID);
+
+       if (btd_device_get_service(device, AVRCP_TARGET_UUID) == NULL)
+               btd_device_add_uuid(device, AVRCP_TARGET_UUID);
+
+       switch (psm) {
+       case AVCTP_CONTROL_PSM:
+               avctp_control_confirm(session, chan, device);
+               break;
+       case AVCTP_BROWSING_PSM:
+               avctp_browsing_confirm(session, chan, device);
+               break;
+       }
+
+       return;
+}
+
+static GIOChannel *avctp_server_socket(const bdaddr_t *src, gboolean master,
+                                               uint8_t mode, uint16_t psm)
+{
+       GError *err = NULL;
+       GIOChannel *io;
+
+       io = bt_io_listen(NULL, avctp_confirm_cb, NULL,
+                               NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_PSM, psm,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_MASTER, master,
+                               BT_IO_OPT_MODE, mode,
+                               BT_IO_OPT_INVALID);
+       if (!io) {
+               error("%s", err->message);
+               g_error_free(err);
+       }
+
+       return io;
+}
+
+int avctp_register(struct btd_adapter *adapter, gboolean master)
+{
+       struct avctp_server *server;
+       const bdaddr_t *src = adapter_get_address(adapter);
+
+       server = g_new0(struct avctp_server, 1);
+
+       server->control_io = avctp_server_socket(src, master, L2CAP_MODE_BASIC,
+                                                       AVCTP_CONTROL_PSM);
+       if (!server->control_io) {
+               g_free(server);
+               return -1;
+       }
+       server->browsing_io = avctp_server_socket(src, master, L2CAP_MODE_ERTM,
+                                                       AVCTP_BROWSING_PSM);
+       if (!server->browsing_io) {
+               if (server->control_io) {
+                       g_io_channel_shutdown(server->control_io, TRUE, NULL);
+                       g_io_channel_unref(server->control_io);
+                       server->control_io = NULL;
+               }
+               g_free(server);
+               return -1;
+       }
+
+       server->adapter = btd_adapter_ref(adapter);
+
+       servers = g_slist_append(servers, server);
+
+       return 0;
+}
+
+void avctp_unregister(struct btd_adapter *adapter)
+{
+       struct avctp_server *server;
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return;
+
+       while (server->sessions)
+               avctp_disconnected(server->sessions->data);
+
+       servers = g_slist_remove(servers, server);
+
+       g_io_channel_shutdown(server->browsing_io, TRUE, NULL);
+       g_io_channel_unref(server->browsing_io);
+       server->browsing_io = NULL;
+
+       g_io_channel_shutdown(server->control_io, TRUE, NULL);
+       g_io_channel_unref(server->control_io);
+       btd_adapter_unref(server->adapter);
+       g_free(server);
+}
+
+static struct avctp_pending_req *pending_create(struct avctp_channel *chan,
+                                               avctp_process_cb process,
+                                               void *data,
+                                               GDestroyNotify destroy)
+{
+       struct avctp_pending_req *p;
+       GSList *l, *tmp;
+
+       if (!chan->processed)
+               goto done;
+
+       tmp = g_slist_copy(chan->processed);
+
+       /* Find first unused transaction id */
+       for (l = tmp; l; l = l->next) {
+               struct avctp_pending_req *req = l->data;
+
+               if (req->transaction == chan->transaction) {
+                       chan->transaction++;
+                       chan->transaction %= 16;
+                       tmp = g_slist_delete_link(tmp, l);
+                       l = tmp;
+               }
+       }
+
+       g_slist_free(tmp);
+
+done:
+       p = g_new0(struct avctp_pending_req, 1);
+       p->chan = chan;
+       p->transaction = chan->transaction;
+       p->process = process;
+       p->data = data;
+       p->destroy = destroy;
+
+       chan->transaction++;
+       chan->transaction %= 16;
+
+       return p;
+}
+
+static int avctp_send_req(struct avctp *session, uint8_t code,
+                               uint8_t subunit, uint8_t opcode,
+                               uint8_t *operands, size_t operand_count,
+                               avctp_rsp_cb func, void *user_data)
+{
+       struct avctp_channel *control = session->control;
+       struct avctp_pending_req *p;
+       struct avctp_control_req *req;
+
+       if (control == NULL)
+               return -ENOTCONN;
+
+       req = g_new0(struct avctp_control_req, 1);
+       req->code = code;
+       req->subunit = subunit;
+       req->op = opcode;
+       req->func = func;
+       req->operands = g_memdup(operands, operand_count);
+       req->operand_count = operand_count;
+       req->user_data = user_data;
+
+       p = pending_create(control, process_control, req, control_req_destroy);
+
+       req->p = p;
+
+       g_queue_push_tail(control->queue, p);
+
+       if (control->process_id == 0)
+               control->process_id = g_idle_add(process_queue, control);
+
+       return 0;
+}
+
+int avctp_send_browsing_req(struct avctp *session,
+                               uint8_t *operands, size_t operand_count,
+                               avctp_browsing_rsp_cb func, void *user_data)
+{
+       struct avctp_channel *browsing = session->browsing;
+       struct avctp_pending_req *p;
+       struct avctp_browsing_req *req;
+
+       if (browsing == NULL)
+               return -ENOTCONN;
+
+       req = g_new0(struct avctp_browsing_req, 1);
+       req->func = func;
+       req->operands = g_memdup(operands, operand_count);
+       req->operand_count = operand_count;
+       req->user_data = user_data;
+
+       p = pending_create(browsing, process_browsing, req,
+                       browsing_req_destroy);
+
+       req->p = p;
+
+       g_queue_push_tail(browsing->queue, p);
+
+       /* Connection did not complete, delay process of the request */
+       if (browsing->watch == 0)
+               return 0;
+
+       if (browsing->process_id == 0)
+               browsing->process_id = g_idle_add(process_queue, browsing);
+
+       return 0;
+}
+
+static char *op2str(uint8_t op)
+{
+       switch (op & 0x7f) {
+       case AVC_VOLUME_UP:
+               return "VOLUME UP";
+       case AVC_VOLUME_DOWN:
+               return "VOLUME DOWN";
+       case AVC_MUTE:
+               return "MUTE";
+       case AVC_PLAY:
+               return "PLAY";
+       case AVC_STOP:
+               return "STOP";
+       case AVC_PAUSE:
+               return "PAUSE";
+       case AVC_RECORD:
+               return "RECORD";
+       case AVC_REWIND:
+               return "REWIND";
+       case AVC_FAST_FORWARD:
+               return "FAST FORWARD";
+       case AVC_EJECT:
+               return "EJECT";
+       case AVC_FORWARD:
+               return "FORWARD";
+       case AVC_BACKWARD:
+               return "BACKWARD";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static int avctp_passthrough_press(struct avctp *session, uint8_t op)
+{
+       uint8_t operands[2];
+
+       DBG("%s", op2str(op));
+
+       /* Button pressed */
+       operands[0] = op & 0x7f;
+       operands[1] = 0;
+
+       return avctp_send_req(session, AVC_CTYPE_CONTROL,
+                               AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+                               operands, sizeof(operands),
+                               avctp_passthrough_rsp, NULL);
+}
+
+static int avctp_passthrough_release(struct avctp *session, uint8_t op)
+{
+       uint8_t operands[2];
+
+       DBG("%s", op2str(op));
+
+       /* Button released */
+       operands[0] = op | 0x80;
+       operands[1] = 0;
+
+       return avctp_send_req(session, AVC_CTYPE_CONTROL,
+                               AVC_SUBUNIT_PANEL, AVC_OP_PASSTHROUGH,
+                               operands, sizeof(operands),
+                               NULL, NULL);
+}
+
+static gboolean repeat_timeout(gpointer user_data)
+{
+       struct avctp *session = user_data;
+
+       avctp_passthrough_release(session, session->key.op);
+       avctp_passthrough_press(session, session->key.op);
+
+       return TRUE;
+}
+
+static void release_pressed(struct avctp *session)
+{
+       avctp_passthrough_release(session, session->key.op);
+
+       if (session->key.timer > 0)
+               g_source_remove(session->key.timer);
+
+       session->key.timer = 0;
+}
+
+static bool set_pressed(struct avctp *session, uint8_t op)
+{
+       if (session->key.timer > 0) {
+               if (session->key.op == op)
+                       return TRUE;
+               release_pressed(session);
+       }
+
+       if (op != AVC_FAST_FORWARD && op != AVC_REWIND)
+               return FALSE;
+
+       session->key.op = op;
+       session->key.timer = g_timeout_add_seconds(AVC_PRESS_TIMEOUT,
+                                                       repeat_timeout,
+                                                       session);
+
+       return TRUE;
+}
+
+static gboolean avctp_passthrough_rsp(struct avctp *session, uint8_t code,
+                                       uint8_t subunit, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       if (code != AVC_CTYPE_ACCEPTED)
+               return FALSE;
+
+       if (set_pressed(session, operands[0]))
+               return FALSE;
+
+       avctp_passthrough_release(session, operands[0]);
+
+       return FALSE;
+}
+
+int avctp_send_passthrough(struct avctp *session, uint8_t op)
+{
+       /* Auto release if key pressed */
+       if (session->key.timer > 0)
+               release_pressed(session);
+
+       return avctp_passthrough_press(session, op);
+}
+
+int avctp_send_vendordep(struct avctp *session, uint8_t transaction,
+                               uint8_t code, uint8_t subunit,
+                               uint8_t *operands, size_t operand_count)
+{
+       struct avctp_channel *control = session->control;
+
+       if (control == NULL)
+               return -ENOTCONN;
+
+       return avctp_send(control, 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)
+{
+       return avctp_send_req(session, code, subunit, AVC_OP_VENDORDEP,
+                                               operands, operand_count,
+                                               func, user_data);
+}
+
+unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb,
+                                                       void *user_data)
+{
+       struct avctp_state_callback *state_cb;
+       static unsigned int id = 0;
+
+       state_cb = g_new(struct avctp_state_callback, 1);
+       state_cb->cb = cb;
+       state_cb->dev = dev;
+       state_cb->id = ++id;
+       state_cb->user_data = user_data;
+
+       callbacks = g_slist_append(callbacks, state_cb);
+
+       return state_cb->id;
+}
+
+gboolean avctp_remove_state_cb(unsigned int id)
+{
+       GSList *l;
+
+       for (l = callbacks; l != NULL; l = l->next) {
+               struct avctp_state_callback *cb = l->data;
+               if (cb && cb->id == id) {
+                       callbacks = g_slist_remove(callbacks, cb);
+                       g_free(cb);
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+                                               avctp_passthrough_cb cb,
+                                               void *user_data)
+{
+       struct avctp_channel *control = session->control;
+       struct avctp_passthrough_handler *handler;
+       static unsigned int id = 0;
+
+       if (control == NULL || session->handler != NULL)
+               return 0;
+
+       handler = g_new(struct avctp_passthrough_handler, 1);
+       handler->cb = cb;
+       handler->user_data = user_data;
+       handler->id = ++id;
+
+       session->handler = handler;
+
+       return handler->id;
+}
+
+bool avctp_unregister_passthrough_handler(unsigned int id)
+{
+       GSList *l;
+
+       for (l = servers; l; l = l->next) {
+               struct avctp_server *server = l->data;
+               GSList *s;
+
+               for (s = server->sessions; s; s = s->next) {
+                       struct avctp *session = s->data;
+
+                       if (session->handler == NULL)
+                               continue;
+
+                       if (session->handler->id == id) {
+                               g_free(session->handler);
+                               session->handler = NULL;
+                               return true;
+                       }
+               }
+       }
+
+       return false;
+}
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+                                               avctp_control_pdu_cb cb,
+                                               void *user_data)
+{
+       struct avctp_channel *control = session->control;
+       struct avctp_pdu_handler *handler;
+       static unsigned int id = 0;
+
+       if (control == NULL)
+               return 0;
+
+       handler = find_handler(control->handlers, opcode);
+       if (handler)
+               return 0;
+
+       handler = g_new(struct avctp_pdu_handler, 1);
+       handler->opcode = opcode;
+       handler->cb = cb;
+       handler->user_data = user_data;
+       handler->id = ++id;
+
+       control->handlers = g_slist_append(control->handlers, handler);
+
+       return handler->id;
+}
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+                                               avctp_browsing_pdu_cb cb,
+                                               void *user_data,
+                                               GDestroyNotify destroy)
+{
+       struct avctp_channel *browsing = session->browsing;
+       struct avctp_browsing_pdu_handler *handler;
+       static unsigned int id = 0;
+
+       if (browsing == NULL)
+               return 0;
+
+       if (browsing->handlers != NULL)
+               return 0;
+
+       handler = g_new(struct avctp_browsing_pdu_handler, 1);
+       handler->cb = cb;
+       handler->user_data = user_data;
+       handler->id = ++id;
+       handler->destroy = destroy;
+
+       browsing->handlers = g_slist_append(browsing->handlers, handler);
+
+       return handler->id;
+}
+
+gboolean avctp_unregister_pdu_handler(unsigned int id)
+{
+       GSList *l;
+
+       for (l = servers; l; l = l->next) {
+               struct avctp_server *server = l->data;
+               GSList *s;
+
+               for (s = server->sessions; s; s = s->next) {
+                       struct avctp *session = s->data;
+                       struct avctp_channel *control = session->control;
+                       GSList *h;
+
+                       if (control == NULL)
+                               continue;
+
+                       for (h = control->handlers; h; h = h->next) {
+                               struct avctp_pdu_handler *handler = h->data;
+
+                               if (handler->id != id)
+                                       continue;
+
+                               control->handlers = g_slist_remove(
+                                                       control->handlers,
+                                                       handler);
+                               g_free(handler);
+                               return TRUE;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+gboolean avctp_unregister_browsing_pdu_handler(unsigned int id)
+{
+       GSList *l;
+
+       for (l = servers; l; l = l->next) {
+               struct avctp_server *server = l->data;
+               GSList *s;
+
+               for (s = server->sessions; s; s = s->next) {
+                       struct avctp *session = s->data;
+                       struct avctp_channel *browsing = session->browsing;
+                       GSList *h;
+
+                       if (browsing == NULL)
+                               continue;
+
+                       for (h = browsing->handlers; h; h = h->next) {
+                               struct avctp_browsing_pdu_handler *handler =
+                                                               h->data;
+
+                               if (handler->id != id)
+                                       continue;
+
+                               browsing->handlers = g_slist_remove(
+                                                       browsing->handlers,
+                                                       handler);
+                               g_free(handler);
+                               return TRUE;
+                       }
+               }
+       }
+
+       return FALSE;
+}
+
+struct avctp *avctp_connect(struct btd_device *device)
+{
+       struct avctp *session;
+       GError *err = NULL;
+       GIOChannel *io;
+
+       session = avctp_get_internal(device);
+       if (!session)
+               return NULL;
+
+       if (session->state > AVCTP_STATE_DISCONNECTED)
+               return session;
+
+       avctp_set_state(session, AVCTP_STATE_CONNECTING);
+
+       io = bt_io_connect(avctp_connect_cb, session, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               adapter_get_address(session->server->adapter),
+                               BT_IO_OPT_DEST_BDADDR,
+                               device_get_address(session->device),
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_PSM, AVCTP_CONTROL_PSM,
+                               BT_IO_OPT_INVALID);
+       if (err) {
+               avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+               error("%s", err->message);
+               g_error_free(err);
+               return NULL;
+       }
+
+       session->control = avctp_channel_create(session, io, NULL);
+       session->initiator = true;
+       g_io_channel_unref(io);
+
+       return session;
+}
+
+int avctp_connect_browsing(struct avctp *session)
+{
+       GError *err = NULL;
+       GIOChannel *io;
+
+       if (session->state != AVCTP_STATE_CONNECTED)
+               return -ENOTCONN;
+
+       if (session->browsing != NULL)
+               return 0;
+
+       avctp_set_state(session, AVCTP_STATE_BROWSING_CONNECTING);
+
+       io = bt_io_connect(avctp_connect_browsing_cb, session, NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               adapter_get_address(session->server->adapter),
+                               BT_IO_OPT_DEST_BDADDR,
+                               device_get_address(session->device),
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                               BT_IO_OPT_PSM, AVCTP_BROWSING_PSM,
+                               BT_IO_OPT_MODE, L2CAP_MODE_ERTM,
+                               BT_IO_OPT_INVALID);
+       if (err) {
+               error("%s", err->message);
+               g_error_free(err);
+               return -EIO;
+       }
+
+       session->browsing = avctp_channel_create(session, io,
+                                               avctp_destroy_browsing);
+       g_io_channel_unref(io);
+
+       return 0;
+}
+
+void avctp_disconnect(struct avctp *session)
+{
+       if (session->state == AVCTP_STATE_DISCONNECTED)
+               return;
+
+       avctp_set_state(session, AVCTP_STATE_DISCONNECTED);
+}
+
+struct avctp *avctp_get(struct btd_device *device)
+{
+       return avctp_get_internal(device);
+}
+
+bool avctp_is_initiator(struct avctp *session)
+{
+       return session->initiator;
+}
diff --git a/profiles/audio/avctp.h b/profiles/audio/avctp.h
new file mode 100644 (file)
index 0000000..f9c665e
--- /dev/null
@@ -0,0 +1,155 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#define AVCTP_CONTROL_PSM              23
+#define AVCTP_BROWSING_PSM             27
+
+#define AVC_MTU 512
+#define AVC_HEADER_LENGTH 3
+
+/* ctype entries */
+#define AVC_CTYPE_CONTROL              0x0
+#define AVC_CTYPE_STATUS               0x1
+#define AVC_CTYPE_NOTIFY               0x3
+#define AVC_CTYPE_NOT_IMPLEMENTED      0x8
+#define AVC_CTYPE_ACCEPTED             0x9
+#define AVC_CTYPE_REJECTED             0xA
+#define AVC_CTYPE_STABLE               0xC
+#define AVC_CTYPE_CHANGED              0xD
+#define AVC_CTYPE_INTERIM              0xF
+
+/* opcodes */
+#define AVC_OP_VENDORDEP               0x00
+#define AVC_OP_UNITINFO                        0x30
+#define AVC_OP_SUBUNITINFO             0x31
+#define AVC_OP_PASSTHROUGH             0x7c
+
+/* subunits of interest */
+#define AVC_SUBUNIT_PANEL              0x09
+
+/* operands in passthrough commands */
+#define AVC_SELECT                     0x00
+#define AVC_UP                         0x01
+#define AVC_DOWN                       0x02
+#define AVC_LEFT                       0x03
+#define AVC_RIGHT                      0x04
+#define AVC_ROOT_MENU                  0x09
+#define AVC_CONTENTS_MENU              0x0b
+#define AVC_FAVORITE_MENU              0x0c
+#define AVC_ENTER                      0x2b
+#define AVC_CHANNEL_UP                 0x30
+#define AVC_CHANNEL_DOWN               0x31
+#define AVC_INPUT_SELECT               0x34
+#define AVC_HELP                       0x36
+#define AVC_POWER                      0x40
+#define AVC_VOLUME_UP                  0x41
+#define AVC_VOLUME_DOWN                        0x42
+#define AVC_MUTE                       0x43
+#define AVC_PLAY                       0x44
+#define AVC_STOP                       0x45
+#define AVC_PAUSE                      0x46
+#define AVC_RECORD                     0x47
+#define AVC_REWIND                     0x48
+#define AVC_FAST_FORWARD               0x49
+#define AVC_EJECT                      0x4a
+#define AVC_FORWARD                    0x4b
+#define AVC_BACKWARD                   0x4c
+#define AVC_F1                         0x71
+#define AVC_F2                         0x72
+#define AVC_F3                         0x73
+#define AVC_F4                         0x74
+
+struct avctp;
+
+typedef enum {
+       AVCTP_STATE_DISCONNECTED = 0,
+       AVCTP_STATE_CONNECTING,
+       AVCTP_STATE_CONNECTED,
+       AVCTP_STATE_BROWSING_CONNECTING,
+       AVCTP_STATE_BROWSING_CONNECTED
+} avctp_state_t;
+
+typedef void (*avctp_state_cb) (struct btd_device *dev,
+                               avctp_state_t old_state,
+                               avctp_state_t new_state,
+                               void *user_data);
+
+typedef bool (*avctp_passthrough_cb) (struct avctp *session,
+                                       uint8_t op, bool pressed,
+                                       void *user_data);
+typedef size_t (*avctp_control_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);
+typedef gboolean (*avctp_browsing_rsp_cb) (struct avctp *session,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data);
+typedef size_t (*avctp_browsing_pdu_cb) (struct avctp *session,
+                                       uint8_t transaction,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data);
+
+unsigned int avctp_add_state_cb(struct btd_device *dev, avctp_state_cb cb,
+                                                       void *user_data);
+gboolean avctp_remove_state_cb(unsigned int id);
+
+int avctp_register(struct btd_adapter *adapter, gboolean master);
+void avctp_unregister(struct btd_adapter *adapter);
+
+struct avctp *avctp_connect(struct btd_device *device);
+struct avctp *avctp_get(struct btd_device *device);
+bool avctp_is_initiator(struct avctp *session);
+int avctp_connect_browsing(struct avctp *session);
+void avctp_disconnect(struct avctp *session);
+
+unsigned int avctp_register_passthrough_handler(struct avctp *session,
+                                               avctp_passthrough_cb cb,
+                                               void *user_data);
+bool avctp_unregister_passthrough_handler(unsigned int id);
+
+unsigned int avctp_register_pdu_handler(struct avctp *session, uint8_t opcode,
+                                               avctp_control_pdu_cb cb,
+                                               void *user_data);
+gboolean avctp_unregister_pdu_handler(unsigned int id);
+
+unsigned int avctp_register_browsing_pdu_handler(struct avctp *session,
+                                               avctp_browsing_pdu_cb cb,
+                                               void *user_data,
+                                               GDestroyNotify destroy);
+gboolean avctp_unregister_browsing_pdu_handler(unsigned int id);
+
+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);
+int avctp_send_browsing_req(struct avctp *session,
+                               uint8_t *operands, size_t operand_count,
+                               avctp_browsing_rsp_cb func, void *user_data);
similarity index 89%
rename from audio/avdtp.c
rename to profiles/audio/avdtp.c
index 041abc3..dab8f1c 100644 (file)
 #include <stdlib.h>
 #include <stdio.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <unistd.h>
 #include <assert.h>
-#include <signal.h>
-#include <netinet/in.h>
 
 #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 <btio/btio.h>
 
 #include "log.h"
 
-#include "../src/adapter.h"
-#include "../src/manager.h"
-#include "../src/device.h"
+#include "lib/uuid.h"
+#include "src/adapter.h"
+#include "src/device.h"
 
-#include "device.h"
-#include "manager.h"
-#include "control.h"
 #include "avdtp.h"
-#include "btio.h"
 #include "sink.h"
 #include "source.h"
 
@@ -92,7 +86,7 @@
 #define REQ_TIMEOUT 6
 #define ABORT_TIMEOUT 2
 #define DISCONNECT_TIMEOUT 1
-#define STREAM_TIMEOUT 20
+#define START_TIMEOUT 1
 
 #if __BYTE_ORDER == __LITTLE_ENDIAN
 
@@ -328,8 +322,7 @@ struct avdtp_remote_sep {
 };
 
 struct avdtp_server {
-       bdaddr_t src;
-       uint16_t version;
+       struct btd_adapter *adapter;
        GIOChannel *io;
        GSList *seps;
        GSList *sessions;
@@ -356,8 +349,15 @@ struct stream_callback {
 
 struct avdtp_state_callback {
        avdtp_session_state_cb cb;
+       struct btd_device *dev;
+       unsigned int id;
        void *user_data;
+};
+
+struct discover_callback {
        unsigned int id;
+       avdtp_discover_cb_t cb;
+       void *user_data;
 };
 
 struct avdtp_stream {
@@ -376,7 +376,7 @@ struct avdtp_stream {
        gboolean open_acp;      /* If we are in ACT role for Open */
        gboolean close_int;     /* If we are in INT role for Close */
        gboolean abort_int;     /* If we are in INT role for Abort */
-       guint idle_timer;
+       guint start_timer;      /* Wait START command timer */
        gboolean delay_reporting;
        uint16_t delay;         /* AVDTP 1.3 Delay Reporting feature */
        gboolean starting;      /* only valid while sep state == OPEN */
@@ -385,22 +385,20 @@ struct avdtp_stream {
 /* Structure describing an AVDTP connection between two devices */
 
 struct avdtp {
-       int ref;
-       int free_lock;
+       unsigned int ref;
 
        uint16_t version;
 
        struct avdtp_server *server;
-       bdaddr_t dst;
+       struct btd_device *device;
 
        avdtp_session_state_t state;
 
-       /* True if the session should be automatically disconnected */
-       gboolean auto_dc;
-
        /* True if the entire device is being disconnected */
        gboolean device_disconnect;
 
+       guint auth_id;
+
        GIOChannel *io;
        guint io_id;
 
@@ -420,24 +418,18 @@ struct avdtp {
 
        char *buf;
 
-       avdtp_discover_cb_t discov_cb;
-       void *user_data;
-
+       struct discover_callback *discover;
        struct pending_req *req;
 
        guint dc_timer;
 
        /* Attempt stream setup instead of disconnecting */
        gboolean stream_setup;
-
-       DBusPendingCall *pending_auth;
 };
 
 static GSList *servers = NULL;
 
-static GSList *avdtp_callbacks = NULL;
-
-static gboolean auto_connect = TRUE;
+static GSList *state_callbacks = NULL;
 
 static int send_request(struct avdtp *session, gboolean priority,
                        struct avdtp_stream *stream, uint8_t signal_id,
@@ -451,18 +443,16 @@ static gboolean avdtp_parse_rej(struct avdtp *session,
                                        uint8_t transaction, uint8_t signal_id,
                                        void *buf, int size);
 static int process_queue(struct avdtp *session);
-static void connection_lost(struct avdtp *session, int err);
 static void avdtp_sep_set_state(struct avdtp *session,
                                struct avdtp_local_sep *sep,
                                avdtp_state_t state);
-static void auth_cb(DBusError *derr, void *user_data);
 
-static struct avdtp_server *find_server(GSList *list, const bdaddr_t *src)
+static struct avdtp_server *find_server(GSList *list, struct btd_adapter *a)
 {
        for (; list; list = list->next) {
                struct avdtp_server *server = list->data;
 
-               if (bacmp(&server->src, src) == 0)
+               if (server->adapter == a)
                        return server;
        }
 
@@ -603,8 +593,10 @@ static gboolean avdtp_send(struct avdtp *session, uint8_t transaction,
        return TRUE;
 }
 
-static void pending_req_free(struct pending_req *req)
+static void pending_req_free(void *data)
 {
+       struct pending_req *req = data;
+
        if (req->timeout)
                g_source_remove(req->timeout);
        g_free(req->data);
@@ -656,50 +648,6 @@ static gboolean stream_open_timeout(gpointer user_data)
        return FALSE;
 }
 
-static gboolean disconnect_timeout(gpointer user_data)
-{
-       struct avdtp *session = user_data;
-       struct audio_device *dev;
-       gboolean stream_setup;
-
-       session->dc_timer = 0;
-       stream_setup = session->stream_setup;
-       session->stream_setup = FALSE;
-
-       dev = manager_get_device(&session->server->src, &session->dst, FALSE);
-
-       if (dev && dev->sink && stream_setup)
-               sink_setup_stream(dev->sink, session);
-       else if (dev && dev->source && stream_setup)
-               source_setup_stream(dev->source, session);
-       else
-               connection_lost(session, ETIMEDOUT);
-
-       return FALSE;
-}
-
-static void remove_disconnect_timer(struct avdtp *session)
-{
-       g_source_remove(session->dc_timer);
-       session->dc_timer = 0;
-       session->stream_setup = FALSE;
-}
-
-static void set_disconnect_timer(struct avdtp *session)
-{
-       if (session->dc_timer)
-               remove_disconnect_timer(session);
-
-       if (session->device_disconnect) {
-               session->dc_timer = g_idle_add(disconnect_timeout, session);
-               return;
-       }
-
-       session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
-                                               disconnect_timeout,
-                                               session);
-}
-
 void avdtp_error_init(struct avdtp_error *err, uint8_t category, int id)
 {
        err->category = category;
@@ -760,27 +708,23 @@ static void avdtp_set_state(struct avdtp *session,
                                        avdtp_session_state_t new_state)
 {
        GSList *l;
-       struct audio_device *dev;
-       bdaddr_t src, dst;
        avdtp_session_state_t old_state = session->state;
 
        session->state = new_state;
 
-       avdtp_get_peers(session, &src, &dst);
-       dev = manager_get_device(&src, &dst, FALSE);
-       if (dev == NULL) {
-               error("avdtp_set_state(): no matching audio device");
-               return;
-       }
-
-       for (l = avdtp_callbacks; l != NULL; l = l->next) {
+       for (l = state_callbacks; l != NULL; l = l->next) {
                struct avdtp_state_callback *cb = l->data;
-               cb->cb(dev, session, old_state, new_state, cb->user_data);
+
+               if (session->device != cb->dev)
+                       continue;
+
+               cb->cb(cb->dev, session, old_state, new_state, cb->user_data);
        }
 }
 
-static void stream_free(struct avdtp_stream *stream)
+static void stream_free(void *data)
 {
+       struct avdtp_stream *stream = data;
        struct avdtp_remote_sep *rsep;
 
        stream->lsep->info.inuse = 0;
@@ -805,19 +749,6 @@ static void stream_free(struct avdtp_stream *stream)
        g_free(stream);
 }
 
-static gboolean stream_timeout(gpointer user_data)
-{
-       struct avdtp_stream *stream = user_data;
-       struct avdtp *session = stream->session;
-
-       if (avdtp_close(session, stream, FALSE) < 0)
-               error("stream_timeout: closing AVDTP stream failed");
-
-       stream->idle_timer = 0;
-
-       return FALSE;
-}
-
 static gboolean transport_cb(GIOChannel *chan, GIOCondition cond,
                                gpointer data)
 {
@@ -908,9 +839,8 @@ static void handle_transport_connect(struct avdtp *session, GIOChannel *io,
        if (sep->info.type != AVDTP_SEP_TYPE_SOURCE)
                goto proceed;
 
-       bt_io_set(stream->io, BT_IO_L2CAP, &err,
-                                       BT_IO_OPT_FLUSHABLE, TRUE,
-                                       BT_IO_OPT_INVALID);
+       bt_io_set(stream->io, &err, BT_IO_OPT_FLUSHABLE, TRUE,
+                                                       BT_IO_OPT_INVALID);
        if (err != NULL) {
                error("Enabling flushable packets failed: %s", err->message);
                g_error_free(err);
@@ -1068,30 +998,25 @@ 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) ||
-                                                       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;
+               if (stream->start_timer) {
+                       g_source_remove(stream->start_timer);
+                       stream->start_timer = 0;
                }
                stream->open_acp = FALSE;
                break;
        case AVDTP_STATE_CLOSING:
        case AVDTP_STATE_ABORTING:
-               if (stream->idle_timer) {
-                       g_source_remove(stream->idle_timer);
-                       stream->idle_timer = 0;
+               if (stream->start_timer) {
+                       g_source_remove(stream->start_timer);
+                       stream->start_timer = 0;
                }
                break;
        case AVDTP_STATE_IDLE:
-               if (stream->idle_timer) {
-                       g_source_remove(stream->idle_timer);
-                       stream->idle_timer = 0;
+               if (stream->start_timer) {
+                       g_source_remove(stream->start_timer);
+                       stream->start_timer = 0;
                }
                if (session->pending_open == stream)
                        handle_transport_connect(session, NULL, 0, 0);
@@ -1120,19 +1045,21 @@ static void avdtp_sep_set_state(struct avdtp *session,
 
 static void finalize_discovery(struct avdtp *session, int err)
 {
+       struct discover_callback *discover = session->discover;
        struct avdtp_error avdtp_err;
 
-       avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
-
-       if (!session->discov_cb)
+       if (!discover)
                return;
 
-       session->discov_cb(session, session->seps,
-                               err ? &avdtp_err : NULL,
-                               session->user_data);
+       avdtp_error_init(&avdtp_err, AVDTP_ERRNO, err);
+
+       if (discover->id > 0)
+               g_source_remove(discover->id);
 
-       session->discov_cb = NULL;
-       session->user_data = NULL;
+       discover->cb(session, session->seps, err ? &avdtp_err : NULL,
+                                                       discover->user_data);
+       g_free(discover);
+       session->discover = NULL;
 }
 
 static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
@@ -1149,45 +1076,51 @@ static void release_stream(struct avdtp_stream *stream, struct avdtp *session)
 
 static int avdtp_cancel_authorization(struct avdtp *session)
 {
-       struct audio_device *dev;
+       int err;
 
        if (session->state != AVDTP_SESSION_STATE_CONNECTING)
                return 0;
 
-       dev = manager_get_device(&session->server->src, &session->dst, FALSE);
-       if (dev == NULL)
-               return -ENODEV;
+       if (session->auth_id == 0)
+               return 0;
+
+       err = btd_cancel_authorization(session->auth_id);
+       if (err < 0)
+               return err;
+
+       session->auth_id = 0;
 
-       return audio_device_cancel_authorization(dev, auth_cb, session);
+       return 0;
 }
 
-static void connection_lost(struct avdtp *session, int err)
+static void sep_free(gpointer data)
 {
-       char address[18];
+       struct avdtp_remote_sep *sep = data;
 
-       ba2str(&session->dst, address);
-       DBG("Disconnected from %s", address);
-
-       if (err != EACCES)
-               avdtp_cancel_authorization(session);
+       g_slist_free_full(sep->caps, g_free);
+       g_free(sep);
+}
 
-       session->free_lock = 1;
+static void remove_disconnect_timer(struct avdtp *session)
+{
+       g_source_remove(session->dc_timer);
+       session->dc_timer = 0;
+       session->stream_setup = FALSE;
+}
 
-       finalize_discovery(session, err);
+static void avdtp_free(void *data)
+{
+       struct avdtp *session = data;
 
-       g_slist_foreach(session->streams, (GFunc) release_stream, session);
-       session->streams = NULL;
+       DBG("%p", session);
 
-       session->free_lock = 0;
+       g_slist_free_full(session->streams, stream_free);
 
        if (session->io) {
                g_io_channel_shutdown(session->io, FALSE, NULL);
                g_io_channel_unref(session->io);
-               session->io = NULL;
        }
 
-       avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
-
        if (session->io_id) {
                g_source_remove(session->io_id);
                session->io_id = 0;
@@ -1196,63 +1129,100 @@ static void connection_lost(struct avdtp *session, int err)
        if (session->dc_timer)
                remove_disconnect_timer(session);
 
-       session->auto_dc = TRUE;
+       if (session->req)
+               pending_req_free(session->req);
 
-       if (session->ref != 1)
-               error("connection_lost: ref count not 1 after all callbacks");
-       else
-               avdtp_unref(session);
+       g_slist_free_full(session->req_queue, pending_req_free);
+       g_slist_free_full(session->prio_queue, pending_req_free);
+       g_slist_free_full(session->seps, sep_free);
+
+       g_free(session->buf);
+
+       g_free(session);
 }
 
-void avdtp_unref(struct avdtp *session)
+static void connection_lost(struct avdtp *session, int err)
 {
-       struct avdtp_server *server;
+       struct avdtp_server *server = session->server;
+       char address[18];
 
-       if (!session)
-               return;
+       ba2str(device_get_address(session->device), address);
+       DBG("Disconnected from %s", address);
 
-       session->ref--;
+       if (err != EACCES)
+               avdtp_cancel_authorization(session);
 
-       DBG("%p: ref=%d", session, session->ref);
+       g_slist_foreach(session->streams, (GFunc) release_stream, session);
+       session->streams = NULL;
 
-       if (session->ref == 1) {
-               if (session->state == AVDTP_SESSION_STATE_CONNECTING &&
-                                                               session->io) {
-                       avdtp_cancel_authorization(session);
-                       g_io_channel_shutdown(session->io, TRUE, NULL);
-                       g_io_channel_unref(session->io);
-                       session->io = NULL;
-                       avdtp_set_state(session,
-                                       AVDTP_SESSION_STATE_DISCONNECTED);
-               }
+       finalize_discovery(session, err);
 
-               if (session->io)
-                       set_disconnect_timer(session);
-               else if (!session->free_lock) /* Drop the local ref if we
-                                                aren't connected */
-                       session->ref--;
-       }
+       avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
 
        if (session->ref > 0)
                return;
 
-       server = session->server;
+       server->sessions = g_slist_remove(server->sessions, session);
+       btd_device_unref(session->device);
+       avdtp_free(session);
+}
+
+static gboolean disconnect_timeout(gpointer user_data)
+{
+       struct avdtp *session = user_data;
+       struct btd_service *service;
+       gboolean stream_setup;
+
+       session->dc_timer = 0;
+
+       stream_setup = session->stream_setup;
+       session->stream_setup = FALSE;
+
+       service = btd_device_get_service(session->device, A2DP_SINK_UUID);
+       if (service && stream_setup) {
+               sink_setup_stream(service, session);
+               return FALSE;
+       }
 
-       DBG("%p: freeing session and removing from list", session);
+       service = btd_device_get_service(session->device, A2DP_SOURCE_UUID);
+       if (service && stream_setup) {
+               source_setup_stream(service, session);
+               return FALSE;
+       }
+
+       connection_lost(session, ETIMEDOUT);
+
+       return FALSE;
+}
 
+static void set_disconnect_timer(struct avdtp *session)
+{
        if (session->dc_timer)
                remove_disconnect_timer(session);
 
-       server->sessions = g_slist_remove(server->sessions, session);
+       if (session->device_disconnect) {
+               session->dc_timer = g_idle_add(disconnect_timeout, session);
+               return;
+       }
 
-       if (session->req)
-               pending_req_free(session->req);
+       session->dc_timer = g_timeout_add_seconds(DISCONNECT_TIMEOUT,
+                                               disconnect_timeout,
+                                               session);
+}
 
-       g_slist_free_full(session->seps, g_free);
+void avdtp_unref(struct avdtp *session)
+{
+       if (!session)
+               return;
 
-       g_free(session->buf);
+       session->ref--;
 
-       g_free(session);
+       DBG("%p: ref=%d", session, session->ref);
+
+       if (session->ref > 0)
+               return;
+
+       set_disconnect_timer(session);
 }
 
 struct avdtp *avdtp_ref(struct avdtp *session)
@@ -1420,9 +1390,6 @@ static gboolean avdtp_getcap_cmd(struct avdtp *session, uint8_t transaction,
                goto failed;
        }
 
-       if (get_all && session->server->version < 0x0103)
-               return avdtp_unknown_cmd(session, transaction, cmd);
-
        if (!sep->ind->get_capability(session, sep, get_all, &caps,
                                                        &err, sep->user_data))
                goto failed;
@@ -1486,8 +1453,7 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
        struct avdtp_local_sep *sep;
        struct avdtp_stream *stream;
        uint8_t err, category = 0x00;
-       struct audio_device *dev;
-       bdaddr_t src, dst;
+       struct btd_service *service;
        GSList *l;
 
        if (size < sizeof(struct setconf_req)) {
@@ -1506,19 +1472,15 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
                goto failed;
        }
 
-       avdtp_get_peers(session, &src, &dst);
-       dev = manager_get_device(&src, &dst, FALSE);
-       if (!dev) {
-               error("Unable to get a audio device object");
-               err = AVDTP_BAD_STATE;
-               goto failed;
-       }
-
        switch (sep->info.type) {
        case AVDTP_SEP_TYPE_SOURCE:
-               if (!dev->sink) {
-                       btd_device_add_uuid(dev->btd_dev, A2DP_SINK_UUID);
-                       if (!dev->sink) {
+               service = btd_device_get_service(session->device,
+                                                       A2DP_SINK_UUID);
+               if (service == NULL) {
+                       btd_device_add_uuid(session->device, A2DP_SINK_UUID);
+                       service = btd_device_get_service(session->device,
+                                                       A2DP_SINK_UUID);
+                       if (service == NULL) {
                                error("Unable to get a audio sink object");
                                err = AVDTP_BAD_STATE;
                                goto failed;
@@ -1526,9 +1488,13 @@ static gboolean avdtp_setconf_cmd(struct avdtp *session, uint8_t transaction,
                }
                break;
        case AVDTP_SEP_TYPE_SINK:
-               if (!dev->source) {
-                       btd_device_add_uuid(dev->btd_dev, A2DP_SOURCE_UUID);
-                       if (!dev->source) {
+               service = btd_device_get_service(session->device,
+                                                       A2DP_SOURCE_UUID);
+               if (service == NULL) {
+                       btd_device_add_uuid(session->device, A2DP_SOURCE_UUID);
+                       service = btd_device_get_service(session->device,
+                                                       A2DP_SOURCE_UUID);
+                       if (service == NULL) {
                                error("Unable to get a audio source object");
                                err = AVDTP_BAD_STATE;
                                goto failed;
@@ -2238,12 +2204,6 @@ static gboolean session_cb(GIOChannel *chan, GIOCondition cond,
                        goto failed;
                }
 
-               if (session->ref == 1 && !session->streams && !session->req)
-                       set_disconnect_timer(session);
-
-               if (session->streams && session->dc_timer)
-                       remove_disconnect_timer(session);
-
                if (session->req && session->req->collided) {
                        DBG("Collision detected");
                        goto next;
@@ -2313,15 +2273,13 @@ failed:
        return FALSE;
 }
 
-static struct avdtp *find_session(GSList *list, const bdaddr_t *dst)
+static struct avdtp *find_session(GSList *list, struct btd_device *device)
 {
        for (; list != NULL; list = g_slist_next(list)) {
                struct avdtp *s = list->data;
 
-               if (bacmp(dst, &s->dst))
-                       continue;
-
-               return s;
+               if (s->device == device)
+                       return s;
        }
 
        return NULL;
@@ -2329,26 +2287,14 @@ static struct avdtp *find_session(GSList *list, const bdaddr_t *dst)
 
 static uint16_t get_version(struct avdtp *session)
 {
-       struct btd_adapter *adapter;
-       struct btd_device *device;
        const sdp_record_t *rec;
        sdp_list_t *protos;
        sdp_data_t *proto_desc;
-       char addr[18];
        uint16_t ver = 0x0100;
 
-       adapter = manager_find_adapter(&session->server->src);
-       if (!adapter)
-               return ver;
-
-       ba2str(&session->dst, addr);
-       device = adapter_find_device(adapter, addr);
-       if (!device)
-               return ver;
-
-       rec = btd_device_get_record(device, A2DP_SINK_UUID);
+       rec = btd_device_get_record(session->device, A2DP_SINK_UUID);
        if (!rec)
-               rec = btd_device_get_record(device, A2DP_SOURCE_UUID);
+               rec = btd_device_get_record(session->device, A2DP_SOURCE_UUID);
 
        if (!rec)
                return ver;
@@ -2366,35 +2312,26 @@ static uint16_t get_version(struct avdtp *session)
        return ver;
 }
 
-static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst)
+static struct avdtp *avdtp_get_internal(struct btd_device *device)
 {
        struct avdtp_server *server;
        struct avdtp *session;
 
-       assert(src != NULL);
-       assert(dst != NULL);
-
-       server = find_server(servers, src);
+       server = find_server(servers, device_get_adapter(device));
        if (server == NULL)
                return NULL;
 
-       session = find_session(server->sessions, dst);
-       if (session) {
-               if (session->pending_auth)
-                       return NULL;
-               else
-                       return session;
-       }
+       session = find_session(server->sessions, device);
+       if (session)
+               return session;
 
        session = g_new0(struct avdtp, 1);
 
        session->server = server;
-       bacpy(&session->dst, dst);
-       session->ref = 1;
+       session->device = btd_device_ref(device);
        /* We don't use avdtp_set_state() here since this isn't a state change
         * but just setting of the initial state */
        session->state = AVDTP_SESSION_STATE_DISCONNECTED;
-       session->auto_dc = TRUE;
 
        session->version = get_version(session);
 
@@ -2403,11 +2340,11 @@ static struct avdtp *avdtp_get_internal(const bdaddr_t *src, const bdaddr_t *dst
        return session;
 }
 
-struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst)
+struct avdtp *avdtp_get(struct btd_device *device)
 {
        struct avdtp *session;
 
-       session = avdtp_get_internal(src, dst);
+       session = avdtp_get_internal(device);
 
        if (!session)
                return NULL;
@@ -2419,9 +2356,10 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
 {
        struct avdtp *session = user_data;
        char address[18];
-       GError *gerr = NULL;
+       int err_no = EIO;
 
        if (err) {
+               err_no = err->code;
                error("%s", err->message);
                goto failed;
        }
@@ -2429,17 +2367,17 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
        if (!session->io)
                session->io = g_io_channel_ref(chan);
 
-       bt_io_get(chan, BT_IO_L2CAP, &gerr,
+       bt_io_get(chan, &err,
                        BT_IO_OPT_OMTU, &session->omtu,
                        BT_IO_OPT_IMTU, &session->imtu,
                        BT_IO_OPT_INVALID);
-       if (gerr) {
-               error("%s", gerr->message);
-               g_error_free(gerr);
+       if (err) {
+               err_no = err->code;
+               error("%s", err->message);
                goto failed;
        }
 
-       ba2str(&session->dst, address);
+       ba2str(device_get_address(session->device), address);
        DBG("AVDTP: connected %s channel to %s",
                        session->pending_open ? "transport" : "signaling",
                        address);
@@ -2467,10 +2405,8 @@ static void avdtp_connect_cb(GIOChannel *chan, GError *err, gpointer user_data)
                                                (GIOFunc) session_cb, session,
                                                NULL);
 
-               if (session->stream_setup) {
+               if (session->stream_setup)
                        set_disconnect_timer(session);
-                       avdtp_set_auto_disconnect(session, FALSE);
-               }
        } else if (session->pending_open)
                handle_transport_connect(session, chan, session->imtu,
                                                                session->omtu);
@@ -2491,7 +2427,7 @@ failed:
                        avdtp_sep_set_state(session, stream->lsep,
                                                AVDTP_STATE_IDLE);
        } else
-               connection_lost(session, EIO);
+               connection_lost(session, err_no);
 }
 
 static void auth_cb(DBusError *derr, void *user_data)
@@ -2521,13 +2457,12 @@ static void auth_cb(DBusError *derr, void *user_data)
 static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
 {
        struct avdtp *session;
-       struct audio_device *dev;
        char address[18];
        bdaddr_t src, dst;
-       int perr;
        GError *err = NULL;
+       struct btd_device *device;
 
-       bt_io_get(chan, BT_IO_L2CAP, &err,
+       bt_io_get(chan, &err,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_DEST, address,
@@ -2540,7 +2475,11 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
 
        DBG("AVDTP: incoming connect from %s", address);
 
-       session = avdtp_get_internal(&src, &dst);
+       device = adapter_find_device(adapter_find(&src), &dst);
+       if (!device)
+               goto drop;
+
+       session = avdtp_get_internal(device);
        if (!session)
                goto drop;
 
@@ -2566,16 +2505,7 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
                goto drop;
        }
 
-       dev = manager_get_device(&src, &dst, FALSE);
-       if (!dev) {
-               dev = manager_get_device(&src, &dst, TRUE);
-               if (!dev) {
-                       error("Unable to get audio device object for %s",
-                                       address);
-                       goto drop;
-               }
-               btd_device_add_uuid(dev->btd_dev, ADVANCED_AUDIO_UUID);
-       }
+       btd_device_add_uuid(device, ADVANCED_AUDIO_UUID);
 
        session->io = g_io_channel_ref(chan);
        avdtp_set_state(session, AVDTP_SESSION_STATE_CONNECTING);
@@ -2583,16 +2513,14 @@ static void avdtp_confirm_cb(GIOChannel *chan, gpointer data)
        session->io_id = g_io_add_watch(chan, G_IO_ERR | G_IO_HUP | G_IO_NVAL,
                                        (GIOFunc) session_cb, session);
 
-       perr = audio_device_request_authorization(dev, ADVANCED_AUDIO_UUID,
+       session->auth_id = btd_request_authorization(&src, &dst,
+                                                       ADVANCED_AUDIO_UUID,
                                                        auth_cb, session);
-       if (perr < 0) {
+       if (session->auth_id == 0) {
                avdtp_set_state(session, AVDTP_SESSION_STATE_DISCONNECTED);
-               avdtp_unref(session);
                goto drop;
        }
 
-       dev->auto_connect = auto_connect;
-
        return;
 
 drop:
@@ -2604,10 +2532,12 @@ static GIOChannel *l2cap_connect(struct avdtp *session)
        GError *err = NULL;
        GIOChannel *io;
 
-       io = bt_io_connect(BT_IO_L2CAP, avdtp_connect_cb, session,
+       io = bt_io_connect(avdtp_connect_cb, session,
                                NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &session->server->src,
-                               BT_IO_OPT_DEST_BDADDR, &session->dst,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               adapter_get_address(session->server->adapter),
+                               BT_IO_OPT_DEST_BDADDR,
+                               device_get_address(session->device),
                                BT_IO_OPT_PSM, AVDTP_PSM,
                                BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
                                BT_IO_OPT_INVALID);
@@ -2823,7 +2753,7 @@ static gboolean avdtp_discover_resp(struct avdtp *session,
        int ret = 0;
        gboolean getcap_pending = FALSE;
 
-       if (session->version >= 0x0103 && session->server->version >= 0x0103)
+       if (session->version >= 0x0103)
                getcap_cmd = AVDTP_GET_ALL_CAPABILITIES;
        else
                getcap_cmd = AVDTP_GET_CAPABILITIES;
@@ -3238,25 +3168,6 @@ static gboolean avdtp_parse_rej(struct avdtp *session,
        }
 }
 
-gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       struct avdtp_server *server;
-       struct avdtp *session;
-
-       server = find_server(servers, src);
-       if (!server)
-               return FALSE;
-
-       session = find_session(server->sessions, dst);
-       if (!session)
-               return FALSE;
-
-       if (session->state != AVDTP_SESSION_STATE_DISCONNECTED)
-               return TRUE;
-
-       return FALSE;
-}
-
 struct avdtp_service_capability *avdtp_stream_get_codec(
                                                struct avdtp_stream *stream)
 {
@@ -3417,6 +3328,8 @@ static gboolean process_discover(gpointer data)
 {
        struct avdtp *session = data;
 
+       session->discover->id = 0;
+
        finalize_discovery(session, 0);
 
        return FALSE;
@@ -3427,20 +3340,22 @@ int avdtp_discover(struct avdtp *session, avdtp_discover_cb_t cb,
 {
        int err;
 
-       if (session->discov_cb)
+       if (session->discover)
                return -EBUSY;
 
+       session->discover = g_new0(struct discover_callback, 1);
+
        if (session->seps) {
-               session->discov_cb = cb;
-               session->user_data = user_data;
-               g_idle_add(process_discover, session);
+               session->discover->cb = cb;
+               session->discover->user_data = user_data;
+               session->discover->id = g_idle_add(process_discover, session);
                return 0;
        }
 
        err = send_request(session, FALSE, NULL, AVDTP_DISCOVER, NULL, 0);
        if (err == 0) {
-               session->discov_cb = cb;
-               session->user_data = user_data;
+               session->discover->cb = cb;
+               session->discover->user_data = user_data;
        }
 
        return err;
@@ -3591,45 +3506,6 @@ int avdtp_set_configuration(struct avdtp *session,
        return err;
 }
 
-int avdtp_reconfigure(struct avdtp *session, GSList *caps,
-                       struct avdtp_stream *stream)
-{
-       struct reconf_req *req;
-       unsigned char *ptr;
-       int caps_len, err;
-       GSList *l;
-       struct avdtp_service_capability *cap;
-
-       if (!g_slist_find(session->streams, stream))
-               return -EINVAL;
-
-       if (stream->lsep->state != AVDTP_STATE_OPEN)
-               return -EINVAL;
-
-       /* Calculate total size of request */
-       for (l = caps, caps_len = 0; l != NULL; l = g_slist_next(l)) {
-               cap = l->data;
-               caps_len += cap->length + 2;
-       }
-
-       req = g_malloc0(sizeof(struct reconf_req) + caps_len);
-
-       req->acp_seid = stream->rseid;
-
-       /* Copy the capabilities into the request */
-       for (l = caps, ptr = req->caps; l != NULL; l = g_slist_next(l)) {
-               cap = l->data;
-               memcpy(ptr, cap, cap->length + 2);
-               ptr += cap->length + 2;
-       }
-
-       err = send_request(session, FALSE, stream, AVDTP_RECONFIGURE, req,
-                                               sizeof(*req) + caps_len);
-       g_free(req);
-
-       return err;
-}
-
 int avdtp_open(struct avdtp *session, struct avdtp_stream *stream)
 {
        struct seid_req req;
@@ -3647,6 +3523,21 @@ int avdtp_open(struct avdtp *session, struct avdtp_stream *stream)
                                                        &req, sizeof(req));
 }
 
+static gboolean start_timeout(gpointer user_data)
+{
+       struct avdtp_stream *stream = user_data;
+       struct avdtp *session = stream->session;
+
+       stream->open_acp = FALSE;
+
+       if (avdtp_start(session, stream) < 0)
+               error("wait_timeout: avdtp_start failed");
+
+       stream->start_timer = 0;
+
+       return FALSE;
+}
+
 int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
 {
        struct start_req req;
@@ -3663,7 +3554,13 @@ int avdtp_start(struct avdtp *session, struct avdtp_stream *stream)
         *  to start the streaming via GAVDP_START.
         */
        if (stream->open_acp) {
-               stream->starting = TRUE;
+               /* If timer already active wait it */
+               if (stream->start_timer)
+                       return 0;
+
+               stream->start_timer = g_timeout_add_seconds(START_TIMEOUT,
+                                                               start_timeout,
+                                                               stream);
                return 0;
        }
 
@@ -3773,8 +3670,7 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                stream->lsep->state != AVDTP_STATE_STREAMING)
                return -EINVAL;
 
-       if (!stream->delay_reporting || session->version < 0x0103 ||
-                                       session->server->version < 0x0103)
+       if (!stream->delay_reporting || session->version < 0x0103)
                return -EINVAL;
 
        stream->delay = delay;
@@ -3787,7 +3683,8 @@ int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        &req, sizeof(req));
 }
 
-struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
+struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
+                                               uint8_t type,
                                                uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
@@ -3798,7 +3695,7 @@ struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
        struct avdtp_server *server;
        struct avdtp_local_sep *sep;
 
-       server = find_server(servers, src);
+       server = find_server(servers, adapter);
        if (!server)
                return NULL;
 
@@ -3851,7 +3748,7 @@ static GIOChannel *avdtp_server_socket(const bdaddr_t *src, gboolean master)
        GError *err = NULL;
        GIOChannel *io;
 
-       io = bt_io_listen(BT_IO_L2CAP, NULL, avdtp_confirm_cb,
+       io = bt_io_listen(NULL, avdtp_confirm_cb,
                                NULL, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, src,
                                BT_IO_OPT_PSM, AVDTP_PSM,
@@ -3899,7 +3796,7 @@ const char *avdtp_strerror(struct avdtp_error *err)
        case AVDTP_BAD_ROHC_FORMAT:
                return "Bad Header Compression Format";
        case AVDTP_BAD_CP_FORMAT:
-               return "Bad Content Protetion Format";
+               return "Bad Content Protection Format";
        case AVDTP_BAD_MULTIPLEXING_FORMAT:
                return "Bad Multiplexing Format";
        case AVDTP_UNSUPPORTED_CONFIGURATION:
@@ -3907,7 +3804,7 @@ const char *avdtp_strerror(struct avdtp_error *err)
        case AVDTP_BAD_STATE:
                return "Bad State";
        default:
-               return "Unknow error";
+               return "Unknown error";
        }
 }
 
@@ -3916,90 +3813,50 @@ avdtp_state_t avdtp_sep_get_state(struct avdtp_local_sep *sep)
        return sep->state;
 }
 
-void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst)
+struct btd_adapter *avdtp_get_adapter(struct avdtp *session)
 {
-       if (src)
-               bacpy(src, &session->server->src);
-       if (dst)
-               bacpy(dst, &session->dst);
+       return session->server->adapter;
 }
 
-int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version)
+struct btd_device *avdtp_get_device(struct avdtp *session)
 {
-       GError *err = NULL;
-       gboolean tmp, master = TRUE;
-       struct avdtp_server *server;
-       uint16_t ver = 0x0102;
-
-       if (!config)
-               goto proceed;
-
-       tmp = g_key_file_get_boolean(config, "General",
-                       "Master", &err);
-       if (err) {
-               DBG("audio.conf: %s", err->message);
-               g_clear_error(&err);
-       } else
-               master = tmp;
-
-       tmp = g_key_file_get_boolean(config, "General", "AutoConnect",
-                       &err);
-       if (err)
-               g_clear_error(&err);
-       else
-               auto_connect = tmp;
+       return session->device;
+}
 
-       if (g_key_file_get_boolean(config, "A2DP", "DelayReporting", NULL))
-               ver = 0x0103;
+int avdtp_init(struct btd_adapter *adapter)
+{
+       struct avdtp_server *server;
 
-proceed:
        server = g_new0(struct avdtp_server, 1);
-       if (!server)
-               return -ENOMEM;
-
-       server->version = ver;
 
-       if (version)
-               *version = server->version;
-
-       server->io = avdtp_server_socket(src, master);
+       server->io = avdtp_server_socket(adapter_get_address(adapter), TRUE);
        if (!server->io) {
                g_free(server);
                return -1;
        }
 
-       bacpy(&server->src, src);
+       server->adapter = btd_adapter_ref(adapter);
 
        servers = g_slist_append(servers, server);
 
        return 0;
 }
 
-void avdtp_exit(const bdaddr_t *src)
+void avdtp_exit(struct btd_adapter *adapter)
 {
        struct avdtp_server *server;
-       GSList *l;
 
-       server = find_server(servers, src);
+       server = find_server(servers, adapter);
        if (!server)
                return;
 
-       l = server->sessions;
-       while (l) {
-               struct avdtp *session = l->data;
-
-               l = l->next;
-               /* value of l pointer should be updated before invoking
-                * connection_lost since it internally uses avdtp_unref
-                * which operates on server->session list as well
-                */
-               connection_lost(session, -ECONNABORTED);
-       }
+       g_slist_free_full(server->sessions, avdtp_free);
 
        servers = g_slist_remove(servers, server);
 
        g_io_channel_shutdown(server->io, TRUE, NULL);
        g_io_channel_unref(server->io);
+       btd_adapter_unref(server->adapter);
        g_free(server);
 }
 
@@ -4008,32 +3865,24 @@ gboolean avdtp_has_stream(struct avdtp *session, struct avdtp_stream *stream)
        return g_slist_find(session->streams, stream) ? TRUE : FALSE;
 }
 
-void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc)
-{
-       session->auto_dc = auto_dc;
-}
-
-gboolean avdtp_stream_setup_active(struct avdtp *session)
-{
-       return session->stream_setup;
-}
-
 void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc)
 {
        session->device_disconnect = dev_dc;
 }
 
-unsigned int avdtp_add_state_cb(avdtp_session_state_cb cb, void *user_data)
+unsigned int avdtp_add_state_cb(struct btd_device *dev,
+                               avdtp_session_state_cb cb, void *user_data)
 {
        struct avdtp_state_callback *state_cb;
        static unsigned int id = 0;
 
        state_cb = g_new(struct avdtp_state_callback, 1);
        state_cb->cb = cb;
-       state_cb->user_data = user_data;
+       state_cb->dev = dev;
        state_cb->id = ++id;
+       state_cb->user_data = user_data;
 
-       avdtp_callbacks = g_slist_append(avdtp_callbacks, state_cb);
+       state_callbacks = g_slist_append(state_callbacks, state_cb);
 
        return state_cb->id;
 }
@@ -4042,10 +3891,10 @@ gboolean avdtp_remove_state_cb(unsigned int id)
 {
        GSList *l;
 
-       for (l = avdtp_callbacks; l != NULL; l = l->next) {
+       for (l = state_callbacks; l != NULL; l = l->next) {
                struct avdtp_state_callback *cb = l->data;
                if (cb && cb->id == id) {
-                       avdtp_callbacks = g_slist_remove(avdtp_callbacks, cb);
+                       state_callbacks = g_slist_remove(state_callbacks, cb);
                        g_free(cb);
                        return TRUE;
                }
similarity index 92%
rename from audio/avdtp.h
rename to profiles/audio/avdtp.h
index dac093b..3bf7503 100644 (file)
@@ -116,7 +116,7 @@ struct avdtp_media_codec_capability {
 #error "Unknown byte order"
 #endif
 
-typedef void (*avdtp_session_state_cb) (struct audio_device *dev,
+typedef void (*avdtp_session_state_cb) (struct btd_device *dev,
                                        struct avdtp *session,
                                        avdtp_session_state_t old_state,
                                        avdtp_session_state_t new_state,
@@ -213,13 +213,11 @@ struct avdtp_sep_ind {
 typedef void (*avdtp_discover_cb_t) (struct avdtp *session, GSList *seps,
                                        struct avdtp_error *err, void *user_data);
 
-struct avdtp *avdtp_get(bdaddr_t *src, bdaddr_t *dst);
+struct avdtp *avdtp_get(struct btd_device *device);
 
 void avdtp_unref(struct avdtp *session);
 struct avdtp *avdtp_ref(struct avdtp *session);
 
-gboolean avdtp_is_connected(const bdaddr_t *src, const bdaddr_t *dst);
-
 struct avdtp_service_capability *avdtp_service_cap_new(uint8_t category,
                                                        void *data, int size);
 
@@ -260,7 +258,8 @@ gboolean avdtp_stream_has_capabilities(struct avdtp_stream *stream,
 struct avdtp_remote_sep *avdtp_stream_get_remote_sep(
                                                struct avdtp_stream *stream);
 
-unsigned int avdtp_add_state_cb(avdtp_session_state_cb cb, void *user_data);
+unsigned int avdtp_add_state_cb(struct btd_device *dev,
+                               avdtp_session_state_cb cb, void *user_data);
 
 gboolean avdtp_remove_state_cb(unsigned int id);
 
@@ -274,8 +273,6 @@ int avdtp_get_configuration(struct avdtp *session,
                                struct avdtp_stream *stream);
 
 int avdtp_open(struct avdtp *session, struct avdtp_stream *stream);
-int avdtp_reconfigure(struct avdtp *session, GSList *caps,
-                       struct avdtp_stream *stream);
 int avdtp_start(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_suspend(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_close(struct avdtp *session, struct avdtp_stream *stream,
@@ -284,7 +281,8 @@ int avdtp_abort(struct avdtp *session, struct avdtp_stream *stream);
 int avdtp_delay_report(struct avdtp *session, struct avdtp_stream *stream,
                                                        uint16_t delay);
 
-struct avdtp_local_sep *avdtp_register_sep(const bdaddr_t *src, uint8_t type,
+struct avdtp_local_sep *avdtp_register_sep(struct btd_adapter *adapter,
+                                               uint8_t type,
                                                uint8_t media_type,
                                                uint8_t codec_type,
                                                gboolean delay_reporting,
@@ -306,11 +304,10 @@ uint8_t avdtp_error_category(struct avdtp_error *err);
 int avdtp_error_error_code(struct avdtp_error *err);
 int avdtp_error_posix_errno(struct avdtp_error *err);
 
-void avdtp_get_peers(struct avdtp *session, bdaddr_t *src, bdaddr_t *dst);
+struct btd_adapter *avdtp_get_adapter(struct avdtp *session);
+struct btd_device *avdtp_get_device(struct avdtp *session);
 
-void avdtp_set_auto_disconnect(struct avdtp *session, gboolean auto_dc);
-gboolean avdtp_stream_setup_active(struct avdtp *session);
 void avdtp_set_device_disconnect(struct avdtp *session, gboolean dev_dc);
 
-int avdtp_init(const bdaddr_t *src, GKeyFile *config, uint16_t *version);
-void avdtp_exit(const bdaddr_t *src);
+int avdtp_init(struct btd_adapter *adapter);
+void avdtp_exit(struct btd_adapter *adapter);
diff --git a/profiles/audio/avrcp.c b/profiles/audio/avrcp.c
new file mode 100644 (file)
index 0000000..296067c
--- /dev/null
@@ -0,0 +1,3957 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  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 <stdlib.h>
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+
+#include "log.h"
+#include "error.h"
+#include "avctp.h"
+#include "avrcp.h"
+#include "sdpd.h"
+#include "dbus-common.h"
+#include "control.h"
+#include "player.h"
+#include "transport.h"
+
+/* Company IDs for vendor dependent commands */
+#define IEEEID_BTSIG           0x001958
+
+/* Status codes */
+#define AVRCP_STATUS_INVALID_COMMAND           0x00
+#define AVRCP_STATUS_INVALID_PARAM             0x01
+#define AVRCP_STATUS_PARAM_NOT_FOUND           0x02
+#define AVRCP_STATUS_INTERNAL_ERROR            0x03
+#define AVRCP_STATUS_SUCCESS                   0x04
+#define AVRCP_STATUS_OUT_OF_BOUNDS             0x0b
+#define AVRCP_STATUS_INVALID_PLAYER_ID         0x11
+#define AVRCP_STATUS_PLAYER_NOT_BROWSABLE      0x12
+#define AVRCP_STATUS_NO_AVAILABLE_PLAYERS      0x15
+#define AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED  0x16
+
+/* Packet types */
+#define AVRCP_PACKET_TYPE_SINGLE       0x00
+#define AVRCP_PACKET_TYPE_START                0x01
+#define AVRCP_PACKET_TYPE_CONTINUING   0x02
+#define AVRCP_PACKET_TYPE_END          0x03
+
+/* PDU types for metadata transfer */
+#define AVRCP_GET_CAPABILITIES         0x10
+#define AVRCP_LIST_PLAYER_ATTRIBUTES   0X11
+#define AVRCP_LIST_PLAYER_VALUES       0x12
+#define AVRCP_GET_CURRENT_PLAYER_VALUE 0x13
+#define AVRCP_SET_PLAYER_VALUE         0x14
+#define AVRCP_GET_PLAYER_ATTRIBUTE_TEXT        0x15
+#define AVRCP_GET_PLAYER_VALUE_TEXT    0x16
+#define AVRCP_DISPLAYABLE_CHARSET      0x17
+#define AVRCP_CT_BATTERY_STATUS                0x18
+#define AVRCP_GET_ELEMENT_ATTRIBUTES   0x20
+#define AVRCP_GET_PLAY_STATUS          0x30
+#define AVRCP_REGISTER_NOTIFICATION    0x31
+#define AVRCP_REQUEST_CONTINUING       0x40
+#define AVRCP_ABORT_CONTINUING         0x41
+#define AVRCP_SET_ABSOLUTE_VOLUME      0x50
+#define AVRCP_SET_BROWSED_PLAYER       0x70
+#define AVRCP_GET_FOLDER_ITEMS         0x71
+#define AVRCP_CHANGE_PATH              0x72
+#define AVRCP_GET_ITEM_ATTRIBUTES      0x73
+#define AVRCP_PLAY_ITEM                        0x74
+#define AVRCP_SEARCH                   0x80
+#define AVRCP_ADD_TO_NOW_PLAYING       0x90
+#define AVRCP_GENERAL_REJECT           0xA0
+
+/* 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_GET_CAPABILITIES_PARAM_LENGTH 1
+
+#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
+#define AVRCP_FEATURE_BROWSING                 0x0040
+
+#define AVRCP_BATTERY_STATUS_NORMAL            0
+#define AVRCP_BATTERY_STATUS_WARNING           1
+#define AVRCP_BATTERY_STATUS_CRITICAL          2
+#define AVRCP_BATTERY_STATUS_EXTERNAL          3
+#define AVRCP_BATTERY_STATUS_FULL_CHARGE       4
+
+#define AVRCP_CHARSET_UTF8             106
+
+#define AVRCP_BROWSING_TIMEOUT         1
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+struct avrcp_header {
+       uint8_t company_id[3];
+       uint8_t pdu_id;
+       uint8_t packet_type:2;
+       uint8_t rsvd:6;
+       uint16_t params_len;
+       uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+struct avrcp_header {
+       uint8_t company_id[3];
+       uint8_t pdu_id;
+       uint8_t rsvd:6;
+       uint8_t packet_type:2;
+       uint16_t params_len;
+       uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_HEADER_LENGTH 7
+
+#else
+#error "Unknown byte order"
+#endif
+
+#define AVRCP_MTU      (AVC_MTU - AVC_HEADER_LENGTH)
+#define AVRCP_PDU_MTU  (AVRCP_MTU - AVRCP_HEADER_LENGTH)
+
+struct avrcp_browsing_header {
+       uint8_t pdu_id;
+       uint16_t param_len;
+       uint8_t params[0];
+} __attribute__ ((packed));
+#define AVRCP_BROWSING_HEADER_LENGTH 3
+
+struct avrcp_server {
+       struct btd_adapter *adapter;
+       uint32_t tg_record_id;
+       uint32_t ct_record_id;
+       GSList *players;
+       GSList *sessions;
+};
+
+struct pending_pdu {
+       uint8_t pdu_id;
+       GList *attr_ids;
+       uint16_t offset;
+};
+
+struct pending_list_items {
+       GSList *items;
+       uint32_t start;
+       uint32_t end;
+};
+
+struct avrcp_player {
+       struct avrcp_server *server;
+       GSList *sessions;
+       uint16_t id;
+       uint8_t scope;
+       uint64_t uid;
+       uint16_t uid_counter;
+       bool browsed;
+       uint8_t *features;
+       char *path;
+
+       struct pending_list_items *p;
+       char *change_path;
+
+       struct avrcp_player_cb *cb;
+       void *user_data;
+       GDestroyNotify destroy;
+};
+
+struct avrcp_data {
+       struct avrcp_player *player;
+       uint16_t version;
+       int features;
+       GSList *players;
+};
+
+struct avrcp {
+       struct avrcp_server *server;
+       struct avctp *conn;
+       struct btd_device *dev;
+       struct avrcp_data *target;
+       struct avrcp_data *controller;
+
+       const struct passthrough_handler *passthrough_handlers;
+       const struct control_pdu_handler *control_handlers;
+
+       unsigned int passthrough_id;
+       unsigned int control_id;
+       unsigned int browsing_id;
+       unsigned int browsing_timer;
+       uint16_t supported_events;
+       uint16_t registered_events;
+       uint8_t transaction;
+       uint8_t transaction_events[AVRCP_EVENT_LAST + 1];
+       struct pending_pdu *pending_pdu;
+};
+
+struct passthrough_handler {
+       uint8_t op;
+       bool (*func) (struct avrcp *session);
+};
+
+struct control_pdu_handler {
+       uint8_t pdu_id;
+       uint8_t code;
+       uint8_t (*func) (struct avrcp *session, struct avrcp_header *pdu,
+                                                       uint8_t transaction);
+};
+
+static GSList *servers = NULL;
+static unsigned int avctp_id = 0;
+
+/* Company IDs supported by this device */
+static uint32_t company_ids[] = {
+       IEEEID_BTSIG,
+};
+
+static void avrcp_register_notification(struct avrcp *session, uint8_t event);
+
+static sdp_record_t *avrcp_ct_record(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *apseq1, *root;
+       uuid_t root_uuid, l2cap, avctp, avrct, avrctr;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto, *aproto1, *proto[2], *proto1[2];
+       sdp_record_t *record;
+       sdp_data_t *psm[2], *version, *features;
+       uint16_t lp = AVCTP_CONTROL_PSM, ap = AVCTP_BROWSING_PSM;
+       uint16_t avrcp_ver = 0x0105, avctp_ver = 0x0103;
+       uint16_t feat = ( AVRCP_FEATURE_CATEGORY_1 |
+                                               AVRCP_FEATURE_CATEGORY_2 |
+                                               AVRCP_FEATURE_CATEGORY_3 |
+                                               AVRCP_FEATURE_CATEGORY_4 |
+                                               AVRCP_FEATURE_BROWSING);
+
+       record = sdp_record_alloc();
+       if (!record)
+               return NULL;
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       /* Service Class ID List */
+       sdp_uuid16_create(&avrct, AV_REMOTE_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &avrct);
+       sdp_uuid16_create(&avrctr, AV_REMOTE_CONTROLLER_SVCLASS_ID);
+       svclass_id = sdp_list_append(svclass_id, &avrctr);
+       sdp_set_service_classes(record, svclass_id);
+
+       /* Protocol Descriptor List */
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto[0] = sdp_list_append(0, &l2cap);
+       psm[0] = sdp_data_alloc(SDP_UINT16, &lp);
+       proto[0] = sdp_list_append(proto[0], psm[0]);
+       apseq = sdp_list_append(0, proto[0]);
+
+       sdp_uuid16_create(&avctp, AVCTP_UUID);
+       proto[1] = sdp_list_append(0, &avctp);
+       version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
+       proto[1] = sdp_list_append(proto[1], version);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       /* Additional Protocol Descriptor List */
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto1[0] = sdp_list_append(0, &l2cap);
+       psm[1] = sdp_data_alloc(SDP_UINT16, &ap);
+       proto1[0] = sdp_list_append(proto1[0], psm[1]);
+       apseq1 = sdp_list_append(0, proto1[0]);
+
+       sdp_uuid16_create(&avctp, AVCTP_UUID);
+       proto1[1] = sdp_list_append(0, &avctp);
+       proto1[1] = sdp_list_append(proto1[1], version);
+       apseq1 = sdp_list_append(apseq1, proto1[1]);
+
+       aproto1 = sdp_list_append(0, apseq1);
+       sdp_set_add_access_protos(record, aproto1);
+
+       /* Bluetooth Profile Descriptor List */
+       sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+       profile[0].version = avrcp_ver;
+       pfseq = sdp_list_append(0, &profile[0]);
+       sdp_set_profile_descs(record, pfseq);
+
+       features = sdp_data_alloc(SDP_UINT16, &feat);
+       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+       sdp_set_info_attr(record, "AVRCP CT", 0, 0);
+
+       free(psm[0]);
+       free(psm[1]);
+       free(version);
+       sdp_list_free(proto[0], 0);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(proto1[0], 0);
+       sdp_list_free(proto1[1], 0);
+       sdp_list_free(aproto1, 0);
+       sdp_list_free(apseq1, 0);
+       sdp_list_free(pfseq, 0);
+       sdp_list_free(aproto, 0);
+       sdp_list_free(root, 0);
+       sdp_list_free(svclass_id, 0);
+
+       return record;
+}
+
+static sdp_record_t *avrcp_tg_record(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *root, *apseq_browsing;
+       uuid_t root_uuid, l2cap, avctp, avrtg;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto_control, *proto_control[2];
+       sdp_record_t *record;
+       sdp_data_t *psm_control, *version, *features, *psm_browsing;
+       sdp_list_t *aproto_browsing, *proto_browsing[2] = {0};
+       uint16_t lp = AVCTP_CONTROL_PSM;
+       uint16_t lp_browsing = AVCTP_BROWSING_PSM;
+       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_BROWSING |
+                                       AVRCP_FEATURE_PLAYER_SETTINGS );
+
+       record = sdp_record_alloc();
+       if (!record)
+               return NULL;
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       /* Service Class ID List */
+       sdp_uuid16_create(&avrtg, AV_REMOTE_TARGET_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &avrtg);
+       sdp_set_service_classes(record, svclass_id);
+
+       /* Protocol Descriptor List */
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto_control[0] = sdp_list_append(0, &l2cap);
+       psm_control = sdp_data_alloc(SDP_UINT16, &lp);
+       proto_control[0] = sdp_list_append(proto_control[0], psm_control);
+       apseq = sdp_list_append(0, proto_control[0]);
+
+       sdp_uuid16_create(&avctp, AVCTP_UUID);
+       proto_control[1] = sdp_list_append(0, &avctp);
+       version = sdp_data_alloc(SDP_UINT16, &avctp_ver);
+       proto_control[1] = sdp_list_append(proto_control[1], version);
+       apseq = sdp_list_append(apseq, proto_control[1]);
+
+       aproto_control = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto_control);
+       proto_browsing[0] = sdp_list_append(0, &l2cap);
+       psm_browsing = sdp_data_alloc(SDP_UINT16, &lp_browsing);
+       proto_browsing[0] = sdp_list_append(proto_browsing[0], psm_browsing);
+       apseq_browsing = sdp_list_append(0, proto_browsing[0]);
+
+       proto_browsing[1] = sdp_list_append(0, &avctp);
+       proto_browsing[1] = sdp_list_append(proto_browsing[1], version);
+       apseq_browsing = sdp_list_append(apseq_browsing, proto_browsing[1]);
+
+       aproto_browsing = sdp_list_append(0, apseq_browsing);
+       sdp_set_add_access_protos(record, aproto_browsing);
+
+       /* Bluetooth Profile Descriptor List */
+       sdp_uuid16_create(&profile[0].uuid, AV_REMOTE_PROFILE_ID);
+       profile[0].version = avrcp_ver;
+       pfseq = sdp_list_append(0, &profile[0]);
+       sdp_set_profile_descs(record, pfseq);
+
+       features = sdp_data_alloc(SDP_UINT16, &feat);
+       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FEATURES, features);
+
+       sdp_set_info_attr(record, "AVRCP TG", 0, 0);
+
+       free(psm_browsing);
+       sdp_list_free(proto_browsing[0], 0);
+       sdp_list_free(proto_browsing[1], 0);
+       sdp_list_free(apseq_browsing, 0);
+       sdp_list_free(aproto_browsing, 0);
+
+       free(psm_control);
+       free(version);
+       sdp_list_free(proto_control[0], 0);
+       sdp_list_free(proto_control[1], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto_control, 0);
+       sdp_list_free(pfseq, 0);
+       sdp_list_free(root, 0);
+       sdp_list_free(svclass_id, 0);
+
+       return record;
+}
+
+static unsigned int attr_get_max_val(uint8_t attr)
+{
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               return AVRCP_EQUALIZER_ON;
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               return AVRCP_REPEAT_MODE_GROUP;
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+               return AVRCP_SHUFFLE_GROUP;
+       case AVRCP_ATTRIBUTE_SCAN:
+               return AVRCP_SCAN_GROUP;
+       }
+
+       return 0;
+}
+
+static const char *battery_status_to_str(uint8_t status)
+{
+       switch (status) {
+       case AVRCP_BATTERY_STATUS_NORMAL:
+               return "normal";
+       case AVRCP_BATTERY_STATUS_WARNING:
+               return "warning";
+       case AVRCP_BATTERY_STATUS_CRITICAL:
+               return "critical";
+       case AVRCP_BATTERY_STATUS_EXTERNAL:
+               return "external";
+       case AVRCP_BATTERY_STATUS_FULL_CHARGE:
+               return "fullcharge";
+       }
+
+       return NULL;
+}
+
+/*
+ * get_company_id:
+ *
+ * Get three-byte Company_ID from incoming AVRCP message
+ */
+static uint32_t get_company_id(const uint8_t cid[3])
+{
+       return cid[0] << 16 | cid[1] << 8 | cid[2];
+}
+
+/*
+ * set_company_id:
+ *
+ * Set three-byte Company_ID into outgoing AVRCP message
+ */
+static void set_company_id(uint8_t cid[3], const uint32_t cid_in)
+{
+       cid[0] = cid_in >> 16;
+       cid[1] = cid_in >> 8;
+       cid[2] = cid_in;
+}
+
+static const char *attr_to_str(uint8_t attr)
+{
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               return "Equalizer";
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               return "Repeat";
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+               return "Shuffle";
+       case AVRCP_ATTRIBUTE_SCAN:
+               return "Scan";
+       }
+
+       return NULL;
+}
+
+static int attrval_to_val(uint8_t attr, const char *value)
+{
+       int ret;
+
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               if (!strcmp(value, "off"))
+                       ret = AVRCP_EQUALIZER_OFF;
+               else if (!strcmp(value, "on"))
+                       ret = AVRCP_EQUALIZER_ON;
+               else
+                       ret = -EINVAL;
+
+               return ret;
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               if (!strcmp(value, "off"))
+                       ret = AVRCP_REPEAT_MODE_OFF;
+               else if (!strcmp(value, "singletrack"))
+                       ret = AVRCP_REPEAT_MODE_SINGLE;
+               else if (!strcmp(value, "alltracks"))
+                       ret = AVRCP_REPEAT_MODE_ALL;
+               else if (!strcmp(value, "group"))
+                       ret = AVRCP_REPEAT_MODE_GROUP;
+               else
+                       ret = -EINVAL;
+
+               return ret;
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+               if (!strcmp(value, "off"))
+                       ret = AVRCP_SHUFFLE_OFF;
+               else if (!strcmp(value, "alltracks"))
+                       ret = AVRCP_SHUFFLE_ALL;
+               else if (!strcmp(value, "group"))
+                       ret = AVRCP_SHUFFLE_GROUP;
+               else
+                       ret = -EINVAL;
+
+               return ret;
+       case AVRCP_ATTRIBUTE_SCAN:
+               if (!strcmp(value, "off"))
+                       ret = AVRCP_SCAN_OFF;
+               else if (!strcmp(value, "alltracks"))
+                       ret = AVRCP_SCAN_ALL;
+               else if (!strcmp(value, "group"))
+                       ret = AVRCP_SCAN_GROUP;
+               else
+                       ret = -EINVAL;
+
+               return ret;
+       }
+
+       return -EINVAL;
+}
+
+static int attr_to_val(const char *str)
+{
+       if (!strcasecmp(str, "Equalizer"))
+               return AVRCP_ATTRIBUTE_EQUALIZER;
+       else if (!strcasecmp(str, "Repeat"))
+               return AVRCP_ATTRIBUTE_REPEAT_MODE;
+       else if (!strcasecmp(str, "Shuffle"))
+               return AVRCP_ATTRIBUTE_SHUFFLE;
+       else if (!strcasecmp(str, "Scan"))
+               return AVRCP_ATTRIBUTE_SCAN;
+
+       return -EINVAL;
+}
+
+static int player_get_setting(struct avrcp_player *player, uint8_t id)
+{
+       const char *key;
+       const char *value;
+
+       if (player == NULL)
+               return -ENOENT;
+
+       key = attr_to_str(id);
+       if (key == NULL)
+               return -EINVAL;
+
+       value = player->cb->get_setting(key, player->user_data);
+       if (value == NULL)
+               return -EINVAL;
+
+       return attrval_to_val(id, value);
+}
+
+static int play_status_to_val(const char *status)
+{
+       if (!strcasecmp(status, "stopped"))
+               return AVRCP_PLAY_STATUS_STOPPED;
+       else if (!strcasecmp(status, "playing"))
+               return AVRCP_PLAY_STATUS_PLAYING;
+       else if (!strcasecmp(status, "paused"))
+               return AVRCP_PLAY_STATUS_PAUSED;
+       else if (!strcasecmp(status, "forward-seek"))
+               return AVRCP_PLAY_STATUS_FWD_SEEK;
+       else if (!strcasecmp(status, "reverse-seek"))
+               return AVRCP_PLAY_STATUS_REV_SEEK;
+       else if (!strcasecmp(status, "error"))
+               return AVRCP_PLAY_STATUS_ERROR;
+
+       return -EINVAL;
+}
+
+void avrcp_player_event(struct avrcp_player *player, uint8_t id,
+                                                       const void *data)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 9];
+       struct avrcp_header *pdu = (void *) buf;
+       uint16_t size;
+       GSList *l;
+       int attr;
+       int val;
+
+       if (player->sessions == NULL)
+               return;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+       pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
+       pdu->params[0] = id;
+
+       DBG("id=%u", id);
+
+       switch (id) {
+       case AVRCP_EVENT_STATUS_CHANGED:
+               size = 2;
+               pdu->params[1] = play_status_to_val(data);
+
+               break;
+       case AVRCP_EVENT_TRACK_CHANGED:
+               size = 9;
+               memcpy(&pdu->params[1], data, sizeof(uint64_t));
+
+               break;
+       case AVRCP_EVENT_TRACK_REACHED_END:
+       case AVRCP_EVENT_TRACK_REACHED_START:
+               size = 1;
+               break;
+       case AVRCP_EVENT_SETTINGS_CHANGED:
+               size = 2;
+               pdu->params[1] = 1;
+
+               attr = attr_to_val(data);
+               if (attr < 0)
+                       return;
+
+               val = player_get_setting(player, attr);
+               if (val < 0)
+                       return;
+
+               pdu->params[size++] = attr;
+               pdu->params[size++] = val;
+               break;
+       default:
+               error("Unknown event %u", id);
+               return;
+       }
+
+       pdu->params_len = htons(size);
+
+       for (l = player->sessions; l; l = l->next) {
+               struct avrcp *session = l->data;
+               int err;
+
+               if (!(session->registered_events & (1 << id)))
+                       continue;
+
+               err = avctp_send_vendordep(session->conn,
+                                       session->transaction_events[id],
+                                       AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
+                                       buf, size + AVRCP_HEADER_LENGTH);
+               if (err < 0)
+                       continue;
+
+               /* Unregister event as per AVRCP 1.3 spec, section 5.4.2 */
+               session->registered_events ^= 1 << id;
+       }
+
+       return;
+}
+
+static const char *metadata_to_str(uint32_t id)
+{
+       switch (id) {
+       case AVRCP_MEDIA_ATTRIBUTE_TITLE:
+               return "Title";
+       case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
+               return "Artist";
+       case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
+               return "Album";
+       case AVRCP_MEDIA_ATTRIBUTE_GENRE:
+               return "Genre";
+       case AVRCP_MEDIA_ATTRIBUTE_TRACK:
+               return "TrackNumber";
+       case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS:
+               return "NumberOfTracks";
+       case AVRCP_MEDIA_ATTRIBUTE_DURATION:
+               return "Duration";
+       }
+
+       return NULL;
+}
+
+static const char *player_get_metadata(struct avrcp_player *player,
+                                                               uint32_t id)
+{
+       const char *key;
+
+       key = metadata_to_str(id);
+       if (key == NULL)
+               return NULL;
+
+       if (player != NULL)
+               return player->cb->get_metadata(key, player->user_data);
+
+       if (id == AVRCP_MEDIA_ATTRIBUTE_TITLE)
+               return "";
+
+       return NULL;
+}
+
+static uint16_t player_write_media_attribute(struct avrcp_player *player,
+                                               uint32_t id, uint8_t *buf,
+                                               uint16_t *pos,
+                                               uint16_t *offset)
+{
+       uint16_t len;
+       uint16_t attr_len;
+       const char *value = NULL;
+
+       DBG("%u", id);
+
+       value = player_get_metadata(player, id);
+       if (value == NULL) {
+               *offset = 0;
+               return 0;
+       }
+
+       attr_len = strlen(value);
+       value = ((char *) value) + *offset;
+       len = attr_len - *offset;
+
+       if (len > AVRCP_PDU_MTU - *pos) {
+               len = AVRCP_PDU_MTU - *pos;
+               *offset += len;
+       } else {
+               *offset = 0;
+       }
+
+       memcpy(&buf[*pos], value, len);
+       *pos += len;
+
+       return attr_len;
+}
+
+static GList *player_fill_media_attribute(struct avrcp_player *player,
+                                       GList *attr_ids, uint8_t *buf,
+                                       uint16_t *pos, uint16_t *offset)
+{
+       struct media_attribute_header {
+               uint32_t id;
+               uint16_t charset;
+               uint16_t len;
+       } *hdr = NULL;
+       GList *l;
+
+       for (l = attr_ids; l != NULL; l = g_list_delete_link(l, l)) {
+               uint32_t attr = GPOINTER_TO_UINT(l->data);
+               uint16_t attr_len;
+
+               if (*offset == 0) {
+                       if (*pos + sizeof(*hdr) >= AVRCP_PDU_MTU)
+                               break;
+
+                       hdr = (void *) &buf[*pos];
+                       hdr->id = htonl(attr);
+                       /* Always use UTF-8 */
+                       hdr->charset = htons(AVRCP_CHARSET_UTF8);
+                       *pos += sizeof(*hdr);
+               }
+
+               attr_len = player_write_media_attribute(player, attr, buf,
+                                                               pos, offset);
+
+               if (hdr != NULL)
+                       hdr->len = htons(attr_len);
+
+               if (*offset > 0)
+                       break;
+       }
+
+       return l;
+}
+
+static struct pending_pdu *pending_pdu_new(uint8_t pdu_id, GList *attr_ids,
+                                                       unsigned int offset)
+{
+       struct pending_pdu *pending = g_new(struct pending_pdu, 1);
+
+       pending->pdu_id = pdu_id;
+       pending->attr_ids = attr_ids;
+       pending->offset = offset;
+
+       return pending;
+}
+
+static gboolean session_abort_pending_pdu(struct avrcp *session)
+{
+       if (session->pending_pdu == NULL)
+               return FALSE;
+
+       g_list_free(session->pending_pdu->attr_ids);
+       g_free(session->pending_pdu);
+       session->pending_pdu = NULL;
+
+       return TRUE;
+}
+
+static const char *attrval_to_str(uint8_t attr, uint8_t value)
+{
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               switch (value) {
+               case AVRCP_EQUALIZER_ON:
+                       return "on";
+               case AVRCP_EQUALIZER_OFF:
+                       return "off";
+               }
+
+               break;
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               switch (value) {
+               case AVRCP_REPEAT_MODE_OFF:
+                       return "off";
+               case AVRCP_REPEAT_MODE_SINGLE:
+                       return "singletrack";
+               case AVRCP_REPEAT_MODE_ALL:
+                       return "alltracks";
+               case AVRCP_REPEAT_MODE_GROUP:
+                       return "group";
+               }
+
+               break;
+       /* Shuffle and scan have the same values */
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+       case AVRCP_ATTRIBUTE_SCAN:
+               switch (value) {
+               case AVRCP_SCAN_OFF:
+                       return "off";
+               case AVRCP_SCAN_ALL:
+                       return "alltracks";
+               case AVRCP_SCAN_GROUP:
+                       return "group";
+               }
+
+               break;
+       }
+
+       return NULL;
+}
+
+static int player_set_setting(struct avrcp_player *player, uint8_t id,
+                                                               uint8_t val)
+{
+       const char *key, *value;
+
+       key = attr_to_str(id);
+       if (key == NULL)
+               return -EINVAL;
+
+       value = attrval_to_str(id, val);
+       if (value == NULL)
+               return -EINVAL;
+
+       if (player == NULL)
+               return -ENOENT;
+
+       return player->cb->set_setting(key, value, player->user_data);
+}
+
+static uint8_t avrcp_handle_get_capabilities(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       uint16_t len = ntohs(pdu->params_len);
+       unsigned int i;
+
+       if (len != 1)
+               goto err;
+
+       DBG("id=%u", pdu->params[0]);
+
+       switch (pdu->params[0]) {
+       case CAP_COMPANY_ID:
+               for (i = 0; i < G_N_ELEMENTS(company_ids); i++) {
+                       set_company_id(&pdu->params[2 + i * 3],
+                                                       company_ids[i]);
+               }
+
+               pdu->params_len = htons(2 + (3 * G_N_ELEMENTS(company_ids)));
+               pdu->params[1] = G_N_ELEMENTS(company_ids);
+
+               return AVC_CTYPE_STABLE;
+       case CAP_EVENTS_SUPPORTED:
+               for (i = 1; i <= AVRCP_EVENT_LAST; i++) {
+                       if (session->supported_events & (1 << i)) {
+                               pdu->params[1]++;
+                               pdu->params[pdu->params[1] + 1] = i;
+                       }
+               }
+
+               pdu->params_len = htons(2 + pdu->params[1]);
+               return AVC_CTYPE_STABLE;
+       }
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_list_player_attributes(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       unsigned int i;
+
+       if (len != 0) {
+               pdu->params_len = htons(1);
+               pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+               return AVC_CTYPE_REJECTED;
+       }
+
+       if (!player)
+               goto done;
+
+       for (i = 1; i <= AVRCP_ATTRIBUTE_SCAN; i++) {
+               if (player_get_setting(player, i) < 0)
+                       continue;
+
+               len++;
+               pdu->params[len] = i;
+       }
+
+done:
+       pdu->params[0] = len;
+       pdu->params_len = htons(len + 1);
+
+       return AVC_CTYPE_STABLE;
+}
+
+static uint8_t avrcp_handle_list_player_values(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       unsigned int i;
+
+       if (len != 1)
+               goto err;
+
+       if (player_get_setting(player, pdu->params[0]) < 0)
+               goto err;
+
+       len = attr_get_max_val(pdu->params[0]);
+
+       for (i = 1; i <= len; i++)
+               pdu->params[i] = i;
+
+       pdu->params[0] = len;
+       pdu->params_len = htons(len + 1);
+
+       return AVC_CTYPE_STABLE;
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint32_t str_to_metadata(const char *str)
+{
+       if (strcasecmp(str, "Title") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_TITLE;
+       else if (strcasecmp(str, "Artist") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_ARTIST;
+       else if (strcasecmp(str, "Album") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_ALBUM;
+       else if (strcasecmp(str, "Genre") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_GENRE;
+       else if (strcasecmp(str, "TrackNumber") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_TRACK;
+       else if (strcasecmp(str, "NumberOfTracks") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_N_TRACKS;
+       else if (strcasecmp(str, "Duration") == 0)
+               return AVRCP_MEDIA_ATTRIBUTE_DURATION;
+
+       return 0;
+}
+
+static GList *player_list_metadata(struct avrcp_player *player)
+{
+       GList *l, *attrs = NULL;
+
+       if (player == NULL)
+               return g_list_prepend(NULL,
+                               GUINT_TO_POINTER(AVRCP_MEDIA_ATTRIBUTE_TITLE));
+
+       l = player->cb->list_metadata(player->user_data);
+       for (; l; l = l->next) {
+               const char *key = l->data;
+
+               attrs = g_list_append(attrs,
+                                       GUINT_TO_POINTER(str_to_metadata(key)));
+       }
+
+       return attrs;
+}
+
+static uint8_t avrcp_handle_get_element_attributes(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       uint64_t identifier = bt_get_le64(&pdu->params[0]);
+       uint16_t pos;
+       uint8_t nattr;
+       GList *attr_ids;
+       uint16_t offset;
+
+       if (len < 9 || identifier != 0)
+               goto err;
+
+       nattr = pdu->params[8];
+
+       if (len < nattr * sizeof(uint32_t) + 1)
+               goto err;
+
+       if (!nattr) {
+               /*
+                * Return all available information, at least
+                * title must be returned if there's a track selected.
+                */
+               attr_ids = player_list_metadata(player);
+               len = g_list_length(attr_ids);
+       } else {
+               unsigned int i;
+               for (i = 0, len = 0, attr_ids = NULL; i < nattr; i++) {
+                       uint32_t id;
+
+                       id = bt_get_be32(&pdu->params[9] + (i * sizeof(id)));
+
+                       /* Don't add invalid attributes */
+                       if (id == AVRCP_MEDIA_ATTRIBUTE_ILLEGAL ||
+                                       id > AVRCP_MEDIA_ATTRIBUTE_LAST)
+                               continue;
+
+                       len++;
+                       attr_ids = g_list_prepend(attr_ids,
+                                                       GUINT_TO_POINTER(id));
+               }
+
+               attr_ids = g_list_reverse(attr_ids);
+       }
+
+       if (!len)
+               goto err;
+
+       session_abort_pending_pdu(session);
+       pos = 1;
+       offset = 0;
+       attr_ids = player_fill_media_attribute(player, attr_ids, pdu->params,
+                                                               &pos, &offset);
+
+       if (attr_ids != NULL) {
+               session->pending_pdu = pending_pdu_new(pdu->pdu_id, attr_ids,
+                                                               offset);
+               pdu->packet_type = AVRCP_PACKET_TYPE_START;
+       }
+
+       pdu->params[0] = len;
+       pdu->params_len = htons(pos);
+
+       return AVC_CTYPE_STABLE;
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_get_current_player_value(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       uint8_t *settings;
+       unsigned int i;
+
+       if (len <= 1 || pdu->params[0] != len - 1)
+               goto err;
+
+       /*
+        * Save a copy of requested settings because we can override them
+        * while responding
+        */
+       settings = g_memdup(&pdu->params[1], pdu->params[0]);
+       len = 0;
+
+       /*
+        * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs
+        * and send a response with the existent ones. Only if all IDs are
+        * non-existent we should send an error.
+        */
+       for (i = 0; i < pdu->params[0]; i++) {
+               int val;
+
+               if (settings[i] < AVRCP_ATTRIBUTE_EQUALIZER ||
+                                       settings[i] > AVRCP_ATTRIBUTE_SCAN) {
+                       DBG("Ignoring %u", settings[i]);
+                       continue;
+               }
+
+               val = player_get_setting(player, settings[i]);
+               if (val < 0)
+                       continue;
+
+               pdu->params[++len] = settings[i];
+               pdu->params[++len] = val;
+       }
+
+       g_free(settings);
+
+       if (len) {
+               pdu->params[0] = len / 2;
+               pdu->params_len = htons(len + 1);
+
+               return AVC_CTYPE_STABLE;
+       }
+
+       error("No valid attributes in request");
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_set_player_value(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       unsigned int i;
+       uint8_t *param;
+
+       if (len < 3 || len > 2 * pdu->params[0] + 1U || player == NULL)
+               goto err;
+
+       /*
+        * From sec. 5.7 of AVRCP 1.3 spec, we should igore non-existent IDs
+        * and set the existent ones. Sec. 5.2.4 is not clear however how to
+        * indicate that a certain ID was not accepted. If at least one
+        * attribute is valid, we respond with no parameters. Otherwise an
+        * AVRCP_STATUS_INVALID_PARAM is sent.
+        */
+       for (len = 0, i = 0, param = &pdu->params[1]; i < pdu->params[0];
+                                                       i++, param += 2) {
+               if (player_set_setting(player, param[0], param[1]) < 0)
+                       continue;
+
+               len++;
+       }
+
+       if (len) {
+               pdu->params_len = 0;
+
+               return AVC_CTYPE_ACCEPTED;
+       }
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_displayable_charset(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       uint16_t len = ntohs(pdu->params_len);
+
+       if (len < 3) {
+               pdu->params_len = htons(1);
+               pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+               return AVC_CTYPE_REJECTED;
+       }
+
+       /*
+        * We acknowledge the commands, but we always use UTF-8 for
+        * encoding since CT is obliged to support it.
+        */
+       pdu->params_len = 0;
+       return AVC_CTYPE_STABLE;
+}
+
+static uint8_t avrcp_handle_ct_battery_status(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       uint16_t len = ntohs(pdu->params_len);
+       const char *valstr;
+
+       if (len != 1)
+               goto err;
+
+       valstr = battery_status_to_str(pdu->params[0]);
+       if (valstr == NULL)
+               goto err;
+
+       pdu->params_len = 0;
+
+       return AVC_CTYPE_STABLE;
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint32_t player_get_position(struct avrcp_player *player)
+{
+       if (player == NULL)
+               return 0;
+
+       return player->cb->get_position(player->user_data);
+}
+
+static uint32_t player_get_duration(struct avrcp_player *player)
+{
+       uint32_t num;
+
+       if (player == NULL)
+               return UINT32_MAX;
+
+       num = player->cb->get_duration(player->user_data);
+       if (num == 0)
+               return UINT32_MAX;
+
+       return num;
+}
+
+static uint8_t player_get_status(struct avrcp_player *player)
+{
+       const char *value;
+
+       if (player == NULL)
+               return AVRCP_PLAY_STATUS_STOPPED;
+
+       value = player->cb->get_status(player->user_data);
+       if (value == NULL)
+               return AVRCP_PLAY_STATUS_STOPPED;
+
+       return play_status_to_val(value);
+}
+
+static uint8_t avrcp_handle_get_play_status(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       uint32_t position;
+       uint32_t duration;
+
+       if (len != 0) {
+               pdu->params_len = htons(1);
+               pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+               return AVC_CTYPE_REJECTED;
+       }
+
+       position = player_get_position(player);
+       duration = player_get_duration(player);
+
+       position = htonl(position);
+       duration = htonl(duration);
+
+       memcpy(&pdu->params[0], &duration, 4);
+       memcpy(&pdu->params[4], &position, 4);
+       pdu->params[8] = player_get_status(player);
+
+       pdu->params_len = htons(9);
+
+       return AVC_CTYPE_STABLE;
+}
+
+static uint64_t player_get_uid(struct avrcp_player *player)
+{
+       if (player == NULL)
+               return UINT64_MAX;
+
+       return player->cb->get_uid(player->user_data);
+}
+
+static GList *player_list_settings(struct avrcp_player *player)
+{
+       if (player == NULL)
+               return NULL;
+
+       return player->cb->list_settings(player->user_data);
+}
+
+static bool avrcp_handle_play(struct avrcp *session)
+{
+       struct avrcp_player *player = session->target->player;
+
+       if (player == NULL)
+               return false;
+
+       return player->cb->play(player->user_data);
+}
+
+static bool avrcp_handle_stop(struct avrcp *session)
+{
+       struct avrcp_player *player = session->target->player;
+
+       if (player == NULL)
+               return false;
+
+       return player->cb->stop(player->user_data);
+}
+
+static bool avrcp_handle_pause(struct avrcp *session)
+{
+       struct avrcp_player *player = session->target->player;
+
+       if (player == NULL)
+               return false;
+
+       return player->cb->pause(player->user_data);
+}
+
+static bool avrcp_handle_next(struct avrcp *session)
+{
+       struct avrcp_player *player = session->target->player;
+
+       if (player == NULL)
+               return false;
+
+       return player->cb->next(player->user_data);
+}
+
+static bool avrcp_handle_previous(struct avrcp *session)
+{
+       struct avrcp_player *player = session->target->player;
+
+       if (player == NULL)
+               return false;
+
+       return player->cb->previous(player->user_data);
+}
+
+static const struct passthrough_handler passthrough_handlers[] = {
+               { AVC_PLAY, avrcp_handle_play },
+               { AVC_STOP, avrcp_handle_stop },
+               { AVC_PAUSE, avrcp_handle_pause },
+               { AVC_FORWARD, avrcp_handle_next },
+               { AVC_BACKWARD, avrcp_handle_previous },
+               { },
+};
+
+static bool handle_passthrough(struct avctp *conn, uint8_t op, bool pressed,
+                                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       const struct passthrough_handler *handler;
+
+       for (handler = session->passthrough_handlers; handler->func;
+                                                               handler++) {
+               if (handler->op == op)
+                       break;
+       }
+
+       if (handler->func == NULL)
+               return false;
+
+       /* Do not trigger handler on release */
+       if (!pressed)
+               return true;
+
+       return handler->func(session);
+}
+
+static uint8_t avrcp_handle_register_notification(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       struct btd_device *dev = session->dev;
+       uint16_t len = ntohs(pdu->params_len);
+       uint64_t uid;
+       GList *settings;
+
+       /*
+        * 1 byte for EventID, 4 bytes for Playback interval but the latest
+        * one is applicable only for EVENT_PLAYBACK_POS_CHANGED. See AVRCP
+        * 1.3 spec, section 5.4.2.
+        */
+       if (len != 5)
+               goto err;
+
+       /* Check if event is supported otherwise reject */
+       if (!(session->supported_events & (1 << pdu->params[0])))
+               goto err;
+
+       switch (pdu->params[0]) {
+       case AVRCP_EVENT_STATUS_CHANGED:
+               len = 2;
+               pdu->params[1] = player_get_status(player);
+
+               break;
+       case AVRCP_EVENT_TRACK_CHANGED:
+               len = 9;
+               uid = player_get_uid(session->target->player);
+               memcpy(&pdu->params[1], &uid, sizeof(uint64_t));
+
+               break;
+       case AVRCP_EVENT_TRACK_REACHED_END:
+       case AVRCP_EVENT_TRACK_REACHED_START:
+               len = 1;
+               break;
+       case AVRCP_EVENT_SETTINGS_CHANGED:
+               len = 1;
+               settings = player_list_settings(player);
+
+               pdu->params[len++] = g_list_length(settings);
+               for (; settings; settings = settings->next) {
+                       const char *key = settings->data;
+                       int attr;
+                       int val;
+
+                       attr = attr_to_val(key);
+                       if (attr < 0)
+                               continue;
+
+                       val = player_get_setting(player, attr);
+                       if (val < 0)
+                               continue;
+
+                       pdu->params[len++] = attr;
+                       pdu->params[len++] = val;
+               }
+
+               break;
+       case AVRCP_EVENT_VOLUME_CHANGED:
+               pdu->params[1] = media_transport_get_device_volume(dev);
+               if (pdu->params[1] > 127)
+                       goto err;
+
+               len = 2;
+
+               break;
+       default:
+               /* All other events are not supported yet */
+               goto err;
+       }
+
+       /* Register event and save the transaction used */
+       session->registered_events |= (1 << pdu->params[0]);
+       session->transaction_events[pdu->params[0]] = transaction;
+
+       pdu->params_len = htons(len);
+
+       return AVC_CTYPE_INTERIM;
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_request_continuing(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->target->player;
+       uint16_t len = ntohs(pdu->params_len);
+       struct pending_pdu *pending;
+
+       if (len != 1 || session->pending_pdu == NULL)
+               goto err;
+
+       pending = session->pending_pdu;
+
+       if (pending->pdu_id != pdu->params[0])
+               goto err;
+
+
+       len = 0;
+       pending->attr_ids = player_fill_media_attribute(player,
+                                                       pending->attr_ids,
+                                                       pdu->params, &len,
+                                                       &pending->offset);
+       pdu->pdu_id = pending->pdu_id;
+
+       if (pending->attr_ids == NULL) {
+               g_free(session->pending_pdu);
+               session->pending_pdu = NULL;
+               pdu->packet_type = AVRCP_PACKET_TYPE_END;
+       } else {
+               pdu->packet_type = AVRCP_PACKET_TYPE_CONTINUING;
+       }
+
+       pdu->params_len = htons(len);
+
+       return AVC_CTYPE_STABLE;
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_abort_continuing(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       uint16_t len = ntohs(pdu->params_len);
+       struct pending_pdu *pending;
+
+       if (len != 1 || session->pending_pdu == NULL)
+               goto err;
+
+       pending = session->pending_pdu;
+
+       if (pending->pdu_id != pdu->params[0])
+               goto err;
+
+       session_abort_pending_pdu(session);
+       pdu->params_len = 0;
+
+       return AVC_CTYPE_ACCEPTED;
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static uint8_t avrcp_handle_set_absolute_volume(struct avrcp *session,
+                                               struct avrcp_header *pdu,
+                                               uint8_t transaction)
+{
+       struct avrcp_player *player = session->controller->player;
+       uint16_t len = ntohs(pdu->params_len);
+       uint8_t volume;
+
+       if (len != 1)
+               goto err;
+
+       volume = pdu->params[0] & 0x7F;
+       if (volume > 127)
+               goto err;
+
+       if (!player)
+               goto err;
+
+       media_transport_update_device_volume(session->dev, pdu->params[0]);
+
+       return AVC_CTYPE_ACCEPTED;
+
+err:
+       pdu->params_len = htons(1);
+       pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+       return AVC_CTYPE_REJECTED;
+}
+
+static const struct control_pdu_handler control_handlers[] = {
+               { AVRCP_GET_CAPABILITIES, AVC_CTYPE_STATUS,
+                                       avrcp_handle_get_capabilities },
+               { AVRCP_LIST_PLAYER_ATTRIBUTES, AVC_CTYPE_STATUS,
+                                       avrcp_handle_list_player_attributes },
+               { AVRCP_LIST_PLAYER_VALUES, AVC_CTYPE_STATUS,
+                                       avrcp_handle_list_player_values },
+               { AVRCP_GET_ELEMENT_ATTRIBUTES, AVC_CTYPE_STATUS,
+                                       avrcp_handle_get_element_attributes },
+               { AVRCP_GET_CURRENT_PLAYER_VALUE, AVC_CTYPE_STATUS,
+                                       avrcp_handle_get_current_player_value },
+               { AVRCP_SET_PLAYER_VALUE, AVC_CTYPE_CONTROL,
+                                       avrcp_handle_set_player_value },
+               { AVRCP_GET_PLAYER_ATTRIBUTE_TEXT, AVC_CTYPE_STATUS,
+                                       NULL },
+               { AVRCP_GET_PLAYER_VALUE_TEXT, AVC_CTYPE_STATUS,
+                                       NULL },
+               { AVRCP_DISPLAYABLE_CHARSET, AVC_CTYPE_STATUS,
+                                       avrcp_handle_displayable_charset },
+               { AVRCP_CT_BATTERY_STATUS, AVC_CTYPE_STATUS,
+                                       avrcp_handle_ct_battery_status },
+               { AVRCP_GET_PLAY_STATUS, AVC_CTYPE_STATUS,
+                                       avrcp_handle_get_play_status },
+               { AVRCP_REGISTER_NOTIFICATION, AVC_CTYPE_NOTIFY,
+                                       avrcp_handle_register_notification },
+               { AVRCP_SET_ABSOLUTE_VOLUME, AVC_CTYPE_CONTROL,
+                                       avrcp_handle_set_absolute_volume },
+               { AVRCP_REQUEST_CONTINUING, AVC_CTYPE_CONTROL,
+                                       avrcp_handle_request_continuing },
+               { AVRCP_ABORT_CONTINUING, AVC_CTYPE_CONTROL,
+                                       avrcp_handle_abort_continuing },
+               { },
+};
+
+/* handle vendordep pdu inside an avctp packet */
+static size_t handle_vendordep_pdu(struct avctp *conn, uint8_t transaction,
+                                       uint8_t *code, uint8_t *subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       const struct control_pdu_handler *handler;
+       struct avrcp_header *pdu = (void *) operands;
+       uint32_t company_id = get_company_id(pdu->company_id);
+
+       if (company_id != IEEEID_BTSIG) {
+               *code = AVC_CTYPE_NOT_IMPLEMENTED;
+               return 0;
+       }
+
+       DBG("AVRCP PDU 0x%02X, company 0x%06X len 0x%04X",
+                       pdu->pdu_id, company_id, pdu->params_len);
+
+       pdu->packet_type = 0;
+       pdu->rsvd = 0;
+
+       if (operand_count < AVRCP_HEADER_LENGTH) {
+               pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
+               goto err_metadata;
+       }
+
+       for (handler = session->control_handlers; handler->pdu_id; handler++) {
+               if (handler->pdu_id == pdu->pdu_id)
+                       break;
+       }
+
+       if (!handler || handler->code != *code) {
+               pdu->params[0] = AVRCP_STATUS_INVALID_COMMAND;
+               goto err_metadata;
+       }
+
+       if (!handler->func) {
+               pdu->params[0] = AVRCP_STATUS_INVALID_PARAM;
+               goto err_metadata;
+       }
+
+       *code = handler->func(session, pdu, transaction);
+
+       if (*code != AVC_CTYPE_REJECTED &&
+                               pdu->pdu_id != AVRCP_GET_ELEMENT_ATTRIBUTES &&
+                               pdu->pdu_id != AVRCP_REQUEST_CONTINUING &&
+                               pdu->pdu_id != AVRCP_ABORT_CONTINUING)
+               session_abort_pending_pdu(session);
+
+       return AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+err_metadata:
+       pdu->params_len = htons(1);
+       *code = AVC_CTYPE_REJECTED;
+
+       return AVRCP_HEADER_LENGTH + 1;
+}
+
+static struct browsing_pdu_handler {
+       uint8_t pdu_id;
+       void (*func) (struct avrcp *session, struct avrcp_browsing_header *pdu,
+                                                       uint8_t transaction);
+} browsing_handlers[] = {
+               { },
+};
+
+size_t avrcp_browsing_general_reject(uint8_t *operands)
+{
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       uint8_t status;
+
+       pdu->pdu_id = AVRCP_GENERAL_REJECT;
+       status = AVRCP_STATUS_INVALID_COMMAND;
+
+       pdu->param_len = htons(sizeof(status));
+       memcpy(pdu->params, &status, (sizeof(status)));
+       return AVRCP_BROWSING_HEADER_LENGTH + sizeof(status);
+}
+
+static size_t handle_browsing_pdu(struct avctp *conn,
+                                       uint8_t transaction, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct browsing_pdu_handler *handler;
+       struct avrcp_browsing_header *pdu = (void *) operands;
+
+       DBG("AVRCP Browsing PDU 0x%02X, len 0x%04X", pdu->pdu_id,
+                                                       pdu->param_len);
+
+       for (handler = browsing_handlers; handler->pdu_id; handler++) {
+               if (handler->pdu_id == pdu->pdu_id)
+                       break;
+       }
+
+       if (handler == NULL || handler->func == NULL)
+               return avrcp_browsing_general_reject(operands);
+
+       session->transaction = transaction;
+       handler->func(session, pdu, transaction);
+       return AVRCP_BROWSING_HEADER_LENGTH + ntohs(pdu->param_len);
+}
+
+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] = AVRCP_STATUS_INTERNAL_ERROR;
+
+       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, struct btd_adapter *a)
+{
+       for (; list; list = list->next) {
+               struct avrcp_server *server = list->data;
+
+               if (server->adapter == a)
+                       return server;
+       }
+
+       return NULL;
+}
+
+static const char *status_to_string(uint8_t status)
+{
+       switch (status) {
+       case AVRCP_PLAY_STATUS_STOPPED:
+               return "stopped";
+       case AVRCP_PLAY_STATUS_PLAYING:
+               return "playing";
+       case AVRCP_PLAY_STATUS_PAUSED:
+               return "paused";
+       case AVRCP_PLAY_STATUS_FWD_SEEK:
+               return "forward-seek";
+       case AVRCP_PLAY_STATUS_REV_SEEK:
+               return "reverse-seek";
+       case AVRCP_PLAY_STATUS_ERROR:
+               return "error";
+       default:
+               return NULL;
+       }
+}
+
+static gboolean avrcp_get_play_status_rsp(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint32_t duration;
+       uint32_t position;
+       uint8_t status;
+
+       if (pdu == NULL || code == AVC_CTYPE_REJECTED ||
+                                               ntohs(pdu->params_len) != 9)
+               return FALSE;
+
+       memcpy(&duration, pdu->params, sizeof(uint32_t));
+       duration = ntohl(duration);
+       media_player_set_duration(mp, duration);
+
+       memcpy(&position, pdu->params + 4, sizeof(uint32_t));
+       position = ntohl(position);
+       media_player_set_position(mp, position);
+
+       memcpy(&status, pdu->params + 8, sizeof(uint8_t));
+       media_player_set_status(mp, status_to_string(status));
+
+       return FALSE;
+}
+
+static void avrcp_get_play_status(struct avrcp *session)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH];
+       struct avrcp_header *pdu = (void *) buf;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_GET_PLAY_STATUS;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+                                       avrcp_get_play_status_rsp,
+                                       session);
+}
+
+static const char *status_to_str(uint8_t status)
+{
+       switch (status) {
+       case AVRCP_STATUS_INVALID_COMMAND:
+               return "Invalid Command";
+       case AVRCP_STATUS_INVALID_PARAM:
+               return "Invalid Parameter";
+       case AVRCP_STATUS_INTERNAL_ERROR:
+               return "Internal Error";
+       case AVRCP_STATUS_SUCCESS:
+               return "Success";
+       default:
+               return "Unknown";
+       }
+}
+
+static gboolean avrcp_player_value_rsp(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t count;
+       int i;
+
+       if (pdu == NULL) {
+               media_player_set_setting(mp, "Error", "Timeout");
+               return FALSE;
+       }
+
+       if (code == AVC_CTYPE_REJECTED) {
+               media_player_set_setting(mp, "Error",
+                                       status_to_str(pdu->params[0]));
+               return FALSE;
+       }
+
+       count = pdu->params[0];
+
+       if (pdu->params_len < count * 2)
+               return FALSE;
+
+       for (i = 1; count > 0; count--, i += 2) {
+               const char *key;
+               const char *value;
+
+               key = attr_to_str(pdu->params[i]);
+               if (key == NULL)
+                       continue;
+
+               value = attrval_to_str(pdu->params[i], pdu->params[i + 1]);
+               if (value == NULL)
+                       continue;
+
+               media_player_set_setting(mp, key, value);
+       }
+
+       return FALSE;
+}
+
+static void avrcp_get_current_player_value(struct avrcp *session,
+                                               uint8_t *attrs, uint8_t count)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 5];
+       struct avrcp_header *pdu = (void *) buf;
+       int i;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_GET_CURRENT_PLAYER_VALUE;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+       pdu->params_len = htons(count + 1);
+       pdu->params[0] = count;
+
+       for (i = 0; count > 0; count--, i++)
+               pdu->params[i + 1] = attrs[i];
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+                                       avrcp_player_value_rsp, session);
+}
+
+static gboolean avrcp_list_player_attributes_rsp(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t count;
+
+       if (code == AVC_CTYPE_REJECTED)
+               return FALSE;
+
+       count = pdu->params[0];
+
+       if (ntohs(pdu->params_len) < count) {
+               error("Invalid parameters");
+               return FALSE;
+       }
+
+       avrcp_get_current_player_value(session, &pdu->params[1],
+                                                       pdu->params[0]);
+
+       return FALSE;
+}
+
+static void avrcp_list_player_attributes(struct avrcp *session)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH];
+       struct avrcp_header *pdu = (void *) buf;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_LIST_PLAYER_ATTRIBUTES;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, sizeof(buf),
+                                       avrcp_list_player_attributes_rsp,
+                                       session);
+}
+
+static void avrcp_parse_attribute_list(struct avrcp_player *player,
+                                       uint8_t *operands, uint8_t count)
+{
+       struct media_player *mp = player->user_data;
+       struct media_item *item;
+       int i;
+
+       item = media_player_set_playlist_item(mp, player->uid);
+
+       for (i = 0; count > 0; count--) {
+               uint32_t id;
+               uint16_t charset, len;
+
+               id = bt_get_be32(&operands[i]);
+               i += sizeof(uint32_t);
+
+               charset = bt_get_be16(&operands[i]);
+               i += sizeof(uint16_t);
+
+               len = bt_get_be16(&operands[i]);
+               i += sizeof(uint16_t);
+
+               if (charset == 106) {
+                       const char *key = metadata_to_str(id);
+
+                       if (key != NULL)
+                               media_player_set_metadata(mp, item,
+                                                       metadata_to_str(id),
+                                                       &operands[i], len);
+               }
+
+               i += len;
+       }
+}
+
+static gboolean avrcp_get_element_attributes_rsp(struct avctp *conn,
+                                               uint8_t code, uint8_t subunit,
+                                               uint8_t *operands,
+                                               size_t operand_count,
+                                               void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t count;
+
+       if (code == AVC_CTYPE_REJECTED)
+               return FALSE;
+
+       count = pdu->params[0];
+
+       if (ntohs(pdu->params_len) - 1 < count * 8) {
+               error("Invalid parameters");
+               return FALSE;
+       }
+
+       avrcp_parse_attribute_list(player, &pdu->params[1], count);
+
+       avrcp_get_play_status(session);
+
+       return FALSE;
+}
+
+static void avrcp_get_element_attributes(struct avrcp *session)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 9];
+       struct avrcp_header *pdu = (void *) buf;
+       uint16_t length;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_GET_ELEMENT_ATTRIBUTES;
+       pdu->params_len = htons(9);
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       avrcp_get_element_attributes_rsp,
+                                       session);
+}
+
+static const char *type_to_string(uint8_t type)
+{
+       switch (type & 0x0F) {
+       case 0x01:
+               return "Audio";
+       case 0x02:
+               return "Video";
+       case 0x03:
+               return "Audio, Video";
+       case 0x04:
+               return "Audio Broadcasting";
+       case 0x05:
+               return "Audio, Audio Broadcasting";
+       case 0x06:
+               return "Video, Audio Broadcasting";
+       case 0x07:
+               return "Audio, Video, Audio Broadcasting";
+       case 0x08:
+               return "Video Broadcasting";
+       case 0x09:
+               return "Audio, Video Broadcasting";
+       case 0x0A:
+               return "Video, Video Broadcasting";
+       case 0x0B:
+               return "Audio, Video, Video Broadcasting";
+       case 0x0C:
+               return "Audio Broadcasting, Video Broadcasting";
+       case 0x0D:
+               return "Audio, Audio Broadcasting, Video Broadcasting";
+       case 0x0E:
+               return "Video, Audio Broadcasting, Video Broadcasting";
+       case 0x0F:
+               return "Audio, Video, Audio Broadcasting, Video Broadcasting";
+       }
+
+       return "None";
+}
+
+static const char *subtype_to_string(uint32_t subtype)
+{
+       switch (subtype & 0x03) {
+       case 0x01:
+               return "Audio Book";
+       case 0x02:
+               return "Podcast";
+       case 0x03:
+               return "Audio Book, Podcast";
+       }
+
+       return "None";
+}
+
+static struct media_item *parse_media_element(struct avrcp *session,
+                                       uint8_t *operands, uint16_t len)
+{
+       struct avrcp_player *player;
+       struct media_player *mp;
+       struct media_item *item;
+       uint16_t namelen;
+       char name[255];
+       uint64_t uid;
+
+       if (len < 13)
+               return NULL;
+
+       uid = bt_get_be64(&operands[0]);
+
+       namelen = MIN(bt_get_be16(&operands[11]), sizeof(name) - 1);
+       if (namelen > 0) {
+               memcpy(name, &operands[13], namelen);
+               name[namelen] = '\0';
+       }
+
+       player = session->controller->player;
+       mp = player->user_data;
+
+       item = media_player_create_item(mp, name, PLAYER_ITEM_TYPE_AUDIO, uid);
+       if (item == NULL)
+               return NULL;
+
+       media_item_set_playable(item, true);
+
+       return item;
+}
+
+static struct media_item *parse_media_folder(struct avrcp *session,
+                                       uint8_t *operands, uint16_t len)
+{
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       uint16_t namelen;
+       char name[255];
+       uint64_t uid;
+       uint8_t type;
+
+       if (len < 12)
+               return NULL;
+
+       uid = bt_get_be64(&operands[0]);
+       type = operands[9];
+
+       namelen = MIN(bt_get_be16(&operands[12]), sizeof(name) - 1);
+       if (namelen > 0) {
+               memcpy(name, &operands[14], namelen);
+               name[namelen] = '\0';
+       }
+
+       return media_player_create_folder(mp, name, type, uid);
+}
+
+static void avrcp_list_items(struct avrcp *session, uint32_t start,
+                                                               uint32_t end);
+static gboolean avrcp_list_items_rsp(struct avctp *conn, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct pending_list_items *p = player->p;
+       uint16_t count;
+       uint32_t items, total;
+       size_t i;
+       int err = 0;
+
+       if (pdu == NULL) {
+               err = -ETIMEDOUT;
+               goto done;
+       }
+
+       /* AVRCP 1.5 - Page 76:
+        * If the TG receives a GetFolderItems command for an empty folder then
+        * the TG shall return the error (= Range Out of Bounds) in the status
+        * field of the GetFolderItems response.
+        */
+       if (pdu->params[0] == AVRCP_STATUS_OUT_OF_BOUNDS)
+               goto done;
+
+       if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 5) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       count = bt_get_be16(&operands[6]);
+       if (count == 0)
+               goto done;
+
+       for (i = 8; count && i + 3 < operand_count; count--) {
+               struct media_item *item;
+               uint8_t type;
+               uint16_t len;
+
+               type = operands[i++];
+               len = bt_get_be16(&operands[i]);
+               i += 2;
+
+               if (type != 0x03 && type != 0x02) {
+                       i += len;
+                       continue;
+               }
+
+               if (i + len > operand_count) {
+                       error("Invalid item length");
+                       break;
+               }
+
+               if (type == 0x03)
+                       item = parse_media_element(session, &operands[i], len);
+               else if (type == 0x02)
+                       item = parse_media_folder(session, &operands[i], len);
+
+               if (item) {
+                       if (g_slist_find(p->items, item))
+                               goto done;
+                       p->items = g_slist_append(p->items, item);
+               }
+
+               i += len;
+       }
+
+       items = g_slist_length(p->items);
+       total = p->end - p->start;
+       if (items < total) {
+               avrcp_list_items(session, p->start + items + 1, p->end);
+               return FALSE;
+       }
+
+done:
+       media_player_list_complete(player->user_data, p->items, err);
+
+       g_slist_free(p->items);
+       g_free(p);
+       player->p = NULL;
+
+       return FALSE;
+}
+
+static void avrcp_list_items(struct avrcp *session, uint32_t start,
+                                                               uint32_t end)
+{
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10 +
+                       AVRCP_MEDIA_ATTRIBUTE_LAST * sizeof(uint32_t)];
+       struct avrcp_player *player = session->controller->player;
+       struct avrcp_browsing_header *pdu = (void *) buf;
+       uint16_t length = AVRCP_BROWSING_HEADER_LENGTH + 10;
+       uint32_t attribute;
+
+       memset(buf, 0, sizeof(buf));
+
+       pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS;
+       pdu->param_len = htons(10 + sizeof(uint32_t));
+
+       pdu->params[0] = player->scope;
+
+       bt_put_be32(start, &pdu->params[1]);
+       bt_put_be32(end, &pdu->params[5]);
+
+       pdu->params[9] = 1;
+
+       /* Only the title (0x01) is mandatory. This can be extended to
+        * support AVRCP_MEDIA_ATTRIBUTE_* attributes */
+       attribute = htonl(AVRCP_MEDIA_ATTRIBUTE_TITLE);
+       memcpy(&pdu->params[10], &attribute, sizeof(uint32_t));
+
+       length += sizeof(uint32_t);
+
+       avctp_send_browsing_req(session->conn, buf, length,
+                                       avrcp_list_items_rsp, session);
+}
+
+static gboolean avrcp_change_path_rsp(struct avctp *conn,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       int ret;
+
+       if (pdu == NULL) {
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+
+       if (pdu->params[0] != AVRCP_STATUS_SUCCESS) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       ret = bt_get_be32(&pdu->params[1]);
+
+done:
+       if (ret < 0) {
+               g_free(player->change_path);
+               player->change_path = NULL;
+       } else {
+               g_free(player->path);
+               player->path = player->change_path;
+               player->change_path = NULL;
+       }
+
+       media_player_change_folder_complete(mp, player->path, ret);
+
+       return FALSE;
+}
+
+static gboolean avrcp_set_browsed_player_rsp(struct avctp *conn,
+                                               uint8_t *operands,
+                                               size_t operand_count,
+                                               void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       uint32_t items;
+       char **folders;
+       uint8_t depth, count;
+       size_t i;
+
+       if (pdu == NULL || pdu->params[0] != AVRCP_STATUS_SUCCESS ||
+                                                       operand_count < 13)
+               return FALSE;
+
+       player->uid_counter = bt_get_be16(&pdu->params[1]);
+       player->browsed = true;
+
+       items = bt_get_be32(&pdu->params[3]);
+
+       depth = pdu->params[9];
+
+       folders = g_new0(char *, depth + 2);
+       folders[0] = g_strdup("/Filesystem");
+
+       for (i = 10, count = 1; count - 1 < depth && i < operand_count;
+                                                               count++) {
+               uint8_t len;
+
+               len = pdu->params[i++];
+
+               if (i + len > operand_count || len == 0) {
+                       error("Invalid folder length");
+                       break;
+               }
+
+               folders[count] = g_memdup(&pdu->params[i], len);
+               i += len;
+       }
+
+       player->path = g_build_pathv("/", folders);
+       g_strfreev(folders);
+
+       media_player_set_folder(mp, player->path, items);
+
+       return FALSE;
+}
+
+static void avrcp_set_browsed_player(struct avrcp *session,
+                                               struct avrcp_player *player)
+{
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 2];
+       struct avrcp_browsing_header *pdu = (void *) buf;
+       uint16_t id;
+
+       memset(buf, 0, sizeof(buf));
+
+       pdu->pdu_id = AVRCP_SET_BROWSED_PLAYER;
+       id = htons(player->id);
+       memcpy(pdu->params, &id, 2);
+       pdu->param_len = htons(2);
+
+       avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+                               avrcp_set_browsed_player_rsp, session);
+}
+
+static gboolean avrcp_get_item_attributes_rsp(struct avctp *conn,
+                                               uint8_t *operands,
+                                               size_t operand_count,
+                                               void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       uint8_t count;
+
+       if (pdu == NULL) {
+               avrcp_get_element_attributes(session);
+               return FALSE;
+       }
+
+       if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 4) {
+               avrcp_get_element_attributes(session);
+               return FALSE;
+       }
+
+       count = pdu->params[1];
+
+       if (ntohs(pdu->param_len) - 1 < count * 8) {
+               error("Invalid parameters");
+               return FALSE;
+       }
+
+       avrcp_parse_attribute_list(player, &pdu->params[2], count);
+
+       avrcp_get_play_status(session);
+
+       return FALSE;
+}
+
+static void avrcp_get_item_attributes(struct avrcp *session, uint64_t uid)
+{
+       struct avrcp_player *player = session->controller->player;
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 12];
+       struct avrcp_browsing_header *pdu = (void *) buf;
+
+       memset(buf, 0, sizeof(buf));
+
+       pdu->pdu_id = AVRCP_GET_ITEM_ATTRIBUTES;
+       pdu->params[0] = 0x03;
+       bt_put_be64(uid, &pdu->params[1]);
+       bt_put_be16(player->uid_counter, &pdu->params[9]);
+       pdu->param_len = htons(12);
+
+       avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+                               avrcp_get_item_attributes_rsp, session);
+}
+
+static void avrcp_player_parse_features(struct avrcp_player *player,
+                                                       uint8_t *features)
+{
+       struct media_player *mp = player->user_data;
+
+       player->features = g_memdup(features, 16);
+
+       if (features[7] & 0x08) {
+               media_player_set_browsable(mp, true);
+               media_player_create_folder(mp, "/Filesystem",
+                                               PLAYER_FOLDER_TYPE_MIXED, 0);
+       }
+
+       if (features[7] & 0x10)
+               media_player_set_searchable(mp, true);
+
+       if (features[8] & 0x02) {
+               media_player_create_folder(mp, "/NowPlaying",
+                                               PLAYER_FOLDER_TYPE_MIXED, 0);
+               media_player_set_playlist(mp, "/NowPlaying");
+       }
+}
+
+static void avrcp_set_player_value(struct avrcp *session, uint8_t attr,
+                                                               uint8_t val)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 3];
+       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_SET_PLAYER_VALUE;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+       pdu->params[0] = 1;
+       pdu->params[1] = attr;
+       pdu->params[2] = val;
+       pdu->params_len = htons(3);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_CONTROL,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       avrcp_player_value_rsp, session);
+}
+
+static bool ct_set_setting(struct media_player *mp, const char *key,
+                                       const char *value, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       int attr;
+       int val;
+       struct avrcp *session;
+
+       session = player->sessions->data;
+       if (session == NULL)
+               return false;
+
+       if (session->controller->version < 0x0103)
+               return false;
+
+       attr = attr_to_val(key);
+       if (attr < 0)
+               return false;
+
+       val = attrval_to_val(attr, value);
+       if (val < 0)
+               return false;
+
+       avrcp_set_player_value(session, attr, val);
+
+       return true;
+}
+
+static int ct_press(struct avrcp_player *player, uint8_t op)
+{
+       int err;
+       struct avrcp *session;
+
+       session = player->sessions->data;
+       if (session == NULL)
+               return -ENOTCONN;
+
+       err = avctp_send_passthrough(session->conn, op);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int ct_play(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_PLAY);
+}
+
+static int ct_pause(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_PAUSE);
+}
+
+static int ct_stop(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_STOP);
+}
+
+static int ct_next(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_FORWARD);
+}
+
+static int ct_previous(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_BACKWARD);
+}
+
+static int ct_fast_forward(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_FAST_FORWARD);
+}
+
+static int ct_rewind(struct media_player *mp, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+
+       return ct_press(player, AVC_REWIND);
+}
+
+static int ct_list_items(struct media_player *mp, const char *name,
+                               uint32_t start, uint32_t end, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp *session;
+       struct pending_list_items *p;
+
+       if (player->p != NULL)
+               return -EBUSY;
+
+       session = player->sessions->data;
+
+       if (g_str_has_prefix(name, "/NowPlaying"))
+               player->scope = 0x03;
+       else if (g_str_has_suffix(name, "/search"))
+               player->scope = 0x02;
+       else
+               player->scope = 0x01;
+
+       avrcp_list_items(session, start, end);
+
+       p = g_new0(struct pending_list_items, 1);
+       p->start = start;
+       p->end = end;
+       player->p = p;
+
+       return 0;
+}
+
+static void avrcp_change_path(struct avrcp *session, uint8_t direction,
+                                                               uint64_t uid)
+{
+       struct avrcp_player *player = session->controller->player;
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 11];
+       struct avrcp_browsing_header *pdu = (void *) buf;
+
+       memset(buf, 0, sizeof(buf));
+       bt_put_be16(player->uid_counter, &pdu->params[0]);
+       pdu->params[2] = direction;
+       bt_put_be64(uid, &pdu->params[3]);
+       pdu->pdu_id = AVRCP_CHANGE_PATH;
+       pdu->param_len = htons(11);
+
+       avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+                                       avrcp_change_path_rsp, session);
+}
+
+static int ct_change_folder(struct media_player *mp, const char *path,
+                                       uint64_t uid, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp *session;
+       uint8_t direction;
+
+       session = player->sessions->data;
+       player->change_path = g_strdup(path);
+
+       direction = g_str_has_prefix(path, player->path) ? 0x01 : 0x00;
+
+       avrcp_change_path(session, direction, uid);
+
+       return 0;
+}
+
+static gboolean avrcp_search_rsp(struct avctp *conn, uint8_t *operands,
+                                       size_t operand_count, void *user_data)
+{
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       struct avrcp *session = (void *) user_data;
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       int ret;
+
+       if (pdu == NULL) {
+               ret = -ETIMEDOUT;
+               goto done;
+       }
+
+       if (pdu->params[0] != AVRCP_STATUS_SUCCESS || operand_count < 7) {
+               ret = -EINVAL;
+               goto done;
+       }
+
+       player->uid_counter = bt_get_be16(&pdu->params[1]);
+       ret = bt_get_be32(&pdu->params[3]);
+
+done:
+       media_player_search_complete(mp, ret);
+
+       return FALSE;
+}
+
+static void avrcp_search(struct avrcp *session, const char *string)
+{
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 255];
+       struct avrcp_browsing_header *pdu = (void *) buf;
+       uint16_t len, stringlen;
+
+       memset(buf, 0, sizeof(buf));
+       len = AVRCP_BROWSING_HEADER_LENGTH + 4;
+       stringlen = strnlen(string, sizeof(buf) - len);
+       len += stringlen;
+
+       bt_put_be16(AVRCP_CHARSET_UTF8, &pdu->params[0]);
+       bt_put_be16(stringlen, &pdu->params[2]);
+       memcpy(&pdu->params[4], string, stringlen);
+       pdu->pdu_id = AVRCP_SEARCH;
+       pdu->param_len = htons(len - AVRCP_BROWSING_HEADER_LENGTH);
+
+       avctp_send_browsing_req(session->conn, buf, len, avrcp_search_rsp,
+                                                               session);
+}
+
+static int ct_search(struct media_player *mp, const char *string,
+                                                       void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp *session;
+
+       session = player->sessions->data;
+
+       avrcp_search(session, string);
+
+       return 0;
+}
+
+static void avrcp_play_item(struct avrcp *session, uint64_t uid)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 11];
+       struct avrcp_player *player = session->controller->player;
+       struct avrcp_header *pdu = (void *) buf;
+       uint16_t length;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_PLAY_ITEM;
+       pdu->params_len = htons(11);
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+       pdu->params[0] = player->scope;
+       bt_put_be64(uid, &pdu->params[1]);
+       bt_put_be16(player->uid_counter, &pdu->params[9]);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       NULL, session);
+}
+
+static int ct_play_item(struct media_player *mp, const char *name,
+                                               uint64_t uid, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp *session;
+
+       if (player->p != NULL)
+               return -EBUSY;
+
+       session = player->sessions->data;
+
+       if (g_strrstr(name, "/NowPlaying"))
+               player->scope = 0x03;
+       else
+               player->scope = 0x01;
+
+       avrcp_play_item(session, uid);
+
+       return 0;
+}
+
+static void avrcp_add_to_nowplaying(struct avrcp *session, uint64_t uid)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + 11];
+       struct avrcp_player *player = session->controller->player;
+       struct avrcp_header *pdu = (void *) buf;
+       uint16_t length;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+       pdu->pdu_id = AVRCP_ADD_TO_NOW_PLAYING;
+       pdu->params_len = htons(11);
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+
+       pdu->params[0] = player->scope;
+       bt_put_be64(uid, &pdu->params[1]);
+       bt_put_be16(player->uid_counter, &pdu->params[9]);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       NULL, session);
+}
+
+static int ct_add_to_nowplaying(struct media_player *mp, const char *name,
+                                               uint64_t uid, void *user_data)
+{
+       struct avrcp_player *player = user_data;
+       struct avrcp *session;
+
+       if (player->p != NULL)
+               return -EBUSY;
+
+       session = player->sessions->data;
+
+       if (g_strrstr(name, "/NowPlaying"))
+               player->scope = 0x03;
+       else
+               player->scope = 0x01;
+
+       avrcp_add_to_nowplaying(session, uid);
+
+       return 0;
+}
+
+static const struct media_player_callback ct_cbs = {
+       .set_setting    = ct_set_setting,
+       .play           = ct_play,
+       .pause          = ct_pause,
+       .stop           = ct_stop,
+       .next           = ct_next,
+       .previous       = ct_previous,
+       .fast_forward   = ct_fast_forward,
+       .rewind         = ct_rewind,
+       .list_items     = ct_list_items,
+       .change_folder  = ct_change_folder,
+       .search         = ct_search,
+       .play_item      = ct_play_item,
+       .add_to_nowplaying = ct_add_to_nowplaying,
+};
+
+static struct avrcp_player *create_ct_player(struct avrcp *session,
+                                                               uint16_t id)
+{
+       struct avrcp_player *player;
+       struct media_player *mp;
+       const char *path;
+
+       player = g_new0(struct avrcp_player, 1);
+       player->sessions = g_slist_prepend(player->sessions, session);
+
+       path = device_get_path(session->dev);
+
+       mp = media_player_controller_create(path, id);
+       if (mp == NULL)
+               return NULL;
+
+       media_player_set_callbacks(mp, &ct_cbs, player);
+       player->user_data = mp;
+       player->destroy = (GDestroyNotify) media_player_destroy;
+
+       if (session->controller->player == NULL)
+               session->controller->player = player;
+
+       session->controller->players = g_slist_prepend(
+                                               session->controller->players,
+                                               player);
+
+       return player;
+}
+
+static struct avrcp_player *find_ct_player(struct avrcp *session, uint16_t id)
+{
+       GSList *l;
+
+       for (l = session->controller->players; l; l = l->next) {
+               struct avrcp_player *player = l->data;
+
+               if (player->id == 0) {
+                       player->id = id;
+                       return player;
+               }
+
+               if (player->id == id)
+                       return player;
+       }
+
+       return NULL;
+}
+
+static struct avrcp_player *
+avrcp_parse_media_player_item(struct avrcp *session, uint8_t *operands,
+                                                       uint16_t len)
+{
+       struct avrcp_player *player;
+       struct media_player *mp;
+       uint16_t id, namelen;
+       uint32_t subtype;
+       const char *curval, *strval;
+       char name[255];
+
+       if (len < 28)
+               return NULL;
+
+       id = bt_get_be16(&operands[0]);
+
+       player = find_ct_player(session, id);
+       if (player == NULL) {
+               player = create_ct_player(session, id);
+               if (player == NULL)
+                       return NULL;
+       } else if (player->features != NULL)
+               return player;
+
+       mp = player->user_data;
+
+       media_player_set_type(mp, type_to_string(operands[2]));
+
+       subtype = bt_get_be32(&operands[3]);
+
+       media_player_set_subtype(mp, subtype_to_string(subtype));
+
+       curval = media_player_get_status(mp);
+       strval = status_to_string(operands[7]);
+
+       if (g_strcmp0(curval, strval) != 0) {
+               media_player_set_status(mp, strval);
+               avrcp_get_play_status(session);
+       }
+
+       avrcp_player_parse_features(player, &operands[8]);
+
+       namelen = bt_get_be16(&operands[26]);
+       if (namelen > 0 && namelen + 28 == len) {
+               namelen = MIN(namelen, sizeof(name) - 1);
+               memcpy(name, &operands[28], namelen);
+               name[namelen] = '\0';
+               media_player_set_name(mp, name);
+       }
+
+       if (session->controller->player == player && !player->browsed)
+               avrcp_set_browsed_player(session, player);
+
+       return player;
+}
+
+static void player_destroy(gpointer data)
+{
+       struct avrcp_player *player = data;
+
+       if (player->destroy)
+               player->destroy(player->user_data);
+
+       g_slist_free(player->sessions);
+       g_free(player->path);
+       g_free(player->change_path);
+       g_free(player->features);
+       g_free(player);
+}
+
+static void player_remove(gpointer data)
+{
+       struct avrcp_player *player = data;
+       GSList *l;
+
+       for (l = player->sessions; l; l = l->next) {
+               struct avrcp *session = l->data;
+
+               session->controller->players = g_slist_remove(
+                                               session->controller->players,
+                                               player);
+       }
+
+       player_destroy(player);
+}
+
+static gboolean avrcp_get_media_player_list_rsp(struct avctp *conn,
+                                               uint8_t *operands,
+                                               size_t operand_count,
+                                               void *user_data)
+{
+       struct avrcp_browsing_header *pdu = (void *) operands;
+       struct avrcp *session = user_data;
+       uint16_t count;
+       size_t i;
+       GSList *removed;
+
+       if (pdu == NULL || pdu->params[0] != AVRCP_STATUS_SUCCESS ||
+                                                       operand_count < 5)
+               return FALSE;
+
+       removed = g_slist_copy(session->controller->players);
+       count = bt_get_be16(&operands[6]);
+
+       for (i = 8; count && i < operand_count; count--) {
+               struct avrcp_player *player;
+               uint8_t type;
+               uint16_t len;
+
+               type = operands[i++];
+               len = bt_get_be16(&operands[i]);
+               i += 2;
+
+               if (type != 0x01) {
+                       i += len;
+                       continue;
+               }
+
+               if (i + len > operand_count) {
+                       error("Invalid player item length");
+                       return FALSE;
+               }
+
+               player = avrcp_parse_media_player_item(session, &operands[i],
+                                                                       len);
+               if (player)
+                       removed = g_slist_remove(removed, player);
+
+               i += len;
+       }
+
+       if (g_slist_find(removed, session->controller->player))
+               session->controller->player = NULL;
+
+       g_slist_free_full(removed, player_remove);
+
+       return FALSE;
+}
+
+static void avrcp_get_media_player_list(struct avrcp *session)
+{
+       uint8_t buf[AVRCP_BROWSING_HEADER_LENGTH + 10];
+       struct avrcp_browsing_header *pdu = (void *) buf;
+
+       memset(buf, 0, sizeof(buf));
+
+       pdu->pdu_id = AVRCP_GET_FOLDER_ITEMS;
+       pdu->param_len = htons(10);
+
+       avctp_send_browsing_req(session->conn, buf, sizeof(buf),
+                               avrcp_get_media_player_list_rsp, session);
+}
+
+static void avrcp_volume_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       struct avrcp_player *player = session->target->player;
+       uint8_t volume;
+
+       if (player == NULL)
+               return;
+
+       volume = pdu->params[1] & 0x7F;
+
+       player->cb->set_volume(volume, session->dev, player->user_data);
+}
+
+static void avrcp_status_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       uint8_t value;
+       const char *curval, *strval;
+
+       value = pdu->params[1];
+
+       curval = media_player_get_status(mp);
+       strval = status_to_string(value);
+
+       if (g_strcmp0(curval, strval) == 0)
+               return;
+
+       media_player_set_status(mp, strval);
+       avrcp_get_play_status(session);
+}
+
+static void avrcp_track_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       if (session->browsing_id) {
+               struct avrcp_player *player = session->controller->player;
+               player->uid = bt_get_be64(&pdu->params[1]);
+               avrcp_get_item_attributes(session, player->uid);
+       } else
+               avrcp_get_element_attributes(session);
+}
+
+static void avrcp_setting_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       struct avrcp_player *player = session->controller->player;
+       struct media_player *mp = player->user_data;
+       uint8_t count = pdu->params[1];
+       int i;
+
+       for (i = 2; count > 0; count--, i += 2) {
+               const char *key;
+               const char *value;
+
+               key = attr_to_str(pdu->params[i]);
+               if (key == NULL)
+                       continue;
+
+               value = attrval_to_str(pdu->params[i], pdu->params[i + 1]);
+               if (value == NULL)
+                       continue;
+
+               media_player_set_setting(mp, key, value);
+       }
+}
+
+static void avrcp_available_players_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       avrcp_get_media_player_list(session);
+}
+
+static void avrcp_addressed_player_changed(struct avrcp *session,
+                                               struct avrcp_header *pdu)
+{
+       struct avrcp_player *player = session->controller->player;
+       uint16_t id = bt_get_be16(&pdu->params[1]);
+
+       if (player != NULL && player->id == id)
+               return;
+
+       player = find_ct_player(session, id);
+       if (player == NULL) {
+               player = create_ct_player(session, id);
+               if (player == NULL)
+                       return;
+       }
+
+       player->uid_counter = bt_get_be16(&pdu->params[3]);
+       session->controller->player = player;
+
+       if (player->features != NULL)
+               return;
+
+       avrcp_get_media_player_list(session);
+}
+
+static void avrcp_uids_changed(struct avrcp *session, struct avrcp_header *pdu)
+{
+       struct avrcp_player *player = session->controller->player;
+
+       player->uid_counter = bt_get_be16(&pdu->params[1]);
+}
+
+static gboolean avrcp_handle_event(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t event;
+
+       if ((code != AVC_CTYPE_INTERIM && code != AVC_CTYPE_CHANGED) ||
+                                                               pdu == NULL)
+               return FALSE;
+
+       event = pdu->params[0];
+
+       if (code == AVC_CTYPE_CHANGED) {
+               session->registered_events ^= (1 << event);
+               avrcp_register_notification(session, event);
+               return FALSE;
+       }
+
+       switch (event) {
+       case AVRCP_EVENT_VOLUME_CHANGED:
+               avrcp_volume_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_STATUS_CHANGED:
+               avrcp_status_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_TRACK_CHANGED:
+               avrcp_track_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_SETTINGS_CHANGED:
+               avrcp_setting_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+               avrcp_available_players_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+               avrcp_addressed_player_changed(session, pdu);
+               break;
+       case AVRCP_EVENT_UIDS_CHANGED:
+               avrcp_uids_changed(session, pdu);
+               break;
+       }
+
+       session->registered_events |= (1 << event);
+
+       return TRUE;
+}
+
+static void avrcp_register_notification(struct avrcp *session, uint8_t event)
+{
+       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] = event;
+       pdu->params_len = htons(AVRCP_REGISTER_NOTIFICATION_PARAM_LENGTH);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_NOTIFY,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       avrcp_handle_event, session);
+}
+
+static gboolean avrcp_get_capabilities_resp(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_header *pdu = (void *) operands;
+       uint16_t events = 0;
+       uint8_t count;
+
+       if (pdu == NULL || pdu->params[0] != CAP_EVENTS_SUPPORTED)
+               return FALSE;
+
+       /* Connect browsing if pending */
+       if (session->browsing_timer > 0) {
+               g_source_remove(session->browsing_timer);
+               session->browsing_timer = 0;
+               avctp_connect_browsing(session->conn);
+       }
+
+       count = pdu->params[1];
+
+       for (; count > 0; count--) {
+               uint8_t event = pdu->params[1 + count];
+
+               events |= (1 << event);
+
+               switch (event) {
+               case AVRCP_EVENT_STATUS_CHANGED:
+               case AVRCP_EVENT_TRACK_CHANGED:
+               case AVRCP_EVENT_SETTINGS_CHANGED:
+               case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+               case AVRCP_EVENT_UIDS_CHANGED:
+               case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+               case AVRCP_EVENT_VOLUME_CHANGED:
+                       avrcp_register_notification(session, event);
+                       break;
+               }
+       }
+
+       if (!(events & (1 << AVRCP_EVENT_SETTINGS_CHANGED)))
+               avrcp_list_player_attributes(session);
+
+       if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
+               avrcp_get_play_status(session);
+
+       if (!(events & (1 << AVRCP_EVENT_STATUS_CHANGED)))
+               avrcp_get_element_attributes(session);
+
+       return FALSE;
+}
+
+static void avrcp_get_capabilities(struct avrcp *session)
+{
+       uint8_t buf[AVRCP_HEADER_LENGTH + AVRCP_GET_CAPABILITIES_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_GET_CAPABILITIES;
+       pdu->packet_type = AVRCP_PACKET_TYPE_SINGLE;
+       pdu->params[0] = CAP_EVENTS_SUPPORTED;
+       pdu->params_len = htons(AVRCP_GET_CAPABILITIES_PARAM_LENGTH);
+
+       length = AVRCP_HEADER_LENGTH + ntohs(pdu->params_len);
+
+       avctp_send_vendordep_req(session->conn, AVC_CTYPE_STATUS,
+                                       AVC_SUBUNIT_PANEL, buf, length,
+                                       avrcp_get_capabilities_resp,
+                                       session);
+}
+
+static struct avrcp *find_session(GSList *list, struct btd_device *dev)
+{
+       for (; list; list = list->next) {
+               struct avrcp *session = list->data;
+
+               if (session->dev == dev)
+                       return session;
+       }
+
+       return NULL;
+}
+
+static void destroy_browsing(void *data)
+{
+       struct avrcp *session = data;
+
+       session->browsing_id = 0;
+}
+
+static void session_init_browsing(struct avrcp *session)
+{
+       if (session->browsing_timer > 0) {
+               g_source_remove(session->browsing_timer);
+               session->browsing_timer = 0;
+       }
+
+       session->browsing_id = avctp_register_browsing_pdu_handler(
+                                                       session->conn,
+                                                       handle_browsing_pdu,
+                                                       session,
+                                                       destroy_browsing);
+}
+
+static struct avrcp_data *data_init(struct avrcp *session, const char *uuid)
+{
+       struct avrcp_data *data;
+       const sdp_record_t *rec;
+       sdp_list_t *list;
+       sdp_profile_desc_t *desc;
+
+       data = g_new0(struct avrcp_data, 1);
+
+       rec = btd_device_get_record(session->dev, uuid);
+       if (rec == NULL)
+               return data;
+
+       if (sdp_get_profile_descs(rec, &list) == 0) {
+               desc = list->data;
+               data->version = desc->version;
+       }
+
+       sdp_get_int_attr(rec, SDP_ATTR_SUPPORTED_FEATURES, &data->features);
+       sdp_list_free(list, free);
+
+       return data;
+}
+
+static gboolean connect_browsing(gpointer user_data)
+{
+       struct avrcp *session = user_data;
+
+       session->browsing_timer = 0;
+
+       avctp_connect_browsing(session->conn);
+
+       return FALSE;
+}
+
+static void avrcp_connect_browsing(struct avrcp *session)
+{
+       /* Immediately connect browsing channel if initiator otherwise delay
+        * it to avoid possible collisions
+        */
+       if (avctp_is_initiator(session->conn)) {
+               avctp_connect_browsing(session->conn);
+               return;
+       }
+
+       if (session->browsing_timer > 0)
+               return;
+
+       session->browsing_timer = g_timeout_add_seconds(AVRCP_BROWSING_TIMEOUT,
+                                                       connect_browsing,
+                                                       session);
+}
+
+static void target_init(struct avrcp *session)
+{
+       struct avrcp_server *server = session->server;
+       struct avrcp_data *target;
+       struct avrcp_player *player;
+       struct btd_service *service;
+
+       if (session->target != NULL)
+               return;
+
+       target = data_init(session, AVRCP_REMOTE_UUID);
+       session->target = target;
+
+       DBG("%p version 0x%04x", target, target->version);
+
+       service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
+       if (service != NULL)
+               btd_service_connecting_complete(service, 0);
+
+       if (target->version < 0x0103)
+               return;
+
+       player = g_slist_nth_data(server->players, 0);
+       if (player != NULL) {
+               target->player = player;
+               player->sessions = g_slist_prepend(player->sessions, session);
+       }
+
+       session->supported_events |= (1 << AVRCP_EVENT_STATUS_CHANGED) |
+                               (1 << AVRCP_EVENT_TRACK_CHANGED) |
+                               (1 << AVRCP_EVENT_TRACK_REACHED_START) |
+                               (1 << AVRCP_EVENT_TRACK_REACHED_END) |
+                               (1 << AVRCP_EVENT_SETTINGS_CHANGED);
+
+       if (target->version < 0x0104)
+               return;
+
+       /* Only check capabilities if controller is not supported */
+       if (session->controller == NULL)
+               avrcp_get_capabilities(session);
+
+       if (!(target->features & AVRCP_FEATURE_BROWSING))
+               return;
+
+       avrcp_connect_browsing(session);
+}
+
+static void controller_init(struct avrcp *session)
+{
+       struct avrcp_player *player;
+       struct btd_service *service;
+       struct avrcp_data *controller;
+
+       if (session->controller != NULL)
+               return;
+
+       controller = data_init(session, AVRCP_TARGET_UUID);
+       session->controller = controller;
+
+       DBG("%p version 0x%04x", controller, controller->version);
+
+       if (controller->version >= 0x0104)
+               session->supported_events |= (1 << AVRCP_EVENT_VOLUME_CHANGED);
+
+       service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
+       if (service != NULL)
+               btd_service_connecting_complete(service, 0);
+
+       /* Only create player if category 1 is supported */
+       if (!(controller->features & AVRCP_FEATURE_CATEGORY_1))
+               return;
+
+       player = create_ct_player(session, 0);
+       if (player == NULL)
+               return;
+
+       if (controller->version < 0x0103)
+               return;
+
+       avrcp_get_capabilities(session);
+
+       if (controller->version < 0x0104)
+               return;
+
+       if (!(controller->features & AVRCP_FEATURE_BROWSING))
+               return;
+
+       avrcp_connect_browsing(session);
+}
+
+static void session_init_control(struct avrcp *session)
+{
+       session->passthrough_id = avctp_register_passthrough_handler(
+                                                       session->conn,
+                                                       handle_passthrough,
+                                                       session);
+       session->passthrough_handlers = passthrough_handlers;
+       session->control_id = avctp_register_pdu_handler(session->conn,
+                                                       AVC_OP_VENDORDEP,
+                                                       handle_vendordep_pdu,
+                                                       session);
+       session->control_handlers = control_handlers;
+
+       if (btd_device_get_service(session->dev, AVRCP_TARGET_UUID) != NULL)
+               controller_init(session);
+
+       if (btd_device_get_service(session->dev, AVRCP_REMOTE_UUID) != NULL)
+               target_init(session);
+}
+
+static void controller_destroy(struct avrcp *session)
+{
+       struct avrcp_data *controller = session->controller;
+       struct btd_service *service;
+
+       DBG("%p", controller);
+
+       g_slist_free_full(controller->players, player_destroy);
+
+       service = btd_device_get_service(session->dev, AVRCP_TARGET_UUID);
+
+       if (session->control_id == 0)
+               btd_service_connecting_complete(service, -EIO);
+       else
+               btd_service_disconnecting_complete(service, 0);
+
+       g_free(controller);
+}
+
+static void target_destroy(struct avrcp *session)
+{
+       struct avrcp_data *target = session->target;
+       struct avrcp_player *player = target->player;
+       struct btd_service *service;
+
+       DBG("%p", target);
+
+       if (player != NULL)
+               player->sessions = g_slist_remove(player->sessions, session);
+
+       service = btd_device_get_service(session->dev, AVRCP_REMOTE_UUID);
+
+       if (session->control_id == 0)
+               btd_service_connecting_complete(service, -EIO);
+       else
+               btd_service_disconnecting_complete(service, 0);
+
+       g_free(target);
+}
+
+static void session_destroy(struct avrcp *session)
+{
+       struct avrcp_server *server = session->server;
+
+       server->sessions = g_slist_remove(server->sessions, session);
+
+       if (session->browsing_timer > 0)
+               g_source_remove(session->browsing_timer);
+
+       if (session->controller != NULL)
+               controller_destroy(session);
+
+       if (session->target != NULL)
+               target_destroy(session);
+
+       if (session->passthrough_id > 0)
+               avctp_unregister_passthrough_handler(session->passthrough_id);
+
+       if (session->control_id > 0)
+               avctp_unregister_pdu_handler(session->control_id);
+
+       if (session->browsing_id > 0)
+               avctp_unregister_browsing_pdu_handler(session->browsing_id);
+
+       g_free(session);
+}
+
+static struct avrcp *session_create(struct avrcp_server *server,
+                                               struct btd_device *device)
+{
+       struct avrcp *session;
+
+       session = g_new0(struct avrcp, 1);
+       session->server = server;
+       session->conn = avctp_connect(device);
+       session->dev = device;
+
+       server->sessions = g_slist_append(server->sessions, session);
+
+       return session;
+}
+
+static void state_changed(struct btd_device *device, avctp_state_t old_state,
+                               avctp_state_t new_state, void *user_data)
+{
+       struct avrcp_server *server;
+       struct avrcp *session;
+
+       server = find_server(servers, device_get_adapter(device));
+       if (!server)
+               return;
+
+       session = find_session(server->sessions, device);
+
+       switch (new_state) {
+       case AVCTP_STATE_DISCONNECTED:
+               if (session == NULL)
+                       break;
+
+               session_destroy(session);
+
+               break;
+       case AVCTP_STATE_CONNECTING:
+               if (session != NULL)
+                       break;
+
+               session_create(server, device);
+
+               break;
+       case AVCTP_STATE_CONNECTED:
+               if (session == NULL || session->control_id > 0)
+                       break;
+
+               session_init_control(session);
+
+               break;
+       case AVCTP_STATE_BROWSING_CONNECTED:
+               if (session == NULL || session->browsing_id > 0)
+                       break;
+
+               session_init_browsing(session);
+
+               break;
+       default:
+               return;
+       }
+}
+
+static struct avrcp_server *avrcp_server_register(struct btd_adapter *adapter)
+{
+       struct avrcp_server *server;
+
+       if (avctp_register(adapter, TRUE) < 0)
+               return NULL;
+
+       server = g_new0(struct avrcp_server, 1);
+       server->adapter = btd_adapter_ref(adapter);
+
+       servers = g_slist_append(servers, server);
+
+       if (!avctp_id)
+               avctp_id = avctp_add_state_cb(NULL, state_changed, NULL);
+
+       return server;
+}
+
+static void avrcp_server_unregister(struct avrcp_server *server)
+{
+       g_slist_free_full(server->sessions, g_free);
+       g_slist_free_full(server->players, player_destroy);
+
+       servers = g_slist_remove(servers, server);
+
+       avctp_unregister(server->adapter);
+       btd_adapter_unref(server->adapter);
+       g_free(server);
+
+       if (servers)
+               return;
+
+       if (avctp_id) {
+               avctp_remove_state_cb(avctp_id);
+               avctp_id = 0;
+       }
+}
+
+struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
+                                               struct avrcp_player_cb *cb,
+                                               void *user_data,
+                                               GDestroyNotify destroy)
+{
+       struct avrcp_server *server;
+       struct avrcp_player *player;
+       GSList *l;
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return NULL;
+
+       player = g_new0(struct avrcp_player, 1);
+       player->server = server;
+       player->cb = cb;
+       player->user_data = user_data;
+       player->destroy = destroy;
+
+       server->players = g_slist_append(server->players, player);
+
+       /* Assign player to session without current player */
+       for (l = server->sessions; l; l = l->next) {
+               struct avrcp *session = l->data;
+               struct avrcp_data *target = session->target;
+
+               if (target == NULL)
+                       continue;
+
+               if (target->player == NULL) {
+                       target->player = player;
+                       player->sessions = g_slist_append(player->sessions,
+                                                               session);
+               }
+       }
+
+       return player;
+}
+
+void avrcp_unregister_player(struct avrcp_player *player)
+{
+       struct avrcp_server *server = player->server;
+       GSList *l;
+
+       server->players = g_slist_remove(server->players, player);
+
+       /* Remove player from sessions using it */
+       for (l = player->sessions; l; l = l->next) {
+               struct avrcp *session = l->data;
+               struct avrcp_data *target = session->target;
+
+               if (target == NULL)
+                       continue;
+
+               if (target->player == player)
+                       target->player = g_slist_nth_data(server->players, 0);
+       }
+
+       player_destroy(player);
+}
+
+static gboolean avrcp_handle_set_volume(struct avctp *conn,
+                                       uint8_t code, uint8_t subunit,
+                                       uint8_t *operands, size_t operand_count,
+                                       void *user_data)
+{
+       struct avrcp *session = user_data;
+       struct avrcp_player *player = session->target->player;
+       struct avrcp_header *pdu = (void *) operands;
+       uint8_t volume;
+
+       if (code == AVC_CTYPE_REJECTED || code == AVC_CTYPE_NOT_IMPLEMENTED ||
+                                                               pdu == NULL)
+               return FALSE;
+
+       volume = pdu->params[0] & 0x7F;
+
+       if (player != NULL)
+               player->cb->set_volume(volume, session->dev, player->user_data);
+
+       return FALSE;
+}
+
+int avrcp_set_volume(struct btd_device *dev, uint8_t volume)
+{
+       struct avrcp_server *server;
+       struct avrcp *session;
+       uint8_t buf[AVRCP_HEADER_LENGTH + 2];
+       struct avrcp_header *pdu = (void *) buf;
+
+       server = find_server(servers, device_get_adapter(dev));
+       if (server == NULL)
+               return -EINVAL;
+
+       session = find_session(server->sessions, dev);
+       if (session == NULL || session->target == NULL)
+               return -ENOTCONN;
+
+       if (session->target->version < 0x0104)
+               return -ENOTSUP;
+
+       memset(buf, 0, sizeof(buf));
+
+       set_company_id(pdu->company_id, IEEEID_BTSIG);
+
+       DBG("volume=%u", volume);
+
+       if (session->target) {
+               pdu->pdu_id = AVRCP_SET_ABSOLUTE_VOLUME;
+               pdu->params[0] = volume;
+               pdu->params_len = htons(1);
+
+               return avctp_send_vendordep_req(session->conn,
+                                       AVC_CTYPE_CONTROL, AVC_SUBUNIT_PANEL,
+                                       buf, sizeof(buf),
+                                       avrcp_handle_set_volume, session);
+       } else if (session->registered_events &
+                                       (1 << AVRCP_EVENT_VOLUME_CHANGED)) {
+               uint8_t id = AVRCP_EVENT_VOLUME_CHANGED;
+               pdu->pdu_id = AVRCP_REGISTER_NOTIFICATION;
+               pdu->params[0] = AVRCP_EVENT_VOLUME_CHANGED;
+               pdu->params[1] = volume;
+               pdu->params_len = htons(2);
+
+               return avctp_send_vendordep(session->conn,
+                                       session->transaction_events[id],
+                                       AVC_CTYPE_CHANGED, AVC_SUBUNIT_PANEL,
+                                       buf, sizeof(buf));
+       }
+
+       return 0;
+}
+
+static int avrcp_connect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return control_connect(service);
+}
+
+static int avrcp_disconnect(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       const char *path = device_get_path(dev);
+
+       DBG("path %s", path);
+
+       return control_disconnect(service);
+}
+
+static int avrcp_target_probe(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("path %s", device_get_path(dev));
+
+       return control_init_target(service);
+}
+
+static void avrcp_target_remove(struct btd_service *service)
+{
+       control_unregister(service);
+}
+
+static void avrcp_target_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct avrcp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return;
+
+       if (server->tg_record_id != 0) {
+               adapter_service_remove(adapter, server->tg_record_id);
+               server->tg_record_id = 0;
+       }
+
+       if (server->ct_record_id == 0)
+               avrcp_server_unregister(server);
+}
+
+static int avrcp_target_server_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       sdp_record_t *record;
+       struct avrcp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (server != NULL)
+               goto done;
+
+       server = avrcp_server_register(adapter);
+       if (server == NULL)
+               return -EPROTONOSUPPORT;
+
+done:
+       record = avrcp_tg_record();
+       if (!record) {
+               error("Unable to allocate new service record");
+               avrcp_target_server_remove(p, adapter);
+               return -1;
+       }
+
+       if (adapter_service_add(adapter, record) < 0) {
+               error("Unable to register AVRCP target service record");
+               avrcp_target_server_remove(p, adapter);
+               sdp_record_free(record);
+               return -1;
+       }
+       server->tg_record_id = record->handle;
+
+       return 0;
+}
+
+static struct btd_profile avrcp_target_profile = {
+       .name           = "audio-avrcp-target",
+
+       .remote_uuid    = AVRCP_TARGET_UUID,
+       .device_probe   = avrcp_target_probe,
+       .device_remove  = avrcp_target_remove,
+
+       .connect        = avrcp_connect,
+       .disconnect     = avrcp_disconnect,
+
+       .adapter_probe  = avrcp_target_server_probe,
+       .adapter_remove = avrcp_target_server_remove,
+};
+
+static int avrcp_controller_probe(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("path %s", device_get_path(dev));
+
+       return control_init_remote(service);
+}
+
+static void avrcp_controller_remove(struct btd_service *service)
+{
+       control_unregister(service);
+}
+
+static void avrcp_controller_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct avrcp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (!server)
+               return;
+
+       if (server->ct_record_id != 0) {
+               adapter_service_remove(adapter, server->ct_record_id);
+               server->ct_record_id = 0;
+       }
+
+       if (server->tg_record_id == 0)
+               avrcp_server_unregister(server);
+}
+
+static int avrcp_controller_server_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       sdp_record_t *record;
+       struct avrcp_server *server;
+
+       DBG("path %s", adapter_get_path(adapter));
+
+       server = find_server(servers, adapter);
+       if (server != NULL)
+               goto done;
+
+       server = avrcp_server_register(adapter);
+       if (server == NULL)
+               return -EPROTONOSUPPORT;
+
+done:
+       record = avrcp_ct_record();
+       if (!record) {
+               error("Unable to allocate new service record");
+               avrcp_controller_server_remove(p, adapter);
+               return -1;
+       }
+
+       if (adapter_service_add(adapter, record) < 0) {
+               error("Unable to register AVRCP service record");
+               avrcp_controller_server_remove(p, adapter);
+               sdp_record_free(record);
+               return -1;
+       }
+       server->ct_record_id = record->handle;
+
+       return 0;
+}
+
+static struct btd_profile avrcp_controller_profile = {
+       .name           = "avrcp-controller",
+
+       .remote_uuid    = AVRCP_REMOTE_UUID,
+       .device_probe   = avrcp_controller_probe,
+       .device_remove  = avrcp_controller_remove,
+
+       .connect        = avrcp_connect,
+       .disconnect     = avrcp_disconnect,
+
+       .adapter_probe  = avrcp_controller_server_probe,
+       .adapter_remove = avrcp_controller_server_remove,
+};
+
+static int avrcp_init(void)
+{
+       btd_profile_register(&avrcp_controller_profile);
+       btd_profile_register(&avrcp_target_profile);
+
+       return 0;
+}
+
+static void avrcp_exit(void)
+{
+       btd_profile_unregister(&avrcp_controller_profile);
+       btd_profile_unregister(&avrcp_target_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(avrcp, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                                       avrcp_init, avrcp_exit)
similarity index 67%
rename from audio/avrcp.h
rename to profiles/audio/avrcp.h
index bf11a6c..4c520ca 100644 (file)
 #define AVRCP_PLAY_STATUS_ERROR                0xFF
 
 /* Notification events */
-#define AVRCP_EVENT_STATUS_CHANGED     0x01
-#define AVRCP_EVENT_TRACK_CHANGED      0x02
-#define AVRCP_EVENT_TRACK_REACHED_END  0x03
-#define AVRCP_EVENT_TRACK_REACHED_START        0x04
-#define AVRCP_EVENT_VOLUME_CHANGED     0x0d
-#define AVRCP_EVENT_LAST               AVRCP_EVENT_VOLUME_CHANGED
+#define AVRCP_EVENT_STATUS_CHANGED             0x01
+#define AVRCP_EVENT_TRACK_CHANGED              0x02
+#define AVRCP_EVENT_TRACK_REACHED_END          0x03
+#define AVRCP_EVENT_TRACK_REACHED_START                0x04
+#define AVRCP_EVENT_SETTINGS_CHANGED           0x08
+#define AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED  0x0a
+#define AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED   0x0b
+#define AVRCP_EVENT_UIDS_CHANGED               0x0c
+#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);
-       int (*set_setting) (uint8_t attr, uint8_t value, void *user_data);
+       GList *(*list_settings) (void *user_data);
+       const char *(*get_setting) (const char *key, void *user_data);
+       int (*set_setting) (const char *key, const char *value,
+                                                       void *user_data);
        uint64_t (*get_uid) (void *user_data);
-       void *(*get_metadata) (uint32_t id, void *user_data);
+       const char *(*get_metadata) (const char *key, void *user_data);
        GList *(*list_metadata) (void *user_data);
-       uint8_t (*get_status) (void *user_data);
+       const char *(*get_status) (void *user_data);
        uint32_t (*get_position) (void *user_data);
-       void (*set_volume) (uint8_t volume, struct audio_device *dev,
+       uint32_t (*get_duration) (void *user_data);
+       void (*set_volume) (uint8_t volume, struct btd_device *dev,
                                                        void *user_data);
+       bool (*play) (void *user_data);
+       bool (*stop) (void *user_data);
+       bool (*pause) (void *user_data);
+       bool (*next) (void *user_data);
+       bool (*previous) (void *user_data);
 };
 
-int avrcp_register(DBusConnection *conn, const bdaddr_t *src, GKeyFile *config);
-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);
+int avrcp_set_volume(struct btd_device *dev, uint8_t volume);
 
-struct avrcp_player *avrcp_register_player(const bdaddr_t *src,
+struct avrcp_player *avrcp_register_player(struct btd_adapter *adapter,
                                                struct avrcp_player_cb *cb,
                                                void *user_data,
                                                GDestroyNotify destroy);
 void avrcp_unregister_player(struct avrcp_player *player);
 
-int avrcp_player_event(struct avrcp_player *player, uint8_t id, void *data);
+void avrcp_player_event(struct avrcp_player *player, uint8_t id,
+                                                       const void *data);
 
 
 size_t avrcp_handle_vendor_reject(uint8_t *code, uint8_t *operands);
+size_t avrcp_browsing_general_reject(uint8_t *operands);
diff --git a/profiles/audio/control.c b/profiles/audio/control.c
new file mode 100644 (file)
index 0000000..5f88a94
--- /dev/null
@@ -0,0 +1,346 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2011  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 <stdlib.h>
+#include <stdint.h>
+#include <errno.h>
+#include <unistd.h>
+#include <assert.h>
+#include <signal.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+
+#include "log.h"
+#include "error.h"
+#include "avctp.h"
+#include "control.h"
+#include "sdpd.h"
+#include "glib-helper.h"
+#include "dbus-common.h"
+
+static GSList *devices = NULL;
+
+struct control {
+       struct btd_device *dev;
+       struct avctp *session;
+       struct btd_service *target;
+       struct btd_service *remote;
+       unsigned int avctp_id;
+};
+
+static void state_changed(struct btd_device *dev, avctp_state_t old_state,
+                               avctp_state_t new_state, void *user_data)
+{
+       struct control *control = user_data;
+       DBusConnection *conn = btd_get_dbus_connection();
+       const char *path = device_get_path(dev);
+
+       switch (new_state) {
+       case AVCTP_STATE_DISCONNECTED:
+               control->session = NULL;
+
+               g_dbus_emit_property_changed(conn, path,
+                                       AUDIO_CONTROL_INTERFACE, "Connected");
+
+               break;
+       case AVCTP_STATE_CONNECTING:
+               if (control->session)
+                       break;
+
+               control->session = avctp_get(dev);
+
+               break;
+       case AVCTP_STATE_CONNECTED:
+               g_dbus_emit_property_changed(conn, path,
+                                       AUDIO_CONTROL_INTERFACE, "Connected");
+               break;
+       default:
+               return;
+       }
+}
+
+int control_connect(struct btd_service *service)
+{
+       struct control *control = btd_service_get_user_data(service);
+
+       if (control->session)
+               return -EALREADY;
+
+       control->session = avctp_connect(control->dev);
+       if (!control->session)
+               return -EIO;
+
+       return 0;
+}
+
+int control_disconnect(struct btd_service *service)
+{
+       struct control *control = btd_service_get_user_data(service);
+
+       if (!control->session)
+               return -ENOTCONN;
+
+       avctp_disconnect(control->session);
+
+       return 0;
+}
+
+static DBusMessage *key_pressed(DBusConnection *conn, DBusMessage *msg,
+                                               uint8_t op, void *data)
+{
+       struct control *control = data;
+       int err;
+
+       if (!control->session)
+               return btd_error_not_connected(msg);
+
+       if (!control->target)
+               return btd_error_not_supported(msg);
+
+       err = avctp_send_passthrough(control->session, op);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *control_volume_up(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_VOLUME_UP, data);
+}
+
+static DBusMessage *control_volume_down(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_VOLUME_DOWN, data);
+}
+
+static DBusMessage *control_play(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_PLAY, data);
+}
+
+static DBusMessage *control_pause(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_PAUSE, data);
+}
+
+static DBusMessage *control_stop(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_STOP, data);
+}
+
+static DBusMessage *control_next(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_FORWARD, data);
+}
+
+static DBusMessage *control_previous(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_BACKWARD, data);
+}
+
+static DBusMessage *control_fast_forward(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_FAST_FORWARD, data);
+}
+
+static DBusMessage *control_rewind(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       return key_pressed(conn, msg, AVC_REWIND, data);
+}
+
+static gboolean control_property_get_connected(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct control *control = data;
+       dbus_bool_t value = (control->session != NULL);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable control_methods[] = {
+       { GDBUS_METHOD("Play", NULL, NULL, control_play) },
+       { GDBUS_METHOD("Pause", NULL, NULL, control_pause) },
+       { GDBUS_METHOD("Stop", NULL, NULL, control_stop) },
+       { GDBUS_METHOD("Next", NULL, NULL, control_next) },
+       { GDBUS_METHOD("Previous", NULL, NULL, control_previous) },
+       { GDBUS_METHOD("VolumeUp", NULL, NULL, control_volume_up) },
+       { GDBUS_METHOD("VolumeDown", NULL, NULL, control_volume_down) },
+       { GDBUS_METHOD("FastForward", NULL, NULL, control_fast_forward) },
+       { GDBUS_METHOD("Rewind", NULL, NULL, control_rewind) },
+       { }
+};
+
+static const GDBusPropertyTable control_properties[] = {
+       { "Connected", "b", control_property_get_connected },
+       { }
+};
+
+static void path_unregister(void *data)
+{
+       struct control *control = data;
+
+       DBG("Unregistered interface %s on path %s",  AUDIO_CONTROL_INTERFACE,
+                                               device_get_path(control->dev));
+
+       if (control->session)
+               avctp_disconnect(control->session);
+
+       avctp_remove_state_cb(control->avctp_id);
+
+       if (control->target)
+               btd_service_unref(control->target);
+
+       if (control->remote)
+               btd_service_unref(control->remote);
+
+       devices = g_slist_remove(devices, control);
+       g_free(control);
+}
+
+void control_unregister(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               device_get_path(dev),
+                                               AUDIO_CONTROL_INTERFACE);
+}
+
+static struct control *find_control(struct btd_device *dev)
+{
+       GSList *l;
+
+       for (l = devices; l; l = l->next) {
+               struct control *control = l->data;
+
+               if (control->dev == dev)
+                       return control;
+       }
+
+       return NULL;
+}
+
+static struct control *control_init(struct btd_service *service)
+{
+       struct control *control;
+       struct btd_device *dev = btd_service_get_device(service);
+
+       control = find_control(dev);
+       if (control != NULL)
+               return control;
+
+       control = g_new0(struct control, 1);
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       device_get_path(dev),
+                                       AUDIO_CONTROL_INTERFACE,
+                                       control_methods, NULL,
+                                       control_properties, control,
+                                       path_unregister)) {
+               g_free(control);
+               return NULL;
+       }
+
+       DBG("Registered interface %s on path %s", AUDIO_CONTROL_INTERFACE,
+                                                       device_get_path(dev));
+
+       control->dev = dev;
+       control->avctp_id = avctp_add_state_cb(dev, state_changed, control);
+       devices = g_slist_prepend(devices, control);
+
+       return control;
+}
+
+int control_init_target(struct btd_service *service)
+{
+       struct control *control;
+
+       control = control_init(service);
+       if (control == NULL)
+               return -EINVAL;
+
+       control->target = btd_service_ref(service);
+
+       btd_service_set_user_data(service, control);
+
+       return 0;
+}
+
+int control_init_remote(struct btd_service *service)
+{
+       struct control *control;
+
+       control = control_init(service);
+       if (control == NULL)
+               return -EINVAL;
+
+       control->remote = btd_service_ref(service);
+
+       btd_service_set_user_data(service, control);
+
+       return 0;
+}
+
+gboolean control_is_active(struct btd_service *service)
+{
+       struct control *control = btd_service_get_user_data(service);
+
+       if (control && control->session)
+               return TRUE;
+
+       return FALSE;
+}
similarity index 69%
rename from audio/control.h
rename to profiles/audio/control.h
index 2219e5f..da8f16c 100644 (file)
  *
  */
 
-#define AUDIO_CONTROL_INTERFACE "org.bluez.Control"
+#define AUDIO_CONTROL_INTERFACE "org.bluez.MediaControl1"
 
-struct control *control_init(struct audio_device *dev, uint16_t uuid16);
-void control_update(struct control *control, uint16_t uuid16);
-void control_unregister(struct audio_device *dev);
-gboolean control_is_active(struct audio_device *dev);
+struct btd_service;
+
+int control_init_target(struct btd_service *service);
+int control_init_remote(struct btd_service *service);
+void control_unregister(struct btd_service *service);
+gboolean control_is_active(struct btd_service *service);
+
+int control_connect(struct btd_service *service);
+int control_disconnect(struct btd_service *service);
similarity index 64%
rename from audio/media.c
rename to profiles/audio/media.c
index 1956653..5edd3de 100644 (file)
 #endif
 
 #include <errno.h>
-
-#include <bluetooth/uuid.h>
+#include <inttypes.h>
 
 #include <glib.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
-#include "../src/adapter.h"
-#include "../src/dbus-common.h"
+#include "lib/uuid.h"
+#include "src/plugin.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/dbus-common.h"
+#include "src/profile.h"
 
 #include "glib-helper.h"
 #include "log.h"
 #include "error.h"
-#include "device.h"
 #include "avdtp.h"
 #include "media.h"
 #include "transport.h"
 #include "a2dp.h"
 #include "avrcp.h"
-#include "headset.h"
-#include "gateway.h"
-#include "manager.h"
 
-#define MEDIA_INTERFACE "org.bluez.Media"
-#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint"
-#define MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer"
+#define MEDIA_INTERFACE "org.bluez.Media1"
+#define MEDIA_ENDPOINT_INTERFACE "org.bluez.MediaEndpoint1"
+#define MEDIA_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
 
 #define REQUEST_TIMEOUT (3 * 1000)             /* 3 seconds */
 
 struct media_adapter {
-       bdaddr_t                src;            /* Adapter address */
-       char                    *path;          /* Adapter path */
-       DBusConnection          *conn;          /* Adapter connection */
+       struct btd_adapter      *btd_adapter;
        GSList                  *endpoints;     /* Endpoints list */
        GSList                  *players;       /* Players list */
 };
@@ -97,20 +94,18 @@ struct media_player {
        GHashTable              *settings;      /* Player settings */
        GHashTable              *track;         /* Player current track */
        guint                   watch;
-       guint                   property_watch;
-       guint                   track_watch;
-       uint8_t                 status;
+       guint                   properties_watch;
+       guint                   seek_watch;
+       char                    *status;
        uint32_t                position;
+       uint32_t                duration;
        uint8_t                 volume;
        GTimer                  *timer;
-};
-
-struct metadata_value {
-       int                     type;
-       union {
-               char            *str;
-               uint32_t        num;
-       } value;
+       bool                    play;
+       bool                    pause;
+       bool                    next;
+       bool                    previous;
+       bool                    control;
 };
 
 static GSList *adapters = NULL;
@@ -136,6 +131,9 @@ static void media_endpoint_cancel(struct endpoint_request *request)
 
        endpoint->requests = g_slist_remove(endpoint->requests, request);
 
+       if (request->cb)
+               request->cb(endpoint, NULL, -1, request->user_data);
+
        endpoint_request_free(request);
 }
 
@@ -147,22 +145,14 @@ static void media_endpoint_cancel_all(struct media_endpoint *endpoint)
 
 static void media_endpoint_destroy(struct media_endpoint *endpoint)
 {
-       struct media_adapter *adapter = endpoint->adapter;
-
        DBG("sender=%s path=%s", endpoint->sender, endpoint->path);
 
-       if (endpoint->hs_watch)
-               headset_remove_state_cb(endpoint->hs_watch);
-
-       if (endpoint->ag_watch)
-               gateway_remove_state_cb(endpoint->ag_watch);
-
        media_endpoint_cancel_all(endpoint);
 
        g_slist_free_full(endpoint->transports,
                                (GDestroyNotify) media_transport_destroy);
 
-       g_dbus_remove_watch(adapter->conn, endpoint->watch);
+       g_dbus_remove_watch(btd_get_dbus_connection(), endpoint->watch);
        g_free(endpoint->capabilities);
        g_free(endpoint->sender);
        g_free(endpoint->path);
@@ -170,6 +160,32 @@ static void media_endpoint_destroy(struct media_endpoint *endpoint)
        g_free(endpoint);
 }
 
+static struct media_endpoint *media_adapter_find_endpoint(
+                                               struct media_adapter *adapter,
+                                               const char *sender,
+                                               const char *path,
+                                               const char *uuid)
+{
+       GSList *l;
+
+       for (l = adapter->endpoints; l; l = l->next) {
+               struct media_endpoint *endpoint = l->data;
+
+               if (sender && g_strcmp0(endpoint->sender, sender) != 0)
+                       continue;
+
+               if (path && g_strcmp0(endpoint->path, path) != 0)
+                       continue;
+
+               if (uuid && strcasecmp(endpoint->uuid, uuid) != 0)
+                       continue;
+
+               return endpoint;
+       }
+
+       return NULL;
+}
+
 static void media_endpoint_remove(struct media_endpoint *endpoint)
 {
        struct media_adapter *adapter = endpoint->adapter;
@@ -184,6 +200,11 @@ static void media_endpoint_remove(struct media_endpoint *endpoint)
 
        adapter->endpoints = g_slist_remove(adapter->endpoints, endpoint);
 
+       if (media_adapter_find_endpoint(adapter, NULL, NULL,
+                                               endpoint->uuid) == NULL)
+               btd_profile_remove_custom_prop(endpoint->uuid,
+                                                       "MediaEndpoints");
+
        media_endpoint_destroy(endpoint);
 }
 
@@ -195,26 +216,12 @@ static void media_endpoint_exit(DBusConnection *connection, void *user_data)
        media_endpoint_remove(endpoint);
 }
 
-static void headset_setconf_cb(struct media_endpoint *endpoint, void *ret,
-                                               int size, void *user_data)
-{
-       struct audio_device *dev = user_data;
-
-       if (ret != NULL)
-               return;
-
-       headset_shutdown(dev);
-}
-
 static void clear_configuration(struct media_endpoint *endpoint,
                                        struct media_transport *transport)
 {
-       DBusConnection *conn;
        DBusMessage *msg;
        const char *path;
 
-       conn = endpoint->adapter->conn;
-
        msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
                                                MEDIA_ENDPOINT_INTERFACE,
                                                "ClearConfiguration");
@@ -226,7 +233,7 @@ static void clear_configuration(struct media_endpoint *endpoint,
        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);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
 done:
        endpoint->transports = g_slist_remove(endpoint->transports, transport);
        media_transport_destroy(transport);
@@ -307,8 +314,7 @@ done:
        endpoint_request_free(request);
 }
 
-static gboolean media_endpoint_async_call(DBusConnection *conn,
-                                       DBusMessage *msg,
+static gboolean media_endpoint_async_call(DBusMessage *msg,
                                        struct media_endpoint *endpoint,
                                        media_endpoint_cb_t cb,
                                        void *user_data,
@@ -319,7 +325,8 @@ static gboolean media_endpoint_async_call(DBusConnection *conn,
        request = g_new0(struct endpoint_request, 1);
 
        /* Timeout should be less than avdtp request timeout (4 seconds) */
-       if (dbus_connection_send_with_reply(conn, msg, &request->call,
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
+                                               msg, &request->call,
                                                REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                g_free(request);
@@ -351,11 +358,8 @@ static gboolean select_configuration(struct media_endpoint *endpoint,
                                                void *user_data,
                                                GDestroyNotify destroy)
 {
-       DBusConnection *conn;
        DBusMessage *msg;
 
-       conn = endpoint->adapter->conn;
-
        msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
                                                MEDIA_ENDPOINT_INTERFACE,
                                                "SelectConfiguration");
@@ -368,16 +372,16 @@ static gboolean select_configuration(struct media_endpoint *endpoint,
                                        &capabilities, length,
                                        DBUS_TYPE_INVALID);
 
-       return media_endpoint_async_call(conn, msg, endpoint, cb, user_data,
-                                                               destroy);
+       return media_endpoint_async_call(msg, endpoint, cb, user_data, destroy);
 }
 
-static gint transport_device_cmp(gconstpointer data, gconstpointer user_data)
+static int transport_device_cmp(gconstpointer data, gconstpointer user_data)
 {
        struct media_transport *transport = (struct media_transport *) data;
-       const struct audio_device *device = user_data;
+       const struct btd_device *device = user_data;
+       const struct btd_device *dev = media_transport_get_dev(transport);
 
-       if (device == media_transport_get_dev(transport))
+       if (device == dev)
                return 0;
 
        return -1;
@@ -385,7 +389,7 @@ static gint transport_device_cmp(gconstpointer data, gconstpointer user_data)
 
 static struct media_transport *find_device_transport(
                                        struct media_endpoint *endpoint,
-                                       struct audio_device *device)
+                                       struct btd_device *device)
 {
        GSList *match;
 
@@ -397,14 +401,20 @@ static struct media_transport *find_device_transport(
        return match->data;
 }
 
+struct a2dp_config_data {
+       struct a2dp_setup *setup;
+       a2dp_endpoint_config_t cb;
+};
+
 static gboolean set_configuration(struct media_endpoint *endpoint,
-                                       struct audio_device *device,
                                        uint8_t *configuration, size_t size,
                                        media_endpoint_cb_t cb,
                                        void *user_data,
                                        GDestroyNotify destroy)
 {
-       DBusConnection *conn;
+       struct a2dp_config_data *data = user_data;
+       struct btd_device *device = a2dp_setup_get_device(data->setup);
+       DBusConnection *conn = btd_get_dbus_connection();
        DBusMessage *msg;
        const char *path;
        DBusMessageIter iter;
@@ -415,10 +425,8 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
        if (transport != NULL)
                return FALSE;
 
-       conn = endpoint->adapter->conn;
-
-       transport = media_transport_create(conn, endpoint, device,
-                                               configuration, size);
+       transport = media_transport_create(device, configuration, size,
+                                                               endpoint);
        if (transport == NULL)
                return FALSE;
 
@@ -438,10 +446,9 @@ static gboolean set_configuration(struct media_endpoint *endpoint,
        path = media_transport_get_path(transport);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
 
-       transport_get_properties(transport, &iter);
+       g_dbus_get_properties(conn, path, "org.bluez.MediaTransport1", &iter);
 
-       return media_endpoint_async_call(conn, msg, endpoint, cb, user_data,
-                                                               destroy);
+       return media_endpoint_async_call(msg, endpoint, cb, user_data, destroy);
 }
 
 static void release_endpoint(struct media_endpoint *endpoint)
@@ -454,6 +461,8 @@ static void release_endpoint(struct media_endpoint *endpoint)
        if (endpoint->watch == 0)
                goto done;
 
+       clear_endpoint(endpoint);
+
        msg = dbus_message_new_method_call(endpoint->sender, endpoint->path,
                                                MEDIA_ENDPOINT_INTERFACE,
                                                "Release");
@@ -462,47 +471,12 @@ static void release_endpoint(struct media_endpoint *endpoint)
                return;
        }
 
-       g_dbus_send_message(endpoint->adapter->conn, msg);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
 
 done:
        media_endpoint_remove(endpoint);
 }
 
-static void headset_state_changed(struct audio_device *dev,
-                                       headset_state_t old_state,
-                                       headset_state_t new_state,
-                                       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:
-               transport = find_device_transport(endpoint, dev);
-
-               if (transport != NULL) {
-                       DBG("Clear endpoint %p", endpoint);
-                       clear_configuration(endpoint, transport);
-               }
-               break;
-       case HEADSET_STATE_CONNECTING:
-               set_configuration(endpoint, dev, NULL, 0, headset_setconf_cb,
-                                                               dev, NULL);
-               break;
-       case HEADSET_STATE_CONNECTED:
-               break;
-       case HEADSET_STATE_PLAY_IN_PROGRESS:
-               break;
-       case HEADSET_STATE_PLAYING:
-               break;
-       }
-}
-
 static const char *get_name(struct a2dp_sep *sep, void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
@@ -519,11 +493,6 @@ static size_t get_capabilities(struct a2dp_sep *sep, uint8_t **capabilities,
        return endpoint->size;
 }
 
-struct a2dp_config_data {
-       struct a2dp_setup *setup;
-       a2dp_endpoint_config_t cb;
-};
-
 struct a2dp_select_data {
        struct a2dp_setup *setup;
        a2dp_endpoint_select_t cb;
@@ -564,8 +533,8 @@ static void config_cb(struct media_endpoint *endpoint, void *ret, int size,
        data->cb(data->setup, ret ? TRUE : FALSE);
 }
 
-static int set_config(struct a2dp_sep *sep, struct audio_device *dev,
-                               uint8_t *configuration, size_t length,
+static int set_config(struct a2dp_sep *sep, uint8_t *configuration,
+                               size_t length,
                                struct a2dp_setup *setup,
                                a2dp_endpoint_config_t cb,
                                void *user_data)
@@ -577,8 +546,8 @@ static int set_config(struct a2dp_sep *sep, struct audio_device *dev,
        data->setup = setup;
        data->cb = cb;
 
-       if (set_configuration(endpoint, dev, configuration, length,
-                                       config_cb, data, g_free) == TRUE)
+       if (set_configuration(endpoint, configuration, length, config_cb, data,
+                                                       g_free) == TRUE)
                return 0;
 
        g_free(data);
@@ -615,60 +584,15 @@ static void a2dp_destroy_endpoint(void *user_data)
 {
        struct media_endpoint *endpoint = user_data;
 
-       clear_endpoint(endpoint);
-
        endpoint->sep = NULL;
        release_endpoint(endpoint);
 }
 
-static void gateway_setconf_cb(struct media_endpoint *endpoint, void *ret,
-                                               int size, void *user_data)
-{
-       struct audio_device *dev = user_data;
-
-       if (ret != NULL)
-               return;
-
-       gateway_set_state(dev, GATEWAY_STATE_DISCONNECTED);
-}
-
-static void gateway_state_changed(struct audio_device *dev,
-                                       gateway_state_t old_state,
-                                       gateway_state_t new_state,
-                                       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:
-               transport = find_device_transport(endpoint, dev);
-               if (transport != NULL) {
-                       DBG("Clear endpoint %p", endpoint);
-                       clear_configuration(endpoint, transport);
-               }
-               break;
-       case GATEWAY_STATE_CONNECTING:
-               set_configuration(endpoint, dev, NULL, 0,
-                                       gateway_setconf_cb, dev, NULL);
-               break;
-       case GATEWAY_STATE_CONNECTED:
-               break;
-       case GATEWAY_STATE_PLAYING:
-               break;
-       }
-}
-
 static gboolean endpoint_init_a2dp_source(struct media_endpoint *endpoint,
                                                gboolean delay_reporting,
                                                int *err)
 {
-       endpoint->sep = a2dp_add_sep(&endpoint->adapter->src,
+       endpoint->sep = a2dp_add_sep(endpoint->adapter->btd_adapter,
                                        AVDTP_SEP_TYPE_SOURCE, endpoint->codec,
                                        delay_reporting, &a2dp_endpoint,
                                        endpoint, a2dp_destroy_endpoint, err);
@@ -682,7 +606,7 @@ static gboolean endpoint_init_a2dp_sink(struct media_endpoint *endpoint,
                                                gboolean delay_reporting,
                                                int *err)
 {
-       endpoint->sep = a2dp_add_sep(&endpoint->adapter->src,
+       endpoint->sep = a2dp_add_sep(endpoint->adapter->btd_adapter,
                                        AVDTP_SEP_TYPE_SINK, endpoint->codec,
                                        delay_reporting, &a2dp_endpoint,
                                        endpoint, a2dp_destroy_endpoint, err);
@@ -692,48 +616,100 @@ static gboolean endpoint_init_a2dp_sink(struct media_endpoint *endpoint,
        return TRUE;
 }
 
-static gboolean endpoint_init_ag(struct media_endpoint *endpoint, int *err)
+static struct media_adapter *find_adapter(struct btd_device *device)
 {
-       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;
+       for (l = adapters; l; l = l->next) {
+               struct media_adapter *adapter = l->data;
 
-               set_configuration(endpoint, dev, NULL, 0,
-                                               headset_setconf_cb, dev, NULL);
+               if (adapter->btd_adapter == device_get_adapter(device))
+                       return adapter;
        }
 
-       g_slist_free(list);
+       return NULL;
+}
 
-       return TRUE;
+static bool endpoint_properties_exists(const char *uuid,
+                                               struct btd_device *dev,
+                                               void *user_data)
+{
+       struct media_adapter *adapter;
+
+       adapter = find_adapter(dev);
+       if (adapter == NULL)
+               return false;
+
+       if (media_adapter_find_endpoint(adapter, NULL, NULL, uuid) == NULL)
+               return false;
+
+       return true;
+}
+
+static void append_endpoint(struct media_endpoint *endpoint,
+                                               DBusMessageIter *dict)
+{
+       DBusMessageIter entry, var, props;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+                                               &endpoint->sender);
+
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, "a{sv}",
+                                                               &var);
+
+       dbus_message_iter_open_container(&var, 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,
+                                       &props);
+
+       dict_append_entry(&props, "Path", DBUS_TYPE_OBJECT_PATH,
+                                                       &endpoint->path);
+       dict_append_entry(&props, "Codec", DBUS_TYPE_BYTE, &endpoint->codec);
+       dict_append_array(&props, "Capabilities", DBUS_TYPE_BYTE,
+                               &endpoint->capabilities, endpoint->size);
+
+       dbus_message_iter_close_container(&var, &props);
+       dbus_message_iter_close_container(&entry, &var);
+       dbus_message_iter_close_container(dict, &entry);
 }
 
-static gboolean endpoint_init_hs(struct media_endpoint *endpoint, int *err)
+static bool endpoint_properties_get(const char *uuid,
+                                               struct btd_device *dev,
+                                               DBusMessageIter *iter,
+                                               void *user_data)
 {
-       GSList *list;
+       struct media_adapter *adapter;
+       DBusMessageIter dict;
        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);
+       adapter = find_adapter(dev);
+       if (adapter == NULL)
+               return false;
 
-       for (l = list; l != NULL; l = l->next) {
-               struct audio_device *dev = l->data;
+       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);
 
-               set_configuration(endpoint, dev, NULL, 0,
-                                               gateway_setconf_cb, dev, NULL);
+       for (l = adapter->endpoints; l; l = l->next) {
+               struct media_endpoint *endpoint = l->data;
+
+               if (strcasecmp(endpoint->uuid, uuid) != 0)
+                       continue;
+
+               append_endpoint(endpoint, &dict);
        }
 
-       g_slist_free(list);
+       dbus_message_iter_close_container(iter, &dict);
 
-       return TRUE;
+       return true;
 }
 
 static struct media_endpoint *media_endpoint_create(struct media_adapter *adapter,
@@ -771,10 +747,10 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
                                                        delay_reporting, err);
        else if (strcasecmp(uuid, HFP_AG_UUID) == 0 ||
                                        strcasecmp(uuid, HSP_AG_UUID) == 0)
-               succeeded = endpoint_init_ag(endpoint, err);
+               succeeded = TRUE;
        else if (strcasecmp(uuid, HFP_HS_UUID) == 0 ||
                                        strcasecmp(uuid, HSP_HS_UUID) == 0)
-               succeeded = endpoint_init_hs(endpoint, err);
+               succeeded = TRUE;
        else {
                succeeded = FALSE;
 
@@ -783,13 +759,20 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
        }
 
        if (!succeeded) {
-               g_free(endpoint);
+               media_endpoint_destroy(endpoint);
                return NULL;
        }
 
-       endpoint->watch = g_dbus_add_disconnect_watch(adapter->conn, sender,
-                                               media_endpoint_exit, endpoint,
+       endpoint->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+                                               sender, media_endpoint_exit,
+                                               endpoint, NULL);
+
+       if (media_adapter_find_endpoint(adapter, NULL, NULL, uuid) == NULL) {
+               btd_profile_add_custom_prop(uuid, "a{sv}", "MediaEndpoints",
+                                               endpoint_properties_exists,
+                                               endpoint_properties_get,
                                                NULL);
+       }
 
        adapter->endpoints = g_slist_append(adapter->endpoints, endpoint);
        info("Endpoint registered: sender=%s path=%s", sender, path);
@@ -799,32 +782,6 @@ static struct media_endpoint *media_endpoint_create(struct media_adapter *adapte
        return endpoint;
 }
 
-static struct media_endpoint *media_adapter_find_endpoint(
-                                               struct media_adapter *adapter,
-                                               const char *sender,
-                                               const char *path,
-                                               const char *uuid)
-{
-       GSList *l;
-
-       for (l = adapter->endpoints; l; l = l->next) {
-               struct media_endpoint *endpoint = l->data;
-
-               if (sender && g_strcmp0(endpoint->sender, sender) != 0)
-                       continue;
-
-               if (path && g_strcmp0(endpoint->path, path) != 0)
-                       continue;
-
-               if (uuid && g_strcmp0(endpoint->uuid, uuid) != 0)
-                       continue;
-
-               return endpoint;
-       }
-
-       return NULL;
-}
-
 static int parse_properties(DBusMessageIter *props, const char **uuid,
                                gboolean *delay_reporting, uint8_t *codec,
                                uint8_t **capabilities, int *size)
@@ -926,7 +883,7 @@ static DBusMessage *unregister_endpoint(DBusConnection *conn, DBusMessage *msg,
        if (!dbus_message_get_args(msg, NULL,
                                DBUS_TYPE_OBJECT_PATH, &path,
                                DBUS_TYPE_INVALID))
-               return NULL;
+               return btd_error_invalid_args(msg);
 
        sender = dbus_message_get_sender(msg);
 
@@ -975,11 +932,12 @@ static void release_player(struct media_player *mp)
                return;
        }
 
-       g_dbus_send_message(mp->adapter->conn, msg);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
 }
 
 static void media_player_free(gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct media_player *mp = data;
        struct media_adapter *adapter = mp->adapter;
 
@@ -988,9 +946,9 @@ static void media_player_free(gpointer data)
                release_player(mp);
        }
 
-       g_dbus_remove_watch(adapter->conn, mp->watch);
-       g_dbus_remove_watch(adapter->conn, mp->property_watch);
-       g_dbus_remove_watch(adapter->conn, mp->track_watch);
+       g_dbus_remove_watch(conn, mp->watch);
+       g_dbus_remove_watch(conn, mp->properties_watch);
+       g_dbus_remove_watch(conn, mp->seek_watch);
 
        if (mp->track)
                g_hash_table_unref(mp->track);
@@ -1001,6 +959,7 @@ static void media_player_free(gpointer data)
        g_timer_destroy(mp->timer);
        g_free(mp->sender);
        g_free(mp->path);
+       g_free(mp->status);
        g_free(mp);
 }
 
@@ -1028,246 +987,97 @@ static void media_player_remove(struct media_player *mp)
        media_player_destroy(mp);
 }
 
-static const char *attrval_to_str(uint8_t attr, uint8_t value)
+static GList *list_settings(void *user_data)
 {
-       switch (attr) {
-       case AVRCP_ATTRIBUTE_EQUALIZER:
-               switch (value) {
-               case AVRCP_EQUALIZER_ON:
-                       return "on";
-               case AVRCP_EQUALIZER_OFF:
-                       return "off";
-               }
-
-               break;
-       case AVRCP_ATTRIBUTE_REPEAT_MODE:
-               switch (value) {
-               case AVRCP_REPEAT_MODE_OFF:
-                       return "off";
-               case AVRCP_REPEAT_MODE_SINGLE:
-                       return "singletrack";
-               case AVRCP_REPEAT_MODE_ALL:
-                       return "alltracks";
-               case AVRCP_REPEAT_MODE_GROUP:
-                       return "group";
-               }
+       struct media_player *mp = user_data;
 
-               break;
-       /* Shuffle and scan have the same values */
-       case AVRCP_ATTRIBUTE_SHUFFLE:
-       case AVRCP_ATTRIBUTE_SCAN:
-               switch (value) {
-               case AVRCP_SCAN_OFF:
-                       return "off";
-               case AVRCP_SCAN_ALL:
-                       return "alltracks";
-               case AVRCP_SCAN_GROUP:
-                       return "group";
-               }
+       DBG("");
 
-               break;
-       }
+       if (mp->settings == NULL)
+               return NULL;
 
-       return NULL;
+       return g_hash_table_get_keys(mp->settings);
 }
 
-static int attrval_to_val(uint8_t attr, const char *value)
+static const char *get_setting(const char *key, void *user_data)
 {
-       int ret;
-
-       switch (attr) {
-       case AVRCP_ATTRIBUTE_EQUALIZER:
-               if (!strcmp(value, "off"))
-                       ret = AVRCP_EQUALIZER_OFF;
-               else if (!strcmp(value, "on"))
-                       ret = AVRCP_EQUALIZER_ON;
-               else
-                       ret = -EINVAL;
-
-               return ret;
-       case AVRCP_ATTRIBUTE_REPEAT_MODE:
-               if (!strcmp(value, "off"))
-                       ret = AVRCP_REPEAT_MODE_OFF;
-               else if (!strcmp(value, "singletrack"))
-                       ret = AVRCP_REPEAT_MODE_SINGLE;
-               else if (!strcmp(value, "alltracks"))
-                       ret = AVRCP_REPEAT_MODE_ALL;
-               else if (!strcmp(value, "group"))
-                       ret = AVRCP_REPEAT_MODE_GROUP;
-               else
-                       ret = -EINVAL;
-
-               return ret;
-       case AVRCP_ATTRIBUTE_SHUFFLE:
-               if (!strcmp(value, "off"))
-                       ret = AVRCP_SHUFFLE_OFF;
-               else if (!strcmp(value, "alltracks"))
-                       ret = AVRCP_SHUFFLE_ALL;
-               else if (!strcmp(value, "group"))
-                       ret = AVRCP_SHUFFLE_GROUP;
-               else
-                       ret = -EINVAL;
-
-               return ret;
-       case AVRCP_ATTRIBUTE_SCAN:
-               if (!strcmp(value, "off"))
-                       ret = AVRCP_SCAN_OFF;
-               else if (!strcmp(value, "alltracks"))
-                       ret = AVRCP_SCAN_ALL;
-               else if (!strcmp(value, "group"))
-                       ret = AVRCP_SCAN_GROUP;
-               else
-                       ret = -EINVAL;
+       struct media_player *mp = user_data;
 
-               return ret;
-       }
+       DBG("%s", key);
 
-       return -EINVAL;
+       return g_hash_table_lookup(mp->settings, key);
 }
 
-static const char *attr_to_str(uint8_t attr)
+static void set_shuffle_setting(DBusMessageIter *iter, const char *value)
 {
-       switch (attr) {
-       case AVRCP_ATTRIBUTE_EQUALIZER:
-               return "Equalizer";
-       case AVRCP_ATTRIBUTE_REPEAT_MODE:
-               return "Repeat";
-       case AVRCP_ATTRIBUTE_SHUFFLE:
-               return "Shuffle";
-       case AVRCP_ATTRIBUTE_SCAN:
-               return "Scan";
-       }
+       const char *key = "Shuffle";
+       dbus_bool_t val;
+       DBusMessageIter var;
 
-       return NULL;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                               DBUS_TYPE_BOOLEAN_AS_STRING,
+                                               &var);
+       val = strcasecmp(value, "off") != 0;
+       dbus_message_iter_append_basic(&var, DBUS_TYPE_BOOLEAN, &val);
+       dbus_message_iter_close_container(iter, &var);
 }
 
-static int attr_to_val(const char *str)
-{
-       if (!strcasecmp(str, "Equalizer"))
-               return AVRCP_ATTRIBUTE_EQUALIZER;
-       else if (!strcasecmp(str, "Repeat"))
-               return AVRCP_ATTRIBUTE_REPEAT_MODE;
-       else if (!strcasecmp(str, "Shuffle"))
-               return AVRCP_ATTRIBUTE_SHUFFLE;
-       else if (!strcasecmp(str, "Scan"))
-               return AVRCP_ATTRIBUTE_SCAN;
-
-       return -EINVAL;
-}
-
-static int play_status_to_val(const char *status)
-{
-       if (!strcasecmp(status, "stopped"))
-               return AVRCP_PLAY_STATUS_STOPPED;
-       else if (!strcasecmp(status, "playing"))
-               return AVRCP_PLAY_STATUS_PLAYING;
-       else if (!strcasecmp(status, "paused"))
-               return AVRCP_PLAY_STATUS_PAUSED;
-       else if (!strcasecmp(status, "forward-seek"))
-               return AVRCP_PLAY_STATUS_FWD_SEEK;
-       else if (!strcasecmp(status, "reverse-seek"))
-               return AVRCP_PLAY_STATUS_REV_SEEK;
-       else if (!strcasecmp(status, "error"))
-               return AVRCP_PLAY_STATUS_ERROR;
-
-       return -EINVAL;
-}
-
-static int metadata_to_val(const char *str)
-{
-       if (!strcasecmp(str, "Title"))
-               return AVRCP_MEDIA_ATTRIBUTE_TITLE;
-       else if (!strcasecmp(str, "Artist"))
-               return AVRCP_MEDIA_ATTRIBUTE_ARTIST;
-       else if (!strcasecmp(str, "Album"))
-               return AVRCP_MEDIA_ATTRIBUTE_ALBUM;
-       else if (!strcasecmp(str, "Genre"))
-               return AVRCP_MEDIA_ATTRIBUTE_GENRE;
-       else if (!strcasecmp(str, "NumberOfTracks"))
-               return AVRCP_MEDIA_ATTRIBUTE_N_TRACKS;
-       else if (!strcasecmp(str, "Number"))
-               return AVRCP_MEDIA_ATTRIBUTE_TRACK;
-       else if (!strcasecmp(str, "Duration"))
-               return AVRCP_MEDIA_ATTRIBUTE_DURATION;
-
-       return -EINVAL;
-}
-
-static const char *metadata_to_str(uint32_t id)
-{
-       switch (id) {
-       case AVRCP_MEDIA_ATTRIBUTE_TITLE:
-               return "Title";
-       case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
-               return "Artist";
-       case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
-               return "Album";
-       case AVRCP_MEDIA_ATTRIBUTE_GENRE:
-               return "Genre";
-       case AVRCP_MEDIA_ATTRIBUTE_TRACK:
+static const char *repeat_to_loop_status(const char *value)
+{
+       if (strcasecmp(value, "off") == 0)
+               return "None";
+       else if (strcasecmp(value, "singletrack") == 0)
                return "Track";
-       case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS:
-               return "NumberOfTracks";
-       case AVRCP_MEDIA_ATTRIBUTE_DURATION:
-               return "Duration";
-       }
+       else if (strcasecmp(value, "alltracks") == 0)
+               return "Playlist";
 
        return NULL;
 }
 
-static int get_setting(uint8_t attr, void *user_data)
+static void set_repeat_setting(DBusMessageIter *iter, const char *value)
 {
-       struct media_player *mp = user_data;
-       guint attr_uint = attr;
-       void *value;
-
-       DBG("%s", attr_to_str(attr));
-
-       value = g_hash_table_lookup(mp->settings, GUINT_TO_POINTER(attr_uint));
-       if (!value)
-               return -EINVAL;
+       const char *key = "LoopStatus";
+       const char *val;
+       DBusMessageIter var;
 
-       return GPOINTER_TO_UINT(value);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &key);
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                               DBUS_TYPE_STRING_AS_STRING,
+                                               &var);
+       val = repeat_to_loop_status(value);
+       dbus_message_iter_append_basic(&var, DBUS_TYPE_STRING, &val);
+       dbus_message_iter_close_container(iter, &var);
 }
 
-static int set_setting(uint8_t attr, uint8_t val, void *user_data)
+static int set_setting(const char *key, const char *value, void *user_data)
 {
        struct media_player *mp = user_data;
-       struct media_adapter *adapter = mp->adapter;
-       const char *property, *value;
-       guint attr_uint = attr;
+       const char *iface = MEDIA_PLAYER_INTERFACE;
        DBusMessage *msg;
-       DBusMessageIter iter, var;
-
-       property = attr_to_str(attr);
-       value = attrval_to_str(attr, val);
-
-       DBG("%s = %s", property, value);
+       DBusMessageIter iter;
 
-       if (property == NULL || value == NULL)
-               return -EINVAL;
+       DBG("%s = %s", key, value);
 
-       if (!g_hash_table_lookup(mp->settings, GUINT_TO_POINTER(attr_uint)))
+       if (!g_hash_table_lookup(mp->settings, key))
                return -EINVAL;
 
        msg = dbus_message_new_method_call(mp->sender, mp->path,
-                                               MEDIA_PLAYER_INTERFACE,
-                                               "SetProperty");
+                                       DBUS_INTERFACE_PROPERTIES, "Set");
        if (msg == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
        }
 
        dbus_message_iter_init_append(msg, &iter);
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &property);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &iface);
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_VARIANT,
-                                               DBUS_TYPE_STRING_AS_STRING,
-                                               &var);
-       dbus_message_iter_append_basic(&var, DBUS_TYPE_STRING, &value);
-       dbus_message_iter_close_container(&iter, &var);
+       if (strcasecmp(key, "Shuffle") == 0)
+               set_shuffle_setting(&iter, value);
+       else if (strcasecmp(key, "Repeat") == 0)
+               set_repeat_setting(&iter, value);
 
-       g_dbus_send_message(adapter->conn, msg);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
 
        return 0;
 }
@@ -1296,31 +1106,19 @@ static uint64_t get_uid(void *user_data)
        return 0;
 }
 
-static void *get_metadata(uint32_t id, void *user_data)
+static const char *get_metadata(const char *key, void *user_data)
 {
        struct media_player *mp = user_data;
-       struct metadata_value *value;
 
-       DBG("%s", metadata_to_str(id));
+       DBG("%s", key);
 
        if (mp->track == NULL)
                return NULL;
 
-       value = g_hash_table_lookup(mp->track, GUINT_TO_POINTER(id));
-       if (!value)
-               return NULL;
-
-       switch (value->type) {
-       case DBUS_TYPE_STRING:
-               return value->value.str;
-       case DBUS_TYPE_UINT32:
-               return GUINT_TO_POINTER(value->value.num);
-       }
-
-       return NULL;
+       return g_hash_table_lookup(mp->track, key);
 }
 
-static uint8_t get_status(void *user_data)
+static const char *get_status(void *user_data)
 {
        struct media_player *mp = user_data;
 
@@ -1333,7 +1131,7 @@ static uint32_t get_position(void *user_data)
        double timedelta;
        uint32_t sec, msec;
 
-       if (mp->status != AVRCP_PLAY_STATUS_PLAYING)
+       if (mp->status == NULL || strcasecmp(mp->status, "Playing") != 0)
                return mp->position;
 
        timedelta = g_timer_elapsed(mp->timer, NULL);
@@ -1344,7 +1142,14 @@ 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)
+static uint32_t get_duration(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       return mp->duration;
+}
+
+static void set_volume(uint8_t volume, struct btd_device *dev, void *user_data)
 {
        struct media_player *mp = user_data;
        GSList *l;
@@ -1370,15 +1175,98 @@ static void set_volume(uint8_t volume, struct audio_device *dev, void *user_data
        }
 }
 
+static bool media_player_send(struct media_player *mp, const char *name)
+{
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(mp->sender, mp->path,
+                                       MEDIA_PLAYER_INTERFACE, name);
+       if (msg == NULL) {
+               error("Couldn't allocate D-Bus message");
+               return false;
+       }
+
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+
+       return true;
+}
+
+static bool play(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       DBG("");
+
+       if (!mp->play || !mp->control)
+               return false;
+
+       return media_player_send(mp, "Play");
+}
+
+static bool stop(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       DBG("");
+
+       if (!mp->control)
+               return false;
+
+       return media_player_send(mp, "Stop");
+}
+
+static bool pause(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       DBG("");
+
+       if (!mp->pause || !mp->control)
+               return false;
+
+       return media_player_send(mp, "Pause");
+}
+
+static bool next(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       DBG("");
+
+       if (!mp->next || !mp->control)
+               return false;
+
+       return media_player_send(mp, "Next");
+}
+
+static bool previous(void *user_data)
+{
+       struct media_player *mp = user_data;
+
+       DBG("");
+
+       if (!mp->previous || !mp->control)
+               return false;
+
+       return media_player_send(mp, "Previous");
+}
+
 static struct avrcp_player_cb player_cb = {
+       .list_settings = list_settings,
        .get_setting = get_setting,
        .set_setting = set_setting,
        .list_metadata = list_metadata,
        .get_uid = get_uid,
        .get_metadata = get_metadata,
        .get_position = get_position,
+       .get_duration = get_duration,
        .get_status = get_status,
-       .set_volume = set_volume
+       .set_volume = set_volume,
+       .play = play,
+       .stop = stop,
+       .pause = pause,
+       .next = next,
+       .previous = previous,
 };
 
 static void media_player_exit(DBusConnection *connection, void *user_data)
@@ -1392,7 +1280,6 @@ static void media_player_exit(DBusConnection *connection, void *user_data)
 static gboolean set_status(struct media_player *mp, DBusMessageIter *iter)
 {
        const char *value;
-       int val;
 
        if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
                return FALSE;
@@ -1400,137 +1287,157 @@ static gboolean set_status(struct media_player *mp, DBusMessageIter *iter)
        dbus_message_iter_get_basic(iter, &value);
        DBG("Status=%s", value);
 
-       val = play_status_to_val(value);
-       if (val < 0) {
-               error("Invalid status");
-               return FALSE;
-       }
-
-       if (mp->status == val)
+       if (g_strcmp0(mp->status, value) == 0)
                return TRUE;
 
        mp->position = get_position(mp);
        g_timer_start(mp->timer);
 
-       mp->status = val;
+       g_free(mp->status);
+       mp->status = g_strdup(value);
 
-       avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, &val);
+       avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, mp->status);
 
        return TRUE;
 }
 
 static gboolean set_position(struct media_player *mp, DBusMessageIter *iter)
 {
-       uint32_t value;
-       struct metadata_value *duration;
+       uint64_t value;
+       const char *status;
 
-       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_INT64)
                        return FALSE;
 
        dbus_message_iter_get_basic(iter, &value);
-       DBG("Position=%u", value);
+
+       value /= 1000;
+
+       if (value > get_position(mp))
+               status = "forward-seek";
+       else
+               status = "reverse-seek";
 
        mp->position = value;
        g_timer_start(mp->timer);
 
+       DBG("Position=%u", mp->position);
+
        if (!mp->position) {
                avrcp_player_event(mp->player,
                                        AVRCP_EVENT_TRACK_REACHED_START, NULL);
                return TRUE;
        }
 
-       duration = g_hash_table_lookup(mp->track, GUINT_TO_POINTER(
-                                       AVRCP_MEDIA_ATTRIBUTE_DURATION));
-
        /*
         * If position is the maximum value allowed or greater than track's
         * duration, we send a track-reached-end event.
         */
-       if (mp->position == UINT32_MAX ||
-                       (duration && mp->position >= duration->value.num))
+       if (mp->position == UINT32_MAX || mp->position >= mp->duration) {
                avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_END,
                                                                        NULL);
+               return TRUE;
+       }
+
+       /* Send a status change to force resync the position */
+       avrcp_player_event(mp->player, AVRCP_EVENT_STATUS_CHANGED, status);
 
        return TRUE;
 }
 
-static gboolean set_property(struct media_player *mp, const char *key,
-                                                       DBusMessageIter *entry)
+static void set_metadata(struct media_player *mp, const char *key,
+                                                       const char *value)
+{
+       DBG("%s=%s", key, value);
+       g_hash_table_replace(mp->track, g_strdup(key), g_strdup(value));
+}
+
+static gboolean parse_string_metadata(struct media_player *mp, const char *key,
+                                                       DBusMessageIter *iter)
 {
-       DBusMessageIter var;
        const char *value;
-       int attr, val;
 
-       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
                return FALSE;
 
-       dbus_message_iter_recurse(entry, &var);
+       dbus_message_iter_get_basic(iter, &value);
 
-       if (strcasecmp(key, "Status") == 0)
-               return set_status(mp, &var);
+       set_metadata(mp, key, value);
 
-       if (strcasecmp(key, "Position") == 0)
-               return set_position(mp, &var);
+       return TRUE;
+}
 
-       attr = attr_to_val(key);
-       if (attr < 0)
-               return FALSE;
+static gboolean parse_array_metadata(struct media_player *mp, const char *key,
+                                                       DBusMessageIter *iter)
+{
+       DBusMessageIter array;
+       const char *value;
 
-       if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_STRING)
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_ARRAY)
                return FALSE;
 
-       dbus_message_iter_get_basic(&var, &value);
+       dbus_message_iter_recurse(iter, &array);
 
-       val = attrval_to_val(attr, value);
-       if (val < 0)
+       if (dbus_message_iter_get_arg_type(&array) == DBUS_TYPE_INVALID)
+               return TRUE;
+
+       if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRING)
                return FALSE;
 
-       DBG("%s=%s", key, value);
+       dbus_message_iter_get_basic(&array, &value);
 
-       g_hash_table_replace(mp->settings, GUINT_TO_POINTER(attr),
-                                               GUINT_TO_POINTER(val));
+       set_metadata(mp, key, value);
 
        return TRUE;
 }
 
-static gboolean property_changed(DBusConnection *connection, DBusMessage *msg,
-                                                       void *user_data)
+static gboolean parse_int64_metadata(struct media_player *mp, const char *key,
+                                                       DBusMessageIter *iter)
 {
-       struct media_player *mp = user_data;
-       DBusMessageIter iter;
-       const char *property;
+       uint64_t value;
+       char valstr[20];
+       int type;
 
-       DBG("sender=%s path=%s", mp->sender, mp->path);
+       type = dbus_message_iter_get_arg_type(iter);
+       if (type == DBUS_TYPE_UINT64)
+               warn("expected DBUS_TYPE_INT64 got DBUS_TYPE_UINT64");
+       else if (type != DBUS_TYPE_INT64)
+               return FALSE;
 
-       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_get_basic(iter, &value);
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-               return TRUE;
+       if (strcasecmp(key, "Duration") == 0) {
+               value /= 1000;
+               mp->duration = value;
        }
 
-       dbus_message_iter_get_basic(&iter, &property);
+       snprintf(valstr, 20, "%" PRIu64, value);
 
-       dbus_message_iter_next(&iter);
-
-       set_property(mp, property, &iter);
+       set_metadata(mp, key, valstr);
 
        return TRUE;
 }
 
-static void metadata_value_free(gpointer data)
+static gboolean parse_int32_metadata(struct media_player *mp, const char *key,
+                                                       DBusMessageIter *iter)
 {
-       struct metadata_value *value = data;
+       uint32_t value;
+       char valstr[20];
+       int type;
 
-       switch (value->type) {
-       case DBUS_TYPE_STRING:
-               g_free(value->value.str);
-               break;
-       }
+       type = dbus_message_iter_get_arg_type(iter);
+       if (type == DBUS_TYPE_UINT32)
+               warn("expected DBUS_TYPE_INT32 got DBUS_TYPE_UINT32");
+       else if (type != DBUS_TYPE_INT32)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       snprintf(valstr, 20, "%u", value);
 
-       g_free(value);
+       set_metadata(mp, key, valstr);
+
+       return TRUE;
 }
 
 static gboolean parse_player_metadata(struct media_player *mp,
@@ -1538,7 +1445,6 @@ static gboolean parse_player_metadata(struct media_player *mp,
 {
        DBusMessageIter dict;
        DBusMessageIter var;
-       GHashTable *track;
        int ctype;
        gboolean title = FALSE;
        uint64_t uid;
@@ -1549,175 +1455,190 @@ static gboolean parse_player_metadata(struct media_player *mp,
 
        dbus_message_iter_recurse(iter, &dict);
 
-       track = g_hash_table_new_full(g_direct_hash, g_direct_equal, NULL,
-                                                       metadata_value_free);
+       if (mp->track != NULL)
+               g_hash_table_unref(mp->track);
+
+       mp->track = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+                                                               g_free);
 
        while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
                                                        DBUS_TYPE_INVALID) {
                DBusMessageIter entry;
                const char *key;
-               struct metadata_value *value;
-               int id;
 
                if (ctype != DBUS_TYPE_DICT_ENTRY)
-                       goto parse_error;
+                       return FALSE;
 
                dbus_message_iter_recurse(&dict, &entry);
                if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       goto parse_error;
+                       return FALSE;
 
                dbus_message_iter_get_basic(&entry, &key);
                dbus_message_iter_next(&entry);
 
-               id = metadata_to_val(key);
-               if (id < 0)
-                       goto parse_error;
-
                if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
-                       goto parse_error;
+                       return FALSE;
 
                dbus_message_iter_recurse(&entry, &var);
 
-               value = g_new0(struct metadata_value, 1);
-               value->type = dbus_message_iter_get_arg_type(&var);
-
-               switch (id) {
-               case AVRCP_MEDIA_ATTRIBUTE_TITLE:
+               if (strcasecmp(key, "xesam:title") == 0) {
+                       if (!parse_string_metadata(mp, "Title", &var))
+                               return FALSE;
                        title = TRUE;
-               case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
-               case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
-               case AVRCP_MEDIA_ATTRIBUTE_GENRE:
-                       if (value->type != DBUS_TYPE_STRING) {
-                               g_free(value);
-                               goto parse_error;
-                       }
-
-                       dbus_message_iter_get_basic(&var, &value->value.str);
-                       break;
-               case AVRCP_MEDIA_ATTRIBUTE_TRACK:
-               case AVRCP_MEDIA_ATTRIBUTE_N_TRACKS:
-               case AVRCP_MEDIA_ATTRIBUTE_DURATION:
-                       if (value->type != DBUS_TYPE_UINT32) {
-                               g_free(value);
-                               goto parse_error;
-                       }
-
-                       dbus_message_iter_get_basic(&var, &value->value.num);
-                       break;
-               default:
-                       goto parse_error;
-               }
-
-               switch (value->type) {
-               case DBUS_TYPE_STRING:
-                       value->value.str = g_strdup(value->value.str);
-                       DBG("%s=%s", key, value->value.str);
-                       break;
-               default:
-                       DBG("%s=%u", key, value->value.num);
-               }
+               } else if (strcasecmp(key, "xesam:artist") == 0) {
+                       if (!parse_array_metadata(mp, "Artist", &var))
+                               return FALSE;
+               } else if (strcasecmp(key, "xesam:album") == 0) {
+                       if (!parse_string_metadata(mp, "Album", &var))
+                               return FALSE;
+               } else if (strcasecmp(key, "xesam:genre") == 0) {
+                       if (!parse_array_metadata(mp, "Genre", &var))
+                               return FALSE;
+               } else if (strcasecmp(key, "mpris:length") == 0) {
+                       if (!parse_int64_metadata(mp, "Duration", &var))
+                               return FALSE;
+               } else if (strcasecmp(key, "xesam:trackNumber") == 0) {
+                       if (!parse_int32_metadata(mp, "TrackNumber", &var))
+                               return FALSE;
+               } else
+                       DBG("%s not supported, ignoring", key);
 
-               g_hash_table_replace(track, GUINT_TO_POINTER(id), value);
                dbus_message_iter_next(&dict);
        }
 
-       if (g_hash_table_size(track) == 0) {
-               g_hash_table_unref(track);
-               track = NULL;
-       } else if (title == FALSE) {
-               struct metadata_value *value = g_new(struct metadata_value, 1);
-               uint32_t id = AVRCP_MEDIA_ATTRIBUTE_TITLE;
+       if (title == FALSE)
+               g_hash_table_insert(mp->track, g_strdup("Title"),
+                                                               g_strdup(""));
 
-               value->type = DBUS_TYPE_STRING;
-               value->value.str = g_strdup("");
-               g_hash_table_insert(track, GUINT_TO_POINTER(id), value);
-       }
-
-       if (mp->track != NULL)
-               g_hash_table_unref(mp->track);
-
-       mp->track = track;
        mp->position = 0;
        g_timer_start(mp->timer);
        uid = get_uid(mp);
 
        avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_CHANGED, &uid);
-       avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_START,
-                                                               NULL);
+       avrcp_player_event(mp->player, AVRCP_EVENT_TRACK_REACHED_START, NULL);
+
+       return TRUE;
+}
+
+static gboolean set_property(struct media_player *mp, const char *key,
+                                                       const char *value)
+{
+       const char *curval;
+
+       curval = g_hash_table_lookup(mp->settings, key);
+       if (g_strcmp0(curval, value) == 0)
+               return TRUE;
+
+       DBG("%s=%s", key, value);
+
+       g_hash_table_replace(mp->settings, g_strdup(key), g_strdup(value));
+
+       avrcp_player_event(mp->player, AVRCP_EVENT_SETTINGS_CHANGED, key);
 
        return TRUE;
+}
+
+static gboolean set_shuffle(struct media_player *mp, DBusMessageIter *iter)
+{
+       dbus_bool_t value;
+       const char *strvalue;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return FALSE;
 
-parse_error:
-       if (track)
-               g_hash_table_unref(track);
+       dbus_message_iter_get_basic(iter, &value);
 
-       return FALSE;
+       strvalue = value ? "alltracks" : "off";
+
+       return set_property(mp, "Shuffle", strvalue);
 }
 
-static gboolean track_changed(DBusConnection *connection, DBusMessage *msg,
-                                                       void *user_data)
+static const char *loop_status_to_repeat(const char *value)
 {
-       struct media_player *mp = user_data;
-       DBusMessageIter iter;
+       if (strcasecmp(value, "None") == 0)
+               return "off";
+       else if (strcasecmp(value, "Track") == 0)
+               return "singletrack";
+       else if (strcasecmp(value, "Playlist") == 0)
+               return "alltracks";
 
-       DBG("sender=%s path=%s", mp->sender, mp->path);
+       return NULL;
+}
 
-       dbus_message_iter_init(msg, &iter);
+static gboolean set_repeat(struct media_player *mp, DBusMessageIter *iter)
+{
+       const char *value;
 
-       if (parse_player_metadata(mp, &iter) == FALSE) {
-               error("Unexpected signature in %s.%s signal",
-                                       dbus_message_get_interface(msg),
-                                       dbus_message_get_member(msg));
-       }
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       value = loop_status_to_repeat(value);
+       if (value == NULL)
+               return FALSE;
+
+       return set_property(mp, "Repeat", value);
+}
+
+static gboolean set_flag(struct media_player *mp, DBusMessageIter *iter,
+                                                               bool *var)
+{
+       dbus_bool_t value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       *var = value;
 
        return TRUE;
 }
 
-static struct media_player *media_player_create(struct media_adapter *adapter,
-                                               const char *sender,
-                                               const char *path,
-                                               int *err)
+static gboolean set_player_property(struct media_player *mp, const char *key,
+                                                       DBusMessageIter *entry)
 {
-       struct media_player *mp;
+       DBusMessageIter var;
 
-       mp = g_new0(struct media_player, 1);
-       mp->adapter = adapter;
-       mp->sender = g_strdup(sender);
-       mp->path = g_strdup(path);
-       mp->timer = g_timer_new();
+       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+               return FALSE;
 
-       mp->watch = g_dbus_add_disconnect_watch(adapter->conn, sender,
-                                               media_player_exit, mp,
-                                               NULL);
-       mp->property_watch = g_dbus_add_signal_watch(adapter->conn, sender,
-                                               path, MEDIA_PLAYER_INTERFACE,
-                                               "PropertyChanged",
-                                               property_changed,
-                                               mp, NULL);
-       mp->track_watch = g_dbus_add_signal_watch(adapter->conn, sender,
-                                               path, MEDIA_PLAYER_INTERFACE,
-                                               "TrackChanged",
-                                               track_changed,
-                                               mp, NULL);
-       mp->player = avrcp_register_player(&adapter->src, &player_cb, mp,
-                                               media_player_free);
-       if (!mp->player) {
-               if (err)
-                       *err = -EPROTONOSUPPORT;
-               media_player_destroy(mp);
-               return NULL;
-       }
+       dbus_message_iter_recurse(entry, &var);
 
-       mp->settings = g_hash_table_new(g_direct_hash, g_direct_equal);
+       if (strcasecmp(key, "PlaybackStatus") == 0)
+               return set_status(mp, &var);
 
-       adapter->players = g_slist_append(adapter->players, mp);
+       if (strcasecmp(key, "Position") == 0)
+               return set_position(mp, &var);
 
-       info("Player registered: sender=%s path=%s", sender, path);
+       if (strcasecmp(key, "Metadata") == 0)
+               return parse_player_metadata(mp, &var);
 
-       if (err)
-               *err = 0;
+       if (strcasecmp(key, "Shuffle") == 0)
+               return set_shuffle(mp, &var);
 
-       return mp;
+       if (strcasecmp(key, "LoopStatus") == 0)
+               return set_repeat(mp, &var);
+
+       if (strcasecmp(key, "CanPlay") == 0)
+               return set_flag(mp, &var, &mp->play);
+
+       if (strcasecmp(key, "CanPause") == 0)
+               return set_flag(mp, &var, &mp->pause);
+
+       if (strcasecmp(key, "CanGoNext") == 0)
+               return set_flag(mp, &var, &mp->next);
+
+       if (strcasecmp(key, "CanGoPrevious") == 0)
+               return set_flag(mp, &var, &mp->previous);
+
+       if (strcasecmp(key, "CanControl") == 0)
+               return set_flag(mp, &var, &mp->control);
+
+       DBG("%s not supported, ignoring", key);
+
+       return TRUE;
 }
 
 static gboolean parse_player_properties(struct media_player *mp,
@@ -1747,7 +1668,7 @@ static gboolean parse_player_properties(struct media_player *mp,
                dbus_message_iter_get_basic(&entry, &key);
                dbus_message_iter_next(&entry);
 
-               if (set_property(mp, key, &entry) == FALSE)
+               if (set_player_property(mp, key, &entry) == FALSE)
                        return FALSE;
 
                dbus_message_iter_next(&dict);
@@ -1756,6 +1677,85 @@ static gboolean parse_player_properties(struct media_player *mp,
        return TRUE;
 }
 
+static gboolean properties_changed(DBusConnection *connection, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct media_player *mp = user_data;
+       DBusMessageIter iter;
+
+       DBG("sender=%s path=%s", mp->sender, mp->path);
+
+       dbus_message_iter_init(msg, &iter);
+
+       dbus_message_iter_next(&iter);
+
+       parse_player_properties(mp, &iter);
+
+       return TRUE;
+}
+
+static gboolean position_changed(DBusConnection *connection, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct media_player *mp = user_data;
+       DBusMessageIter iter;
+
+       DBG("sender=%s path=%s", mp->sender, mp->path);
+
+       dbus_message_iter_init(msg, &iter);
+
+       set_position(mp, &iter);
+
+       return TRUE;
+}
+
+static struct media_player *media_player_create(struct media_adapter *adapter,
+                                               const char *sender,
+                                               const char *path,
+                                               int *err)
+{
+       DBusConnection *conn = btd_get_dbus_connection();
+       struct media_player *mp;
+
+       mp = g_new0(struct media_player, 1);
+       mp->adapter = adapter;
+       mp->sender = g_strdup(sender);
+       mp->path = g_strdup(path);
+       mp->timer = g_timer_new();
+
+       mp->watch = g_dbus_add_disconnect_watch(conn, sender,
+                                               media_player_exit, mp,
+                                               NULL);
+       mp->properties_watch = g_dbus_add_properties_watch(conn, sender,
+                                               path, MEDIA_PLAYER_INTERFACE,
+                                               properties_changed,
+                                               mp, NULL);
+       mp->seek_watch = g_dbus_add_signal_watch(conn, sender,
+                                               path, MEDIA_PLAYER_INTERFACE,
+                                               "Seeked", position_changed,
+                                               mp, NULL);
+       mp->player = avrcp_register_player(adapter->btd_adapter, &player_cb,
+                                                       mp, media_player_free);
+       if (!mp->player) {
+               if (err)
+                       *err = -EPROTONOSUPPORT;
+               media_player_destroy(mp);
+               return NULL;
+       }
+
+       mp->settings = g_hash_table_new_full(g_str_hash, g_str_equal, g_free,
+                                                               g_free);
+
+       adapter->players = g_slist_append(adapter->players, mp);
+
+       info("Player registered: sender=%s path=%s", sender, path);
+
+       if (err)
+               *err = 0;
+
+       return mp;
+}
+
 static DBusMessage *register_player(DBusConnection *conn, DBusMessage *msg,
                                        void *data)
 {
@@ -1788,13 +1788,6 @@ static DBusMessage *register_player(DBusConnection *conn, DBusMessage *msg,
                return btd_error_invalid_args(msg);
        }
 
-       dbus_message_iter_next(&args);
-
-       if (parse_player_metadata(mp, &args) == FALSE) {
-               media_player_destroy(mp);
-               return btd_error_invalid_args(msg);
-       }
-
        return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
 }
 
@@ -1808,7 +1801,7 @@ static DBusMessage *unregister_player(DBusConnection *conn, DBusMessage *msg,
        if (!dbus_message_get_args(msg, NULL,
                                DBUS_TYPE_OBJECT_PATH, &path,
                                DBUS_TYPE_INVALID))
-               return NULL;
+               return btd_error_invalid_args(msg);
 
        sender = dbus_message_get_sender(msg);
 
@@ -1827,11 +1820,10 @@ static const GDBusMethodTable media_methods[] = {
                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}" }),
+       { GDBUS_EXPERIMENTAL_METHOD("RegisterPlayer",
+               GDBUS_ARGS({ "player", "o" }, { "properties", "a{sv}" }),
                NULL, register_player) },
-       { GDBUS_METHOD("UnregisterPlayer",
+       { GDBUS_EXPERIMENTAL_METHOD("UnregisterPlayer",
                GDBUS_ARGS({ "player", "o" }), NULL, unregister_player) },
        { },
 };
@@ -1843,27 +1835,29 @@ static void path_free(void *data)
        while (adapter->endpoints)
                release_endpoint(adapter->endpoints->data);
 
-       dbus_connection_unref(adapter->conn);
+       while (adapter->players)
+               media_player_destroy(adapter->players->data);
 
        adapters = g_slist_remove(adapters, adapter);
 
-       g_free(adapter->path);
+       btd_adapter_unref(adapter->btd_adapter);
        g_free(adapter);
 }
 
-int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src)
+int media_register(struct btd_adapter *btd_adapter)
 {
        struct media_adapter *adapter;
 
        adapter = g_new0(struct media_adapter, 1);
-       adapter->conn = dbus_connection_ref(conn);
-       bacpy(&adapter->src, src);
-       adapter->path = g_strdup(path);
+       adapter->btd_adapter = btd_adapter_ref(btd_adapter);
 
-       if (!g_dbus_register_interface(conn, path, MEDIA_INTERFACE,
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(btd_adapter),
+                                       MEDIA_INTERFACE,
                                        media_methods, NULL, NULL,
                                        adapter, path_free)) {
-               error("D-Bus failed to register %s path", path);
+               error("D-Bus failed to register %s path",
+                                               adapter_get_path(btd_adapter));
                path_free(adapter);
                return -1;
        }
@@ -1873,16 +1867,17 @@ int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src)
        return 0;
 }
 
-void media_unregister(const char *path)
+void media_unregister(struct btd_adapter *btd_adapter)
 {
        GSList *l;
 
        for (l = adapters; l; l = l->next) {
                struct media_adapter *adapter = l->data;
 
-               if (g_strcmp0(path, adapter->path) == 0) {
-                       g_dbus_unregister_interface(adapter->conn, path,
-                                                       MEDIA_INTERFACE);
+               if (adapter->btd_adapter == btd_adapter) {
+                       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(btd_adapter),
+                                               MEDIA_INTERFACE);
                        return;
                }
        }
similarity index 85%
rename from audio/media.h
rename to profiles/audio/media.h
index ee9a51e..dd630d4 100644 (file)
@@ -27,11 +27,9 @@ struct media_endpoint;
 typedef void (*media_endpoint_cb_t) (struct media_endpoint *endpoint,
                                        void *ret, int size, void *user_data);
 
-int media_register(DBusConnection *conn, const char *path, const bdaddr_t *src);
-void media_unregister(const char *path);
+int media_register(struct btd_adapter *btd_adapter);
+void media_unregister(struct btd_adapter *btd_adapter);
 
 struct a2dp_sep *media_endpoint_get_sep(struct media_endpoint *endpoint);
 const char *media_endpoint_get_uuid(struct media_endpoint *endpoint);
 uint8_t media_endpoint_get_codec(struct media_endpoint *endpoint);
-struct media_transport *media_endpoint_get_transport(
-                                       struct media_endpoint *endpoint);
diff --git a/profiles/audio/player.c b/profiles/audio/player.c
new file mode 100644 (file)
index 0000000..6150c8a
--- /dev/null
@@ -0,0 +1,1897 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2007  Nokia Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012-2012  Intel Corporation
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdint.h>
+#include <inttypes.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+#include "player.h"
+#include "dbus-common.h"
+#include "error.h"
+
+#define MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
+#define MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
+
+struct player_callback {
+       const struct media_player_callback *cbs;
+       void *user_data;
+};
+
+struct pending_req {
+       GDBusPendingPropertySet id;
+       const char *key;
+       const char *value;
+};
+
+struct media_item {
+       struct media_player     *player;
+       char                    *path;          /* Item object path */
+       char                    *name;          /* Item name */
+       player_item_type_t      type;           /* Item type */
+       player_folder_type_t    folder_type;    /* Folder type */
+       bool                    playable;       /* Item playable flag */
+       uint64_t                uid;            /* Item uid */
+       GHashTable              *metadata;      /* Item metadata */
+};
+
+struct media_folder {
+       struct media_folder     *parent;
+       struct media_item       *item;          /* Folder item */
+       uint32_t                number_of_items;/* Number of items */
+       GSList                  *subfolders;
+       GSList                  *items;
+       DBusMessage             *msg;
+};
+
+struct media_player {
+       char                    *device;        /* Device path */
+       char                    *name;          /* Player name */
+       char                    *type;          /* Player type */
+       char                    *subtype;       /* Player subtype */
+       bool                    browsable;      /* Player browsing feature */
+       bool                    searchable;     /* Player searching feature */
+       struct media_folder     *scope;         /* Player current scope */
+       struct media_folder     *folder;        /* Player current folder */
+       struct media_folder     *search;        /* Player search folder */
+       struct media_folder     *playlist;      /* Player current playlist */
+       char                    *path;          /* Player object path */
+       GHashTable              *settings;      /* Player settings */
+       GHashTable              *track;         /* Player current track */
+       char                    *status;
+       uint32_t                position;
+       GTimer                  *progress;
+       guint                   process_id;
+       struct player_callback  *cb;
+       GSList                  *pending;
+       GSList                  *folders;
+};
+
+static void append_track(void *key, void *value, void *user_data)
+{
+       DBusMessageIter *dict = user_data;
+       const char *strkey = key;
+
+       if (strcasecmp(strkey, "Duration") == 0 ||
+                       strcasecmp(strkey, "TrackNumber") == 0 ||
+                       strcasecmp(strkey, "NumberOfTracks") == 0)  {
+               uint32_t num = atoi(value);
+               dict_append_entry(dict, key, DBUS_TYPE_UINT32, &num);
+       } else if (strcasecmp(strkey, "Item") == 0) {
+               dict_append_entry(dict, key, DBUS_TYPE_OBJECT_PATH, &value);
+       } else {
+               dict_append_entry(dict, key, DBUS_TYPE_STRING, &value);
+       }
+}
+
+static struct pending_req *find_pending(struct media_player *mp,
+                                                       const char *key)
+{
+       GSList *l;
+
+       for (l = mp->pending; l; l = l->next) {
+               struct pending_req *p = l->data;
+
+               if (strcasecmp(key, p->key) == 0)
+                       return p;
+       }
+
+       return NULL;
+}
+
+static struct pending_req *pending_new(GDBusPendingPropertySet id,
+                                       const char *key, const char *value)
+{
+       struct pending_req *p;
+
+       p = g_new0(struct pending_req, 1);
+       p->id = id;
+       p->key = key;
+       p->value = value;
+
+       return p;
+}
+
+static uint32_t media_player_get_position(struct media_player *mp)
+{
+       double timedelta;
+       uint32_t sec, msec;
+
+       if (g_strcmp0(mp->status, "playing") != 0 ||
+                                               mp->position == UINT32_MAX)
+               return mp->position;
+
+       timedelta = g_timer_elapsed(mp->progress, NULL);
+
+       sec = (uint32_t) timedelta;
+       msec = (uint32_t) ((timedelta - sec) * 1000);
+
+       return mp->position + sec * 1000 + msec;
+}
+
+static gboolean get_position(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       uint32_t position;
+
+       position = media_player_get_position(mp);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &position);
+
+       return TRUE;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->status != NULL;
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+
+       if (mp->status == NULL)
+               return FALSE;
+
+       DBG("%s", mp->status);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &mp->status);
+
+       return TRUE;
+}
+
+static gboolean setting_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+       const char *value;
+
+       value = g_hash_table_lookup(mp->settings, property->name);
+
+       return value ? TRUE : FALSE;
+}
+
+static gboolean get_setting(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       const char *value;
+
+       value = g_hash_table_lookup(mp->settings, property->name);
+       if (value == NULL)
+               return FALSE;
+
+       DBG("%s %s", property->name, value);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &value);
+
+       return TRUE;
+}
+
+static void player_set_setting(struct media_player *mp,
+                                       GDBusPendingPropertySet id,
+                                       const char *key, const char *value)
+{
+       struct player_callback *cb = mp->cb;
+       struct pending_req *p;
+
+       if (cb == NULL || cb->cbs->set_setting == NULL) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".NotSupported",
+                                       "Operation is not supported");
+               return;
+       }
+
+       p = find_pending(mp, key);
+       if (p != NULL) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InProgress",
+                                       "Operation already in progress");
+               return;
+       }
+
+       if (!cb->cbs->set_setting(mp, key, value, cb->user_data)) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       p = pending_new(id, key, value);
+
+       mp->pending = g_slist_append(mp->pending, p);
+}
+
+static void set_setting(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       struct media_player *mp = data;
+       const char *value, *current;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       current = g_hash_table_lookup(mp->settings, property->name);
+       if (g_strcmp0(current, value) == 0) {
+               g_dbus_pending_property_success(id);
+               return;
+       }
+
+       player_set_setting(mp, id, property->name, value);
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return g_hash_table_size(mp->track) != 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       g_hash_table_foreach(mp->track, append_track, &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+
+       return TRUE;
+}
+
+static gboolean get_device(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                                               &mp->device);
+
+       return TRUE;
+}
+
+static gboolean name_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->name != NULL;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+
+       if (mp->name == NULL)
+               return FALSE;
+
+       DBG("%s", mp->name);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &mp->name);
+
+       return TRUE;
+}
+
+static gboolean type_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->type != NULL;
+}
+
+static gboolean get_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+
+       if (mp->type == NULL)
+               return FALSE;
+
+       DBG("%s", mp->type);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &mp->type);
+
+       return TRUE;
+}
+
+static gboolean subtype_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->subtype != NULL;
+}
+
+static gboolean get_subtype(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+
+       if (mp->subtype == NULL)
+               return FALSE;
+
+       DBG("%s", mp->subtype);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &mp->subtype);
+
+       return TRUE;
+}
+
+static gboolean browsable_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->scope != NULL;
+}
+
+static gboolean get_browsable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       dbus_bool_t value;
+
+       if (mp->scope == NULL)
+               return FALSE;
+
+       DBG("%s", mp->browsable ? "true" : "false");
+
+       value = mp->browsable;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static gboolean searchable_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->scope != NULL;
+}
+
+static gboolean get_searchable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       dbus_bool_t value;
+
+       if (mp->folder == NULL)
+               return FALSE;
+
+       DBG("%s", mp->searchable ? "true" : "false");
+
+       value = mp->searchable;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static gboolean playlist_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->playlist != NULL;
+}
+
+static gboolean get_playlist(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *playlist = mp->playlist;
+
+       if (playlist == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &playlist->item->path);
+
+       return TRUE;
+}
+
+static DBusMessage *media_player_play(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->play == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->play(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_pause(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->pause == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->pause(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_stop(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->stop == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->stop(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_next(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->next == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->next(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_previous(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->previous == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->previous(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_fast_forward(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->fast_forward == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->fast_forward(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_player_rewind(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (cb->cbs->rewind == NULL)
+               return btd_error_not_supported(msg);
+
+       err = cb->cbs->rewind(mp, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static void parse_folder_list(gpointer data, gpointer user_data)
+{
+       struct media_item *item = data;
+       DBusMessageIter *array = user_data;
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(array, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH,
+                                                               &item->path);
+
+       g_dbus_get_properties(btd_get_dbus_connection(), item->path,
+                                               MEDIA_ITEM_INTERFACE, &entry);
+
+       dbus_message_iter_close_container(array, &entry);
+}
+
+void media_player_change_folder_complete(struct media_player *mp,
+                                               const char *path, int ret)
+{
+       struct media_folder *folder = mp->scope;
+       DBusMessage *reply;
+
+       if (folder == NULL || folder->msg == NULL)
+               return;
+
+       if (ret < 0) {
+               reply = btd_error_failed(folder->msg, strerror(-ret));
+               goto done;
+       }
+
+       media_player_set_folder(mp, path, ret);
+
+       reply = g_dbus_create_reply(folder->msg, DBUS_TYPE_INVALID);
+
+done:
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+       dbus_message_unref(folder->msg);
+       folder->msg = NULL;
+}
+
+void media_player_list_complete(struct media_player *mp, GSList *items,
+                                                               int err)
+{
+       struct media_folder *folder = mp->scope;
+       DBusMessage *reply;
+       DBusMessageIter iter, array;
+
+       if (folder == NULL || folder->msg == NULL)
+               return;
+
+       if (err < 0) {
+               reply = btd_error_failed(folder->msg, strerror(-err));
+               goto done;
+       }
+
+       reply = dbus_message_new_method_return(folder->msg);
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &array);
+
+       g_slist_foreach(items, parse_folder_list, &array);
+       dbus_message_iter_close_container(&iter, &array);
+
+done:
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+       dbus_message_unref(folder->msg);
+       folder->msg = NULL;
+}
+
+static struct media_item *
+media_player_create_subfolder(struct media_player *mp, const char *name,
+                                                               uint64_t uid)
+{
+       struct media_folder *folder = mp->scope;
+       struct media_item *item;
+       char *path;
+
+       path = g_strdup_printf("%s/%s", folder->item->name, name);
+
+       DBG("%s", path);
+
+       item = media_player_create_item(mp, path, PLAYER_ITEM_TYPE_FOLDER,
+                                                                       uid);
+       g_free(path);
+
+       return item;
+}
+
+void media_player_search_complete(struct media_player *mp, int ret)
+{
+       struct media_folder *folder = mp->scope;
+       struct media_folder *search = mp->search;
+       DBusMessage *reply;
+
+       if (folder == NULL || folder->msg == NULL)
+               return;
+
+       if (ret < 0) {
+               reply = btd_error_failed(folder->msg, strerror(-ret));
+               goto done;
+       }
+
+       if (search == NULL) {
+               search = g_new0(struct media_folder, 1);
+               search->item = media_player_create_subfolder(mp, "search", 0);
+               mp->search = search;
+               mp->folders = g_slist_prepend(mp->folders, search);
+       }
+
+       search->number_of_items = ret;
+
+       reply = g_dbus_create_reply(folder->msg,
+                               DBUS_TYPE_OBJECT_PATH, &search->item->path,
+                               DBUS_TYPE_INVALID);
+
+done:
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+       dbus_message_unref(folder->msg);
+       folder->msg = NULL;
+}
+
+static const GDBusMethodTable media_player_methods[] = {
+       { GDBUS_EXPERIMENTAL_METHOD("Play", NULL, NULL, media_player_play) },
+       { GDBUS_EXPERIMENTAL_METHOD("Pause", NULL, NULL, media_player_pause) },
+       { GDBUS_EXPERIMENTAL_METHOD("Stop", NULL, NULL, media_player_stop) },
+       { GDBUS_EXPERIMENTAL_METHOD("Next", NULL, NULL, media_player_next) },
+       { GDBUS_EXPERIMENTAL_METHOD("Previous", NULL, NULL,
+                                               media_player_previous) },
+       { GDBUS_EXPERIMENTAL_METHOD("FastForward", NULL, NULL,
+                                               media_player_fast_forward) },
+       { GDBUS_EXPERIMENTAL_METHOD("Rewind", NULL, NULL,
+                                               media_player_rewind) },
+       { }
+};
+
+static const GDBusSignalTable media_player_signals[] = {
+       { }
+};
+
+static const GDBusPropertyTable media_player_properties[] = {
+       { "Name", "s", get_name, NULL, name_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Type", "s", get_type, NULL, type_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Subtype", "s", get_subtype, NULL, subtype_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Position", "u", get_position, NULL, NULL,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Status", "s", get_status, NULL, status_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Equalizer", "s", get_setting, set_setting, setting_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Repeat", "s", get_setting, set_setting, setting_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Shuffle", "s", get_setting, set_setting, setting_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Scan", "s", get_setting, set_setting, setting_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Track", "a{sv}", get_track, NULL, track_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Device", "o", get_device, NULL, NULL,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Browsable", "b", get_browsable, NULL, browsable_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Searchable", "b", get_searchable, NULL, searchable_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Playlist", "o", get_playlist, NULL, playlist_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { }
+};
+
+static DBusMessage *media_folder_search(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+       struct player_callback *cb = mp->cb;
+       DBusMessageIter iter;
+       const char *string;
+       int err;
+
+       dbus_message_iter_init(msg, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return btd_error_failed(msg, strerror(EINVAL));
+
+       dbus_message_iter_get_basic(&iter, &string);
+
+       if (!mp->searchable || folder != mp->folder)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       if (folder->msg != NULL)
+               return btd_error_failed(msg, strerror(EINVAL));
+
+       if (cb->cbs->search == NULL)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       err = cb->cbs->search(mp, string, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       folder->msg = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static int parse_filters(struct media_player *player, DBusMessageIter *iter,
+                                               uint32_t *start, uint32_t *end)
+{
+       struct media_folder *folder = player->scope;
+       DBusMessageIter dict;
+       int ctype;
+
+       *start = 0;
+       *end = folder->number_of_items ? folder->number_of_items : UINT32_MAX;
+
+       ctype = dbus_message_iter_get_arg_type(iter);
+       if (ctype != DBUS_TYPE_ARRAY)
+               return FALSE;
+
+       dbus_message_iter_recurse(iter, &dict);
+
+       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+                                                       DBUS_TYPE_INVALID) {
+               DBusMessageIter entry, var;
+               const char *key;
+
+               if (ctype != DBUS_TYPE_DICT_ENTRY)
+                       return -EINVAL;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&entry, &key);
+               dbus_message_iter_next(&entry);
+
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_VARIANT)
+                       return -EINVAL;
+
+               dbus_message_iter_recurse(&entry, &var);
+
+               if (dbus_message_iter_get_arg_type(&var) != DBUS_TYPE_UINT32)
+                       return -EINVAL;
+
+               if (strcasecmp(key, "Start") == 0)
+                       dbus_message_iter_get_basic(&var, start);
+               else if (strcasecmp(key, "End") == 0)
+                       dbus_message_iter_get_basic(&var, end);
+
+               dbus_message_iter_next(&dict);
+       }
+
+       if (folder->number_of_items > 0 && *end > folder->number_of_items)
+               *end = folder->number_of_items;
+
+       return 0;
+}
+
+static DBusMessage *media_folder_list_items(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+       struct player_callback *cb = mp->cb;
+       DBusMessageIter iter;
+       uint32_t start, end;
+       int err;
+
+       dbus_message_iter_init(msg, &iter);
+
+       if (parse_filters(mp, &iter, &start, &end) < 0)
+               return btd_error_invalid_args(msg);
+
+       if (cb->cbs->list_items == NULL)
+               return btd_error_not_supported(msg);
+
+       if (folder->msg != NULL)
+               return btd_error_failed(msg, strerror(EBUSY));
+
+       err = cb->cbs->list_items(mp, folder->item->name, start, end,
+                                                       cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       folder->msg = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static void media_item_free(struct media_item *item)
+{
+       if (item->metadata != NULL)
+               g_hash_table_unref(item->metadata);
+
+       g_free(item->path);
+       g_free(item->name);
+       g_free(item);
+}
+
+static void media_item_destroy(void *data)
+{
+       struct media_item *item = data;
+
+       DBG("%s", item->path);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(), item->path,
+                                               MEDIA_ITEM_INTERFACE);
+
+       media_item_free(item);
+}
+
+static void media_folder_destroy(void *data)
+{
+       struct media_folder *folder = data;
+
+       g_slist_free_full(folder->subfolders, media_folder_destroy);
+       g_slist_free_full(folder->items, media_item_destroy);
+
+       if (folder->msg != NULL)
+               dbus_message_unref(folder->msg);
+
+       media_item_destroy(folder->item);
+       g_free(folder);
+}
+
+static void media_player_change_scope(struct media_player *mp,
+                                               struct media_folder *folder)
+{
+       if (mp->scope == folder)
+               return;
+
+       DBG("%s", folder->item->name);
+
+       /* Skip setting current folder if folder is current playlist/search */
+       if (folder == mp->playlist || folder == mp->search)
+               goto cleanup;
+
+       mp->folder = folder;
+
+       /* Skip item cleanup if scope is the current playlist */
+       if (mp->scope == mp->playlist)
+               goto done;
+
+cleanup:
+       g_slist_free_full(mp->scope->items, media_item_destroy);
+       mp->scope->items = NULL;
+
+       /* Destroy search folder if it exists and is not being set as scope */
+       if (mp->search != NULL && folder != mp->search) {
+               mp->folders = g_slist_remove(mp->folders, mp->search);
+               media_folder_destroy(mp->search);
+               mp->search = NULL;
+       }
+
+done:
+       mp->scope = folder;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                               MEDIA_FOLDER_INTERFACE, "Name");
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                               MEDIA_FOLDER_INTERFACE, "NumberOfItems");
+}
+
+static struct media_folder *find_folder(GSList *folders, const char *pattern)
+{
+       GSList *l;
+
+       for (l = folders; l; l = l->next) {
+               struct media_folder *folder = l->data;
+
+               if (g_str_equal(folder->item->name, pattern))
+                       return folder;
+
+               if (g_str_equal(folder->item->path, pattern))
+                       return folder;
+
+               folder = find_folder(folder->subfolders, pattern);
+               if (folder != NULL)
+                       return folder;
+       }
+
+       return NULL;
+}
+
+static struct media_folder *media_player_find_folder(struct media_player *mp,
+                                                       const char *pattern)
+{
+       return find_folder(mp->folders, pattern);
+}
+
+static DBusMessage *media_folder_change_folder(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+       struct player_callback *cb = mp->cb;
+       const char *path;
+       int err;
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID))
+               return btd_error_failed(msg, strerror(EINVAL));
+
+       if (folder->msg != NULL)
+               return btd_error_failed(msg, strerror(EBUSY));
+
+       folder = media_player_find_folder(mp, path);
+       if (folder == NULL)
+               return btd_error_failed(msg, strerror(EINVAL));
+
+       if (mp->scope == folder)
+               return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+       if (folder == mp->playlist || folder == mp->folder ||
+                                               folder == mp->search) {
+               media_player_change_scope(mp, folder);
+               return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+       }
+
+       if (cb->cbs->change_folder == NULL)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       err = cb->cbs->change_folder(mp, folder->item->name, folder->item->uid,
+                                                               cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       mp->scope->msg = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+static gboolean folder_name_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+
+       if (folder == NULL || folder->item == NULL)
+               return FALSE;
+
+       return folder->item->name != NULL;
+}
+
+static gboolean get_folder_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+
+       if (folder == NULL || folder->item == NULL)
+               return FALSE;
+
+       DBG("%s", folder->item->name);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &folder->item->name);
+
+       return TRUE;
+}
+
+static gboolean items_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_player *mp = data;
+
+       return mp->scope != NULL;
+}
+
+static gboolean get_items(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_player *mp = data;
+       struct media_folder *folder = mp->scope;
+
+       if (folder == NULL)
+               return FALSE;
+
+       DBG("%u", folder->number_of_items);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32,
+                                               &folder->number_of_items);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable media_folder_methods[] = {
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("Search",
+                       GDBUS_ARGS({ "string", "s" }, { "filter", "a{sv}" }),
+                       GDBUS_ARGS({ "folder", "o" }),
+                       media_folder_search) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ListItems",
+                       GDBUS_ARGS({ "filter", "a{sv}" }),
+                       GDBUS_ARGS({ "items", "a{oa{sv}}" }),
+                       media_folder_list_items) },
+       { GDBUS_EXPERIMENTAL_ASYNC_METHOD("ChangeFolder",
+                       GDBUS_ARGS({ "folder", "o" }), NULL,
+                       media_folder_change_folder) },
+       { }
+};
+
+static const GDBusPropertyTable media_folder_properties[] = {
+       { "Name", "s", get_folder_name, NULL, folder_name_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "NumberOfItems", "u", get_items, NULL, items_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { }
+};
+
+static void media_player_set_scope(struct media_player *mp,
+                                               struct media_folder *folder)
+{
+       if (mp->scope == NULL) {
+               if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_FOLDER_INTERFACE,
+                                       media_folder_methods,
+                                       NULL,
+                                       media_folder_properties, mp, NULL)) {
+                       error("D-Bus failed to register %s on %s path",
+                                       MEDIA_FOLDER_INTERFACE, mp->path);
+                       return;
+               }
+               mp->scope = folder;
+               return;
+       }
+
+       return media_player_change_scope(mp, folder);
+}
+
+void media_player_destroy(struct media_player *mp)
+{
+       DBG("%s", mp->path);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(), mp->path,
+                                               MEDIA_PLAYER_INTERFACE);
+
+       if (mp->track)
+               g_hash_table_unref(mp->track);
+
+       if (mp->settings)
+               g_hash_table_unref(mp->settings);
+
+       if (mp->process_id > 0)
+               g_source_remove(mp->process_id);
+
+       if (mp->scope)
+               g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               mp->path,
+                                               MEDIA_FOLDER_INTERFACE);
+
+       g_slist_free_full(mp->pending, g_free);
+       g_slist_free_full(mp->folders, media_folder_destroy);
+
+       g_timer_destroy(mp->progress);
+       g_free(mp->cb);
+       g_free(mp->status);
+       g_free(mp->path);
+       g_free(mp->device);
+       g_free(mp->subtype);
+       g_free(mp->type);
+       g_free(mp->name);
+       g_free(mp);
+}
+
+struct media_player *media_player_controller_create(const char *path,
+                                                               uint16_t id)
+{
+       struct media_player *mp;
+
+       mp = g_new0(struct media_player, 1);
+       mp->device = g_strdup(path);
+       mp->path = g_strdup_printf("%s/player%u", path, id);
+       mp->settings = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       g_free, g_free);
+       mp->track = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       g_free, g_free);
+       mp->progress = g_timer_new();
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       media_player_methods,
+                                       media_player_signals,
+                                       media_player_properties, mp, NULL)) {
+               error("D-Bus failed to register %s path", mp->path);
+               media_player_destroy(mp);
+               return NULL;
+       }
+
+       DBG("%s", mp->path);
+
+       return mp;
+}
+
+void media_player_set_duration(struct media_player *mp, uint32_t duration)
+{
+       char *value, *curval;
+
+       DBG("%u", duration);
+
+       /* Only update duration if track exists */
+       if (g_hash_table_size(mp->track) == 0)
+               return;
+
+       /* Ignore if duration is already set */
+       curval = g_hash_table_lookup(mp->track, "Duration");
+       if (curval != NULL)
+               return;
+
+       value = g_strdup_printf("%u", duration);
+
+       g_hash_table_replace(mp->track, g_strdup("Duration"), value);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Track");
+}
+
+void media_player_set_position(struct media_player *mp, uint32_t position)
+{
+       DBG("%u", position);
+
+       /* Only update duration if track exists */
+       if (g_hash_table_size(mp->track) == 0)
+               return;
+
+       mp->position = position;
+       g_timer_start(mp->progress);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                                       MEDIA_PLAYER_INTERFACE, "Position");
+}
+
+void media_player_set_setting(struct media_player *mp, const char *key,
+                                                       const char *value)
+{
+       char *curval;
+       struct pending_req *p;
+
+       DBG("%s: %s", key, value);
+
+       if (strcasecmp(key, "Error") == 0) {
+               p = g_slist_nth_data(mp->pending, 0);
+               if (p == NULL)
+                       return;
+
+               g_dbus_pending_property_error(p->id, ERROR_INTERFACE ".Failed",
+                                                                       value);
+               goto send;
+       }
+
+       curval = g_hash_table_lookup(mp->settings, key);
+       if (g_strcmp0(curval, value) == 0)
+               goto done;
+
+       g_hash_table_replace(mp->settings, g_strdup(key), g_strdup(value));
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                                       MEDIA_PLAYER_INTERFACE, key);
+
+done:
+       p = find_pending(mp, key);
+       if (p == NULL)
+               return;
+
+       if (strcasecmp(value, p->value) == 0)
+               g_dbus_pending_property_success(p->id);
+       else
+               g_dbus_pending_property_error(p->id,
+                                       ERROR_INTERFACE ".NotSupported",
+                                       "Operation is not supported");
+
+send:
+       mp->pending = g_slist_remove(mp->pending, p);
+       g_free(p);
+
+       return;
+}
+
+const char *media_player_get_status(struct media_player *mp)
+{
+       return mp->status;
+}
+
+void media_player_set_status(struct media_player *mp, const char *status)
+{
+       DBG("%s", status);
+
+       if (g_strcmp0(mp->status, status) == 0)
+               return;
+
+       g_free(mp->status);
+       mp->status = g_strdup(status);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                                       MEDIA_PLAYER_INTERFACE, "Status");
+
+       mp->position = media_player_get_position(mp);
+       g_timer_start(mp->progress);
+}
+
+static gboolean process_metadata_changed(void *user_data)
+{
+       struct media_player *mp = user_data;
+       const char *item;
+
+       mp->process_id = 0;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Track");
+
+       item = g_hash_table_lookup(mp->track, "Item");
+       if (item == NULL)
+               return FALSE;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       item, MEDIA_ITEM_INTERFACE,
+                                       "Metadata");
+
+       return FALSE;
+}
+
+void media_player_set_metadata(struct media_player *mp,
+                               struct media_item *item, const char *key,
+                               void *data, size_t len)
+{
+       char *value, *curval;
+
+       value = g_strndup(data, len);
+
+       DBG("%s: %s", key, value);
+
+       curval = g_hash_table_lookup(mp->track, key);
+       if (g_strcmp0(curval, value) == 0) {
+               g_free(value);
+               return;
+       }
+
+       if (mp->process_id == 0) {
+               g_hash_table_remove_all(mp->track);
+               mp->process_id = g_idle_add(process_metadata_changed, mp);
+       }
+
+       g_hash_table_replace(mp->track, g_strdup(key), value);
+}
+
+void media_player_set_type(struct media_player *mp, const char *type)
+{
+       if (g_strcmp0(mp->type, type) == 0)
+               return;
+
+       DBG("%s", type);
+
+       mp->type = g_strdup(type);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Type");
+}
+
+void media_player_set_subtype(struct media_player *mp, const char *subtype)
+{
+       if (g_strcmp0(mp->subtype, subtype) == 0)
+               return;
+
+       DBG("%s", subtype);
+
+       mp->subtype = g_strdup(subtype);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Subtype");
+}
+
+void media_player_set_name(struct media_player *mp, const char *name)
+{
+       if (g_strcmp0(mp->name, name) == 0)
+               return;
+
+       DBG("%s", name);
+
+       mp->name = g_strdup(name);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Name");
+}
+
+void media_player_set_browsable(struct media_player *mp, bool enabled)
+{
+       if (mp->browsable == enabled)
+               return;
+
+       DBG("%s", enabled ? "true" : "false");
+
+       mp->browsable = enabled;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Browsable");
+}
+
+void media_player_set_searchable(struct media_player *mp, bool enabled)
+{
+       if (mp->browsable == enabled)
+               return;
+
+       DBG("%s", enabled ? "true" : "false");
+
+       mp->searchable = enabled;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       mp->path, MEDIA_PLAYER_INTERFACE,
+                                       "Searchable");
+}
+
+void media_player_set_folder(struct media_player *mp, const char *name,
+                                               uint32_t number_of_items)
+{
+       struct media_folder *folder;
+
+       DBG("%s number of items %u", name, number_of_items);
+
+       folder = media_player_find_folder(mp, name);
+       if (folder == NULL) {
+               error("Unknown folder: %s", name);
+               return;
+       }
+
+       folder->number_of_items = number_of_items;
+
+       media_player_set_scope(mp, folder);
+}
+
+void media_player_set_playlist(struct media_player *mp, const char *name)
+{
+       struct media_folder *folder;
+
+       DBG("%s", name);
+
+       folder = media_player_find_folder(mp, name);
+       if (folder == NULL) {
+               error("Unknown folder: %s", name);
+               return;
+       }
+
+       mp->playlist = folder;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), mp->path,
+                                       MEDIA_PLAYER_INTERFACE, "Playlist");
+}
+
+static struct media_item *media_folder_find_item(struct media_folder *folder,
+                                                               uint64_t uid)
+{
+       GSList *l;
+
+       if (uid == 0)
+               return NULL;
+
+       for (l = folder->items; l; l = l->next) {
+               struct media_item *item = l->data;
+
+               if (item->uid == uid)
+                       return item;
+       }
+
+       return NULL;
+}
+
+static DBusMessage *media_item_play(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_item *item = data;
+       struct media_player *mp = item->player;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (!item->playable)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       if (cb->cbs->play_item == NULL)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       err = cb->cbs->play_item(mp, item->path, item->uid, cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *media_item_add_to_nowplaying(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct media_item *item = data;
+       struct media_player *mp = item->player;
+       struct player_callback *cb = mp->cb;
+       int err;
+
+       if (!item->playable)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       if (cb->cbs->play_item == NULL)
+               return btd_error_failed(msg, strerror(ENOTSUP));
+
+       err = cb->cbs->add_to_nowplaying(mp, item->path, item->uid,
+                                                       cb->user_data);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static gboolean get_player(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+
+       DBG("%s", item->player->path);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
+                                                       &item->player->path);
+
+       return TRUE;
+}
+
+static gboolean item_name_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct media_item *item = data;
+
+       return item->name != NULL;
+}
+
+static gboolean get_item_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+
+       if (item->name == NULL)
+               return FALSE;
+
+       DBG("%s", item->name);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &item->name);
+
+       return TRUE;
+}
+
+static const char *type_to_string(uint8_t type)
+{
+       switch (type) {
+       case PLAYER_ITEM_TYPE_AUDIO:
+               return "audio";
+       case PLAYER_ITEM_TYPE_VIDEO:
+               return "video";
+       case PLAYER_ITEM_TYPE_FOLDER:
+               return "folder";
+       }
+
+       return NULL;
+}
+
+static gboolean get_item_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+       const char *string;
+
+       string = type_to_string(item->type);
+
+       DBG("%s", string);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &string);
+
+       return TRUE;
+}
+
+static gboolean get_playable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+       dbus_bool_t value;
+
+       DBG("%s", item->playable ? "true" : "false");
+
+       value = item->playable;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static const char *folder_type_to_string(uint8_t type)
+{
+       switch (type) {
+       case PLAYER_FOLDER_TYPE_MIXED:
+               return "mixed";
+       case PLAYER_FOLDER_TYPE_TITLES:
+               return "titles";
+       case PLAYER_FOLDER_TYPE_ALBUMS:
+               return "albums";
+       case PLAYER_FOLDER_TYPE_ARTISTS:
+               return "artists";
+       case PLAYER_FOLDER_TYPE_GENRES:
+               return "genres";
+       case PLAYER_FOLDER_TYPE_PLAYLISTS:
+               return "playlists";
+       case PLAYER_FOLDER_TYPE_YEARS:
+               return "years";
+       }
+
+       return NULL;
+}
+
+static gboolean folder_type_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct media_item *item = data;
+
+       return folder_type_to_string(item->folder_type) != NULL;
+}
+
+static gboolean get_folder_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+       const char *string;
+
+       string = folder_type_to_string(item->folder_type);
+       if (string == NULL)
+               return FALSE;
+
+       DBG("%s", string);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &string);
+
+       return TRUE;
+}
+
+static gboolean metadata_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_item *item = data;
+
+       return item->metadata != NULL;
+}
+
+static void append_metadata(void *key, void *value, void *user_data)
+{
+       DBusMessageIter *dict = user_data;
+       const char *strkey = key;
+
+       if (strcasecmp(strkey, "Item") == 0)
+               return;
+
+       if (strcasecmp(strkey, "Duration") == 0 ||
+                       strcasecmp(strkey, "TrackNumber") == 0 ||
+                       strcasecmp(strkey, "NumberOfTracks") == 0)  {
+               uint32_t num = atoi(value);
+               dict_append_entry(dict, key, DBUS_TYPE_UINT32, &num);
+       } else {
+               dict_append_entry(dict, key, DBUS_TYPE_STRING, &value);
+       }
+}
+
+static gboolean get_metadata(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_item *item = data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       if (g_hash_table_size(item->metadata) > 0)
+               g_hash_table_foreach(item->metadata, append_metadata, &dict);
+       else if (item->name != NULL)
+               dict_append_entry(&dict, "Title", DBUS_TYPE_STRING,
+                                                               &item->name);
+
+       dbus_message_iter_close_container(iter, &dict);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable media_item_methods[] = {
+       { GDBUS_EXPERIMENTAL_METHOD("Play", NULL, NULL,
+                                       media_item_play) },
+       { GDBUS_EXPERIMENTAL_METHOD("AddtoNowPlaying", NULL, NULL,
+                                       media_item_add_to_nowplaying) },
+       { }
+};
+
+static const GDBusPropertyTable media_item_properties[] = {
+       { "Player", "o", get_player, NULL, NULL,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Name", "s", get_item_name, NULL, item_name_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Type", "s", get_item_type, NULL, NULL,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "FolderType", "s", get_folder_type, NULL, folder_type_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Playable", "b", get_playable, NULL, NULL,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { "Metadata", "a{sv}", get_metadata, NULL, metadata_exists,
+                                       G_DBUS_PROPERTY_FLAG_EXPERIMENTAL },
+       { }
+};
+
+void media_item_set_playable(struct media_item *item, bool value)
+{
+       if (item->playable == value)
+               return;
+
+       item->playable = value;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), item->path,
+                                       MEDIA_ITEM_INTERFACE, "Playable");
+}
+
+static struct media_item *media_folder_create_item(struct media_player *mp,
+                                               struct media_folder *folder,
+                                               const char *name,
+                                               player_item_type_t type,
+                                               uint64_t uid)
+{
+       struct media_item *item;
+       const char *strtype;
+
+       item = media_folder_find_item(folder, uid);
+       if (item != NULL)
+               return item;
+
+       strtype = type_to_string(type);
+       if (strtype == NULL)
+               return NULL;
+
+       DBG("%s type %s uid %" PRIu64 "", name, strtype, uid);
+
+       item = g_new0(struct media_item, 1);
+       item->player = mp;
+       item->uid = uid;
+
+       if (uid > 0)
+               item->path = g_strdup_printf("%s/item%" PRIu64 "",
+                                               folder->item->path, uid);
+       else
+               item->path = g_strdup_printf("%s%s", mp->path, name);
+
+       item->name = g_strdup(name);
+       item->type = type;
+       item->folder_type = PLAYER_FOLDER_TYPE_INVALID;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       item->path, MEDIA_ITEM_INTERFACE,
+                                       media_item_methods,
+                                       NULL,
+                                       media_item_properties, item, NULL)) {
+               error("D-Bus failed to register %s on %s path",
+                                       MEDIA_ITEM_INTERFACE, item->path);
+               media_item_free(item);
+               return NULL;
+       }
+
+       if (type != PLAYER_ITEM_TYPE_FOLDER) {
+               folder->items = g_slist_prepend(folder->items, item);
+               item->metadata = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                                       g_free, g_free);
+       }
+
+       DBG("%s", item->path);
+
+       return item;
+}
+
+struct media_item *media_player_create_item(struct media_player *mp,
+                                               const char *name,
+                                               player_item_type_t type,
+                                               uint64_t uid)
+{
+       return media_folder_create_item(mp, mp->scope, name, type, uid);
+}
+
+static struct media_folder *
+media_player_find_folder_by_uid(struct media_player *mp, uint64_t uid)
+{
+       struct media_folder *folder = mp->scope;
+       GSList *l;
+
+       for (l = folder->subfolders; l; l = l->next) {
+               struct media_folder *folder = l->data;
+
+               if (folder->item->uid == uid)
+                       return folder;
+       }
+
+       return NULL;
+}
+
+struct media_item *media_player_create_folder(struct media_player *mp,
+                                               const char *name,
+                                               player_folder_type_t type,
+                                               uint64_t uid)
+{
+       struct media_folder *folder;
+       struct media_item *item;
+
+       if (uid > 0)
+               folder = media_player_find_folder_by_uid(mp, uid);
+       else
+               folder = media_player_find_folder(mp, name);
+
+       if (folder != NULL)
+               return folder->item;
+
+       if (uid > 0)
+               item = media_player_create_subfolder(mp, name, uid);
+       else
+               item = media_player_create_item(mp, name,
+                                               PLAYER_ITEM_TYPE_FOLDER, uid);
+
+       if (item == NULL)
+               return NULL;
+
+       folder = g_new0(struct media_folder, 1);
+       folder->item = item;
+
+       item->folder_type = type;
+
+       if (mp->folder != NULL)
+               goto done;
+
+       mp->folder = folder;
+
+done:
+       if (uid > 0) {
+               folder->parent = mp->folder;
+               mp->folder->subfolders = g_slist_prepend(
+                                                       mp->folder->subfolders,
+                                                       folder);
+       } else
+               mp->folders = g_slist_prepend(mp->folders, folder);
+
+       return item;
+}
+
+void media_player_set_callbacks(struct media_player *mp,
+                               const struct media_player_callback *cbs,
+                               void *user_data)
+{
+       struct player_callback *cb;
+
+       if (mp->cb)
+               g_free(mp->cb);
+
+       cb = g_new0(struct player_callback, 1);
+       cb->cbs = cbs;
+       cb->user_data = user_data;
+
+       mp->cb = cb;
+}
+
+struct media_item *media_player_set_playlist_item(struct media_player *mp,
+                                                               uint64_t uid)
+{
+       struct media_folder *folder = mp->playlist;
+       struct media_item *item;
+
+       DBG("%" PRIu64 "", uid);
+
+       if (folder == NULL || uid == 0)
+               return NULL;
+
+       item = media_folder_create_item(mp, folder, NULL,
+                                               PLAYER_ITEM_TYPE_AUDIO, uid);
+       if (item == NULL)
+               return NULL;
+
+       media_item_set_playable(item, true);
+
+       if (mp->track != item->metadata) {
+               g_hash_table_unref(mp->track);
+               mp->track = g_hash_table_ref(item->metadata);
+       }
+
+       if (item == g_hash_table_lookup(mp->track, "Item"))
+               return item;
+
+       if (mp->process_id == 0) {
+               g_hash_table_remove_all(mp->track);
+               mp->process_id = g_idle_add(process_metadata_changed, mp);
+       }
+
+       g_hash_table_replace(mp->track, g_strdup("Item"),
+                                               g_strdup(item->path));
+
+       return item;
+}
diff --git a/profiles/audio/player.h b/profiles/audio/player.h
new file mode 100644 (file)
index 0000000..ac2a3da
--- /dev/null
@@ -0,0 +1,110 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2007  Nokia Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012-2012  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef enum {
+       PLAYER_ITEM_TYPE_AUDIO,
+       PLAYER_ITEM_TYPE_VIDEO,
+       PLAYER_ITEM_TYPE_FOLDER,
+       PLAYER_ITEM_TYPE_INVALID,
+} player_item_type_t;
+
+typedef enum {
+       PLAYER_FOLDER_TYPE_MIXED,
+       PLAYER_FOLDER_TYPE_TITLES,
+       PLAYER_FOLDER_TYPE_ALBUMS,
+       PLAYER_FOLDER_TYPE_ARTISTS,
+       PLAYER_FOLDER_TYPE_GENRES,
+       PLAYER_FOLDER_TYPE_PLAYLISTS,
+       PLAYER_FOLDER_TYPE_YEARS,
+       PLAYER_FOLDER_TYPE_INVALID,
+} player_folder_type_t;
+
+struct media_player;
+struct media_item;
+
+struct media_player_callback {
+       bool (*set_setting) (struct media_player *mp, const char *key,
+                               const char *value, void *user_data);
+       int (*play) (struct media_player *mp, void *user_data);
+       int (*pause) (struct media_player *mp, void *user_data);
+       int (*stop) (struct media_player *mp, void *user_data);
+       int (*next) (struct media_player *mp, void *user_data);
+       int (*previous) (struct media_player *mp, void *user_data);
+       int (*fast_forward) (struct media_player *mp, void *user_data);
+       int (*rewind) (struct media_player *mp, void *user_data);
+       int (*list_items) (struct media_player *mp, const char *name,
+                               uint32_t start, uint32_t end, void *user_data);
+       int (*change_folder) (struct media_player *mp, const char *path,
+                                               uint64_t uid, void *user_data);
+       int (*search) (struct media_player *mp, const char *string,
+                                               void *user_data);
+       int (*play_item) (struct media_player *mp, const char *name,
+                                       uint64_t uid, void *user_data);
+       int (*add_to_nowplaying) (struct media_player *mp, const char *name,
+                                       uint64_t uid, void *user_data);
+};
+
+struct media_player *media_player_controller_create(const char *path,
+                                                               uint16_t id);
+void media_player_destroy(struct media_player *mp);
+void media_player_set_duration(struct media_player *mp, uint32_t duration);
+void media_player_set_position(struct media_player *mp, uint32_t position);
+void media_player_set_setting(struct media_player *mp, const char *key,
+                                                       const char *value);
+const char *media_player_get_status(struct media_player *mp);
+void media_player_set_status(struct media_player *mp, const char *status);
+void media_player_set_metadata(struct media_player *mp,
+                               struct media_item *item, const char *key,
+                               void *data, size_t len);
+void media_player_set_type(struct media_player *mp, const char *type);
+void media_player_set_subtype(struct media_player *mp, const char *subtype);
+void media_player_set_name(struct media_player *mp, const char *name);
+void media_player_set_browsable(struct media_player *mp, bool enabled);
+void media_player_set_searchable(struct media_player *mp, bool enabled);
+void media_player_set_folder(struct media_player *mp, const char *path,
+                                                               uint32_t items);
+void media_player_set_playlist(struct media_player *mp, const char *name);
+struct media_item *media_player_set_playlist_item(struct media_player *mp,
+                                                               uint64_t uid);
+
+struct media_item *media_player_create_folder(struct media_player *mp,
+                                               const char *name,
+                                               player_folder_type_t type,
+                                               uint64_t uid);
+struct media_item *media_player_create_item(struct media_player *mp,
+                                               const char *name,
+                                               player_item_type_t type,
+                                               uint64_t uid);
+
+void media_item_set_playable(struct media_item *item, bool value);
+void media_player_list_complete(struct media_player *mp, GSList *items,
+                                                               int err);
+void media_player_change_folder_complete(struct media_player *player,
+                                               const char *path, int ret);
+void media_player_search_complete(struct media_player *mp, int ret);
+
+void media_player_set_callbacks(struct media_player *mp,
+                               const struct media_player_callback *cbs,
+                               void *user_data);
diff --git a/profiles/audio/sink.c b/profiles/audio/sink.c
new file mode 100644 (file)
index 0000000..400af06
--- /dev/null
@@ -0,0 +1,454 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/service.h"
+
+#include "avdtp.h"
+#include "media.h"
+#include "a2dp.h"
+#include "error.h"
+#include "sink.h"
+#include "dbus-common.h"
+
+#define STREAM_SETUP_RETRY_TIMER 2
+
+struct sink {
+       struct btd_service *service;
+       struct avdtp *session;
+       struct avdtp_stream *stream;
+       unsigned int cb_id;
+       avdtp_session_state_t session_state;
+       avdtp_state_t stream_state;
+       sink_state_t state;
+       unsigned int connect_id;
+       unsigned int disconnect_id;
+       unsigned int avdtp_callback_id;
+};
+
+struct sink_state_callback {
+       sink_state_cb cb;
+       struct btd_service *service;
+       void *user_data;
+       unsigned int id;
+};
+
+static GSList *sink_callbacks = NULL;
+
+static char *str_state[] = {
+       "SINK_STATE_DISCONNECTED",
+       "SINK_STATE_CONNECTING",
+       "SINK_STATE_CONNECTED",
+       "SINK_STATE_PLAYING",
+};
+
+static void sink_set_state(struct sink *sink, sink_state_t new_state)
+{
+       struct btd_service *service = sink->service;
+       struct btd_device *dev = btd_service_get_device(service);
+       sink_state_t old_state = sink->state;
+       GSList *l;
+
+       sink->state = new_state;
+
+       DBG("State changed %s: %s -> %s", device_get_path(dev),
+                               str_state[old_state], str_state[new_state]);
+
+       for (l = sink_callbacks; l != NULL; l = l->next) {
+               struct sink_state_callback *cb = l->data;
+
+               if (cb->service != service)
+                       continue;
+
+               cb->cb(service, old_state, new_state, cb->user_data);
+       }
+
+       if (new_state != SINK_STATE_DISCONNECTED)
+               return;
+
+       if (sink->session) {
+               avdtp_unref(sink->session);
+               sink->session = NULL;
+       }
+}
+
+static void avdtp_state_callback(struct btd_device *dev,
+                                       struct avdtp *session,
+                                       avdtp_session_state_t old_state,
+                                       avdtp_session_state_t new_state,
+                                       void *user_data)
+{
+       struct sink *sink = user_data;
+
+       switch (new_state) {
+       case AVDTP_SESSION_STATE_DISCONNECTED:
+               sink_set_state(sink, SINK_STATE_DISCONNECTED);
+               break;
+       case AVDTP_SESSION_STATE_CONNECTING:
+               sink_set_state(sink, SINK_STATE_CONNECTING);
+               break;
+       case AVDTP_SESSION_STATE_CONNECTED:
+               break;
+       }
+
+       sink->session_state = new_state;
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+                                       avdtp_state_t old_state,
+                                       avdtp_state_t new_state,
+                                       struct avdtp_error *err,
+                                       void *user_data)
+{
+       struct btd_service *service = user_data;
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (err)
+               return;
+
+       switch (new_state) {
+       case AVDTP_STATE_IDLE:
+               btd_service_disconnecting_complete(sink->service, 0);
+
+               if (sink->disconnect_id > 0) {
+                       a2dp_cancel(sink->disconnect_id);
+                       sink->disconnect_id = 0;
+               }
+
+               if (sink->session) {
+                       avdtp_unref(sink->session);
+                       sink->session = NULL;
+               }
+               sink->stream = NULL;
+               sink->cb_id = 0;
+               break;
+       case AVDTP_STATE_OPEN:
+               btd_service_connecting_complete(sink->service, 0);
+               sink_set_state(sink, SINK_STATE_CONNECTED);
+               break;
+       case AVDTP_STATE_STREAMING:
+               sink_set_state(sink, SINK_STATE_PLAYING);
+               break;
+       case AVDTP_STATE_CONFIGURED:
+       case AVDTP_STATE_CLOSING:
+       case AVDTP_STATE_ABORTING:
+       default:
+               break;
+       }
+
+       sink->stream_state = new_state;
+}
+
+static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
+                                       struct avdtp_stream *stream,
+                                       struct avdtp_error *err, void *user_data)
+{
+       struct sink *sink = user_data;
+
+       sink->connect_id = 0;
+
+       if (stream)
+               return;
+
+       avdtp_unref(sink->session);
+       sink->session = NULL;
+       if (avdtp_error_category(err) == AVDTP_ERRNO
+                               && avdtp_error_posix_errno(err) != EHOSTDOWN)
+               btd_service_connecting_complete(sink->service, -EAGAIN);
+       else
+               btd_service_connecting_complete(sink->service, -EIO);
+}
+
+static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
+                       GSList *caps, void *user_data)
+{
+       struct sink *sink = user_data;
+       int id;
+
+       sink->connect_id = 0;
+
+       id = a2dp_config(session, sep, stream_setup_complete, caps, sink);
+       if (id == 0)
+               goto failed;
+
+       sink->connect_id = id;
+       return;
+
+failed:
+       btd_service_connecting_complete(sink->service, -EIO);
+
+       avdtp_unref(sink->session);
+       sink->session = NULL;
+}
+
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
+                               void *user_data)
+{
+       struct sink *sink = user_data;
+       int id, perr;
+
+       if (err) {
+               avdtp_unref(sink->session);
+               sink->session = NULL;
+               if (avdtp_error_category(err) == AVDTP_ERRNO
+                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+                       perr = -EAGAIN;
+               } else
+                       perr = -EIO;
+               goto failed;
+       }
+
+       DBG("Discovery complete");
+
+       id = a2dp_select_capabilities(sink->session, AVDTP_SEP_TYPE_SINK, NULL,
+                                               select_complete, sink);
+       if (id == 0) {
+               perr = -EIO;
+               goto failed;
+       }
+
+       sink->connect_id = id;
+       return;
+
+failed:
+       btd_service_connecting_complete(sink->service, perr);
+       avdtp_unref(sink->session);
+       sink->session = NULL;
+}
+
+gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (sink->connect_id > 0 || sink->disconnect_id > 0)
+               return FALSE;
+
+       if (session && !sink->session)
+               sink->session = avdtp_ref(session);
+
+       if (!sink->session)
+               return FALSE;
+
+       if (avdtp_discover(sink->session, discovery_complete, sink) < 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+int sink_connect(struct btd_service *service)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (!sink->session)
+               sink->session = avdtp_get(btd_service_get_device(service));
+
+       if (!sink->session) {
+               DBG("Unable to get a session");
+               return -EIO;
+       }
+
+       if (sink->connect_id > 0 || sink->disconnect_id > 0)
+               return -EBUSY;
+
+       if (sink->stream_state >= AVDTP_STATE_OPEN)
+               return -EALREADY;
+
+       if (!sink_setup_stream(service, NULL)) {
+               DBG("Failed to create a stream");
+               return -EIO;
+       }
+
+       DBG("stream creation in progress");
+
+       return 0;
+}
+
+static void sink_free(struct btd_service *service)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (sink->cb_id)
+               avdtp_stream_remove_cb(sink->session, sink->stream,
+                                       sink->cb_id);
+
+       if (sink->session)
+               avdtp_unref(sink->session);
+
+       if (sink->connect_id > 0) {
+               btd_service_connecting_complete(sink->service, -ECANCELED);
+               a2dp_cancel(sink->connect_id);
+               sink->connect_id = 0;
+       }
+
+       if (sink->disconnect_id > 0) {
+               btd_service_disconnecting_complete(sink->service, -ECANCELED);
+               a2dp_cancel(sink->disconnect_id);
+               sink->disconnect_id = 0;
+       }
+
+       avdtp_remove_state_cb(sink->avdtp_callback_id);
+       btd_service_unref(sink->service);
+
+       g_free(sink);
+}
+
+void sink_unregister(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("%s", device_get_path(dev));
+
+       sink_free(service);
+}
+
+int sink_init(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct sink *sink;
+
+       DBG("%s", device_get_path(dev));
+
+       sink = g_new0(struct sink, 1);
+
+       sink->service = btd_service_ref(service);
+
+       sink->avdtp_callback_id = avdtp_add_state_cb(dev, avdtp_state_callback,
+                                                                       sink);
+
+       btd_service_set_user_data(service, sink);
+
+       return 0;
+}
+
+gboolean sink_is_active(struct btd_service *service)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (sink->session)
+               return TRUE;
+
+       return FALSE;
+}
+
+gboolean sink_new_stream(struct btd_service *service, struct avdtp *session,
+                               struct avdtp_stream *stream)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (sink->stream)
+               return FALSE;
+
+       if (!sink->session)
+               sink->session = avdtp_ref(session);
+
+       sink->stream = stream;
+
+       sink->cb_id = avdtp_stream_add_cb(session, stream,
+                                               stream_state_changed, service);
+
+       return TRUE;
+}
+
+int sink_disconnect(struct btd_service *service, gboolean shutdown)
+{
+       struct sink *sink = btd_service_get_user_data(service);
+
+       if (!sink->session)
+               return -ENOTCONN;
+
+       if (shutdown)
+               avdtp_set_device_disconnect(sink->session, TRUE);
+
+       /* cancel pending connect */
+       if (sink->connect_id > 0) {
+               a2dp_cancel(sink->connect_id);
+               sink->connect_id = 0;
+               btd_service_connecting_complete(sink->service, -ECANCELED);
+
+               avdtp_unref(sink->session);
+               sink->session = NULL;
+
+               return 0;
+       }
+
+       /* disconnect already ongoing */
+       if (sink->disconnect_id > 0)
+               return -EBUSY;
+
+       if (!sink->stream)
+               return -ENOTCONN;
+
+       return avdtp_close(sink->session, sink->stream, FALSE);
+}
+
+unsigned int sink_add_state_cb(struct btd_service *service, sink_state_cb cb,
+                                                               void *user_data)
+{
+       struct sink_state_callback *state_cb;
+       static unsigned int id = 0;
+
+       state_cb = g_new(struct sink_state_callback, 1);
+       state_cb->cb = cb;
+       state_cb->service = service;
+       state_cb->user_data = user_data;
+       state_cb->id = ++id;
+
+       sink_callbacks = g_slist_append(sink_callbacks, state_cb);
+
+       return state_cb->id;
+}
+
+gboolean sink_remove_state_cb(unsigned int id)
+{
+       GSList *l;
+
+       for (l = sink_callbacks; l != NULL; l = l->next) {
+               struct sink_state_callback *cb = l->data;
+               if (cb && cb->id == id) {
+                       sink_callbacks = g_slist_remove(sink_callbacks, cb);
+                       g_free(cb);
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
similarity index 66%
rename from audio/sink.h
rename to profiles/audio/sink.h
index 4fea5ba..904a33d 100644 (file)
@@ -22,8 +22,6 @@
  *
  */
 
-#define AUDIO_SINK_INTERFACE "org.bluez.AudioSink"
-
 typedef enum {
        SINK_STATE_DISCONNECTED,
        SINK_STATE_CONNECTING,
@@ -31,19 +29,22 @@ typedef enum {
        SINK_STATE_PLAYING,
 } sink_state_t;
 
-typedef void (*sink_state_cb) (struct audio_device *dev,
+typedef void (*sink_state_cb) (struct btd_service *service,
                                sink_state_t old_state,
                                sink_state_t new_state,
                                void *user_data);
 
-unsigned int sink_add_state_cb(sink_state_cb cb, void *user_data);
+struct btd_service;
+
+unsigned int sink_add_state_cb(struct btd_service *service, sink_state_cb cb,
+                                                       void *user_data);
 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);
-sink_state_t sink_get_state(struct audio_device *dev);
-gboolean sink_new_stream(struct audio_device *dev, struct avdtp *session,
+int sink_init(struct btd_service *service);
+void sink_unregister(struct btd_service *service);
+gboolean sink_is_active(struct btd_service *service);
+int sink_connect(struct btd_service *service);
+gboolean sink_new_stream(struct btd_service *service, struct avdtp *session,
                                struct avdtp_stream *stream);
-gboolean sink_setup_stream(struct sink *sink, struct avdtp *session);
-gboolean sink_shutdown(struct sink *sink);
+gboolean sink_setup_stream(struct btd_service *service, struct avdtp *session);
+int sink_disconnect(struct btd_service *service, gboolean shutdown);
diff --git a/profiles/audio/source.c b/profiles/audio/source.c
new file mode 100644 (file)
index 0000000..24a4353
--- /dev/null
@@ -0,0 +1,446 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2010  Nokia Corporation
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2009  Joao Paulo Rechi Vita
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/service.h"
+
+#include "avdtp.h"
+#include "media.h"
+#include "a2dp.h"
+#include "error.h"
+#include "source.h"
+#include "dbus-common.h"
+
+struct source {
+       struct btd_service *service;
+       struct avdtp *session;
+       struct avdtp_stream *stream;
+       unsigned int cb_id;
+       avdtp_session_state_t session_state;
+       avdtp_state_t stream_state;
+       source_state_t state;
+       unsigned int connect_id;
+       unsigned int disconnect_id;
+       unsigned int avdtp_callback_id;
+};
+
+struct source_state_callback {
+       source_state_cb cb;
+       struct btd_service *service;
+       void *user_data;
+       unsigned int id;
+};
+
+static GSList *source_callbacks = NULL;
+
+static char *str_state[] = {
+       "SOURCE_STATE_DISCONNECTED",
+       "SOURCE_STATE_CONNECTING",
+       "SOURCE_STATE_CONNECTED",
+       "SOURCE_STATE_PLAYING",
+};
+
+static void source_set_state(struct source *source, source_state_t new_state)
+{
+       struct btd_device *dev = btd_service_get_device(source->service);
+       source_state_t old_state = source->state;
+       GSList *l;
+
+       source->state = new_state;
+
+       DBG("State changed %s: %s -> %s", device_get_path(dev),
+                               str_state[old_state], str_state[new_state]);
+
+       for (l = source_callbacks; l != NULL; l = l->next) {
+               struct source_state_callback *cb = l->data;
+
+               if (cb->service != source->service)
+                       continue;
+
+               cb->cb(source->service, old_state, new_state, cb->user_data);
+       }
+
+       if (new_state != SOURCE_STATE_DISCONNECTED)
+               return;
+
+       if (source->session) {
+               avdtp_unref(source->session);
+               source->session = NULL;
+       }
+}
+
+static void avdtp_state_callback(struct btd_device *dev, struct avdtp *session,
+                                       avdtp_session_state_t old_state,
+                                       avdtp_session_state_t new_state,
+                                       void *user_data)
+{
+       struct source *source = user_data;
+
+       switch (new_state) {
+       case AVDTP_SESSION_STATE_DISCONNECTED:
+               source_set_state(source, SOURCE_STATE_DISCONNECTED);
+               break;
+       case AVDTP_SESSION_STATE_CONNECTING:
+               source_set_state(source, SOURCE_STATE_CONNECTING);
+               break;
+       case AVDTP_SESSION_STATE_CONNECTED:
+               break;
+       }
+
+       source->session_state = new_state;
+}
+
+static void stream_state_changed(struct avdtp_stream *stream,
+                                       avdtp_state_t old_state,
+                                       avdtp_state_t new_state,
+                                       struct avdtp_error *err,
+                                       void *user_data)
+{
+       struct btd_service *service = user_data;
+       struct source *source = btd_service_get_user_data(service);
+
+       if (err)
+               return;
+
+       switch (new_state) {
+       case AVDTP_STATE_IDLE:
+               btd_service_disconnecting_complete(source->service, 0);
+
+               if (source->disconnect_id > 0) {
+                       a2dp_cancel(source->disconnect_id);
+                       source->disconnect_id = 0;
+               }
+
+               if (source->session) {
+                       avdtp_unref(source->session);
+                       source->session = NULL;
+               }
+               source->stream = NULL;
+               source->cb_id = 0;
+               break;
+       case AVDTP_STATE_OPEN:
+               btd_service_connecting_complete(source->service, 0);
+               source_set_state(source, SOURCE_STATE_CONNECTED);
+               break;
+       case AVDTP_STATE_STREAMING:
+               source_set_state(source, SOURCE_STATE_PLAYING);
+               break;
+       case AVDTP_STATE_CONFIGURED:
+       case AVDTP_STATE_CLOSING:
+       case AVDTP_STATE_ABORTING:
+       default:
+               break;
+       }
+
+       source->stream_state = new_state;
+}
+
+static void stream_setup_complete(struct avdtp *session, struct a2dp_sep *sep,
+                                       struct avdtp_stream *stream,
+                                       struct avdtp_error *err, void *user_data)
+{
+       struct source *source = user_data;
+
+       source->connect_id = 0;
+
+       if (stream)
+               return;
+
+       avdtp_unref(source->session);
+       source->session = NULL;
+       if (avdtp_error_category(err) == AVDTP_ERRNO
+                               && avdtp_error_posix_errno(err) != EHOSTDOWN)
+               btd_service_connecting_complete(source->service, -EAGAIN);
+       else
+               btd_service_connecting_complete(source->service, -EIO);
+}
+
+static void select_complete(struct avdtp *session, struct a2dp_sep *sep,
+                       GSList *caps, void *user_data)
+{
+       struct source *source = user_data;
+       int id;
+
+       source->connect_id = 0;
+
+       if (caps == NULL)
+               goto failed;
+
+       id = a2dp_config(session, sep, stream_setup_complete, caps, source);
+       if (id == 0)
+               goto failed;
+
+       source->connect_id = id;
+       return;
+
+failed:
+       btd_service_connecting_complete(source->service, -EIO);
+
+       avdtp_unref(source->session);
+       source->session = NULL;
+}
+
+static void discovery_complete(struct avdtp *session, GSList *seps, struct avdtp_error *err,
+                               void *user_data)
+{
+       struct source *source = user_data;
+       int id, perr;
+
+       if (err) {
+               avdtp_unref(source->session);
+               source->session = NULL;
+               if (avdtp_error_category(err) == AVDTP_ERRNO
+                               && avdtp_error_posix_errno(err) != EHOSTDOWN) {
+                       perr = -EAGAIN;
+               } else
+                       perr = -EIO;
+               goto failed;
+       }
+
+       DBG("Discovery complete");
+
+       id = a2dp_select_capabilities(source->session, AVDTP_SEP_TYPE_SOURCE, NULL,
+                                               select_complete, source);
+       if (id == 0) {
+               perr = -EIO;
+               goto failed;
+       }
+
+       source->connect_id = id;
+       return;
+
+failed:
+       btd_service_connecting_complete(source->service, perr);
+       avdtp_unref(source->session);
+       source->session = NULL;
+}
+
+gboolean source_setup_stream(struct btd_service *service,
+                                                       struct avdtp *session)
+{
+       struct source *source = btd_service_get_user_data(service);
+
+       if (source->connect_id > 0 || source->disconnect_id > 0)
+               return FALSE;
+
+       if (session && !source->session)
+               source->session = avdtp_ref(session);
+
+       if (!source->session)
+               return FALSE;
+
+       if (avdtp_discover(source->session, discovery_complete, source) < 0)
+               return FALSE;
+
+       return TRUE;
+}
+
+int source_connect(struct btd_service *service)
+{
+       struct source *source = btd_service_get_user_data(service);
+
+       if (!source->session)
+               source->session = avdtp_get(btd_service_get_device(service));
+
+       if (!source->session) {
+               DBG("Unable to get a session");
+               return -EIO;
+       }
+
+       if (source->connect_id > 0 || source->disconnect_id > 0)
+               return -EBUSY;
+
+       if (source->stream_state >= AVDTP_STATE_OPEN)
+               return -EALREADY;
+
+       if (!source_setup_stream(service, NULL)) {
+               DBG("Failed to create a stream");
+               return -EIO;
+       }
+
+       DBG("stream creation in progress");
+
+       return 0;
+}
+
+static void source_free(struct btd_service *service)
+{
+       struct source *source = btd_service_get_user_data(service);
+
+       if (source->cb_id)
+               avdtp_stream_remove_cb(source->session, source->stream,
+                                       source->cb_id);
+
+       if (source->session)
+               avdtp_unref(source->session);
+
+       if (source->connect_id > 0) {
+               btd_service_connecting_complete(source->service, -ECANCELED);
+               a2dp_cancel(source->connect_id);
+               source->connect_id = 0;
+       }
+
+       if (source->disconnect_id > 0) {
+               btd_service_disconnecting_complete(source->service, -ECANCELED);
+               a2dp_cancel(source->disconnect_id);
+               source->disconnect_id = 0;
+       }
+
+       avdtp_remove_state_cb(source->avdtp_callback_id);
+       btd_service_unref(source->service);
+
+       g_free(source);
+}
+
+void source_unregister(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+
+       DBG("%s", device_get_path(dev));
+
+       source_free(service);
+}
+
+int source_init(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct source *source;
+
+       DBG("%s", device_get_path(dev));
+
+       source = g_new0(struct source, 1);
+
+       source->service = btd_service_ref(service);
+
+       source->avdtp_callback_id = avdtp_add_state_cb(dev,
+                                                       avdtp_state_callback,
+                                                       source);
+
+       btd_service_set_user_data(service, source);
+
+       return 0;
+}
+
+gboolean source_new_stream(struct btd_service *service, struct avdtp *session,
+                               struct avdtp_stream *stream)
+{
+       struct source *source = btd_service_get_user_data(service);
+
+       if (source->stream)
+               return FALSE;
+
+       if (!source->session)
+               source->session = avdtp_ref(session);
+
+       source->stream = stream;
+
+       source->cb_id = avdtp_stream_add_cb(session, stream,
+                                               stream_state_changed, service);
+
+       return TRUE;
+}
+
+int source_disconnect(struct btd_service *service, gboolean shutdown)
+{
+       struct source *source = btd_service_get_user_data(service);
+
+       if (!source->session)
+               return -ENOTCONN;
+
+       if (shutdown)
+               avdtp_set_device_disconnect(source->session, TRUE);
+
+       /* cancel pending connect */
+       if (source->connect_id > 0) {
+               a2dp_cancel(source->connect_id);
+               source->connect_id = 0;
+               btd_service_connecting_complete(source->service, -ECANCELED);
+
+               avdtp_unref(source->session);
+               source->session = NULL;
+
+               return 0;
+       }
+
+       /* disconnect already ongoing */
+       if (source->disconnect_id > 0)
+               return -EBUSY;
+
+       if (!source->stream)
+               return -ENOTCONN;
+
+       return avdtp_close(source->session, source->stream, FALSE);
+}
+
+unsigned int source_add_state_cb(struct btd_service *service,
+                                       source_state_cb cb, void *user_data)
+{
+       struct source_state_callback *state_cb;
+       static unsigned int id = 0;
+
+       state_cb = g_new(struct source_state_callback, 1);
+       state_cb->cb = cb;
+       state_cb->service = service;
+       state_cb->user_data = user_data;
+       state_cb->id = ++id;
+
+       source_callbacks = g_slist_append(source_callbacks, state_cb);
+
+       return state_cb->id;
+}
+
+gboolean source_remove_state_cb(unsigned int id)
+{
+       GSList *l;
+
+       for (l = source_callbacks; l != NULL; l = l->next) {
+               struct source_state_callback *cb = l->data;
+               if (cb && cb->id == id) {
+                       source_callbacks = g_slist_remove(source_callbacks, cb);
+                       g_free(cb);
+                       return TRUE;
+               }
+       }
+
+       return FALSE;
+}
similarity index 67%
rename from audio/source.h
rename to profiles/audio/source.h
index 695bded..c16fb4b 100644 (file)
@@ -23,8 +23,6 @@
  *
  */
 
-#define AUDIO_SOURCE_INTERFACE "org.bluez.AudioSource"
-
 typedef enum {
        SOURCE_STATE_DISCONNECTED,
        SOURCE_STATE_CONNECTING,
@@ -32,19 +30,22 @@ typedef enum {
        SOURCE_STATE_PLAYING,
 } source_state_t;
 
-typedef void (*source_state_cb) (struct audio_device *dev,
+typedef void (*source_state_cb) (struct btd_service *service,
                                source_state_t old_state,
                                source_state_t new_state,
                                void *user_data);
 
-unsigned int source_add_state_cb(source_state_cb cb, void *user_data);
+struct btd_service;
+
+unsigned int source_add_state_cb(struct btd_service *service,
+                                       source_state_cb cb, void *user_data);
 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);
-source_state_t source_get_state(struct audio_device *dev);
-gboolean source_new_stream(struct audio_device *dev, struct avdtp *session,
+int source_init(struct btd_service *service);
+void source_unregister(struct btd_service *service);
+int source_connect(struct btd_service *service);
+gboolean source_new_stream(struct btd_service *service, struct avdtp *session,
                                struct avdtp_stream *stream);
-gboolean source_setup_stream(struct source *source, struct avdtp *session);
-gboolean source_shutdown(struct source *source);
+gboolean source_setup_stream(struct btd_service *service,
+                                                       struct avdtp *session);
+int source_disconnect(struct btd_service *service, gboolean shutdown);
diff --git a/profiles/audio/transport.c b/profiles/audio/transport.c
new file mode 100644 (file)
index 0000000..087c0ee
--- /dev/null
@@ -0,0 +1,953 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2006-2007  Nokia Corporation
+ *  Copyright (C) 2004-2009  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/dbus-common.h"
+
+#include "log.h"
+#include "error.h"
+#include "avdtp.h"
+#include "media.h"
+#include "transport.h"
+#include "a2dp.h"
+#include "sink.h"
+#include "source.h"
+#include "avrcp.h"
+
+#define MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
+
+typedef enum {
+       TRANSPORT_STATE_IDLE,           /* Not acquired and suspended */
+       TRANSPORT_STATE_PENDING,        /* Playing but not acquired */
+       TRANSPORT_STATE_REQUESTING,     /* Acquire in progress */
+       TRANSPORT_STATE_ACTIVE,         /* Acquired and playing */
+       TRANSPORT_STATE_SUSPENDING,     /* Release in progress */
+} transport_state_t;
+
+static char *str_state[] = {
+       "TRANSPORT_STATE_IDLE",
+       "TRANSPORT_STATE_PENDING",
+       "TRANSPORT_STATE_REQUESTING",
+       "TRANSPORT_STATE_ACTIVE",
+       "TRANSPORT_STATE_SUSPENDING",
+};
+
+struct media_request {
+       DBusMessage             *msg;
+       guint                   id;
+};
+
+struct media_owner {
+       struct media_transport  *transport;
+       struct media_request    *pending;
+       char                    *name;
+       guint                   watch;
+};
+
+struct a2dp_transport {
+       struct avdtp            *session;
+       uint16_t                delay;
+       uint16_t                volume;
+};
+
+struct media_transport {
+       char                    *path;          /* Transport object path */
+       struct btd_device       *device;        /* Transport device */
+       struct media_endpoint   *endpoint;      /* Transport endpoint */
+       struct media_owner      *owner;         /* Transport owner */
+       uint8_t                 *configuration; /* Transport configuration */
+       int                     size;           /* Transport configuration size */
+       int                     fd;             /* Transport file descriptor */
+       uint16_t                imtu;           /* Transport input mtu */
+       uint16_t                omtu;           /* Transport output mtu */
+       transport_state_t       state;
+       guint                   hs_watch;
+       guint                   source_watch;
+       guint                   sink_watch;
+       guint                   (*resume) (struct media_transport *transport,
+                                       struct media_owner *owner);
+       guint                   (*suspend) (struct media_transport *transport,
+                                       struct media_owner *owner);
+       void                    (*cancel) (struct media_transport *transport,
+                                                               guint id);
+       GDestroyNotify          destroy;
+       void                    *data;
+};
+
+static GSList *transports = NULL;
+
+static const char *state2str(transport_state_t state)
+{
+       switch (state) {
+       case TRANSPORT_STATE_IDLE:
+       case TRANSPORT_STATE_REQUESTING:
+               return "idle";
+       case TRANSPORT_STATE_PENDING:
+               return "pending";
+       case TRANSPORT_STATE_ACTIVE:
+       case TRANSPORT_STATE_SUSPENDING:
+               return "active";
+       }
+
+       return NULL;
+}
+
+static gboolean state_in_use(transport_state_t state)
+{
+       switch (state) {
+       case TRANSPORT_STATE_IDLE:
+       case TRANSPORT_STATE_PENDING:
+               return FALSE;
+       case TRANSPORT_STATE_REQUESTING:
+       case TRANSPORT_STATE_ACTIVE:
+       case TRANSPORT_STATE_SUSPENDING:
+               return TRUE;
+       }
+
+       return FALSE;
+}
+
+static void transport_set_state(struct media_transport *transport,
+                                                       transport_state_t state)
+{
+       transport_state_t old_state = transport->state;
+       const char *str;
+
+       if (old_state == state)
+               return;
+
+       transport->state = state;
+
+       DBG("State changed %s: %s -> %s", transport->path, str_state[old_state],
+                                                       str_state[state]);
+
+       str = state2str(state);
+
+       if (g_strcmp0(str, state2str(old_state)) != 0)
+               g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                               transport->path,
+                                               MEDIA_TRANSPORT_INTERFACE,
+                                               "State");
+}
+
+void media_transport_destroy(struct media_transport *transport)
+{
+       char *path;
+
+       if (transport->sink_watch)
+               sink_remove_state_cb(transport->sink_watch);
+
+       if (transport->source_watch)
+               source_remove_state_cb(transport->source_watch);
+
+       path = g_strdup(transport->path);
+       g_dbus_unregister_interface(btd_get_dbus_connection(), path,
+                                               MEDIA_TRANSPORT_INTERFACE);
+
+       g_free(path);
+}
+
+static struct media_request *media_request_create(DBusMessage *msg, guint id)
+{
+       struct media_request *req;
+
+       req = g_new0(struct media_request, 1);
+       req->msg = dbus_message_ref(msg);
+       req->id = id;
+
+       DBG("Request created: method=%s id=%u", dbus_message_get_member(msg),
+                                                                       id);
+
+       return req;
+}
+
+static void media_request_reply(struct media_request *req, int err)
+{
+       DBusMessage *reply;
+
+       DBG("Request %s Reply %s", dbus_message_get_member(req->msg),
+                                                       strerror(err));
+
+       if (!err)
+               reply = g_dbus_create_reply(req->msg, DBUS_TYPE_INVALID);
+       else
+               reply = g_dbus_create_error(req->msg,
+                                               ERROR_INTERFACE ".Failed",
+                                               "%s", strerror(err));
+
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+}
+
+static void media_owner_remove(struct media_owner *owner)
+{
+       struct media_transport *transport = owner->transport;
+       struct media_request *req = owner->pending;
+
+       if (!req)
+               return;
+
+       DBG("Owner %s Request %s", owner->name,
+                                       dbus_message_get_member(req->msg));
+
+       if (req->id)
+               transport->cancel(transport, req->id);
+
+       owner->pending = NULL;
+       if (req->msg)
+               dbus_message_unref(req->msg);
+
+       g_free(req);
+}
+
+static void media_owner_free(struct media_owner *owner)
+{
+       DBG("Owner %s", owner->name);
+
+       media_owner_remove(owner);
+
+       g_free(owner->name);
+       g_free(owner);
+}
+
+static void media_transport_remove_owner(struct media_transport *transport)
+{
+       struct media_owner *owner = transport->owner;
+
+       DBG("Transport %s Owner %s", transport->path, owner->name);
+
+       /* Reply if owner has a pending request */
+       if (owner->pending)
+               media_request_reply(owner->pending, EIO);
+
+       transport->owner = NULL;
+
+       if (owner->watch)
+               g_dbus_remove_watch(btd_get_dbus_connection(), owner->watch);
+
+       media_owner_free(owner);
+
+       if (state_in_use(transport->state))
+               transport->suspend(transport, NULL);
+}
+
+static gboolean media_transport_set_fd(struct media_transport *transport,
+                                       int fd, uint16_t imtu, uint16_t omtu)
+{
+       if (transport->fd == fd)
+               return TRUE;
+
+       transport->fd = fd;
+       transport->imtu = imtu;
+       transport->omtu = omtu;
+
+       info("%s: fd(%d) ready", transport->path, fd);
+
+       return TRUE;
+}
+
+static void a2dp_resume_complete(struct avdtp *session,
+                               struct avdtp_error *err, void *user_data)
+{
+       struct media_owner *owner = user_data;
+       struct media_request *req = owner->pending;
+       struct media_transport *transport = owner->transport;
+       struct a2dp_sep *sep = media_endpoint_get_sep(transport->endpoint);
+       struct avdtp_stream *stream;
+       int fd;
+       uint16_t imtu, omtu;
+       gboolean ret;
+
+       req->id = 0;
+
+       if (err)
+               goto fail;
+
+       stream = a2dp_sep_get_stream(sep);
+       if (stream == NULL)
+               goto fail;
+
+       ret = avdtp_stream_get_transport(stream, &fd, &imtu, &omtu, NULL);
+       if (ret == FALSE)
+               goto fail;
+
+       media_transport_set_fd(transport, fd, imtu, omtu);
+
+       ret = g_dbus_send_reply(btd_get_dbus_connection(), req->msg,
+                                               DBUS_TYPE_UNIX_FD, &fd,
+                                               DBUS_TYPE_UINT16, &imtu,
+                                               DBUS_TYPE_UINT16, &omtu,
+                                               DBUS_TYPE_INVALID);
+       if (ret == FALSE)
+               goto fail;
+
+       media_owner_remove(owner);
+
+       transport_set_state(transport, TRANSPORT_STATE_ACTIVE);
+
+       return;
+
+fail:
+       media_transport_remove_owner(transport);
+}
+
+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 a2dp_sep *sep = media_endpoint_get_sep(endpoint);
+       guint id;
+
+       if (a2dp->session == NULL) {
+               a2dp->session = avdtp_get(transport->device);
+               if (a2dp->session == NULL)
+                       return 0;
+       }
+
+       if (state_in_use(transport->state))
+               return a2dp_resume(a2dp->session, sep, a2dp_resume_complete,
+                                                                       owner);
+
+       if (a2dp_sep_lock(sep, a2dp->session) == FALSE)
+               return 0;
+
+       id = a2dp_resume(a2dp->session, sep, a2dp_resume_complete, owner);
+
+       if (id == 0) {
+               a2dp_sep_unlock(sep, a2dp->session);
+               return 0;
+       }
+
+       if (transport->state == TRANSPORT_STATE_IDLE)
+               transport_set_state(transport, TRANSPORT_STATE_REQUESTING);
+
+       return id;
+}
+
+static void a2dp_suspend_complete(struct avdtp *session,
+                               struct avdtp_error *err, void *user_data)
+{
+       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 */
+       if (owner->pending) {
+               owner->pending->id = 0;
+               media_request_reply(owner->pending, 0);
+               media_owner_remove(owner);
+       }
+
+       a2dp_sep_unlock(sep, a2dp->session);
+       transport_set_state(transport, TRANSPORT_STATE_IDLE);
+       media_transport_remove_owner(transport);
+}
+
+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 != NULL)
+               return a2dp_suspend(a2dp->session, sep, a2dp_suspend_complete,
+                                                                       owner);
+
+       transport_set_state(transport, TRANSPORT_STATE_IDLE);
+       a2dp_sep_unlock(sep, a2dp->session);
+
+       return 0;
+}
+
+static void cancel_a2dp(struct media_transport *transport, guint id)
+{
+       a2dp_cancel(id);
+}
+
+static void media_owner_exit(DBusConnection *connection, void *user_data)
+{
+       struct media_owner *owner = user_data;
+
+       owner->watch = 0;
+
+       media_owner_remove(owner);
+
+       media_transport_remove_owner(owner->transport);
+}
+
+static void media_transport_set_owner(struct media_transport *transport,
+                                       struct media_owner *owner)
+{
+       DBG("Transport %s Owner %s", transport->path, owner->name);
+       transport->owner = owner;
+       owner->transport = transport;
+       owner->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+                                                       owner->name,
+                                                       media_owner_exit,
+                                                       owner, NULL);
+}
+
+static struct media_owner *media_owner_create(DBusMessage *msg)
+{
+       struct media_owner *owner;
+
+       owner = g_new0(struct media_owner, 1);
+       owner->name = g_strdup(dbus_message_get_sender(msg));
+
+       DBG("Owner created: sender=%s", owner->name);
+
+       return owner;
+}
+
+static void media_owner_add(struct media_owner *owner,
+                                               struct media_request *req)
+{
+       DBG("Owner %s Request %s", owner->name,
+                                       dbus_message_get_member(req->msg));
+
+       owner->pending = req;
+}
+
+static DBusMessage *acquire(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
+{
+       struct media_transport *transport = data;
+       struct media_owner *owner;
+       struct media_request *req;
+       guint id;
+
+       if (transport->owner != NULL)
+               return btd_error_not_authorized(msg);
+
+       if (transport->state >= TRANSPORT_STATE_REQUESTING)
+               return btd_error_not_authorized(msg);
+
+       owner = media_owner_create(msg);
+       id = transport->resume(transport, owner);
+       if (id == 0) {
+               media_owner_free(owner);
+               return btd_error_not_authorized(msg);
+       }
+
+       req = media_request_create(msg, id);
+       media_owner_add(owner, req);
+       media_transport_set_owner(transport, owner);
+
+       return NULL;
+}
+
+static DBusMessage *try_acquire(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct media_transport *transport = data;
+       struct media_owner *owner;
+       struct media_request *req;
+       guint id;
+
+       if (transport->owner != NULL)
+               return btd_error_not_authorized(msg);
+
+       if (transport->state >= TRANSPORT_STATE_REQUESTING)
+               return btd_error_not_authorized(msg);
+
+       if (transport->state != TRANSPORT_STATE_PENDING)
+               return btd_error_not_available(msg);
+
+       owner = media_owner_create(msg);
+       id = transport->resume(transport, owner);
+       if (id == 0) {
+               media_owner_free(owner);
+               return btd_error_not_authorized(msg);
+       }
+
+       req = media_request_create(msg, id);
+       media_owner_add(owner, req);
+       media_transport_set_owner(transport, owner);
+
+       return NULL;
+}
+
+static DBusMessage *release(DBusConnection *conn, DBusMessage *msg,
+                                       void *data)
+{
+       struct media_transport *transport = data;
+       struct media_owner *owner = transport->owner;
+       const char *sender;
+       struct media_request *req;
+       guint id;
+
+       sender = dbus_message_get_sender(msg);
+
+       if (owner == NULL || g_strcmp0(owner->name, sender) != 0)
+               return btd_error_not_authorized(msg);
+
+       if (owner->pending) {
+               const char *member;
+
+               member = dbus_message_get_member(owner->pending->msg);
+               /* Cancel Acquire request if that exist */
+               if (g_str_equal(member, "Acquire"))
+                       media_owner_remove(owner);
+               else
+                       return btd_error_in_progress(msg);
+       }
+
+       transport_set_state(transport, TRANSPORT_STATE_SUSPENDING);
+
+       id = transport->suspend(transport, owner);
+       if (id == 0) {
+               media_transport_remove_owner(transport);
+               return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+       }
+
+       req = media_request_create(msg, id);
+       media_owner_add(owner, req);
+
+       return NULL;
+}
+
+static gboolean get_device(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       const char *path = device_get_path(transport->device);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       return TRUE;
+}
+
+static gboolean get_uuid(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       const char *uuid = media_endpoint_get_uuid(transport->endpoint);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+       return TRUE;
+}
+
+static gboolean get_codec(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       uint8_t codec = media_endpoint_get_codec(transport->endpoint);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BYTE, &codec);
+
+       return TRUE;
+}
+
+static gboolean get_configuration(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       DBusMessageIter array;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_BYTE_AS_STRING, &array);
+
+       dbus_message_iter_append_fixed_array(&array, DBUS_TYPE_BYTE,
+                                               &transport->configuration,
+                                               transport->size);
+
+       dbus_message_iter_close_container(iter, &array);
+
+       return TRUE;
+}
+
+static gboolean get_state(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       const char *state = state2str(transport->state);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &state);
+
+       return TRUE;
+}
+
+static gboolean delay_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_transport *transport = data;
+       struct a2dp_transport *a2dp = transport->data;
+
+       return a2dp->delay != 0;
+}
+
+static gboolean get_delay(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       struct a2dp_transport *a2dp = transport->data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &a2dp->delay);
+
+       return TRUE;
+}
+
+static gboolean volume_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct media_transport *transport = data;
+       struct a2dp_transport *a2dp = transport->data;
+
+       return a2dp->volume <= 127;
+}
+
+static gboolean get_volume(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct media_transport *transport = data;
+       struct a2dp_transport *a2dp = transport->data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &a2dp->volume);
+
+       return TRUE;
+}
+
+static void set_volume(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       struct media_transport *transport = data;
+       struct a2dp_transport *a2dp = transport->data;
+       uint16_t volume;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &volume);
+
+       if (volume > 127) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       if (a2dp->volume != volume)
+               avrcp_set_volume(transport->device, volume);
+
+       a2dp->volume = volume;
+
+       g_dbus_pending_property_success(id);
+}
+
+static const GDBusMethodTable transport_methods[] = {
+       { GDBUS_ASYNC_METHOD("Acquire",
+                       NULL,
+                       GDBUS_ARGS({ "fd", "h" }, { "mtu_r", "q" },
+                                                       { "mtu_w", "q" }),
+                       acquire) },
+       { GDBUS_ASYNC_METHOD("TryAcquire",
+                       NULL,
+                       GDBUS_ARGS({ "fd", "h" }, { "mtu_r", "q" },
+                                                       { "mtu_w", "q" }),
+                       try_acquire) },
+       { GDBUS_ASYNC_METHOD("Release", NULL, NULL, release) },
+       { },
+};
+
+static const GDBusPropertyTable transport_properties[] = {
+       { "Device", "o", get_device },
+       { "UUID", "s", get_uuid },
+       { "Codec", "y", get_codec },
+       { "Configuration", "ay", get_configuration },
+       { "State", "s", get_state },
+       { "Delay", "q", get_delay, NULL, delay_exists },
+       { "Volume", "q", get_volume, set_volume, volume_exists },
+       { }
+};
+
+static void destroy_a2dp(void *data)
+{
+       struct a2dp_transport *a2dp = data;
+
+       if (a2dp->session)
+               avdtp_unref(a2dp->session);
+
+       g_free(a2dp);
+}
+
+static void media_transport_free(void *data)
+{
+       struct media_transport *transport = data;
+
+       transports = g_slist_remove(transports, transport);
+
+       if (transport->owner)
+               media_transport_remove_owner(transport);
+
+       if (transport->destroy != NULL)
+               transport->destroy(transport->data);
+
+       g_free(transport->configuration);
+       g_free(transport->path);
+       g_free(transport);
+}
+
+static void transport_update_playing(struct media_transport *transport,
+                                                       gboolean playing)
+{
+       DBG("%s State=%s Playing=%d", transport->path,
+                                       str_state[transport->state], playing);
+
+       if (playing == FALSE) {
+               if (transport->state == TRANSPORT_STATE_PENDING)
+                       transport_set_state(transport, TRANSPORT_STATE_IDLE);
+               else if (transport->state == TRANSPORT_STATE_ACTIVE) {
+                       /* Remove owner */
+                       if (transport->owner != NULL)
+                               media_transport_remove_owner(transport);
+               }
+       } else if (transport->state == TRANSPORT_STATE_IDLE)
+               transport_set_state(transport, TRANSPORT_STATE_PENDING);
+}
+
+static void sink_state_changed(struct btd_service *service,
+                                               sink_state_t old_state,
+                                               sink_state_t new_state,
+                                               void *user_data)
+{
+       struct media_transport *transport = user_data;
+
+       if (new_state == SINK_STATE_PLAYING)
+               transport_update_playing(transport, TRUE);
+       else
+               transport_update_playing(transport, FALSE);
+}
+
+static void source_state_changed(struct btd_service *service,
+                                               source_state_t old_state,
+                                               source_state_t new_state,
+                                               void *user_data)
+{
+       struct media_transport *transport = user_data;
+
+       if (new_state == SOURCE_STATE_PLAYING)
+               transport_update_playing(transport, TRUE);
+       else
+               transport_update_playing(transport, FALSE);
+}
+
+static int media_transport_init_source(struct media_transport *transport)
+{
+       struct btd_service *service;
+       struct a2dp_transport *a2dp;
+
+       service = btd_device_get_service(transport->device, A2DP_SINK_UUID);
+       if (service == NULL)
+               return -EINVAL;
+
+       a2dp = g_new0(struct a2dp_transport, 1);
+
+       transport->resume = resume_a2dp;
+       transport->suspend = suspend_a2dp;
+       transport->cancel = cancel_a2dp;
+       transport->data = a2dp;
+       transport->destroy = destroy_a2dp;
+
+       a2dp->volume = -1;
+       transport->sink_watch = sink_add_state_cb(service, sink_state_changed,
+                                                               transport);
+
+       return 0;
+}
+
+static int media_transport_init_sink(struct media_transport *transport)
+{
+       struct btd_service *service;
+       struct a2dp_transport *a2dp;
+
+       service = btd_device_get_service(transport->device, A2DP_SOURCE_UUID);
+       if (service == NULL)
+               return -EINVAL;
+
+       a2dp = g_new0(struct a2dp_transport, 1);
+
+       transport->resume = resume_a2dp;
+       transport->suspend = suspend_a2dp;
+       transport->cancel = cancel_a2dp;
+       transport->data = a2dp;
+       transport->destroy = destroy_a2dp;
+
+       a2dp->volume = 127;
+       avrcp_set_volume(transport->device, a2dp->volume);
+       transport->source_watch = source_add_state_cb(service,
+                                                       source_state_changed,
+                                                       transport);
+
+       return 0;
+}
+
+struct media_transport *media_transport_create(struct btd_device *device,
+                                               uint8_t *configuration,
+                                               size_t size, void *data)
+{
+       struct media_endpoint *endpoint = data;
+       struct media_transport *transport;
+       const char *uuid;
+       static int fd = 0;
+
+       transport = g_new0(struct media_transport, 1);
+       transport->device = device;
+       transport->endpoint = endpoint;
+       transport->configuration = g_new(uint8_t, size);
+       memcpy(transport->configuration, configuration, size);
+       transport->size = size;
+       transport->path = g_strdup_printf("%s/fd%d", device_get_path(device),
+                                                                       fd++);
+       transport->fd = -1;
+
+       uuid = media_endpoint_get_uuid(endpoint);
+       if (strcasecmp(uuid, A2DP_SOURCE_UUID) == 0) {
+               if (media_transport_init_source(transport) < 0)
+                       goto fail;
+       } else if (strcasecmp(uuid, A2DP_SINK_UUID) == 0) {
+               if (media_transport_init_sink(transport) < 0)
+                       goto fail;
+       } else
+               goto fail;
+
+       if (g_dbus_register_interface(btd_get_dbus_connection(),
+                               transport->path, MEDIA_TRANSPORT_INTERFACE,
+                               transport_methods, NULL, transport_properties,
+                               transport, media_transport_free) == FALSE) {
+               error("Could not register transport %s", transport->path);
+               goto fail;
+       }
+
+       transports = g_slist_append(transports, transport);
+
+       return transport;
+
+fail:
+       media_transport_free(transport);
+       return NULL;
+}
+
+const char *media_transport_get_path(struct media_transport *transport)
+{
+       return transport->path;
+}
+
+void media_transport_update_delay(struct media_transport *transport,
+                                                       uint16_t delay)
+{
+       struct a2dp_transport *a2dp = transport->data;
+
+       /* Check if delay really changed */
+       if (a2dp->delay == delay)
+               return;
+
+       a2dp->delay = delay;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       transport->path,
+                                       MEDIA_TRANSPORT_INTERFACE, "Delay");
+}
+
+struct btd_device *media_transport_get_dev(struct media_transport *transport)
+{
+       return transport->device;
+}
+
+uint16_t media_transport_get_volume(struct media_transport *transport)
+{
+       struct a2dp_transport *a2dp = transport->data;
+       return a2dp->volume;
+}
+
+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;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       transport->path,
+                                       MEDIA_TRANSPORT_INTERFACE, "Volume");
+}
+
+uint8_t media_transport_get_device_volume(struct btd_device *dev)
+{
+       GSList *l;
+
+       if (dev == NULL)
+               return 128;
+
+       for (l = transports; l; l = l->next) {
+               struct media_transport *transport = l->data;
+               if (transport->device != dev)
+                       continue;
+
+               /* Volume is A2DP only */
+               if (media_endpoint_get_sep(transport->endpoint))
+                       return media_transport_get_volume(transport);
+       }
+
+       return 0;
+}
+
+void media_transport_update_device_volume(struct btd_device *dev,
+                                                               uint8_t volume)
+{
+       GSList *l;
+
+       if (dev == NULL)
+               return;
+
+       for (l = transports; l; l = l->next) {
+               struct media_transport *transport = l->data;
+               if (transport->device != dev)
+                       continue;
+
+               /* Volume is A2DP only */
+               if (media_endpoint_get_sep(transport->endpoint))
+                       media_transport_update_volume(transport, volume);
+       }
+}
similarity index 76%
rename from audio/transport.h
rename to profiles/audio/transport.h
index d20c327..505ad5c 100644 (file)
 
 struct media_transport;
 
-struct media_transport *media_transport_create(DBusConnection *conn,
-                                               struct media_endpoint *endpoint,
-                                               struct audio_device *device,
+struct media_transport *media_transport_create(struct btd_device *device,
                                                uint8_t *configuration,
-                                               size_t size);
+                                               size_t size, void *data);
 
 void media_transport_destroy(struct media_transport *transport);
 const char *media_transport_get_path(struct media_transport *transport);
-struct audio_device *media_transport_get_dev(struct media_transport *transport);
+struct btd_device *media_transport_get_dev(struct media_transport *transport);
+uint16_t media_transport_get_volume(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);
+
+uint8_t media_transport_get_device_volume(struct btd_device *dev);
+void media_transport_update_device_volume(struct btd_device *dev,
+                                                               uint8_t volume);
similarity index 100%
rename from cups/cups.h
rename to profiles/cups/cups.h
similarity index 100%
rename from cups/hcrp.c
rename to profiles/cups/hcrp.c
similarity index 94%
rename from cups/main.c
rename to profiles/cups/main.c
index a884c6e..2079812 100644 (file)
@@ -31,6 +31,7 @@
 #include <unistd.h>
 #include <stdlib.h>
 #include <string.h>
+#include <assert.h>
 #include <signal.h>
 #include <sys/socket.h>
 #include <glib.h>
@@ -39,7 +40,7 @@
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "cups.h"
 
@@ -62,9 +63,9 @@ struct context_data {
 };
 
 static void element_start(GMarkupParseContext *context,
-                               const gchar *element_name,
-                               const gchar **attribute_names,
-                               const gchar **attribute_values,
+                               const char *element_name,
+                               const char **attribute_names,
+                               const char **attribute_values,
                                gpointer user_data, GError **err)
 {
        struct context_data *ctx_data = user_data;
@@ -132,7 +133,7 @@ static char *device_get_ieee1284_id(const char *adapter, const char *device)
 
        /* Look for the service handle of the HCRP service */
        message = dbus_message_new_method_call("org.bluez", device,
-                                               "org.bluez.Device",
+                                               "org.bluez.Device1",
                                                "DiscoverServices");
        dbus_message_iter_init_append(message, &iter);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &hcr_print);
@@ -308,7 +309,7 @@ static gboolean device_is_printer(const char *adapter, const char *device_path,
        gboolean retval;
 
        message = dbus_message_new_method_call("org.bluez", device_path,
-                                                       "org.bluez.Device",
+                                                       "org.bluez.Device1",
                                                        "GetProperties");
 
        reply = dbus_connection_send_with_reply_and_block(conn,
@@ -338,29 +339,10 @@ static void remote_device_found(const char *adapter, const char *bdaddr,
 
        adapter_reply = NULL;
 
-       if (adapter == NULL) {
-               message = dbus_message_new_method_call("org.bluez", "/",
-                                                       "org.bluez.Manager",
-                                                       "DefaultAdapter");
-
-               adapter_reply = dbus_connection_send_with_reply_and_block(conn,
-                                                       message, -1, NULL);
-
-               dbus_message_unref(message);
-
-               if (!adapter_reply)
-                       return;
-
-               if (dbus_message_get_args(adapter_reply, NULL,
-                                       DBUS_TYPE_OBJECT_PATH, &adapter,
-                                       DBUS_TYPE_INVALID) == FALSE) {
-                       dbus_message_unref(adapter_reply);
-                       return;
-               }
-       }
+       assert(adapter != NULL);
 
        message = dbus_message_new_method_call("org.bluez", adapter,
-                                                       "org.bluez.Adapter",
+                                                       "org.bluez.Adapter1",
                                                        "FindDevice");
        dbus_message_iter_init_append(message, &iter);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
@@ -375,7 +357,7 @@ static void remote_device_found(const char *adapter, const char *bdaddr,
 
        if (!reply) {
                message = dbus_message_new_method_call("org.bluez", adapter,
-                                                       "org.bluez.Adapter",
+                                                       "org.bluez.Adapter1",
                                                        "CreateDevice");
                dbus_message_iter_init_append(message, &iter);
                dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
@@ -435,7 +417,7 @@ static gboolean list_known_printers(const char *adapter)
        DBusMessage *message, *reply;
 
        message = dbus_message_new_method_call("org.bluez", adapter,
-                                               "org.bluez.Adapter",
+                                               "org.bluez.Adapter1",
                                                "ListDevices");
        if (message == NULL)
                return FALSE;
@@ -446,8 +428,10 @@ static gboolean list_known_printers(const char *adapter)
 
        dbus_message_unref(message);
 
-       if (dbus_error_is_set(&error))
+       if (dbus_error_is_set(&error)) {
+               dbus_error_free(&error);
                return FALSE;
+       }
 
        dbus_message_iter_init(reply, &reply_iter);
        if (dbus_message_iter_get_arg_type(&reply_iter) != DBUS_TYPE_ARRAY) {
@@ -483,7 +467,7 @@ static gboolean list_known_printers(const char *adapter)
 static DBusHandlerResult filter_func(DBusConnection *connection,
                                        DBusMessage *message, void *user_data)
 {
-       if (dbus_message_is_signal(message, "org.bluez.Adapter",
+       if (dbus_message_is_signal(message, "org.bluez.Adapter1",
                                                "DeviceFound")) {
                const char *adapter, *bdaddr;
                char *name;
@@ -497,7 +481,7 @@ static DBusHandlerResult filter_func(DBusConnection *connection,
                if (parse_device_properties(&iter, &name, NULL))
                        remote_device_found(adapter, bdaddr, name);
                g_free (name);
-       } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+       } else if (dbus_message_is_signal(message, "org.bluez.Adapter1",
                                                "DeviceDisappeared")) {
                const char *bdaddr;
 
@@ -505,7 +489,7 @@ static DBusHandlerResult filter_func(DBusConnection *connection,
                                        DBUS_TYPE_STRING, &bdaddr,
                                        DBUS_TYPE_INVALID);
                remote_device_disappeared(bdaddr);
-       } else if (dbus_message_is_signal(message, "org.bluez.Adapter",
+       } else if (dbus_message_is_signal(message, "org.bluez.Adapter1",
                                                "PropertyChanged")) {
                DBusMessageIter iter, value_iter;
                const char *name;
@@ -549,8 +533,10 @@ static gboolean list_printers(void)
 
        dbus_error_init(&error);
        hcid_exists = dbus_bus_name_has_owner(conn, "org.bluez", &error);
-       if (dbus_error_is_set(&error))
+       if (dbus_error_is_set(&error)) {
+               dbus_error_free(&error);
                return TRUE;
+       }
 
        if (!hcid_exists)
                return TRUE;
@@ -570,6 +556,7 @@ static gboolean list_printers(void)
        dbus_message_unref(message);
 
        if (dbus_error_is_set(&error)) {
+               dbus_error_free(&error);
                dbus_connection_unref(conn);
                /* No adapter */
                return TRUE;
@@ -595,7 +582,7 @@ static gboolean list_printers(void)
 
 #define MATCH_FORMAT                           \
        "type='signal',"                        \
-       "interface='org.bluez.Adapter',"        \
+       "interface='org.bluez.Adapter1',"       \
        "sender='org.bluez',"                   \
        "path='%s'"
 
@@ -608,7 +595,7 @@ static gboolean list_printers(void)
 
        doing_disco = TRUE;
        message = dbus_message_new_method_call("org.bluez", adapter,
-                                       "org.bluez.Adapter",
+                                       "org.bluez.Adapter1",
                                        "StartDiscovery");
 
        if (!dbus_connection_send_with_reply(conn, message, NULL, -1)) {
@@ -662,7 +649,7 @@ static gboolean print_ieee1284(const char *bdaddr)
        }
 
        message = dbus_message_new_method_call("org.bluez", adapter,
-                       "org.bluez.Adapter",
+                       "org.bluez.Adapter1",
                        "FindDevice");
        dbus_message_iter_init_append(message, &iter);
        dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &bdaddr);
@@ -677,7 +664,7 @@ static gboolean print_ieee1284(const char *bdaddr)
 
        if (!reply) {
                message = dbus_message_new_method_call("org.bluez", adapter,
-                               "org.bluez.Adapter",
+                               "org.bluez.Adapter1",
                                "CreateDevice");
                dbus_message_iter_init_append(message, &iter);
                dbus_message_iter_append_basic(&iter,
similarity index 100%
rename from cups/sdp.c
rename to profiles/cups/sdp.c
similarity index 100%
rename from cups/spp.c
rename to profiles/cups/spp.c
diff --git a/profiles/cyclingspeed/cyclingspeed.c b/profiles/cyclingspeed/cyclingspeed.c
new file mode 100644 (file)
index 0000000..6ecc985
--- /dev/null
@@ -0,0 +1,1281 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "dbus-common.h"
+#include "error.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attio.h"
+#include "log.h"
+
+/* min length for ATT indication or notification: opcode (1b) + handle (2b) */
+#define ATT_HDR_LEN 3
+
+#define ATT_TIMEOUT 30
+
+#define CYCLINGSPEED_INTERFACE         "org.bluez.CyclingSpeed1"
+#define CYCLINGSPEED_MANAGER_INTERFACE "org.bluez.CyclingSpeedManager1"
+#define CYCLINGSPEED_WATCHER_INTERFACE "org.bluez.CyclingSpeedWatcher1"
+
+#define WHEEL_REV_SUPPORT              0x01
+#define CRANK_REV_SUPPORT              0x02
+#define MULTI_SENSOR_LOC_SUPPORT       0x04
+
+#define WHEEL_REV_PRESENT      0x01
+#define CRANK_REV_PRESENT      0x02
+
+#define SET_CUMULATIVE_VALUE           0x01
+#define START_SENSOR_CALIBRATION       0x02
+#define UPDATE_SENSOR_LOC              0x03
+#define REQUEST_SUPPORTED_SENSOR_LOC   0x04
+#define RESPONSE_CODE                  0x10
+
+#define RSP_SUCCESS            0x01
+#define RSP_NOT_SUPPORTED      0x02
+#define RSP_INVALID_PARAM      0x03
+#define RSP_FAILED             0x04
+
+struct csc;
+
+struct controlpoint_req {
+       struct csc              *csc;
+       uint8_t                 opcode;
+       guint                   timeout;
+       GDBusPendingReply       reply_id;
+       DBusMessage             *msg;
+
+       uint8_t                 pending_location;
+};
+
+struct csc_adapter {
+       struct btd_adapter      *adapter;
+       GSList                  *devices;       /* list of registered devices */
+       GSList                  *watchers;
+};
+
+struct csc {
+       struct btd_device       *dev;
+       struct csc_adapter      *cadapter;
+
+       GAttrib                 *attrib;
+       guint                   attioid;
+       /* attio id for measurement characteristics value notifications */
+       guint                   attio_measurement_id;
+       /* attio id for SC Control Point characteristics value indications */
+       guint                   attio_controlpoint_id;
+
+       struct att_range        *svc_range;
+
+       uint16_t                measurement_ccc_handle;
+       uint16_t                controlpoint_val_handle;
+
+       uint16_t                feature;
+       gboolean                has_location;
+       uint8_t                 location;
+       uint8_t                 num_locations;
+       uint8_t                 *locations;
+
+       struct controlpoint_req *pending_req;
+};
+
+struct watcher {
+       struct csc_adapter      *cadapter;
+       guint                   id;
+       char                    *srv;
+       char                    *path;
+};
+
+struct measurement {
+       struct csc      *csc;
+
+       bool            has_wheel_rev;
+       uint32_t        wheel_rev;
+       uint16_t        last_wheel_time;
+
+       bool            has_crank_rev;
+       uint16_t        crank_rev;
+       uint16_t        last_crank_time;
+};
+
+struct characteristic {
+       struct csc      *csc;
+       char            uuid[MAX_LEN_UUID_STR + 1];
+};
+
+static GSList *csc_adapters = NULL;
+
+static const char * const location_enum[] = {
+       "other", "top-of-shoe", "in-shoe", "hip", "front-wheel", "left-crank",
+       "right-crank", "left-pedal", "right-pedal", "front-hub",
+       "rear-dropout", "chainstay", "rear-wheel", "rear-hub"
+};
+
+static const char *location2str(uint8_t value)
+{
+       if (value < G_N_ELEMENTS(location_enum))
+               return location_enum[value];
+
+       info("Body Sensor Location [%d] is RFU", value);
+
+       return location_enum[0];
+}
+
+static int str2location(const char *location)
+{
+       size_t i;
+
+       for (i = 0; i < G_N_ELEMENTS(location_enum); i++)
+               if (!strcmp(location_enum[i], location))
+                       return i;
+
+       return -1;
+}
+
+static int cmp_adapter(gconstpointer a, gconstpointer b)
+{
+       const struct csc_adapter *cadapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (adapter == cadapter->adapter)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct csc *csc = a;
+       const struct btd_device *dev = b;
+
+       if (dev == csc->dev)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_watcher(gconstpointer a, gconstpointer b)
+{
+       const struct watcher *watcher = a;
+       const struct watcher *match = b;
+       int ret;
+
+       ret = g_strcmp0(watcher->srv, match->srv);
+       if (ret != 0)
+               return ret;
+
+       return g_strcmp0(watcher->path, match->path);
+}
+
+static struct csc_adapter *find_csc_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(csc_adapters, adapter, cmp_adapter);
+
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       g_free(watcher->path);
+       g_free(watcher->srv);
+       g_free(watcher);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+                                                       const char *path)
+{
+       struct watcher *match;
+       GSList *l;
+
+       match = g_new0(struct watcher, 1);
+       match->srv = g_strdup(sender);
+       match->path = g_strdup(path);
+
+       l = g_slist_find_custom(list, match, cmp_watcher);
+       destroy_watcher(match);
+
+       if (l != NULL)
+               return l->data;
+
+       return NULL;
+}
+
+static void remove_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+}
+
+static void destroy_csc_adapter(gpointer user_data)
+{
+       struct csc_adapter *cadapter = user_data;
+
+       g_slist_free_full(cadapter->watchers, remove_watcher);
+
+       g_free(cadapter);
+}
+
+static void destroy_csc(gpointer user_data)
+{
+       struct csc *csc = user_data;
+
+       if (csc->attioid > 0)
+               btd_device_remove_attio_callback(csc->dev, csc->attioid);
+
+       if (csc->attrib != NULL) {
+               g_attrib_unregister(csc->attrib, csc->attio_measurement_id);
+               g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id);
+               g_attrib_unref(csc->attrib);
+       }
+
+       btd_device_unref(csc->dev);
+       g_free(csc->svc_range);
+       g_free(csc->locations);
+       g_free(csc);
+}
+
+static void char_write_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 gboolean controlpoint_timeout(gpointer user_data)
+{
+       struct controlpoint_req *req = user_data;
+
+       if (req->opcode == UPDATE_SENSOR_LOC) {
+               g_dbus_pending_property_error(req->reply_id,
+                                               ERROR_INTERFACE ".Failed",
+                                               "Operation failed (timeout)");
+       } else if (req->opcode == SET_CUMULATIVE_VALUE) {
+               DBusMessage *reply;
+
+               reply = btd_error_failed(req->msg,
+                                               "Operation failed (timeout)");
+
+               g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+               dbus_message_unref(req->msg);
+       }
+
+       req->csc->pending_req = NULL;
+       g_free(req);
+
+       return FALSE;
+}
+
+static void controlpoint_write_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct controlpoint_req *req = user_data;
+
+       if (status == 0) {
+               req->timeout = g_timeout_add_seconds(ATT_TIMEOUT,
+                                                       controlpoint_timeout,
+                                                       req);
+               return;
+       }
+
+       error("SC Control Point write failed (opcode=%d)", req->opcode);
+
+       if (req->opcode == UPDATE_SENSOR_LOC) {
+               g_dbus_pending_property_error(req->reply_id,
+                                       ERROR_INTERFACE ".Failed",
+                                       "Operation failed (%d)", status);
+       } else if  (req->opcode == SET_CUMULATIVE_VALUE) {
+               DBusMessage *reply;
+
+               reply = btd_error_failed(req->msg, "Operation failed");
+
+               g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+               dbus_message_unref(req->msg);
+       }
+
+       req->csc->pending_req = NULL;
+       g_free(req);
+}
+
+static void read_supported_locations(struct csc *csc)
+{
+       struct controlpoint_req *req;
+
+       req = g_new0(struct controlpoint_req, 1);
+       req->csc = csc;
+       req->opcode = REQUEST_SUPPORTED_SENSOR_LOC;
+
+       csc->pending_req = req;
+
+       gatt_write_char(csc->attrib, csc->controlpoint_val_handle,
+                                       &req->opcode, sizeof(req->opcode),
+                                       controlpoint_write_cb, req);
+}
+
+static void read_feature_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct csc *csc = user_data;
+       uint8_t value[2];
+       ssize_t vlen;
+
+       if (status) {
+               error("CSC Feature read failed: %s", att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, value, sizeof(value));
+       if (vlen < 0) {
+               error("Protocol error");
+               return;
+       }
+
+       if (vlen != sizeof(value)) {
+               error("Invalid value length for CSC Feature");
+               return;
+       }
+
+       csc->feature = att_get_u16(value);
+
+       if ((csc->feature & MULTI_SENSOR_LOC_SUPPORT)
+                                               && (csc->locations == NULL))
+               read_supported_locations(csc);
+}
+
+static void read_location_cb(guint8 status, const guint8 *pdu,
+                                               guint16 len, gpointer user_data)
+{
+       struct csc *csc = user_data;
+       uint8_t value;
+       ssize_t vlen;
+
+       if (status) {
+               error("Sensor Location read failed: %s", att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+       if (vlen < 0) {
+               error("Protocol error");
+               return;
+       }
+
+       if (vlen != sizeof(value)) {
+               error("Invalid value length for Sensor Location");
+               return;
+       }
+
+       csc->has_location = TRUE;
+       csc->location = value;
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       device_get_path(csc->dev),
+                                       CYCLINGSPEED_INTERFACE, "Location");
+}
+
+static void discover_desc_cb(guint8 status, const guint8 *pdu,
+                                       guint16 len, gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       struct att_data_list *list = NULL;
+       uint8_t format;
+       int i;
+
+       if (status != 0) {
+               error("Discover %s descriptors failed: %s", ch->uuid,
+                                                       att_ecode2str(status));
+               goto done;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               goto done;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       for (i = 0; i < list->num; i++) {
+               uint8_t *value;
+               uint16_t handle, uuid;
+               uint8_t attr_val[2];
+               char *msg;
+
+               value = list->data[i];
+               handle = att_get_u16(value);
+               uuid = att_get_u16(value + 2);
+
+               if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
+                       continue;
+
+               if (g_strcmp0(ch->uuid, CSC_MEASUREMENT_UUID) == 0) {
+                       ch->csc->measurement_ccc_handle = handle;
+
+                       if (g_slist_length(ch->csc->cadapter->watchers) == 0) {
+                               att_put_u16(0x0000, attr_val);
+                               msg = g_strdup("Disable measurement");
+                       } else {
+                               att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT,
+                                                               attr_val);
+                               msg = g_strdup("Enable measurement");
+                       }
+
+               } else if (g_strcmp0(ch->uuid, SC_CONTROL_POINT_UUID) == 0) {
+                       att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, attr_val);
+                       msg = g_strdup("Enable SC Control Point indications");
+               } else {
+                       break;
+               }
+
+               gatt_write_char(ch->csc->attrib, handle, attr_val,
+                                       sizeof(attr_val), char_write_cb, msg);
+
+               /* We only want CCC, can break here */
+               break;
+       }
+
+done:
+       if (list)
+               att_data_list_free(list);
+       g_free(ch);
+}
+
+static void discover_desc(struct csc *csc, struct gatt_char *c,
+                                               struct gatt_char *c_next)
+{
+       struct characteristic *ch;
+       uint16_t start, end;
+
+       start = c->value_handle + 1;
+
+       if (c_next != NULL) {
+               if (start == c_next->handle)
+                       return;
+               end = c_next->handle - 1;
+       } else if (c->value_handle != csc->svc_range->end) {
+               end = csc->svc_range->end;
+       } else {
+               return;
+       }
+
+       ch = g_new0(struct characteristic, 1);
+       ch->csc = csc;
+       memcpy(ch->uuid, c->uuid, sizeof(c->uuid));
+
+       gatt_discover_char_desc(csc->attrib, start, end, discover_desc_cb, ch);
+}
+
+static void update_watcher(gpointer data, gpointer user_data)
+{
+       struct watcher *w = data;
+       struct measurement *m = user_data;
+       struct csc *csc = m->csc;
+       const char *path = device_get_path(csc->dev);
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(w->srv, w->path,
+                       CYCLINGSPEED_WATCHER_INTERFACE, "MeasurementReceived");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       if (m->has_wheel_rev) {
+               dict_append_entry(&dict, "WheelRevolutions",
+                                       DBUS_TYPE_UINT32, &m->wheel_rev);
+               dict_append_entry(&dict, "LastWheelEventTime",
+                                       DBUS_TYPE_UINT16, &m->last_wheel_time);
+       }
+
+       if (m->has_crank_rev) {
+               dict_append_entry(&dict, "CrankRevolutions",
+                                       DBUS_TYPE_UINT16, &m->crank_rev);
+               dict_append_entry(&dict, "LastCrankEventTime",
+                                       DBUS_TYPE_UINT16, &m->last_crank_time);
+       }
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void process_measurement(struct csc *csc, const uint8_t *pdu,
+                                                               uint16_t len)
+{
+       struct measurement m;
+       uint8_t flags;
+
+       flags = *pdu;
+
+       pdu++;
+       len--;
+
+       memset(&m, 0, sizeof(m));
+
+       if ((flags & WHEEL_REV_PRESENT) && (csc->feature & WHEEL_REV_SUPPORT)) {
+               if (len < 6) {
+                       error("Wheel revolutions data fields missing");
+                       return;
+               }
+
+               m.has_wheel_rev = true;
+               m.wheel_rev = att_get_u32(pdu);
+               m.last_wheel_time = att_get_u16(pdu + 4);
+               pdu += 6;
+               len -= 6;
+       }
+
+       if ((flags & CRANK_REV_PRESENT) && (csc->feature & CRANK_REV_SUPPORT)) {
+               if (len < 4) {
+                       error("Crank revolutions data fields missing");
+                       return;
+               }
+
+               m.has_crank_rev = true;
+               m.crank_rev = att_get_u16(pdu);
+               m.last_crank_time = att_get_u16(pdu + 2);
+               pdu += 4;
+               len -= 4;
+       }
+
+       /* Notify all registered watchers */
+       m.csc = csc;
+       g_slist_foreach(csc->cadapter->watchers, update_watcher, &m);
+}
+
+static void measurement_notify_handler(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct csc *csc = user_data;
+
+       /* should be at least opcode (1b) + handle (2b) */
+       if (len < 3) {
+               error("Invalid PDU received");
+               return;
+       }
+
+       process_measurement(csc, pdu + 3, len - 3);
+}
+
+static void controlpoint_property_reply(struct controlpoint_req *req,
+                                                               uint8_t code)
+{
+       switch (code) {
+       case RSP_SUCCESS:
+               g_dbus_pending_property_success(req->reply_id);
+               break;
+
+       case RSP_NOT_SUPPORTED:
+               g_dbus_pending_property_error(req->reply_id,
+                                       ERROR_INTERFACE ".NotSupported",
+                                       "Feature is not supported");
+               break;
+
+       case RSP_INVALID_PARAM:
+               g_dbus_pending_property_error(req->reply_id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               break;
+
+       case RSP_FAILED:
+               g_dbus_pending_property_error(req->reply_id,
+                                       ERROR_INTERFACE ".Failed",
+                                       "Operation failed");
+               break;
+
+       default:
+               g_dbus_pending_property_error(req->reply_id,
+                                       ERROR_INTERFACE ".Failed",
+                                       "Operation failed (%d)", code);
+               break;
+       }
+}
+
+static void controlpoint_method_reply(struct controlpoint_req *req,
+                                                               uint8_t code)
+{
+       DBusMessage *reply;
+
+       switch (code) {
+       case RSP_SUCCESS:
+               reply = dbus_message_new_method_return(req->msg);
+               break;
+       case RSP_NOT_SUPPORTED:
+               reply = btd_error_not_supported(req->msg);
+               break;
+       case RSP_INVALID_PARAM:
+               reply = btd_error_invalid_args(req->msg);
+               break;
+       case RSP_FAILED:
+               reply = btd_error_failed(req->msg, "Failed");
+               break;
+       default:
+               reply = btd_error_failed(req->msg, "Unknown error");
+               break;
+       }
+
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
+
+       dbus_message_unref(req->msg);
+}
+
+static void controlpoint_ind_handler(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct csc *csc = user_data;
+       struct controlpoint_req *req = csc->pending_req;
+       uint8_t opcode;
+       uint8_t req_opcode;
+       uint8_t rsp_code;
+       uint8_t *opdu;
+       uint16_t olen;
+       size_t plen;
+
+       if (len < ATT_HDR_LEN) {
+               error("Invalid PDU received");
+               return;
+       }
+
+       /* skip ATT header */
+       pdu += ATT_HDR_LEN;
+       len -= ATT_HDR_LEN;
+
+       if (len < 1) {
+               error("Op Code missing");
+               goto done;
+       }
+
+       opcode = *pdu;
+       pdu++;
+       len--;
+
+       if (opcode != RESPONSE_CODE) {
+               DBG("Unsupported Op Code received (%d)", opcode);
+               goto done;
+       }
+
+       if (len < 2) {
+               error("Invalid Response Code PDU received");
+               goto done;
+       }
+
+       req_opcode = *pdu;
+       rsp_code = *(pdu + 1);
+       pdu += 2;
+       len -= 2;
+
+       if (req == NULL || req->opcode != req_opcode) {
+               DBG("Indication received without pending request");
+               goto done;
+       }
+
+       switch (req->opcode) {
+       case SET_CUMULATIVE_VALUE:
+               controlpoint_method_reply(req, rsp_code);
+               break;
+
+       case REQUEST_SUPPORTED_SENSOR_LOC:
+               if (rsp_code == RSP_SUCCESS) {
+                       csc->num_locations = len;
+                       csc->locations = g_memdup(pdu, len);
+               } else {
+                       error("Failed to read Supported Sendor Locations");
+               }
+               break;
+
+       case UPDATE_SENSOR_LOC:
+               csc->location = req->pending_location;
+
+               controlpoint_property_reply(req, rsp_code);
+
+               g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       device_get_path(csc->dev),
+                                       CYCLINGSPEED_INTERFACE, "Location");
+               break;
+       }
+
+       csc->pending_req = NULL;
+       g_source_remove(req->timeout);
+       g_free(req);
+
+done:
+       opdu = g_attrib_get_buffer(csc->attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
+       if (olen > 0)
+               g_attrib_send(csc->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
+
+static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+       struct csc *csc = user_data;
+       uint16_t feature_val_handle = 0;
+
+       if (status) {
+               error("Discover CSCS characteristics: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       for (; chars; chars = chars->next) {
+               struct gatt_char *c = chars->data;
+               struct gatt_char *c_next =
+                               (chars->next ? chars->next->data : NULL);
+
+               if (g_strcmp0(c->uuid, CSC_MEASUREMENT_UUID) == 0) {
+                       csc->attio_measurement_id =
+                               g_attrib_register(csc->attrib,
+                                       ATT_OP_HANDLE_NOTIFY, c->value_handle,
+                                       measurement_notify_handler, csc, NULL);
+
+                       discover_desc(csc, c, c_next);
+               } else if (g_strcmp0(c->uuid, CSC_FEATURE_UUID) == 0) {
+                       feature_val_handle = c->value_handle;
+               } else if (g_strcmp0(c->uuid, SENSOR_LOCATION_UUID) == 0) {
+                       DBG("Sensor Location supported");
+                       gatt_read_char(csc->attrib, c->value_handle,
+                                                       read_location_cb, csc);
+               } else if (g_strcmp0(c->uuid, SC_CONTROL_POINT_UUID) == 0) {
+                       DBG("SC Control Point supported");
+                       csc->controlpoint_val_handle = c->value_handle;
+
+                       csc->attio_controlpoint_id = g_attrib_register(
+                                       csc->attrib, ATT_OP_HANDLE_IND,
+                                       c->value_handle,
+                                       controlpoint_ind_handler, csc, NULL);
+
+                       discover_desc(csc, c, c_next);
+               }
+       }
+
+       if (feature_val_handle > 0)
+               gatt_read_char(csc->attrib, feature_val_handle,
+                                                       read_feature_cb, csc);
+}
+
+static void enable_measurement(gpointer data, gpointer user_data)
+{
+       struct csc *csc = data;
+       uint16_t handle = csc->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (csc->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+       msg = g_strdup("Enable measurement");
+
+       gatt_write_char(csc->attrib, handle, value, sizeof(value),
+                                                       char_write_cb, msg);
+}
+
+static void disable_measurement(gpointer data, gpointer user_data)
+{
+       struct csc *csc = data;
+       uint16_t handle = csc->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (csc->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(0x0000, value);
+       msg = g_strdup("Disable measurement");
+
+       gatt_write_char(csc->attrib, handle, value, sizeof(value),
+                                                       char_write_cb, msg);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct csc *csc = user_data;
+
+       DBG("");
+
+       csc->attrib = g_attrib_ref(attrib);
+
+       gatt_discover_char(csc->attrib, csc->svc_range->start,
+                                               csc->svc_range->end, NULL,
+                                               discover_char_cb, csc);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct csc *csc = user_data;
+
+       DBG("");
+
+       if (csc->attio_measurement_id > 0) {
+               g_attrib_unregister(csc->attrib, csc->attio_measurement_id);
+               csc->attio_measurement_id = 0;
+       }
+
+       if (csc->attio_controlpoint_id > 0) {
+               g_attrib_unregister(csc->attrib, csc->attio_controlpoint_id);
+               csc->attio_controlpoint_id = 0;
+       }
+
+       g_attrib_unref(csc->attrib);
+       csc->attrib = NULL;
+}
+
+static void watcher_exit_cb(DBusConnection *conn, void *user_data)
+{
+       struct watcher *watcher = user_data;
+       struct csc_adapter *cadapter = watcher->cadapter;
+
+       DBG("cycling watcher [%s] disconnected", watcher->path);
+
+       cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
+       g_dbus_remove_watch(conn, watcher->id);
+
+       if (g_slist_length(cadapter->watchers) == 0)
+               g_slist_foreach(cadapter->devices, disable_measurement, 0);
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct csc_adapter *cadapter = data;
+       struct watcher *watcher;
+       const char *sender = dbus_message_get_sender(msg);
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(cadapter->watchers, sender, path);
+       if (watcher != NULL)
+               return btd_error_already_exists(msg);
+
+       watcher = g_new0(struct watcher, 1);
+       watcher->cadapter = cadapter;
+       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb,
+                                               watcher, destroy_watcher);
+       watcher->srv = g_strdup(sender);
+       watcher->path = g_strdup(path);
+
+       if (g_slist_length(cadapter->watchers) == 0)
+               g_slist_foreach(cadapter->devices, enable_measurement, 0);
+
+       cadapter->watchers = g_slist_prepend(cadapter->watchers, watcher);
+
+       DBG("cycling watcher [%s] registered", path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct csc_adapter *cadapter = data;
+       struct watcher *watcher;
+       const char *sender = dbus_message_get_sender(msg);
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(cadapter->watchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       cadapter->watchers = g_slist_remove(cadapter->watchers, watcher);
+       g_dbus_remove_watch(conn, watcher->id);
+
+       if (g_slist_length(cadapter->watchers) == 0)
+               g_slist_foreach(cadapter->devices, disable_measurement, 0);
+
+       DBG("cycling watcher [%s] unregistered", path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable cyclingspeed_manager_methods[] = {
+       { GDBUS_METHOD("RegisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       register_watcher) },
+       { GDBUS_METHOD("UnregisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       unregister_watcher) },
+       { }
+};
+
+static int csc_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       struct csc_adapter *cadapter;
+
+       cadapter = g_new0(struct csc_adapter, 1);
+       cadapter->adapter = adapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               CYCLINGSPEED_MANAGER_INTERFACE,
+                                               cyclingspeed_manager_methods,
+                                               NULL, NULL, cadapter,
+                                               destroy_csc_adapter)) {
+               error("D-Bus failed to register %s interface",
+                                               CYCLINGSPEED_MANAGER_INTERFACE);
+               destroy_csc_adapter(cadapter);
+               return -EIO;
+       }
+
+       csc_adapters = g_slist_prepend(csc_adapters, cadapter);
+
+       return 0;
+}
+
+static void csc_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct csc_adapter *cadapter;
+
+       cadapter = find_csc_adapter(adapter);
+       if (cadapter == NULL)
+               return;
+
+       csc_adapters = g_slist_remove(csc_adapters, cadapter);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(cadapter->adapter),
+                                       CYCLINGSPEED_MANAGER_INTERFACE);
+}
+
+static gboolean property_get_location(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct csc *csc = data;
+       const char *loc;
+
+       if (!csc->has_location)
+               return FALSE;
+
+       loc = location2str(csc->location);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &loc);
+
+       return TRUE;
+}
+
+static void property_set_location(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter,
+                                       GDBusPendingPropertySet id, void *data)
+{
+       struct csc *csc = data;
+       char *loc;
+       int loc_val;
+       uint8_t att_val[2];
+       struct controlpoint_req *req;
+
+       if (csc->pending_req != NULL) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InProgress",
+                                       "Operation already in progress");
+               return;
+       }
+
+       if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT)) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".NotSupported",
+                                       "Feature is not supported");
+               return;
+       }
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &loc);
+
+       loc_val = str2location(loc);
+
+       if (loc_val < 0) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       req = g_new(struct controlpoint_req, 1);
+       req->csc = csc;
+       req->reply_id = id;
+       req->opcode = UPDATE_SENSOR_LOC;
+       req->pending_location = loc_val;
+
+       csc->pending_req = req;
+
+       att_val[0] = UPDATE_SENSOR_LOC;
+       att_val[1] = loc_val;
+
+       gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val,
+                               sizeof(att_val), controlpoint_write_cb, req);
+}
+
+static gboolean property_exists_location(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct csc *csc = data;
+
+       return csc->has_location;
+}
+
+static gboolean property_get_locations(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct csc *csc = data;
+       DBusMessageIter entry;
+       int i;
+
+       if (!(csc->feature & MULTI_SENSOR_LOC_SUPPORT))
+               return FALSE;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
+       for (i = 0; i < csc->num_locations; i++) {
+               char *loc = g_strdup(location2str(csc->locations[i]));
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &loc);
+               g_free(loc);
+       }
+
+       dbus_message_iter_close_container(iter, &entry);
+
+       return TRUE;
+}
+
+static gboolean property_exists_locations(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct csc *csc = data;
+
+       return !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT);
+}
+
+static gboolean property_get_wheel_rev_sup(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct csc *csc = data;
+       dbus_bool_t val;
+
+       val = !!(csc->feature & WHEEL_REV_SUPPORT);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+       return TRUE;
+}
+
+static gboolean property_get_multi_loc_sup(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct csc *csc = data;
+       dbus_bool_t val;
+
+       val = !!(csc->feature & MULTI_SENSOR_LOC_SUPPORT);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable cyclingspeed_device_properties[] = {
+       { "Location", "s", property_get_location, property_set_location,
+                                               property_exists_location },
+       { "SupportedLocations", "as", property_get_locations, NULL,
+                                               property_exists_locations },
+       { "WheelRevolutionDataSupported", "b", property_get_wheel_rev_sup },
+       { "MultipleLocationsSupported", "b", property_get_multi_loc_sup },
+       { }
+};
+
+static DBusMessage *set_cumulative_wheel_rev(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct csc *csc = data;
+       dbus_uint32_t value;
+       struct controlpoint_req *req;
+       uint8_t att_val[5]; /* uint8 opcode + uint32 value */
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &value,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       if (csc->pending_req != NULL)
+               return btd_error_in_progress(msg);
+
+       req = g_new(struct controlpoint_req, 1);
+       req->csc = csc;
+       req->opcode = SET_CUMULATIVE_VALUE;
+       req->msg = dbus_message_ref(msg);
+
+       csc->pending_req = req;
+
+       att_val[0] = SET_CUMULATIVE_VALUE;
+       att_put_u32(value, att_val + 1);
+
+       gatt_write_char(csc->attrib, csc->controlpoint_val_handle, att_val,
+               sizeof(att_val), controlpoint_write_cb, req);
+
+       return NULL;
+}
+
+static const GDBusMethodTable cyclingspeed_device_methods[] = {
+       { GDBUS_ASYNC_METHOD("SetCumulativeWheelRevolutions",
+                               GDBUS_ARGS({ "value", "u" }), NULL,
+                                               set_cumulative_wheel_rev) },
+       { }
+};
+
+static int csc_device_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct btd_adapter *adapter;
+       struct csc_adapter *cadapter;
+       struct csc *csc;
+       struct gatt_primary *prim;
+
+       prim = btd_device_get_primary(device, CYCLING_SC_UUID);
+       if (prim == NULL)
+               return -EINVAL;
+
+       adapter = device_get_adapter(device);
+
+       cadapter = find_csc_adapter(adapter);
+       if (cadapter == NULL)
+               return -1;
+
+       csc = g_new0(struct csc, 1);
+       csc->dev = btd_device_ref(device);
+       csc->cadapter = cadapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               device_get_path(device),
+                                               CYCLINGSPEED_INTERFACE,
+                                               cyclingspeed_device_methods,
+                                               NULL,
+                                               cyclingspeed_device_properties,
+                                               csc, destroy_csc)) {
+               error("D-Bus failed to register %s interface",
+                                               CYCLINGSPEED_INTERFACE);
+               destroy_csc(csc);
+               return -EIO;
+       }
+
+       csc->svc_range = g_new0(struct att_range, 1);
+       csc->svc_range->start = prim->range.start;
+       csc->svc_range->end = prim->range.end;
+
+       cadapter->devices = g_slist_prepend(cadapter->devices, csc);
+
+       csc->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+                                               attio_disconnected_cb, csc);
+
+       return 0;
+}
+
+static void csc_device_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct btd_adapter *adapter;
+       struct csc_adapter *cadapter;
+       struct csc *csc;
+       GSList *l;
+
+       adapter = device_get_adapter(device);
+
+       cadapter = find_csc_adapter(adapter);
+       if (cadapter == NULL)
+               return;
+
+       l = g_slist_find_custom(cadapter->devices, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       csc = l->data;
+
+       cadapter->devices = g_slist_remove(cadapter->devices, csc);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               device_get_path(device),
+                                               CYCLINGSPEED_INTERFACE);
+}
+
+static struct btd_profile cscp_profile = {
+       .name           = "Cycling Speed and Cadence GATT Driver",
+       .remote_uuid    = CYCLING_SC_UUID,
+
+       .adapter_probe  = csc_adapter_probe,
+       .adapter_remove = csc_adapter_remove,
+
+       .device_probe   = csc_device_probe,
+       .device_remove  = csc_device_remove,
+};
+
+static int cyclingspeed_init(void)
+{
+       return btd_profile_register(&cscp_profile);
+}
+
+static void cyclingspeed_exit(void)
+{
+       btd_profile_unregister(&cscp_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(cyclingspeed, VERSION,
+                                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       cyclingspeed_init, cyclingspeed_exit)
similarity index 69%
rename from deviceinfo/deviceinfo.c
rename to profiles/deviceinfo/deviceinfo.c
index 8c3af93..8343bb5 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+#include <errno.h>
+
 #include <glib.h>
-#include <bluetooth/uuid.h>
 
+#include "lib/uuid.h"
+#include "plugin.h"
 #include "adapter.h"
 #include "device.h"
-#include "gattrib.h"
+#include "profile.h"
+#include "service.h"
+#include "attrib/gattrib.h"
 #include "attio.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
 #include "log.h"
-#include "deviceinfo.h"
+
+#define PNP_ID_SIZE    7
 
 struct deviceinfo {
        struct btd_device       *dev;           /* Device reference */
@@ -45,16 +51,14 @@ struct deviceinfo {
        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)
+static void deviceinfo_driver_remove(struct btd_service *service)
 {
-       struct deviceinfo *d = user_data;
+       struct deviceinfo *d = btd_service_get_user_data(service);
 
        if (d->attioid > 0)
                btd_device_remove_attio_callback(d->dev, d->attioid);
@@ -69,30 +73,20 @@ static void deviceinfo_free(gpointer user_data)
        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;
+       uint8_t value[PNP_ID_SIZE];
+       ssize_t vlen;
 
        if (status != 0) {
                error("Error reading PNP_ID value: %s", att_ecode2str(status));
                return;
        }
 
-       if (!dec_read_resp(pdu, len, value, &vlen)) {
+       vlen = dec_read_resp(pdu, len, value, sizeof(value));
+       if (vlen < 0) {
                error("Error reading PNP_ID: Protocol error");
                return;
        }
@@ -102,14 +96,14 @@ static void read_pnpid_cb(guint8 status, const guint8 *pdu, guint16 len,
                return;
        }
 
-       device_set_pnpid(ch->d->dev, value[0], att_get_u16(&value[1]),
+       btd_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,
+               gatt_read_char(ch->d->attrib, ch->attr.value_handle,
                                                        read_pnpid_cb, ch);
 }
 
@@ -159,8 +153,10 @@ static void attio_disconnected_cb(gpointer user_data)
        d->attrib = NULL;
 }
 
-int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
+static int deviceinfo_register(struct btd_service *service,
+                                               struct gatt_primary *prim)
 {
+       struct btd_device *device = btd_service_get_device(service);
        struct deviceinfo *d;
 
        d = g_new0(struct deviceinfo, 1);
@@ -169,24 +165,41 @@ int deviceinfo_register(struct btd_device *device, struct gatt_primary *prim)
        d->svc_range->start = prim->range.start;
        d->svc_range->end = prim->range.end;
 
-       servers = g_slist_prepend(servers, d);
+       btd_service_set_user_data(service, 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)
+static int deviceinfo_driver_probe(struct btd_service *service)
 {
-       struct deviceinfo *d;
-       GSList *l;
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *prim;
 
-       l = g_slist_find_custom(servers, device, cmp_device);
-       if (l == NULL)
-               return;
+       prim = btd_device_get_primary(device, DEVICE_INFORMATION_UUID);
+       if (prim == NULL)
+               return -EINVAL;
+
+       return deviceinfo_register(service, prim);
+}
+
+static struct btd_profile deviceinfo_profile = {
+       .name           = "deviceinfo",
+       .remote_uuid    = DEVICE_INFORMATION_UUID,
+       .device_probe   = deviceinfo_driver_probe,
+       .device_remove  = deviceinfo_driver_remove
+};
 
-       d = l->data;
-       servers = g_slist_remove(servers, d);
+static int deviceinfo_init(void)
+{
+       return btd_profile_register(&deviceinfo_profile);
+}
 
-       deviceinfo_free(d);
+static void deviceinfo_exit(void)
+{
+       btd_profile_unregister(&deviceinfo_profile);
 }
+
+BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       deviceinfo_init, deviceinfo_exit)
diff --git a/profiles/gatt/gas.c b/profiles/gatt/gas.c
new file mode 100644 (file)
index 0000000..5d6880f
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+ *
+ *  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 <stdbool.h>
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <btio/btio.h>
+
+#include "lib/uuid.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attio.h"
+#include "attrib/gatt.h"
+#include "log.h"
+#include "textfile.h"
+
+/* Generic Attribute/Access Service */
+struct gas {
+       struct btd_device *device;
+       struct att_range gap;   /* GAP Primary service range */
+       struct att_range gatt;  /* GATT Primary service range */
+       GAttrib *attrib;
+       guint attioid;
+       guint changed_ind;
+       uint16_t changed_handle;
+       uint16_t mtu;
+};
+
+static GSList *devices = NULL;
+
+static void gas_free(struct gas *gas)
+{
+       if (gas->attioid)
+               btd_device_remove_attio_callback(gas->device, gas->attioid);
+
+       g_attrib_unref(gas->attrib);
+       btd_device_unref(gas->device);
+       g_free(gas);
+}
+
+static int cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct gas *gas = a;
+       const struct btd_device *device = b;
+
+       return (gas->device == device ? 0 : -1);
+}
+
+static void write_ctp_handle(struct btd_device *device, uint16_t uuid,
+                                       uint16_t handle)
+{
+       char *filename, group[6], value[7];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
+
+       filename = btd_device_get_storage_path(device, "gatt");
+       if (!filename) {
+               warn("Unable to get gatt storage path for device");
+               return;
+       }
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       snprintf(group, sizeof(group), "%hu", uuid);
+       snprintf(value, sizeof(value), "0x%4.4X", handle);
+       g_key_file_set_string(key_file, group, "Value", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_free(filename);
+       g_key_file_free(key_file);
+}
+
+static int read_ctp_handle(struct btd_device *device, uint16_t uuid,
+                                       uint16_t *value)
+{
+       char *filename, group[6];
+       GKeyFile *key_file;
+       char *str;
+       int err = 0;
+
+       filename = btd_device_get_storage_path(device, "gatt");
+       if (!filename) {
+               warn("Unable to get gatt storage path for device");
+               return -ENOENT;
+       }
+
+       snprintf(group, sizeof(group), "%hu", uuid);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       str = g_key_file_get_string(key_file, group, "Value", NULL);
+       if (str == NULL || sscanf(str, "%hx", value) != 1)
+               err = -ENOENT;
+
+       g_free(str);
+       g_free(filename);
+       g_key_file_free(key_file);
+
+       return err;
+}
+
+static void gap_appearance_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct gas *gas = user_data;
+       struct att_data_list *list =  NULL;
+       uint16_t app;
+       uint8_t *atval;
+
+       if (status != 0) {
+               error("Read characteristics by UUID failed: %s",
+                               att_ecode2str(status));
+               return;
+       }
+
+       list = dec_read_by_type_resp(pdu, plen);
+       if (list == NULL)
+               return;
+
+       if (list->len != 4) {
+               error("GAP Appearance value: invalid data");
+               goto done;
+       }
+
+       atval = list->data[0] + 2; /* skip handle value */
+       app = att_get_u16(atval);
+
+       DBG("GAP Appearance: 0x%04x", app);
+
+       device_set_appearance(gas->device, app);
+
+done:
+       att_data_list_free(list);
+}
+
+static void indication_cb(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+       struct gas *gas = user_data;
+       uint16_t start, end, olen;
+       size_t plen;
+       uint8_t *opdu;
+
+       if (len < 7) { /* 1-byte opcode + 2-byte handle + 4 range */
+               error("Malformed ATT notification");
+               return;
+       }
+
+       start = att_get_u16(&pdu[3]);
+       end = att_get_u16(&pdu[5]);
+
+       DBG("Service Changed start: 0x%04X end: 0x%04X", start, end);
+
+       /* Confirming indication received */
+       opdu = g_attrib_get_buffer(gas->attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
+       g_attrib_send(gas->attrib, 0, opdu, olen, NULL, NULL, NULL);
+
+       if (device_is_bonded(gas->device) == FALSE) {
+               DBG("Ignoring Service Changed: device is not bonded");
+               return;
+       }
+
+       btd_device_gatt_set_service_changed(gas->device, start, end);
+}
+
+static void ccc_written_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct gas *gas = user_data;
+
+       if (status) {
+               error("Write Service Changed CCC failed: %s",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       DBG("Service Changed indications enabled");
+
+       gas->changed_ind = g_attrib_register(gas->attrib, ATT_OP_HANDLE_IND,
+                                               gas->changed_handle,
+                                               indication_cb, gas, NULL);
+
+       write_ctp_handle(gas->device, GATT_CHARAC_SERVICE_CHANGED,
+                                       gas->changed_handle);
+}
+
+static void write_ccc(GAttrib *attrib, uint16_t handle, gpointer user_data)
+{
+       uint8_t value[2];
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, value);
+       gatt_write_char(attrib, handle, value, sizeof(value), ccc_written_cb,
+                                                               user_data);
+}
+
+static void gatt_descriptors_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct gas *gas = user_data;
+       struct att_data_list *list;
+       int i;
+       uint8_t format;
+
+       if (status) {
+               error("Discover all GATT characteristic descriptors: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               return;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       for (i = 0; i < list->num; i++) {
+               uint16_t uuid16, ccc;
+               uint8_t *value;
+
+               value = list->data[i];
+               ccc = att_get_u16(value);
+               uuid16 = att_get_u16(&value[2]);
+               DBG("CCC: 0x%04x UUID: 0x%04x", ccc, uuid16);
+               write_ccc(gas->attrib, ccc, user_data);
+       }
+
+done:
+       att_data_list_free(list);
+}
+
+static void gatt_characteristic_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct gas *gas = user_data;
+       struct gatt_char *chr;
+       uint16_t start, end;
+
+       if (status) {
+               error("Discover Service Changed handle: %s", att_ecode2str(status));
+               return;
+       }
+
+       chr = characteristics->data;
+
+       start = chr->value_handle + 1;
+       end = gas->gatt.end;
+
+       if (start > end) {
+               error("Inconsistent database: Service Changed CCC missing");
+               return;
+       }
+
+       gas->changed_handle = chr->value_handle;
+       gatt_discover_char_desc(gas->attrib, start, end, gatt_descriptors_cb,
+                                                                       gas);
+}
+
+static void exchange_mtu_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct gas *gas = user_data;
+       uint16_t rmtu;
+
+       if (status) {
+               error("MTU exchange: %s", att_ecode2str(status));
+               return;
+       }
+
+       if (!dec_mtu_resp(pdu, plen, &rmtu)) {
+               error("MTU exchange: protocol error");
+               return;
+       }
+
+       gas->mtu = MIN(rmtu, gas->mtu);
+       if (g_attrib_set_mtu(gas->attrib, gas->mtu))
+               DBG("MTU exchange succeeded: %d", gas->mtu);
+       else
+               DBG("MTU exchange failed");
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct gas *gas = user_data;
+       GIOChannel *io;
+       GError *gerr = NULL;
+       uint16_t cid, imtu;
+       uint16_t app;
+
+       gas->attrib = g_attrib_ref(attrib);
+       io = g_attrib_get_channel(attrib);
+
+       if (bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu,
+                               BT_IO_OPT_CID, &cid, BT_IO_OPT_INVALID) &&
+                                                       cid == ATT_CID) {
+               gatt_exchange_mtu(gas->attrib, imtu, exchange_mtu_cb, gas);
+               gas->mtu = imtu;
+               DBG("MTU Exchange: Requesting %d", imtu);
+       }
+
+       if (device_get_appearance(gas->device, &app) < 0) {
+               bt_uuid_t uuid;
+
+               bt_uuid16_create(&uuid, GATT_CHARAC_APPEARANCE);
+
+               gatt_read_char_by_uuid(gas->attrib, gas->gap.start,
+                                               gas->gap.end, &uuid,
+                                               gap_appearance_cb, gas);
+       }
+
+       /* TODO: Read other GAP characteristics - See Core spec page 1739 */
+
+       /*
+        * When re-connecting <<Service Changed>> handle and characteristic
+        * value doesn't need to read again: known information from the
+        * previous interaction.
+        */
+       if (gas->changed_handle == 0) {
+               bt_uuid_t uuid;
+
+               bt_uuid16_create(&uuid, GATT_CHARAC_SERVICE_CHANGED);
+
+               gatt_discover_char(gas->attrib, gas->gatt.start, gas->gatt.end,
+                                       &uuid, gatt_characteristic_cb, gas);
+       }
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct gas *gas = user_data;
+
+       g_attrib_unregister(gas->attrib, gas->changed_ind);
+       gas->changed_ind = 0;
+
+       g_attrib_unref(gas->attrib);
+       gas->attrib = NULL;
+}
+
+static int gas_register(struct btd_device *device, struct att_range *gap,
+                                               struct att_range *gatt)
+{
+       struct gas *gas;
+
+       gas = g_new0(struct gas, 1);
+       gas->gap.start = gap->start;
+       gas->gap.end = gap->end;
+       gas->gatt.start = gatt->start;
+       gas->gatt.end = gatt->end;
+
+       gas->device = btd_device_ref(device);
+
+       devices = g_slist_append(devices, gas);
+
+       gas->attioid = btd_device_add_attio_callback(device,
+                                               attio_connected_cb,
+                                               attio_disconnected_cb, gas);
+
+       read_ctp_handle(gas->device, GATT_CHARAC_SERVICE_CHANGED,
+                                       &gas->changed_handle);
+
+       return 0;
+}
+
+static void gas_unregister(struct btd_device *device)
+{
+       struct gas *gas;
+       GSList *l;
+
+       l = g_slist_find_custom(devices, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       gas = l->data;
+       devices = g_slist_remove(devices, gas);
+       gas_free(gas);
+}
+
+static int gatt_driver_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *gap, *gatt;
+
+       gap = btd_device_get_primary(device, GAP_UUID);
+       gatt = btd_device_get_primary(device, GATT_UUID);
+
+       if (gap == NULL || gatt == NULL) {
+               error("GAP and GATT are mandatory");
+               return -EINVAL;
+       }
+
+       return gas_register(device, &gap->range, &gatt->range);
+}
+
+static void gatt_driver_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       gas_unregister(device);
+}
+
+static struct btd_profile gatt_profile = {
+       .name           = "gap-gatt-profile",
+       .remote_uuid    = GATT_UUID,
+       .device_probe   = gatt_driver_probe,
+       .device_remove  = gatt_driver_remove
+};
+
+static int gatt_init(void)
+{
+       btd_profile_register(&gatt_profile);
+
+       return 0;
+}
+
+static void gatt_exit(void)
+{
+       btd_profile_unregister(&gatt_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(gatt, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       gatt_init, gatt_exit)
similarity index 86%
rename from health/hdp.c
rename to profiles/health/hdp.c
index 2316204..7b4e799 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <stdlib.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <sdpd.h>
 #include <unistd.h>
 
 #include <glib.h>
 
 #include <bluetooth/l2cap.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 #include <dbus-common.h>
 #include <log.h>
 #include <error.h>
 #include <adapter.h>
 #include <device.h>
-#include <btio.h>
+#include <btio/btio.h>
 
 #include "mcap_lib.h"
 #include "hdp_types.h"
@@ -45,8 +50,6 @@
 #define ECHO_TIMEOUT   1 /* second */
 #define HDP_ECHO_LEN   15
 
-static DBusConnection *connection = NULL;
-
 static GSList *applications = NULL;
 static GSList *devices = NULL;
 static uint8_t next_app_id = HDP_MDEP_INITIAL;
@@ -54,12 +57,10 @@ static uint8_t next_app_id = HDP_MDEP_INITIAL;
 static GSList *adapters;
 
 static gboolean update_adapter(struct hdp_adapter *adapter);
-static struct hdp_device *create_health_device(DBusConnection *conn,
-                                               struct btd_device *device);
+static struct hdp_device *create_health_device(struct btd_device *device);
 static void free_echo_data(struct hdp_echo_data *edata);
 
 struct hdp_create_dc {
-       DBusConnection                  *conn;
        DBusMessage                     *msg;
        struct hdp_application          *app;
        struct hdp_device               *dev;
@@ -70,7 +71,6 @@ struct hdp_create_dc {
 };
 
 struct hdp_tmp_dc_data {
-       DBusConnection                  *conn;
        DBusMessage                     *msg;
        struct hdp_channel              *hdp_chann;
        guint                           ref;
@@ -125,7 +125,6 @@ static void hdp_channel_unref(struct hdp_channel *chan)
 static void free_hdp_create_dc(struct hdp_create_dc *dc_data)
 {
        dbus_message_unref(dc_data->msg);
-       dbus_connection_unref(dc_data->conn);
        hdp_application_unref(dc_data->app);
        health_device_unref(dc_data->dev);
 
@@ -156,7 +155,6 @@ static void hdp_create_data_unref(struct hdp_create_dc *dc_data)
 static void free_hdp_conn_dc(struct hdp_tmp_dc_data *data)
 {
        dbus_message_unref(data->msg);
-       dbus_connection_unref(data->conn);
        hdp_channel_unref(data->hdp_chann);
 
        g_free(data);
@@ -213,16 +211,14 @@ static int cmp_device(gconstpointer a, gconstpointer b)
        return -1;
 }
 
-static gint cmp_dev_addr(gconstpointer a, gconstpointer dst)
+static int cmp_dev_addr(gconstpointer a, gconstpointer dst)
 {
        const struct hdp_device *device = a;
-       bdaddr_t addr;
 
-       device_get_address(device->dev, &addr, NULL);
-       return bacmp(&addr, dst);
+       return bacmp(device_get_address(device->dev), dst);
 }
 
-static gint cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
+static int cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
 {
        const struct hdp_device *device = a;
 
@@ -231,7 +227,7 @@ static gint cmp_dev_mcl(gconstpointer a, gconstpointer mcl)
        return -1;
 }
 
-static gint cmp_chan_mdlid(gconstpointer a, gconstpointer b)
+static int cmp_chan_mdlid(gconstpointer a, gconstpointer b)
 {
        const struct hdp_channel *chan = a;
        const uint16_t *mdlid = b;
@@ -239,7 +235,7 @@ static gint cmp_chan_mdlid(gconstpointer a, gconstpointer b)
        return chan->mdlid - *mdlid;
 }
 
-static gint cmp_chan_path(gconstpointer a, gconstpointer b)
+static int cmp_chan_path(gconstpointer a, gconstpointer b)
 {
        const struct hdp_channel *chan = a;
        const char *path = b;
@@ -247,7 +243,7 @@ static gint cmp_chan_path(gconstpointer a, gconstpointer b)
        return g_ascii_strcasecmp(chan->path, path);
 }
 
-static gint cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
+static int cmp_chan_mdl(gconstpointer a, gconstpointer mdl)
 {
        const struct hdp_channel *chan = a;
 
@@ -304,11 +300,6 @@ static void device_unref_mcl(struct hdp_device *hdp_device)
 
 static void free_health_device(struct hdp_device *device)
 {
-       if (device->conn != NULL) {
-               dbus_connection_unref(device->conn);
-               device->conn = NULL;
-       }
-
        if (device->dev != NULL) {
                btd_device_unref(device->dev);
                device->dev = NULL;
@@ -369,12 +360,12 @@ static DBusMessage *manager_create_application(DBusConnection *conn,
        }
 
        app->oname = g_strdup(name);
-       app->conn = dbus_connection_ref(conn);
 
        applications = g_slist_prepend(applications, app);
 
-       app->dbus_watcher = g_dbus_add_disconnect_watch(conn, name,
-                                               client_disconnected, app, NULL);
+       app->dbus_watcher =
+                       g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+                                       name, client_disconnected, app, NULL);
        g_slist_foreach(adapters, (GFunc) update_adapter, NULL);
 
        DBG("Health application created with id %s", app->path);
@@ -431,44 +422,43 @@ static const GDBusMethodTable health_manager_methods[] = {
        { }
 };
 
-static DBusMessage *channel_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
+static gboolean channel_property_get_device(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct hdp_channel *chan = user_data;
-       DBusMessageIter iter, dict;
-       DBusMessage *reply;
-       const char *path;
-       char *type;
+       struct hdp_channel *chan = data;
+       const char *path = device_get_path(chan->dev->dev);
 
-       reply = dbus_message_new_method_return(msg);
-       if (reply == NULL)
-               return NULL;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       return TRUE;
+}
 
-       dbus_message_iter_init_append(reply, &iter);
+static gboolean channel_property_get_application(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct hdp_channel *chan = data;
+       const char *path = chan->app->path;
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
 
-       path = device_get_path(chan->dev->dev);
-       dict_append_entry(&dict, "Device", DBUS_TYPE_OBJECT_PATH, &path);
+       return TRUE;
+}
 
-       path = chan->app->path;
-       dict_append_entry(&dict, "Application", DBUS_TYPE_OBJECT_PATH, &path);
+static gboolean channel_property_get_type(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct hdp_channel *chan = data;
+       const char *type;
 
        if (chan->config == HDP_RELIABLE_DC)
-               type = g_strdup("Reliable");
+               type = "reliable";
        else
-               type = g_strdup("Streaming");
-
-       dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &type);
+               type = "streaming";
 
-       g_free(type);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &type);
 
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
+       return TRUE;
 }
 
 static void hdp_tmp_dc_data_destroy(gpointer data)
@@ -486,6 +476,7 @@ static void abort_mdl_cb(GError *err, gpointer data)
 
 static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *dc_data = data;
        DBusMessage *reply;
        int fd;
@@ -498,7 +489,7 @@ static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
                reply = g_dbus_create_error(dc_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "Cannot reconnect: %s", err->message);
-               g_dbus_send_message(dc_data->conn, reply);
+               g_dbus_send_message(conn, reply);
 
                /* Send abort request because remote side */
                /* is now in PENDING state */
@@ -515,16 +506,15 @@ static void hdp_mdl_reconn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
                reply = g_dbus_create_error(dc_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "Cannot get file descriptor");
-               g_dbus_send_message(dc_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
        reply = g_dbus_create_reply(dc_data->msg, DBUS_TYPE_UNIX_FD,
                                                        &fd, DBUS_TYPE_INVALID);
-       g_dbus_send_message(dc_data->conn, reply);
+       g_dbus_send_message(conn, reply);
 
-       g_dbus_emit_signal(dc_data->conn,
-                       device_get_path(dc_data->hdp_chann->dev->dev),
+       g_dbus_emit_signal(conn, device_get_path(dc_data->hdp_chann->dev->dev),
                        HEALTH_DEVICE, "ChannelConnected",
                        DBUS_TYPE_OBJECT_PATH, &dc_data->hdp_chann->path,
                        DBUS_TYPE_INVALID);
@@ -552,14 +542,15 @@ static void hdp_get_dcpsm_cb(uint16_t dcpsm, gpointer user_data, GError *err)
                                        hdp_tmp_dc_data_destroy, &gerr))
                return;
 
-       hdp_tmp_dc_data_unref(hdp_conn);
        hdp_conn->cb(hdp_chann->mdl, err, hdp_conn);
        g_error_free(gerr);
+       hdp_tmp_dc_data_unref(hdp_conn);
 }
 
 static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
                                                                gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *dc_data = data;
        GError *gerr = NULL;
        DBusMessage *reply;
@@ -568,7 +559,7 @@ static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
                reply = g_dbus_create_error(dc_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "Cannot reconnect: %s", err->message);
-               g_dbus_send_message(dc_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
@@ -584,7 +575,7 @@ static void device_reconnect_mdl_cb(struct mcap_mdl *mdl, GError *err,
        reply = g_dbus_create_error(dc_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "Cannot reconnect: %s", gerr->message);
-       g_dbus_send_message(dc_data->conn, reply);
+       g_dbus_send_message(conn, reply);
        hdp_tmp_dc_data_unref(dc_data);
        g_error_free(gerr);
 
@@ -618,23 +609,22 @@ static DBusMessage *channel_acquire_continue(struct hdp_tmp_dc_data *data,
                                        data, hdp_tmp_dc_data_destroy, &gerr))
                return NULL;
 
-       hdp_tmp_dc_data_unref(data);
        reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
                                        "Cannot reconnect: %s", gerr->message);
        g_error_free(gerr);
+       hdp_tmp_dc_data_unref(data);
 
        return reply;
 }
 
 static void channel_acquire_cb(gpointer data, GError *err)
 {
-       struct hdp_tmp_dc_data *dc_data = data;
        DBusMessage *reply;
 
        reply = channel_acquire_continue(data, err);
 
        if (reply != NULL)
-               g_dbus_send_message(dc_data->conn, reply);
+               g_dbus_send_message(btd_get_dbus_connection(), reply);
 }
 
 static DBusMessage *channel_acquire(DBusConnection *conn,
@@ -646,7 +636,6 @@ static DBusMessage *channel_acquire(DBusConnection *conn,
        DBusMessage *reply;
 
        dc_data = g_new0(struct hdp_tmp_dc_data, 1);
-       dc_data->conn = dbus_connection_ref(conn);
        dc_data->msg = dbus_message_ref(msg);
        dc_data->hdp_chann = hdp_channel_ref(chan);
 
@@ -718,7 +707,8 @@ static void health_channel_destroy(void *data)
        dev->channels = g_slist_remove(dev->channels, hdp_chan);
 
        if (hdp_chan->mdep != HDP_MDEP_ECHO)
-               g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
+               g_dbus_emit_signal(btd_get_dbus_connection(),
+                                       device_get_path(dev->dev),
                                        HEALTH_DEVICE, "ChannelDeleted",
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
                                        DBUS_TYPE_INVALID);
@@ -733,9 +723,6 @@ end:
 }
 
 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) },
@@ -743,6 +730,13 @@ static const GDBusMethodTable health_channels_methods[] = {
        { }
 };
 
+static const GDBusPropertyTable health_channels_properties[] = {
+       { "Device", "o",  channel_property_get_device },
+       { "Application", "o", channel_property_get_application },
+       { "Type", "s", channel_property_get_type },
+       { }
+};
+
 static struct hdp_channel *create_channel(struct hdp_device *dev,
                                                uint8_t config,
                                                struct mcap_mdl *mdl,
@@ -779,10 +773,11 @@ static struct hdp_channel *create_channel(struct hdp_device *dev,
        if (hdp_chann->mdep == HDP_MDEP_ECHO)
                return hdp_channel_ref(hdp_chann);
 
-       if (!g_dbus_register_interface(dev->conn, hdp_chann->path,
-                                       HEALTH_CHANNEL,
-                                       health_channels_methods, NULL, NULL,
-                                       hdp_chann, health_channel_destroy)) {
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       hdp_chann->path, HEALTH_CHANNEL,
+                                       health_channels_methods, NULL,
+                                       health_channels_properties, hdp_chann,
+                                       health_channel_destroy)) {
                g_set_error(err, HDP_ERROR, HDP_UNSPECIFIED_ERROR,
                                        "Can't register the channel interface");
                health_channel_destroy(hdp_chann);
@@ -801,8 +796,8 @@ static void remove_channels(struct hdp_device *dev)
                chan = dev->channels->data;
 
                path = g_strdup(chan->path);
-               if (!g_dbus_unregister_interface(dev->conn, path,
-                                                               HEALTH_CHANNEL))
+               if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_CHANNEL))
                        health_channel_destroy(chan);
                g_free(path);
        }
@@ -826,7 +821,8 @@ static void close_device_con(struct hdp_device *dev, gboolean cache)
                const char *path;
 
                path = device_get_path(dev->dev);
-               g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
+               g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_DEVICE);
        }
 }
 
@@ -887,7 +883,7 @@ static gboolean check_channel_conf(struct hdp_channel *chan)
                return FALSE;
        io = g_io_channel_unix_new(fd);
 
-       if (!bt_io_get(io, BT_IO_L2CAP, &err,
+       if (!bt_io_get(io, &err,
                        BT_IO_OPT_MODE, &mode,
                        BT_IO_OPT_IMTU, &imtu,
                        BT_IO_OPT_OMTU, &omtu,
@@ -966,19 +962,19 @@ static void hdp_mcap_mdl_connected_cb(struct mcap_mdl *mdl, void *data)
                goto end;
        }
 
-       g_dbus_emit_signal(dev->conn, device_get_path(dev->dev), HEALTH_DEVICE,
-                                       "ChannelConnected",
-                                       DBUS_TYPE_OBJECT_PATH, &chan->path,
-                                       DBUS_TYPE_INVALID);
+       g_dbus_emit_signal(btd_get_dbus_connection(), device_get_path(dev->dev),
+                               HEALTH_DEVICE, "ChannelConnected",
+                               DBUS_TYPE_OBJECT_PATH, &chan->path,
+                               DBUS_TYPE_INVALID);
 
        if (dev->fr != NULL)
                goto end;
 
        dev->fr = hdp_channel_ref(chan);
 
-       emit_property_changed(dev->conn, device_get_path(dev->dev),
-                                       HEALTH_DEVICE, "MainChannel",
-                                       DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                               device_get_path(dev->dev), HEALTH_DEVICE,
+                               "MainChannel");
 
 end:
        hdp_channel_unref(dev->ndc);
@@ -1009,7 +1005,8 @@ static void hdp_mcap_mdl_deleted_cb(struct mcap_mdl *mdl, void *data)
        chan = l->data;
 
        path = g_strdup(chan->path);
-       if (!g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL))
+       if (!g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_CHANNEL))
                health_channel_destroy(chan);
        g_free(path);
 }
@@ -1029,7 +1026,8 @@ static void hdp_mcap_mdl_aborted_cb(struct mcap_mdl *mdl, void *data)
                                                hdp_channel_ref(dev->ndc));
 
        if (dev->ndc->mdep != HDP_MDEP_ECHO)
-               g_dbus_emit_signal(dev->conn, device_get_path(dev->dev),
+               g_dbus_emit_signal(btd_get_dbus_connection(),
+                                       device_get_path(dev->dev),
                                        HEALTH_DEVICE, "ChannelConnected",
                                        DBUS_TYPE_OBJECT_PATH, &dev->ndc->path,
                                        DBUS_TYPE_INVALID);
@@ -1122,7 +1120,8 @@ static uint8_t hdp_mcap_mdl_conn_req_cb(struct mcap_mcl *mcl, uint8_t mdepid,
                char *path;
 
                path = g_strdup(chan->path);
-               g_dbus_unregister_interface(dev->conn, path, HEALTH_CHANNEL);
+               g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_CHANNEL);
                g_free(path);
        }
 
@@ -1205,14 +1204,12 @@ static void mcl_connected(struct mcap_mcl *mcl, gpointer data)
        if (l == NULL) {
                struct hdp_adapter *hdp_adapter = data;
                struct btd_device *device;
-               char str[18];
 
-               ba2str(&addr, str);
-               device = adapter_get_device(connection,
-                                       hdp_adapter->btd_adapter, str);
+               device = adapter_get_device(hdp_adapter->btd_adapter, &addr,
+                                                               BDADDR_BREDR);
                if (!device)
                        return;
-               hdp_device = create_health_device(connection, device);
+               hdp_device = create_health_device(device);
                if (!hdp_device)
                        return;
                devices = g_slist_append(devices, hdp_device);
@@ -1280,7 +1277,8 @@ static void mcl_uncached(struct mcap_mcl *mcl, gpointer data)
        /* be removed. Then we have to remove the HealthDevice */
        /* interface manually */
        path = device_get_path(hdp_device->dev);
-       g_dbus_unregister_interface(hdp_device->conn, path, HEALTH_DEVICE);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_DEVICE);
        DBG("Mcl uncached %s", path);
 }
 
@@ -1303,7 +1301,8 @@ static void check_devices_mcl(void)
                const char *path;
 
                path = device_get_path(dev->dev);
-               g_dbus_unregister_interface(dev->conn, path, HEALTH_DEVICE);
+               g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_DEVICE);
        }
 
        g_slist_free(to_delete);
@@ -1323,7 +1322,6 @@ static void release_adapter_instance(struct hdp_adapter *hdp_adapter)
 static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
 {
        GError *err = NULL;
-       bdaddr_t addr;
 
        if (applications == NULL) {
                release_adapter_instance(hdp_adapter);
@@ -1333,12 +1331,13 @@ static gboolean update_adapter(struct hdp_adapter *hdp_adapter)
        if (hdp_adapter->mi != NULL)
                goto update;
 
-       adapter_get_address(hdp_adapter->btd_adapter, &addr);
-       hdp_adapter->mi = mcap_create_instance(&addr, BT_IO_SEC_MEDIUM, 0, 0,
-                                       mcl_connected, mcl_reconnected,
-                                       mcl_disconnected, mcl_uncached,
-                                       NULL, /* CSP is not used by now */
-                                       hdp_adapter, &err);
+       hdp_adapter->mi = mcap_create_instance(
+                               adapter_get_address(hdp_adapter->btd_adapter),
+                               BT_IO_SEC_MEDIUM, 0, 0,
+                               mcl_connected, mcl_reconnected,
+                               mcl_disconnected, mcl_uncached,
+                               NULL, /* CSP is not used by now */
+                               hdp_adapter, &err);
 
        if (hdp_adapter->mi == NULL) {
                error("Error creating the MCAP instance: %s", err->message);
@@ -1371,7 +1370,7 @@ fail:
        return FALSE;
 }
 
-int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *adapter)
+int hdp_adapter_register(struct btd_adapter *adapter)
 {
        struct hdp_adapter *hdp_adapter;
 
@@ -1404,7 +1403,7 @@ void hdp_adapter_unregister(struct btd_adapter *adapter)
        hdp_adapter = l->data;
        adapters = g_slist_remove(adapters, hdp_adapter);
        if (hdp_adapter->sdp_handler > 0)
-               remove_record_from_server(hdp_adapter->sdp_handler);
+               adapter_service_remove(adapter, hdp_adapter->sdp_handler);
        release_adapter_instance(hdp_adapter);
        btd_adapter_unref(hdp_adapter->btd_adapter);
        g_free(hdp_adapter);
@@ -1511,7 +1510,7 @@ static gboolean check_echo(GIOChannel *io_chan, GIOCondition cond,
 end:
        reply = g_dbus_create_reply(hdp_conn->msg, DBUS_TYPE_BOOLEAN, &value,
                                                        DBUS_TYPE_INVALID);
-       g_dbus_send_message(hdp_conn->conn, reply);
+       g_dbus_send_message(btd_get_dbus_connection(), reply);
        g_source_remove(edata->tid);
        edata->tid = 0;
        g_free(edata->buf);
@@ -1548,6 +1547,7 @@ static gboolean echo_timeout(gpointer data)
 static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
                                                                gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *hdp_conn =  data;
        struct hdp_echo_data *edata;
        GError *gerr = NULL;
@@ -1559,7 +1559,7 @@ static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
                reply = g_dbus_create_error(hdp_conn->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
-               g_dbus_send_message(hdp_conn->conn, reply);
+               g_dbus_send_message(conn, reply);
 
                /* Send abort request because remote */
                /* side is now in PENDING state. */
@@ -1580,7 +1580,7 @@ static void hdp_echo_connect_cb(struct mcap_mdl *mdl, GError *err,
                reply = g_dbus_create_error(hdp_conn->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "Can't write in echo channel");
-               g_dbus_send_message(hdp_conn->conn, reply);
+               g_dbus_send_message(conn, reply);
                delete_echo_channel(hdp_conn->hdp_chann);
                return;
        }
@@ -1638,16 +1638,16 @@ static void abort_mdl_connection_cb(GError *err, gpointer data)
        /* Connection operation has failed but we have to */
        /* notify the channel created at MCAP level */
        if (hdp_chann->mdep != HDP_MDEP_ECHO)
-               g_dbus_emit_signal(hdp_conn->conn,
+               g_dbus_emit_signal(btd_get_dbus_connection(),
                                        device_get_path(hdp_chann->dev->dev),
-                                       HEALTH_DEVICE,
-                                       "ChannelConnected",
+                                       HEALTH_DEVICE, "ChannelConnected",
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
                                        DBUS_TYPE_INVALID);
 }
 
 static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *hdp_conn =  data;
        struct hdp_channel *hdp_chann = hdp_conn->hdp_chann;
        struct hdp_device *dev = hdp_chann->dev;
@@ -1659,7 +1659,7 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
                reply = g_dbus_create_reply(hdp_conn->msg,
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
                                        DBUS_TYPE_INVALID);
-               g_dbus_send_message(hdp_conn->conn, reply);
+               g_dbus_send_message(conn, reply);
 
                /* Send abort request because remote side */
                /* is now in PENDING state */
@@ -1676,14 +1676,12 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
        reply = g_dbus_create_reply(hdp_conn->msg,
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
                                        DBUS_TYPE_INVALID);
-       g_dbus_send_message(hdp_conn->conn, reply);
+       g_dbus_send_message(conn, reply);
 
-       g_dbus_emit_signal(hdp_conn->conn,
-                                       device_get_path(hdp_chann->dev->dev),
-                                       HEALTH_DEVICE,
-                                       "ChannelConnected",
-                                       DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
-                                       DBUS_TYPE_INVALID);
+       g_dbus_emit_signal(conn, device_get_path(hdp_chann->dev->dev),
+                               HEALTH_DEVICE, "ChannelConnected",
+                               DBUS_TYPE_OBJECT_PATH, &hdp_chann->path,
+                               DBUS_TYPE_INVALID);
 
        if (!check_channel_conf(hdp_chann)) {
                close_mdl(hdp_chann);
@@ -1695,14 +1693,15 @@ static void hdp_mdl_conn_cb(struct mcap_mdl *mdl, GError *err, gpointer data)
 
        dev->fr = hdp_channel_ref(hdp_chann);
 
-       emit_property_changed(dev->conn, device_get_path(dev->dev),
-                                       HEALTH_DEVICE, "MainChannel",
-                                       DBUS_TYPE_OBJECT_PATH, &dev->fr->path);
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                               device_get_path(dev->dev), HEALTH_DEVICE,
+                               "MainChannel");
 }
 
 static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
                                                GError *err, gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_create_dc *user_data = data;
        struct hdp_tmp_dc_data *hdp_conn;
        struct hdp_channel *hdp_chan;
@@ -1713,7 +1712,7 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
                reply = g_dbus_create_error(user_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
-               g_dbus_send_message(user_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
@@ -1741,7 +1740,6 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
 
        hdp_conn = g_new0(struct hdp_tmp_dc_data, 1);
        hdp_conn->msg = dbus_message_ref(user_data->msg);
-       hdp_conn->conn = dbus_connection_ref(user_data->conn);
        hdp_conn->hdp_chann = hdp_chan;
        hdp_conn->cb = user_data->cb;
        hdp_chan->mdep = user_data->mdep;
@@ -1757,7 +1755,7 @@ static void device_create_mdl_cb(struct mcap_mdl *mdl, uint8_t conf,
        reply = g_dbus_create_reply(hdp_conn->msg,
                                        DBUS_TYPE_OBJECT_PATH, &hdp_chan->path,
                                        DBUS_TYPE_INVALID);
-       g_dbus_send_message(hdp_conn->conn, reply);
+       g_dbus_send_message(conn, reply);
        hdp_tmp_dc_data_unref(hdp_conn);
 
        /* Send abort request because remote side is now in PENDING state */
@@ -1775,7 +1773,7 @@ fail:
        reply = g_dbus_create_error(user_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", gerr->message);
-       g_dbus_send_message(user_data->conn, reply);
+       g_dbus_send_message(conn, reply);
        g_error_free(gerr);
 
        /* Send abort request because remote side is now in PENDING */
@@ -1791,6 +1789,7 @@ fail:
 
 static void device_create_dc_cb(gpointer user_data, GError *err)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_create_dc *data = user_data;
        DBusMessage *reply;
        GError *gerr = NULL;
@@ -1799,7 +1798,7 @@ static void device_create_dc_cb(gpointer user_data, GError *err)
                reply = g_dbus_create_error(data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
-               g_dbus_send_message(data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
@@ -1821,7 +1820,7 @@ fail:
        reply = g_dbus_create_error(data->msg, ERROR_INTERFACE ".HealthError",
                                                        "%s", gerr->message);
        g_error_free(gerr);
-       g_dbus_send_message(data->conn, reply);
+       g_dbus_send_message(conn, reply);
 }
 
 static DBusMessage *device_echo(DBusConnection *conn,
@@ -1837,7 +1836,6 @@ static DBusMessage *device_echo(DBusConnection *conn,
        data->mdep = HDP_MDEP_ECHO;
        data->config = HDP_RELIABLE_DC;
        data->msg = dbus_message_ref(msg);
-       data->conn = dbus_connection_ref(conn);
        data->cb = hdp_echo_connect_cb;
        hdp_create_data_ref(data);
 
@@ -1863,6 +1861,7 @@ fail:
 
 static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_create_dc *dc_data, *user_data = data;
        DBusMessage *reply;
        GError *gerr = NULL;
@@ -1871,7 +1870,7 @@ static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
                reply = g_dbus_create_error(user_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
-               g_dbus_send_message(user_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
@@ -1893,7 +1892,7 @@ static void device_get_mdep_cb(uint8_t mdep, gpointer data, GError *err)
                                                "%s", gerr->message);
        hdp_create_data_unref(dc_data);
        g_error_free(gerr);
-       g_dbus_send_message(user_data->conn, reply);
+       g_dbus_send_message(conn, reply);
 }
 
 static DBusMessage *device_create_channel(DBusConnection *conn,
@@ -1919,11 +1918,11 @@ static DBusMessage *device_create_channel(DBusConnection *conn,
 
        app = l->data;
 
-       if (g_ascii_strcasecmp("Reliable", conf) == 0)
+       if (g_ascii_strcasecmp("reliable", conf) == 0)
                config = HDP_RELIABLE_DC;
-       else if (g_ascii_strcasecmp("Streaming", conf) == 0)
+       else if (g_ascii_strcasecmp("streaming", conf) == 0)
                config = HDP_STREAMING_DC;
-       else if (g_ascii_strcasecmp("Any", conf) == 0)
+       else if (g_ascii_strcasecmp("any", conf) == 0)
                config = HDP_NO_PREFERENCE_DC;
        else
                return btd_error_invalid_args(msg);
@@ -1942,7 +1941,6 @@ static DBusMessage *device_create_channel(DBusConnection *conn,
        data->config = config;
        data->app = hdp_application_ref(app);
        data->msg = dbus_message_ref(msg);
-       data->conn = dbus_connection_ref(conn);
        data->cb = hdp_mdl_conn_cb;
 
        if (hdp_get_mdep(device, l->data, device_get_mdep_cb,
@@ -1959,6 +1957,7 @@ static DBusMessage *device_create_channel(DBusConnection *conn,
 
 static void hdp_mdl_delete_cb(GError *err, gpointer data)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *del_data = data;
        DBusMessage *reply;
        char *path;
@@ -1967,20 +1966,21 @@ static void hdp_mdl_delete_cb(GError *err, gpointer data)
                reply = g_dbus_create_error(del_data->msg,
                                                ERROR_INTERFACE ".HealthError",
                                                "%s", err->message);
-               g_dbus_send_message(del_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
        path = g_strdup(del_data->hdp_chann->path);
-       g_dbus_unregister_interface(del_data->conn, path, HEALTH_CHANNEL);
+       g_dbus_unregister_interface(conn, path, HEALTH_CHANNEL);
        g_free(path);
 
        reply = g_dbus_create_reply(del_data->msg, DBUS_TYPE_INVALID);
-       g_dbus_send_message(del_data->conn, reply);
+       g_dbus_send_message(conn, reply);
 }
 
 static void hdp_continue_del_cb(gpointer user_data, GError *err)
 {
+       DBusConnection *conn = btd_get_dbus_connection();
        struct hdp_tmp_dc_data *del_data = user_data;
        GError *gerr = NULL;
        DBusMessage *reply;
@@ -1989,7 +1989,7 @@ static void hdp_continue_del_cb(gpointer user_data, GError *err)
                reply = g_dbus_create_error(del_data->msg,
                                        ERROR_INTERFACE ".HealthError",
                                        "%s", err->message);
-               g_dbus_send_message(del_data->conn, reply);
+               g_dbus_send_message(conn, reply);
                return;
        }
 
@@ -2003,7 +2003,7 @@ static void hdp_continue_del_cb(gpointer user_data, GError *err)
                                                "%s", gerr->message);
        hdp_tmp_dc_data_unref(del_data);
        g_error_free(gerr);
-       g_dbus_send_message(del_data->conn, reply);
+       g_dbus_send_message(conn, reply);
 }
 
 static DBusMessage *device_destroy_channel(DBusConnection *conn,
@@ -2029,7 +2029,6 @@ static DBusMessage *device_destroy_channel(DBusConnection *conn,
        hdp_chan = l->data;
        del_data = g_new0(struct hdp_tmp_dc_data, 1);
        del_data->msg = dbus_message_ref(msg);
-       del_data->conn = dbus_connection_ref(conn);
        del_data->hdp_chann = hdp_channel_ref(hdp_chan);
 
        if (device->mcl_conn) {
@@ -2053,31 +2052,26 @@ fail:
        return reply;
 }
 
-static DBusMessage *device_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
+static gboolean dev_property_exists_main_channel(
+                               const GDBusPropertyTable *property, void *data)
 {
-       struct hdp_device *device = user_data;
-       DBusMessageIter iter, dict;
-       DBusMessage *reply;
-
-       reply = dbus_message_new_method_return(msg);
-       if (reply == NULL)
-               return NULL;
+       struct hdp_device *device = data;
+       return device->fr != NULL;
+}
 
-       dbus_message_iter_init_append(reply, &iter);
+static gboolean dev_property_get_main_channel(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct hdp_device *device = data;
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       if (device->fr == NULL)
+               return FALSE;
 
-       if (device->fr != NULL)
-               dict_append_entry(&dict, "MainChannel", DBUS_TYPE_OBJECT_PATH,
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH,
                                                        &device->fr->path);
 
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
+       return TRUE;
 }
 
 static void health_device_destroy(void *data)
@@ -2108,9 +2102,6 @@ static const GDBusMethodTable health_device_methods[] = {
        { GDBUS_ASYNC_METHOD("DestroyChannel",
                        GDBUS_ARGS({ "channel", "o" }), NULL,
                        device_destroy_channel) },
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       device_get_properties) },
        { }
 };
 
@@ -2119,16 +2110,19 @@ static const GDBusSignalTable health_device_signals[] = {
                        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,
-                                               struct btd_device *device)
+static const GDBusPropertyTable health_device_properties[] = {
+       { "MainChannel", "o", dev_property_get_main_channel, NULL,
+                                       dev_property_exists_main_channel },
+       { }
+};
+
+static struct hdp_device *create_health_device(struct btd_device *device)
 {
        struct btd_adapter *adapter = device_get_adapter(device);
-       const gchar *path = device_get_path(device);
+       const char *path = device_get_path(device);
        struct hdp_device *dev;
        GSList *l;
 
@@ -2136,7 +2130,6 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
                return NULL;
 
        dev = g_new0(struct hdp_device, 1);
-       dev->conn = dbus_connection_ref(conn);
        dev->dev = btd_device_ref(device);
        health_device_ref(dev);
 
@@ -2146,8 +2139,8 @@ static struct hdp_device *create_health_device(DBusConnection *conn,
 
        dev->hdp_adapter = l->data;
 
-       if (!g_dbus_register_interface(conn, path,
-                                       HEALTH_DEVICE,
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       path, HEALTH_DEVICE,
                                        health_device_methods,
                                        health_device_signals, NULL,
                                        dev, health_device_destroy)) {
@@ -2163,7 +2156,7 @@ fail:
        return NULL;
 }
 
-int hdp_device_register(DBusConnection *conn, struct btd_device *device)
+int hdp_device_register(struct btd_device *device)
 {
        struct hdp_device *hdev;
        GSList *l;
@@ -2175,7 +2168,7 @@ int hdp_device_register(DBusConnection *conn, struct btd_device *device)
                return 0;
        }
 
-       hdev = create_health_device(conn, device);
+       hdev = create_health_device(device);
        if (hdev == NULL)
                return -1;
 
@@ -2197,31 +2190,30 @@ void hdp_device_unregister(struct btd_device *device)
 
        hdp_dev = l->data;
        path = device_get_path(hdp_dev->dev);
-       g_dbus_unregister_interface(hdp_dev->conn, path, HEALTH_DEVICE);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                                       path, HEALTH_DEVICE);
 }
 
-int hdp_manager_start(DBusConnection *conn)
+int hdp_manager_start(void)
 {
        DBG("Starting Health manager");
 
-       if (!g_dbus_register_interface(conn, MANAGER_PATH,
-                                       HEALTH_MANAGER,
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       MANAGER_PATH, HEALTH_MANAGER,
                                        health_manager_methods, NULL, NULL,
                                        NULL, manager_path_unregister)) {
                error("D-Bus failed to register %s interface", HEALTH_MANAGER);
                return -1;
        }
 
-       connection = dbus_connection_ref(conn);
-
        return 0;
 }
 
 void hdp_manager_stop(void)
 {
-       g_dbus_unregister_interface(connection, MANAGER_PATH, HEALTH_MANAGER);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               MANAGER_PATH, HEALTH_MANAGER);
 
-       dbus_connection_unref(connection);
        DBG("Stopped Health manager");
 }
 
similarity index 84%
rename from health/hdp.h
rename to profiles/health/hdp.h
index 39f0441..6e78b09 100644 (file)
  *
  */
 
-int hdp_adapter_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
+int hdp_adapter_register(struct btd_adapter *btd_adapter);
 void hdp_adapter_unregister(struct btd_adapter *btd_adapter);
 
-int hdp_device_register(DBusConnection *conn, struct btd_device *device);
+int hdp_device_register(struct btd_device *device);
 void hdp_device_unregister(struct btd_device *device);
 
-int hdp_manager_start(DBusConnection *conn);
+int hdp_manager_start(void);
 void hdp_manager_stop(void);
 
 gboolean hdp_set_mcl_cb(struct hdp_device *device, GError **err);
similarity index 78%
rename from health/hdp_main.c
rename to profiles/health/hdp_main.c
index 9367e73..e705ee9 100644 (file)
 
 #include <errno.h>
 
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "plugin.h"
 #include "hdp_manager.h"
 
-static DBusConnection *connection = NULL;
-
 static int hdp_init(void)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
-
-       if (hdp_manager_init(connection) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
-       }
-
-       return 0;
+       return hdp_manager_init();
 }
 
 static void hdp_exit(void)
 {
        hdp_manager_exit();
-
-       dbus_connection_unref(connection);
-       connection = NULL;
 }
 
 BLUETOOTH_PLUGIN_DEFINE(health, VERSION,
similarity index 50%
rename from health/hdp_manager.c
rename to profiles/health/hdp_manager.c
index ffaed5d..1bb6007 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
 
-#include <btio.h>
+#include "lib/uuid.h"
+#include <btio/btio.h>
 #include <adapter.h>
 #include <device.h>
+#include <profile.h>
+#include <service.h>
 #include <glib-helper.h>
 #include <log.h>
 
 #include "hdp_manager.h"
 #include "hdp.h"
 
-static DBusConnection *connection = NULL;
-
-static int hdp_adapter_probe(struct btd_adapter *adapter)
+static int hdp_adapter_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
 {
-       return hdp_adapter_register(connection, adapter);
+       return hdp_adapter_register(adapter);
 }
 
-static void hdp_adapter_remove(struct btd_adapter *adapter)
+static void hdp_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
 {
        hdp_adapter_unregister(adapter);
 }
 
-static struct btd_adapter_driver hdp_adapter_driver = {
-       .name   = "hdp-adapter-driver",
-       .probe  = hdp_adapter_probe,
-       .remove = hdp_adapter_remove,
-};
-
-static int hdp_driver_probe(struct btd_device *device, GSList *uuids)
+static int hdp_driver_probe(struct btd_service *service)
 {
-       return hdp_device_register(connection, device);
+       struct btd_device *device = btd_service_get_device(service);
+
+       return hdp_device_register(device);
 }
 
-static void hdp_driver_remove(struct btd_device *device)
+static void hdp_driver_remove(struct btd_service *service)
 {
+       struct btd_device *device = btd_service_get_device(service);
+
        hdp_device_unregister(device);
 }
 
-static struct btd_device_driver hdp_device_driver = {
-       .name   = "hdp-device-driver",
-       .uuids  = BTD_UUIDS(HDP_UUID, HDP_SOURCE_UUID, HDP_SINK_UUID),
-       .probe  = hdp_driver_probe,
-       .remove = hdp_driver_remove
+static struct btd_profile hdp_source_profile = {
+       .name           = "hdp-source",
+       .remote_uuid    = HDP_SOURCE_UUID,
+
+       .device_probe   = hdp_driver_probe,
+       .device_remove  = hdp_driver_remove,
+
+       .adapter_probe  = hdp_adapter_probe,
+       .adapter_remove = hdp_adapter_remove,
+};
+
+static struct btd_profile hdp_sink_profile = {
+       .name           = "hdp-sink",
+       .remote_uuid    = HDP_SINK_UUID,
+
+       .device_probe   = hdp_driver_probe,
+       .device_remove  = hdp_driver_remove,
 };
 
-int hdp_manager_init(DBusConnection *conn)
+int hdp_manager_init(void)
 {
-       if (hdp_manager_start(conn) < 0)
+       if (hdp_manager_start() < 0)
                return -1;
 
-       connection = dbus_connection_ref(conn);
-       btd_register_adapter_driver(&hdp_adapter_driver);
-       btd_register_device_driver(&hdp_device_driver);
+       btd_profile_register(&hdp_source_profile);
+       btd_profile_register(&hdp_sink_profile);
 
        return 0;
 }
 
 void hdp_manager_exit(void)
 {
-       btd_unregister_device_driver(&hdp_device_driver);
-       btd_unregister_adapter_driver(&hdp_adapter_driver);
-       hdp_manager_stop();
+       btd_profile_unregister(&hdp_sink_profile);
+       btd_profile_unregister(&hdp_source_profile);
 
-       dbus_connection_unref(connection);
-       connection = NULL;
+       hdp_manager_stop();
 }
similarity index 95%
rename from health/hdp_manager.h
rename to profiles/health/hdp_manager.h
index d39f190..1cab4d0 100644 (file)
@@ -20,5 +20,5 @@
  *
  */
 
-int hdp_manager_init(DBusConnection *conn);
+int hdp_manager_init(void);
 void hdp_manager_exit(void);
similarity index 91%
rename from health/hdp_types.h
rename to profiles/health/hdp_types.h
index 7f8b015..b34b5e0 100644 (file)
@@ -25,9 +25,9 @@
 
 #define MANAGER_PATH           "/org/bluez"
 
-#define HEALTH_MANAGER         "org.bluez.HealthManager"
-#define HEALTH_DEVICE          "org.bluez.HealthDevice"
-#define HEALTH_CHANNEL         "org.bluez.HealthChannel"
+#define HEALTH_MANAGER         "org.bluez.HealthManager1"
+#define HEALTH_DEVICE          "org.bluez.HealthDevice1"
+#define HEALTH_CHANNEL         "org.bluez.HealthChannel1"
 
 #define HDP_VERSION            0x0100
 
@@ -66,7 +66,6 @@ enum data_specs {
 };
 
 struct hdp_application {
-       DBusConnection          *conn;          /* For dbus watcher */
        char                    *path;          /* The path of the application */
        uint16_t                data_type;      /* Data type handled for this application */
        gboolean                data_type_set;  /* Flag for dictionary parsing */
@@ -78,7 +77,7 @@ struct hdp_application {
        uint8_t                 id;             /* The identification is also the mdepid */
        char                    *oname;         /* Name of the owner application */
        guint                   dbus_watcher;   /* Watch for clients disconnection */
-       gint                    ref;            /* Reference counter */
+       int                     ref;            /* Reference counter */
 };
 
 struct hdp_adapter {
@@ -91,7 +90,6 @@ struct hdp_adapter {
 };
 
 struct hdp_device {
-       DBusConnection          *conn;          /* For name listener handling */
        struct btd_device       *dev;           /* Device reference */
        struct hdp_adapter      *hdp_adapter;   /* hdp_adapater */
        struct mcap_mcl         *mcl;           /* The mcap control channel */
@@ -100,7 +98,7 @@ struct hdp_device {
        GSList                  *channels;      /* Data Channel list */
        struct hdp_channel      *ndc;           /* Data channel being negotiated */
        struct hdp_channel      *fr;            /* First reliable data channel */
-       gint                    ref;            /* Reference counting */
+       int                     ref;            /* Reference counting */
 };
 
 struct hdp_echo_data;
@@ -116,7 +114,7 @@ struct hdp_channel {
        uint16_t                imtu;           /* Channel incoming MTU */
        uint16_t                omtu;           /* Channel outgoing MTU */
        struct hdp_echo_data    *edata;         /* private data used by echo channels */
-       gint                    ref;            /* Reference counter */
+       int                     ref;            /* Reference counter */
 };
 
 #endif /* __HDP_TYPES_H__ */
similarity index 93%
rename from health/hdp_util.c
rename to profiles/health/hdp_util.c
index 744e390..34e4671 100644 (file)
 #endif
 
 #include <stdint.h>
+#include <stdbool.h>
 
 #include <glib.h>
 
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include <adapter.h>
 #include <device.h>
 
 #include <sdpd.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
 #include <sdp-client.h>
 #include <glib-helper.h>
 
-#include <btio.h>
+#include "lib/uuid.h"
+#include "btio/btio.h"
 
-#include <log.h>
+#include "log.h"
 
+#include "dbus-common.h"
 #include "mcap.h"
 #include "mcap_lib.h"
 #include "hdp_types.h"
@@ -151,13 +153,12 @@ static gboolean parse_data_type(DBusMessageIter *iter, gpointer data,
 {
        struct hdp_application *app = data;
        DBusMessageIter *value;
+       DBusMessageIter variant;
        int ctype;
 
        ctype = dbus_message_iter_get_arg_type(iter);
        value = iter;
        if (ctype == DBUS_TYPE_VARIANT) {
-               DBusMessageIter variant;
-
                /* Get value inside the variable */
                dbus_message_iter_recurse(iter, &variant);
                ctype = dbus_message_iter_get_arg_type(&variant);
@@ -179,13 +180,12 @@ static gboolean parse_role(DBusMessageIter *iter, gpointer data, GError **err)
 {
        struct hdp_application *app = data;
        DBusMessageIter *string;
+       DBusMessageIter value;
        int ctype;
        const char *role;
 
        ctype = dbus_message_iter_get_arg_type(iter);
        if (ctype == DBUS_TYPE_VARIANT) {
-               DBusMessageIter value;
-
                /* Get value inside the variable */
                dbus_message_iter_recurse(iter, &value);
                ctype = dbus_message_iter_get_arg_type(&value);
@@ -220,13 +220,12 @@ static gboolean parse_desc(DBusMessageIter *iter, gpointer data, GError **err)
 {
        struct hdp_application *app = data;
        DBusMessageIter *string;
+       DBusMessageIter variant;
        int ctype;
        const char *desc;
 
        ctype = dbus_message_iter_get_arg_type(iter);
        if (ctype == DBUS_TYPE_VARIANT) {
-               DBusMessageIter variant;
-
                /* Get value inside the variable */
                dbus_message_iter_recurse(iter, &variant);
                ctype = dbus_message_iter_get_arg_type(&variant);
@@ -251,14 +250,13 @@ static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data,
 {
        struct hdp_application *app = data;
        DBusMessageIter *value;
+       DBusMessageIter variant;
        char *chan_type;
        int ctype;
 
        ctype = dbus_message_iter_get_arg_type(iter);
        value = iter;
        if (ctype == DBUS_TYPE_VARIANT) {
-               DBusMessageIter variant;
-
                /* Get value inside the variable */
                dbus_message_iter_recurse(iter, &variant);
                ctype = dbus_message_iter_get_arg_type(&variant);
@@ -273,9 +271,9 @@ static gboolean parse_chan_type(DBusMessageIter *iter, gpointer data,
 
        dbus_message_iter_get_basic(value, &chan_type);
 
-       if (g_ascii_strcasecmp("Reliable", chan_type) == 0)
+       if (g_ascii_strcasecmp("reliable", chan_type) == 0)
                app->chan_type = HDP_RELIABLE_DC;
-       else if (g_ascii_strcasecmp("Streaming", chan_type) == 0)
+       else if (g_ascii_strcasecmp("streaming", chan_type) == 0)
                app->chan_type = HDP_STREAMING_DC;
        else {
                g_set_error(err, HDP_ERROR, HDP_DIC_ENTRY_PARSE_ERROR,
@@ -693,10 +691,10 @@ static gboolean register_mcap_features(sdp_record_t *sdp_record)
 gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
 {
        sdp_record_t *sdp_record;
-       bdaddr_t addr;
 
        if (adapter->sdp_handler > 0)
-               remove_record_from_server(adapter->sdp_handler);
+               adapter_service_remove(adapter->btd_adapter,
+                                       adapter->sdp_handler);
 
        if (app_list == NULL) {
                adapter->sdp_handler = 0;
@@ -736,9 +734,7 @@ gboolean hdp_update_sdp_record(struct hdp_adapter *adapter, GSList *app_list)
        if (sdp_set_record_state(sdp_record, adapter->record_state++) < 0)
                goto fail;
 
-       adapter_get_address(adapter->btd_adapter, &addr);
-
-       if (add_record_to_server(&addr, sdp_record) < 0)
+       if (adapter_service_add(adapter->btd_adapter, sdp_record) < 0)
                goto fail;
        adapter->sdp_handler = sdp_record->handle;
        return TRUE;
@@ -767,15 +763,13 @@ static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
                return TRUE;
 
        list = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES_LIST);
-       if (list == NULL || (list->dtd != SDP_SEQ8 && list->dtd != SDP_SEQ16 &&
-                                                       list->dtd != SDP_SEQ32))
+       if (list == NULL || !SDP_IS_SEQ(list->dtd))
                return FALSE;
 
        for (feat = list->val.dataseq; feat; feat = feat->next) {
                sdp_data_t *data_type, *mdepid, *role_t, *desc_t;
 
-               if (feat->dtd != SDP_SEQ8 && feat->dtd != SDP_SEQ16 &&
-                                               feat->dtd != SDP_SEQ32)
+               if (!SDP_IS_SEQ(feat->dtd))
                        continue;
 
                mdepid = feat->val.dataseq;
@@ -803,10 +797,8 @@ static gboolean get_mdep_from_rec(const sdp_record_t *rec, uint8_t role,
                if (mdep != NULL)
                        *mdep = mdepid->val.uint8;
 
-               if (desc != NULL  && desc_t != NULL  &&
-                                       (desc_t->dtd == SDP_TEXT_STR8 ||
-                                       desc_t->dtd == SDP_TEXT_STR16  ||
-                                       desc_t->dtd == SDP_TEXT_STR32))
+               if (desc != NULL && desc_t != NULL &&
+                                               SDP_IS_TEXT_STR(desc_t->dtd))
                        *desc = g_strdup(desc_t->val.str);
 
                return TRUE;
@@ -857,11 +849,12 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app,
                                GDestroyNotify destroy, GError **err)
 {
        struct get_mdep_data *mdep_data;
-       bdaddr_t dst, src;
+       const bdaddr_t *src;
+       const bdaddr_t *dst;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst, NULL);
-       adapter_get_address(device_get_adapter(device->dev), &src);
+       src = adapter_get_address(device_get_adapter(device->dev));
+       dst = device_get_address(device->dev);
 
        mdep_data = g_new0(struct get_mdep_data, 1);
        mdep_data->app = hdp_application_ref(app);
@@ -870,7 +863,7 @@ gboolean hdp_get_mdep(struct hdp_device *device, struct hdp_application *app,
        mdep_data->destroy = destroy;
 
        bt_string2uuid(&uuid, HDP_UUID);
-       if (bt_search_service(&src, &dst, &uuid, get_mdep_cb, mdep_data,
+       if (bt_search_service(src, dst, &uuid, get_mdep_cb, mdep_data,
                                                        free_mdep_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
@@ -886,8 +879,7 @@ static gboolean get_prot_desc_entry(sdp_data_t *entry, int type, guint16 *val)
        sdp_data_t *iter;
        int proto;
 
-       if (entry == NULL || (entry->dtd != SDP_SEQ8 &&
-                       entry->dtd != SDP_SEQ16 && entry->dtd != SDP_SEQ32))
+       if (entry == NULL || !SDP_IS_SEQ(entry->dtd))
                return FALSE;
 
        iter = entry->val.dataseq;
@@ -919,8 +911,7 @@ static gboolean hdp_get_prot_desc_list(const sdp_record_t *rec, guint16 *psm,
                return TRUE;
 
        pdl = sdp_data_get(rec, SDP_ATTR_PROTO_DESC_LIST);
-       if (pdl == NULL || (pdl->dtd != SDP_SEQ8 && pdl->dtd != SDP_SEQ16 &&
-                                                       pdl->dtd != SDP_SEQ32))
+       if (pdl == NULL || !SDP_IS_SEQ(pdl->dtd))
                return FALSE;
 
        p0 = pdl->val.dataseq;
@@ -1043,7 +1034,6 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
        struct conn_mcl_data *conn_data = user_data;
        GError *gerr = NULL;
-       bdaddr_t dst;
        uint16_t ccpsm;
 
        if (conn_data->dev->hdp_adapter->mi == NULL) {
@@ -1066,10 +1056,10 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 
        conn_data = con_mcl_data_ref(conn_data);
 
-       device_get_address(conn_data->dev->dev, &dst, NULL);
-       if (!mcap_create_mcl(conn_data->dev->hdp_adapter->mi, &dst, ccpsm,
-                                               create_mcl_cb, conn_data,
-                                               destroy_con_mcl_data, &gerr)) {
+       if (!mcap_create_mcl(conn_data->dev->hdp_adapter->mi,
+                                       device_get_address(conn_data->dev->dev),
+                                       ccpsm, create_mcl_cb, conn_data,
+                                       destroy_con_mcl_data, &gerr)) {
                con_mcl_data_unref(conn_data);
                goto fail;
        }
@@ -1086,11 +1076,12 @@ gboolean hdp_establish_mcl(struct hdp_device *device,
                                                GError **err)
 {
        struct conn_mcl_data *conn_data;
-       bdaddr_t dst, src;
+       const bdaddr_t *src;
+       const bdaddr_t *dst;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst, NULL);
-       adapter_get_address(device_get_adapter(device->dev), &src);
+       src = adapter_get_address(device_get_adapter(device->dev));
+       dst = device_get_address(device->dev);
 
        conn_data = g_new0(struct conn_mcl_data, 1);
        conn_data->refs = 1;
@@ -1100,7 +1091,7 @@ gboolean hdp_establish_mcl(struct hdp_device *device,
        conn_data->dev = health_device_ref(device);
 
        bt_string2uuid(&uuid, HDP_UUID);
-       if (bt_search_service(&src, &dst, &uuid, search_cb, conn_data,
+       if (bt_search_service(src, dst, &uuid, search_cb, conn_data,
                                                destroy_con_mcl_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
@@ -1156,11 +1147,12 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
                                                        GError **err)
 {
        struct get_dcpsm_data *dcpsm_data;
-       bdaddr_t dst, src;
+       const bdaddr_t *src;
+       const bdaddr_t *dst;
        uuid_t uuid;
 
-       device_get_address(device->dev, &dst, NULL);
-       adapter_get_address(device_get_adapter(device->dev), &src);
+       src = adapter_get_address(device_get_adapter(device->dev));
+       dst = device_get_address(device->dev);
 
        dcpsm_data = g_new0(struct get_dcpsm_data, 1);
        dcpsm_data->func = func;
@@ -1168,7 +1160,7 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
        dcpsm_data->destroy = destroy;
 
        bt_string2uuid(&uuid, HDP_UUID);
-       if (bt_search_service(&src, &dst, &uuid, get_dcpsm_cb, dcpsm_data,
+       if (bt_search_service(src, dst, &uuid, get_dcpsm_cb, dcpsm_data,
                                                        free_dcpsm_data) < 0) {
                g_set_error(err, HDP_ERROR, HDP_CONNECTION_ERROR,
                                                "Can't get remote SDP record");
@@ -1182,10 +1174,9 @@ gboolean hdp_get_dcpsm(struct hdp_device *device, hdp_continue_dcpsm_f func,
 static void hdp_free_application(struct hdp_application *app)
 {
        if (app->dbus_watcher > 0)
-               g_dbus_remove_watch(app->conn, app->dbus_watcher);
+               g_dbus_remove_watch(btd_get_dbus_connection(),
+                                                       app->dbus_watcher);
 
-       if (app->conn != NULL)
-               dbus_connection_unref(app->conn);
        g_free(app->oname);
        g_free(app->description);
        g_free(app->path);
similarity index 100%
rename from health/hdp_util.h
rename to profiles/health/hdp_util.h
similarity index 98%
rename from health/mcap.c
rename to profiles/health/mcap.c
index b76d88a..6d821f3 100644 (file)
  *
  */
 
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
 #include <netinet/in.h>
 #include <stdlib.h>
 #include <errno.h>
@@ -30,7 +34,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 
-#include <btio.h>
+#include <btio/btio.h>
 #include <log.h>
 #include <error.h>
 
@@ -249,7 +253,7 @@ static void free_mdl(struct mcap_mdl *mdl)
        g_free(mdl);
 }
 
-static gint cmp_mdl_state(gconstpointer a, gconstpointer b)
+static int cmp_mdl_state(gconstpointer a, gconstpointer b)
 {
        const struct mcap_mdl *mdl = a;
        const MDLState *st = b;
@@ -429,7 +433,7 @@ static mcap_md_create_mdl_req *create_mdl_req(uint16_t mdl_id, uint8_t mdep,
        return req_mdl;
 }
 
-static gint compare_mdl(gconstpointer a, gconstpointer b)
+static int compare_mdl(gconstpointer a, gconstpointer b)
 {
        const struct mcap_mdl *mdla = a;
        const struct mcap_mdl *mdlb = b;
@@ -1270,7 +1274,7 @@ static gboolean check_err_rsp(struct mcap_mcl *mcl, mcap_rsp *rsp,
                                uint32_t rlen, uint32_t len, GError **gerr)
 {
        mcap_md_req *cmdlast = (mcap_md_req *) mcl->lcmd;
-       gint err = MCAP_ERROR_FAILED;
+       int err = MCAP_ERROR_FAILED;
        gboolean close = FALSE;
        char *msg;
 
@@ -1674,7 +1678,7 @@ gboolean mcap_connect_mdl(struct mcap_mdl *mdl, uint8_t mode,
        con->destroy = destroy;
        con->user_data = user_data;
 
-       mdl->dc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mdl_cb, con,
+       mdl->dc = bt_io_connect(mcap_connect_mdl_cb, con,
                                (GDestroyNotify) free_mcap_mdl_op, err,
                                BT_IO_OPT_SOURCE_BDADDR, &mdl->mcl->mi->src,
                                BT_IO_OPT_DEST_BDADDR, &mdl->mcl->addr,
@@ -1847,7 +1851,7 @@ gboolean mcap_create_mcl(struct mcap_instance *mi,
        con->destroy = destroy;
        con->user_data = user_data;
 
-       mcl->cc = bt_io_connect(BT_IO_L2CAP, mcap_connect_mcl_cb, con,
+       mcl->cc = bt_io_connect(mcap_connect_mcl_cb, con,
                                mcl_io_destroy, err,
                                BT_IO_OPT_SOURCE_BDADDR, &mi->src,
                                BT_IO_OPT_DEST_BDADDR, addr,
@@ -1883,9 +1887,7 @@ static void connect_dc_event_cb(GIOChannel *chan, GError *gerr,
        if (gerr)
                return;
 
-       bt_io_get(chan, BT_IO_L2CAP, &err,
-                       BT_IO_OPT_DEST_BDADDR, &dst,
-                       BT_IO_OPT_INVALID);
+       bt_io_get(chan, &err, BT_IO_OPT_DEST_BDADDR, &dst, BT_IO_OPT_INVALID);
        if (err) {
                error("%s", err->message);
                g_error_free(err);
@@ -1952,7 +1954,7 @@ static void connect_mcl_event_cb(GIOChannel *chan, GError *gerr,
        if (gerr)
                return;
 
-       bt_io_get(chan, BT_IO_L2CAP, &err,
+       bt_io_get(chan, &err,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_DEST, address,
                        BT_IO_OPT_INVALID);
@@ -1986,7 +1988,7 @@ drop:
        g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
-struct mcap_instance *mcap_create_instance(bdaddr_t *src,
+struct mcap_instance *mcap_create_instance(const bdaddr_t *src,
                                        BtIOSecLevel sec,
                                        uint16_t ccpsm,
                                        uint16_t dcpsm,
@@ -2028,7 +2030,7 @@ struct mcap_instance *mcap_create_instance(bdaddr_t *src,
        mi->csp_enabled = FALSE;
 
        /* Listen incoming connections in control channel */
-       mi->ccio = bt_io_listen(BT_IO_L2CAP, connect_mcl_event_cb, NULL, mi,
+       mi->ccio = bt_io_listen(connect_mcl_event_cb, NULL, mi,
                                NULL, gerr,
                                BT_IO_OPT_SOURCE_BDADDR, &mi->src,
                                BT_IO_OPT_PSM, ccpsm,
@@ -2043,7 +2045,7 @@ struct mcap_instance *mcap_create_instance(bdaddr_t *src,
        }
 
        /* Listen incoming connections in data channels */
-       mi->dcio = bt_io_listen(BT_IO_L2CAP, connect_dc_event_cb, NULL, mi,
+       mi->dcio = bt_io_listen(connect_dc_event_cb, NULL, mi,
                                NULL, gerr,
                                BT_IO_OPT_SOURCE_BDADDR, &mi->src,
                                BT_IO_OPT_PSM, dcpsm,
@@ -2133,9 +2135,7 @@ uint16_t mcap_get_ctrl_psm(struct mcap_instance *mi, GError **err)
                return 0;
        }
 
-       if (!bt_io_get(mi->ccio, BT_IO_L2CAP, err,
-                       BT_IO_OPT_PSM, &lpsm,
-                       BT_IO_OPT_INVALID))
+       if (!bt_io_get(mi->ccio, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID))
                return 0;
 
        return lpsm;
@@ -2151,9 +2151,7 @@ uint16_t mcap_get_data_psm(struct mcap_instance *mi, GError **err)
                return 0;
        }
 
-       if (!bt_io_get(mi->dcio, BT_IO_L2CAP, err,
-                       BT_IO_OPT_PSM, &lpsm,
-                       BT_IO_OPT_INVALID))
+       if (!bt_io_get(mi->dcio, err, BT_IO_OPT_PSM, &lpsm, BT_IO_OPT_INVALID))
                return 0;
 
        return lpsm;
@@ -2168,7 +2166,7 @@ gboolean mcap_set_data_chan_mode(struct mcap_instance *mi, uint8_t mode,
                return FALSE;
        }
 
-       return bt_io_set(mi->dcio, BT_IO_L2CAP, err, BT_IO_OPT_MODE, mode,
+       return bt_io_set(mi->dcio, err, BT_IO_OPT_MODE, mode,
                                                        BT_IO_OPT_INVALID);
 }
 
similarity index 99%
rename from health/mcap.h
rename to profiles/health/mcap.h
index 34a8382..1129e69 100644 (file)
@@ -35,7 +35,7 @@ extern "C" {
 
 /* maximum transmission unit for channels */
 #define MCAP_CC_MTU    48
-#define MCAP_DC_MTU    L2CAP_DEFAULT_MTU
+#define MCAP_DC_MTU    65535
 
 /* MCAP Standard Op Codes */
 #define MCAP_ERROR_RSP                 0x00
similarity index 97%
rename from health/mcap_internal.h
rename to profiles/health/mcap_internal.h
index 7b044ef..7191b23 100644 (file)
@@ -74,7 +74,7 @@ struct mcap_instance {
        mcap_mcl_event_cb       mcl_uncached_cb;        /* MCL has been removed from MCAP cache */
        mcap_info_ind_event_cb  mcl_sync_infoind_cb;    /* (CSP Master) Received info indication */
        gpointer                user_data;              /* Data to be provided in callbacks */
-       gint                    ref;                    /* Reference counter */
+       int                     ref;                    /* Reference counter */
 
        gboolean                csp_enabled;            /* CSP: functionality enabled */
 };
@@ -95,7 +95,7 @@ struct mcap_mcl {
        struct mcap_mdl_cb      *cb;            /* MDL callbacks */
        guint                   tid;            /* Timer id for waiting for a response */
        uint8_t                 *lcmd;          /* Last command sent */
-       gint                    ref;            /* References counter */
+       int                     ref;            /* References counter */
        uint8_t                 ctrl;           /* MCL control flag */
        uint16_t                next_mdl;       /* id used to create next MDL */
        struct mcap_csp         *csp;           /* CSP control structure */
@@ -115,7 +115,7 @@ struct mcap_mdl {
        uint16_t                mdlid;          /* MDL id */
        uint8_t                 mdep_id;        /* MCAP Data End Point */
        MDLState                state;          /* MDL state */
-       gint                    ref;            /* References counter */
+       int                     ref;            /* References counter */
 };
 
 struct sync_info_ind_data {
similarity index 99%
rename from health/mcap_lib.h
rename to profiles/health/mcap_lib.h
index 8fcc141..603ccc0 100644 (file)
@@ -196,7 +196,7 @@ void mcap_sync_set_req(struct mcap_mcl *mcl,
 
 /* MCAP main operations */
 
-struct mcap_instance *mcap_create_instance(bdaddr_t *src,
+struct mcap_instance *mcap_create_instance(const bdaddr_t *src,
                                        BtIOSecLevel sec, uint16_t ccpsm,
                                        uint16_t dcpsm,
                                        mcap_mcl_event_cb mcl_connected,
similarity index 99%
rename from health/mcap_sync.c
rename to profiles/health/mcap_sync.c
index 6d8d66b..0d9f17d 100644 (file)
@@ -34,8 +34,7 @@
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 #include <adapter.h>
-#include <manager.h>
-#include <btio.h>
+#include <btio/btio.h>
 #include <log.h>
 
 #include "mcap.h"
@@ -231,8 +230,7 @@ static gboolean read_btclock(struct mcap_mcl *mcl, uint32_t *btclock,
        int which = 1;
        struct btd_adapter *adapter;
 
-       adapter = manager_find_adapter(&mcl->mi->src);
-
+       adapter = adapter_find(&mcl->mi->src);
        if (!adapter)
                return FALSE;
 
diff --git a/profiles/heartrate/heartrate.c b/profiles/heartrate/heartrate.c
new file mode 100644 (file)
index 0000000..d87f0ff
--- /dev/null
@@ -0,0 +1,886 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012 Tieto Poland
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "dbus-common.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "error.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attio.h"
+#include "log.h"
+
+#define HEART_RATE_INTERFACE           "org.bluez.HeartRate1"
+#define HEART_RATE_MANAGER_INTERFACE   "org.bluez.HeartRateManager1"
+#define HEART_RATE_WATCHER_INTERFACE   "org.bluez.HeartRateWatcher1"
+
+#define HR_VALUE_FORMAT                0x01
+#define SENSOR_CONTACT_DETECTED        0x02
+#define SENSOR_CONTACT_SUPPORT 0x04
+#define ENERGY_EXP_STATUS      0x08
+#define RR_INTERVAL            0x10
+
+struct heartrate_adapter {
+       struct btd_adapter      *adapter;
+       GSList                  *devices;
+       GSList                  *watchers;
+};
+
+struct heartrate {
+       struct btd_device               *dev;
+       struct heartrate_adapter        *hradapter;
+       GAttrib                         *attrib;
+       guint                           attioid;
+       guint                           attionotid;
+
+       struct att_range                *svc_range;     /* primary svc range */
+
+       uint16_t                        measurement_ccc_handle;
+       uint16_t                        hrcp_val_handle;
+
+       gboolean                        has_location;
+       uint8_t                         location;
+};
+
+struct watcher {
+       struct heartrate_adapter        *hradapter;
+       guint                           id;
+       char                            *srv;
+       char                            *path;
+};
+
+struct measurement {
+       struct heartrate        *hr;
+       uint16_t                value;
+       gboolean                has_energy;
+       uint16_t                energy;
+       gboolean                has_contact;
+       gboolean                contact;
+       uint16_t                num_interval;
+       uint16_t                *interval;
+};
+
+static GSList *heartrate_adapters = NULL;
+
+static const char * const location_enum[] = {
+       "other",
+       "chest",
+       "wrist",
+       "finger",
+       "hand",
+       "earlobe",
+       "foot",
+};
+
+static const char *location2str(uint8_t value)
+{
+        if (value < G_N_ELEMENTS(location_enum))
+               return location_enum[value];
+
+       error("Body Sensor Location [%d] is RFU", value);
+
+       return NULL;
+}
+
+static int cmp_adapter(gconstpointer a, gconstpointer b)
+{
+       const struct heartrate_adapter *hradapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (adapter == hradapter->adapter)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct heartrate *hr = a;
+       const struct btd_device *dev = b;
+
+       if (dev == hr->dev)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_watcher(gconstpointer a, gconstpointer b)
+{
+       const struct watcher *watcher = a;
+       const struct watcher *match = b;
+       int ret;
+
+       ret = g_strcmp0(watcher->srv, match->srv);
+       if (ret != 0)
+               return ret;
+
+       return g_strcmp0(watcher->path, match->path);
+}
+
+static struct heartrate_adapter *
+find_heartrate_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(heartrate_adapters, adapter,
+                                                               cmp_adapter);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       g_free(watcher->path);
+       g_free(watcher->srv);
+       g_free(watcher);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+                                                       const char *path)
+{
+       struct watcher *match;
+       GSList *l;
+
+       match = g_new0(struct watcher, 1);
+       match->srv = g_strdup(sender);
+       match->path = g_strdup(path);
+
+       l = g_slist_find_custom(list, match, cmp_watcher);
+       destroy_watcher(match);
+
+       if (l != NULL)
+               return l->data;
+
+       return NULL;
+}
+
+static void destroy_heartrate(gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+
+       if (hr->attioid > 0)
+               btd_device_remove_attio_callback(hr->dev, hr->attioid);
+
+       if (hr->attrib != NULL) {
+               g_attrib_unregister(hr->attrib, hr->attionotid);
+               g_attrib_unref(hr->attrib);
+       }
+
+       btd_device_unref(hr->dev);
+       g_free(hr->svc_range);
+       g_free(hr);
+}
+
+static void remove_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+}
+
+static void destroy_heartrate_adapter(gpointer user_data)
+{
+       struct heartrate_adapter *hradapter = user_data;
+
+       g_slist_free_full(hradapter->watchers, remove_watcher);
+
+       g_free(hradapter);
+}
+
+static void read_sensor_location_cb(guint8 status, const guint8 *pdu,
+                                               guint16 len, gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+       uint8_t value;
+       ssize_t vlen;
+
+       if (status != 0) {
+               error("Body Sensor Location read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, &value, sizeof(value));
+       if (vlen < 0) {
+               error("Protocol error");
+               return;
+       }
+
+       if (vlen != sizeof(value)) {
+               error("Invalid length for Body Sensor Location");
+               return;
+       }
+
+       hr->has_location = TRUE;
+       hr->location = value;
+}
+
+static void char_write_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 update_watcher(gpointer data, gpointer user_data)
+{
+       struct watcher *w = data;
+       struct measurement *m = user_data;
+       struct heartrate *hr = m->hr;
+       const char *path = device_get_path(hr->dev);
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(w->srv, w->path,
+                       HEART_RATE_WATCHER_INTERFACE, "MeasurementReceived");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dict_append_entry(&dict, "Value", DBUS_TYPE_UINT16, &m->value);
+
+       if (m->has_energy)
+               dict_append_entry(&dict, "Energy", DBUS_TYPE_UINT16,
+                                                               &m->energy);
+
+       if (m->has_contact)
+               dict_append_entry(&dict, "Contact", DBUS_TYPE_BOOLEAN,
+                                                               &m->contact);
+
+       if (m->num_interval > 0)
+               dict_append_array(&dict, "Interval", DBUS_TYPE_UINT16,
+                                               &m->interval, m->num_interval);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void process_measurement(struct heartrate *hr, const uint8_t *pdu,
+                                                               uint16_t len)
+{
+       struct measurement m;
+       uint8_t flags;
+
+       flags = *pdu;
+
+       pdu++;
+       len--;
+
+       memset(&m, 0, sizeof(m));
+
+       if (flags & HR_VALUE_FORMAT) {
+               if (len < 2) {
+                       error("Heart Rate Measurement field missing");
+                       return;
+               }
+
+               m.value = att_get_u16(pdu);
+               pdu += 2;
+               len -= 2;
+       } else {
+               if (len < 1) {
+                       error("Heart Rate Measurement field missing");
+                       return;
+               }
+
+               m.value = *pdu;
+               pdu++;
+               len--;
+       }
+
+       if (flags & ENERGY_EXP_STATUS) {
+               if (len < 2) {
+                       error("Energy Expended field missing");
+                       return;
+               }
+
+               m.has_energy = TRUE;
+               m.energy = att_get_u16(pdu);
+               pdu += 2;
+               len -= 2;
+       }
+
+       if (flags & RR_INTERVAL) {
+               int i;
+
+               if (len == 0 || (len % 2 != 0)) {
+                       error("RR-Interval field malformed");
+                       return;
+               }
+
+               m.num_interval = len / 2;
+               m.interval = g_new(uint16_t, m.num_interval);
+
+               for (i = 0; i < m.num_interval; pdu += 2, i++)
+                       m.interval[i] = att_get_u16(pdu);
+       }
+
+       if (flags & SENSOR_CONTACT_SUPPORT) {
+               m.has_contact = TRUE;
+               m.contact = !!(flags & SENSOR_CONTACT_DETECTED);
+       }
+
+       /* Notify all registered watchers */
+       m.hr = hr;
+       g_slist_foreach(hr->hradapter->watchers, update_watcher, &m);
+
+       g_free(m.interval);
+}
+
+static void notify_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+
+       /* should be at least opcode (1b) + handle (2b) */
+       if (len < 3) {
+               error("Invalid PDU received");
+               return;
+       }
+
+       process_measurement(hr, pdu + 3, len - 3);
+}
+
+static void discover_ccc_cb(guint8 status, const guint8 *pdu,
+                                               guint16 len, gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+       struct att_data_list *list;
+       uint8_t format;
+       int i;
+
+       if (status != 0) {
+               error("Discover Heart Rate Measurement descriptors failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               return;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       for (i = 0; i < list->num; i++) {
+               uint8_t *value;
+               uint16_t handle, uuid;
+               char *msg;
+               uint8_t attr_val[2];
+
+               value = list->data[i];
+               handle = att_get_u16(value);
+               uuid = att_get_u16(value + 2);
+
+               if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
+                       continue;
+
+               hr->measurement_ccc_handle = handle;
+
+               if (g_slist_length(hr->hradapter->watchers) == 0) {
+                       att_put_u16(0x0000, attr_val);
+                       msg = g_strdup("Disable measurement");
+               } else {
+                       att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, attr_val);
+                       msg = g_strdup("Enable measurement");
+               }
+
+               gatt_write_char(hr->attrib, handle, attr_val,
+                                       sizeof(attr_val), char_write_cb, msg);
+
+               break;
+       }
+
+done:
+       att_data_list_free(list);
+}
+
+static void discover_measurement_ccc(struct heartrate *hr,
+                               struct gatt_char *c, struct gatt_char *c_next)
+{
+       uint16_t start, end;
+
+       start = c->value_handle + 1;
+
+       if (c_next != NULL) {
+               if (start == c_next->handle)
+                       return;
+               end = c_next->handle - 1;
+       } else if (c->value_handle != hr->svc_range->end) {
+               end = hr->svc_range->end;
+       } else {
+               return;
+       }
+
+       gatt_discover_char_desc(hr->attrib, start, end, discover_ccc_cb, hr);
+}
+
+static void discover_char_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+
+       if (status) {
+               error("Discover HRS characteristics failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       for (; chars; chars = chars->next) {
+               struct gatt_char *c = chars->data;
+
+               if (g_strcmp0(c->uuid, HEART_RATE_MEASUREMENT_UUID) == 0) {
+                       struct gatt_char *c_next =
+                               (chars->next ? chars->next->data : NULL);
+
+                       hr->attionotid = g_attrib_register(hr->attrib,
+                                               ATT_OP_HANDLE_NOTIFY,
+                                               c->value_handle,
+                                               notify_handler, hr, NULL);
+
+                       discover_measurement_ccc(hr, c, c_next);
+               } else if (g_strcmp0(c->uuid, BODY_SENSOR_LOCATION_UUID) == 0) {
+                       DBG("Body Sensor Location supported");
+
+                       gatt_read_char(hr->attrib, c->value_handle,
+                                               read_sensor_location_cb, hr);
+               } else if (g_strcmp0(c->uuid,
+                                       HEART_RATE_CONTROL_POINT_UUID) == 0) {
+                       DBG("Heart Rate Control Point supported");
+                       hr->hrcp_val_handle = c->value_handle;
+               }
+       }
+}
+
+static void enable_measurement(gpointer data, gpointer user_data)
+{
+       struct heartrate *hr = data;
+       uint16_t handle = hr->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (hr->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+       msg = g_strdup("Enable measurement");
+
+       gatt_write_char(hr->attrib, handle, value, sizeof(value),
+                                                       char_write_cb, msg);
+}
+
+static void disable_measurement(gpointer data, gpointer user_data)
+{
+       struct heartrate *hr = data;
+       uint16_t handle = hr->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (hr->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(0x0000, value);
+       msg = g_strdup("Disable measurement");
+
+       gatt_write_char(hr->attrib, handle, value, sizeof(value),
+                                                       char_write_cb, msg);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+
+       DBG("");
+
+       hr->attrib = g_attrib_ref(attrib);
+
+       gatt_discover_char(hr->attrib, hr->svc_range->start, hr->svc_range->end,
+                                               NULL, discover_char_cb, hr);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct heartrate *hr = user_data;
+
+       DBG("");
+
+       if (hr->attionotid > 0) {
+               g_attrib_unregister(hr->attrib, hr->attionotid);
+               hr->attionotid = 0;
+       }
+
+       g_attrib_unref(hr->attrib);
+       hr->attrib = NULL;
+}
+
+static void watcher_exit_cb(DBusConnection *conn, void *user_data)
+{
+       struct watcher *watcher = user_data;
+       struct heartrate_adapter *hradapter = watcher->hradapter;
+
+       DBG("heartrate watcher [%s] disconnected", watcher->path);
+
+       hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+       g_dbus_remove_watch(conn, watcher->id);
+
+       if (g_slist_length(hradapter->watchers) == 0)
+               g_slist_foreach(hradapter->devices, disable_measurement, 0);
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct heartrate_adapter *hradapter = data;
+       struct watcher *watcher;
+       const char *sender = dbus_message_get_sender(msg);
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(hradapter->watchers, sender, path);
+       if (watcher != NULL)
+               return btd_error_already_exists(msg);
+
+       watcher = g_new0(struct watcher, 1);
+       watcher->hradapter = hradapter;
+       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit_cb,
+                                               watcher, destroy_watcher);
+       watcher->srv = g_strdup(sender);
+       watcher->path = g_strdup(path);
+
+       if (g_slist_length(hradapter->watchers) == 0)
+               g_slist_foreach(hradapter->devices, enable_measurement, 0);
+
+       hradapter->watchers = g_slist_prepend(hradapter->watchers, watcher);
+
+       DBG("heartrate watcher [%s] registered", path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct heartrate_adapter *hradapter = data;
+       struct watcher *watcher;
+       const char *sender = dbus_message_get_sender(msg);
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(hradapter->watchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       hradapter->watchers = g_slist_remove(hradapter->watchers, watcher);
+       g_dbus_remove_watch(conn, watcher->id);
+
+       if (g_slist_length(hradapter->watchers) == 0)
+               g_slist_foreach(hradapter->devices, disable_measurement, 0);
+
+       DBG("heartrate watcher [%s] unregistered", path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_manager_methods[] = {
+       { GDBUS_METHOD("RegisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       register_watcher) },
+       { GDBUS_METHOD("UnregisterWatcher",
+                       GDBUS_ARGS({ "agent", "o" }), NULL,
+                       unregister_watcher) },
+       { }
+};
+
+static gboolean property_get_location(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct heartrate *hr = data;
+       char *loc;
+
+       if (!hr->has_location)
+               return FALSE;
+
+       loc = g_strdup(location2str(hr->location));
+
+       if (loc == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &loc);
+
+       g_free(loc);
+
+       return TRUE;
+}
+
+static gboolean property_exists_location(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct heartrate *hr = data;
+
+       if (!hr->has_location || location2str(hr->location) == NULL)
+               return FALSE;
+
+       return TRUE;
+}
+
+static gboolean property_get_reset_supported(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct heartrate *hr = data;
+       dbus_bool_t has_reset = !!hr->hrcp_val_handle;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &has_reset);
+
+       return TRUE;
+}
+
+static DBusMessage *hrcp_reset(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct heartrate *hr = data;
+       uint8_t value;
+       char *vmsg;
+
+       if (!hr->hrcp_val_handle)
+               return btd_error_not_supported(msg);
+
+       if (!hr->attrib)
+               return btd_error_not_available(msg);
+
+       value = 0x01;
+       vmsg = g_strdup("Reset Control Point");
+       gatt_write_char(hr->attrib, hr->hrcp_val_handle, &value,
+                                       sizeof(value), char_write_cb, vmsg);
+
+       DBG("Energy Expended Value has been reset");
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable heartrate_device_methods[] = {
+       { GDBUS_METHOD("Reset", NULL, NULL, hrcp_reset) },
+       { }
+};
+
+static const GDBusPropertyTable heartrate_device_properties[] = {
+       { "Location", "s", property_get_location, NULL,
+                                               property_exists_location },
+       { "ResetSupported", "b", property_get_reset_supported },
+       { }
+};
+
+static int heartrate_adapter_register(struct btd_adapter *adapter)
+{
+       struct heartrate_adapter *hradapter;
+
+       hradapter = g_new0(struct heartrate_adapter, 1);
+       hradapter->adapter = adapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               HEART_RATE_MANAGER_INTERFACE,
+                                               heartrate_manager_methods,
+                                               NULL, NULL, hradapter,
+                                               destroy_heartrate_adapter)) {
+               error("D-Bus failed to register %s interface",
+                                               HEART_RATE_MANAGER_INTERFACE);
+               destroy_heartrate_adapter(hradapter);
+               return -EIO;
+       }
+
+       heartrate_adapters = g_slist_prepend(heartrate_adapters, hradapter);
+
+       return 0;
+}
+
+static void heartrate_adapter_unregister(struct btd_adapter *adapter)
+{
+       struct heartrate_adapter *hradapter;
+
+       hradapter = find_heartrate_adapter(adapter);
+       if (hradapter == NULL)
+               return;
+
+       heartrate_adapters = g_slist_remove(heartrate_adapters, hradapter);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(hradapter->adapter),
+                                       HEART_RATE_MANAGER_INTERFACE);
+}
+
+static int heartrate_device_register(struct btd_device *device,
+                                               struct gatt_primary *prim)
+{
+       struct btd_adapter *adapter;
+       struct heartrate_adapter *hradapter;
+       struct heartrate *hr;
+
+       adapter = device_get_adapter(device);
+
+       hradapter = find_heartrate_adapter(adapter);
+
+       if (hradapter == NULL)
+               return -1;
+
+       hr = g_new0(struct heartrate, 1);
+       hr->dev = btd_device_ref(device);
+       hr->hradapter = hradapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               device_get_path(device),
+                                               HEART_RATE_INTERFACE,
+                                               heartrate_device_methods,
+                                               NULL,
+                                               heartrate_device_properties,
+                                               hr, destroy_heartrate)) {
+               error("D-Bus failed to register %s interface",
+                                               HEART_RATE_INTERFACE);
+               destroy_heartrate(hr);
+               return -EIO;
+       }
+
+       hr->svc_range = g_new0(struct att_range, 1);
+       hr->svc_range->start = prim->range.start;
+       hr->svc_range->end = prim->range.end;
+
+       hradapter->devices = g_slist_prepend(hradapter->devices, hr);
+
+       hr->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+                                               attio_disconnected_cb, hr);
+
+       return 0;
+}
+
+static void heartrate_device_unregister(struct btd_device *device)
+{
+       struct btd_adapter *adapter;
+       struct heartrate_adapter *hradapter;
+       struct heartrate *hr;
+       GSList *l;
+
+       adapter = device_get_adapter(device);
+
+       hradapter = find_heartrate_adapter(adapter);
+       if (hradapter == NULL)
+               return;
+
+       l = g_slist_find_custom(hradapter->devices, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       hr = l->data;
+
+       hradapter->devices = g_slist_remove(hradapter->devices, hr);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                               device_get_path(device), HEART_RATE_INTERFACE);
+}
+
+static int heartrate_adapter_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       return heartrate_adapter_register(adapter);
+}
+
+static void heartrate_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       heartrate_adapter_unregister(adapter);
+}
+
+static int heartrate_device_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *prim;
+
+       prim = btd_device_get_primary(device, HEART_RATE_UUID);
+       if (prim == NULL)
+               return -EINVAL;
+
+       return heartrate_device_register(device, prim);
+}
+
+static void heartrate_device_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       heartrate_device_unregister(device);
+}
+
+static struct btd_profile hrp_profile = {
+       .name           = "Heart Rate GATT Driver",
+       .remote_uuid    = HEART_RATE_UUID,
+
+       .device_probe   = heartrate_device_probe,
+       .device_remove  = heartrate_device_remove,
+
+       .adapter_probe  = heartrate_adapter_probe,
+       .adapter_remove = heartrate_adapter_remove,
+};
+
+static int heartrate_init(void)
+{
+       return btd_profile_register(&hrp_profile);
+}
+
+static void heartrate_exit(void)
+{
+       btd_profile_unregister(&hrp_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(heartrate, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       heartrate_init, heartrate_exit)
diff --git a/profiles/iap/main.c b/profiles/iap/main.c
new file mode 100644 (file)
index 0000000..0e8f43f
--- /dev/null
@@ -0,0 +1,465 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  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 <signal.h>
+#include <sys/signalfd.h>
+
+#include <glib.h>
+#include <gdbus.h>
+
+#define IAP_PATH "/org/bluez/iap"
+
+#define IAP_UUID "00000000-deca-fade-deca-deafdecacafe"
+
+#define IAP_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"%s\" />                   \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0002\">                               \
+                       <uint32 value=\"0x00000000\" />                 \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0006\">                               \
+                       <sequence>                                      \
+                               <uint16 value=\"0x656e\" />             \
+                               <uint16 value=\"0x006a\" />             \
+                               <uint16 value=\"0x0100\" />             \
+                               <uint16 value=\"0x6672\" />             \
+                               <uint16 value=\"0x006a\" />             \
+                               <uint16 value=\"0x0110\" />             \
+                               <uint16 value=\"0x6465\" />             \
+                               <uint16 value=\"0x006a\" />             \
+                               <uint16 value=\"0x0120\" />             \
+                               <uint16 value=\"0x6a61\" />             \
+                               <uint16 value=\"0x006a\" />             \
+                               <uint16 value=\"0x0130\" />             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0008\">                               \
+                       <uint8 value=\"0xff\" />                        \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1101\" />       \
+                                       <uint16 value=\"0x0100\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"Wireless iAP\" />                 \
+               </attribute>                                            \
+       </record>"
+
+static GMainLoop *main_loop;
+
+static guint iap_source = 0;
+
+static gboolean iap_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       unsigned char buf[512];
+       ssize_t len;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               iap_source = 0;
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0) {
+               iap_source = 0;
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static guint create_source(int fd, GIOFunc func)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL, func, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static void remove_source(const char *path)
+{
+       if (iap_source > 0) {
+               g_source_remove(iap_source);
+               iap_source = 0;
+       }
+}
+
+static DBusMessage *release_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       g_print("Profile released\n");
+
+       remove_source(IAP_PATH);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *new_connection(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *path, *device;
+       int fd;
+
+       g_print("New connection\n");
+
+       path = dbus_message_get_path(msg);
+
+       dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &device,
+                               DBUS_TYPE_UNIX_FD, &fd, DBUS_TYPE_INVALID);
+
+       g_print("  from %s\n", path);
+       g_print("  for device %s with fd %d\n", device, fd);
+
+       if (iap_source == 0)
+               iap_source = create_source(fd, iap_handler);
+       else
+               close(fd);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_disconnection(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       DBusMessageIter iter;
+       const char *path, *device;
+
+       g_print("Request disconnection\n");
+
+       path = dbus_message_get_path(msg);
+
+       dbus_message_iter_init(msg, &iter);
+       dbus_message_iter_get_basic(&iter, &device);
+
+       g_print("  from %s\n", path);
+       g_print("  for device %s\n", device);
+
+       remove_source(path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *cancel_request(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *path;
+
+       g_print("Request canceled\n");
+
+       path = dbus_message_get_path(msg);
+
+       g_print("  from %s\n", path);
+
+       remove_source(path);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+       { GDBUS_METHOD("Release", NULL, NULL, release_profile) },
+       { GDBUS_METHOD("NewConnection",
+                       GDBUS_ARGS({ "device", "o" },
+                                       { "fd", "h"}, { "opts", "a{sv}"}),
+                       NULL, new_connection) },
+       { GDBUS_METHOD("RequestDisconnection",
+                       GDBUS_ARGS({ "device", "o" }),
+                       NULL, request_disconnection) },
+       { GDBUS_METHOD("Cancel", NULL, NULL, cancel_request) },
+       { }
+};
+
+static void register_profile_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = IAP_PATH;
+       const char *uuid = IAP_UUID;
+       DBusMessageIter dict, entry, value;
+       dbus_uint16_t channel;
+       char *record;
+       const char *str;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                               DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                               DBUS_TYPE_STRING_AS_STRING
+                               DBUS_TYPE_VARIANT_AS_STRING
+                               DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+       str = "Role";
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+                                       DBUS_TYPE_STRING_AS_STRING, &value);
+       str = "server";
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &str);
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(&dict, &entry);
+
+       dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+       str = "Channel";
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+                                       DBUS_TYPE_UINT16_AS_STRING, &value);
+       channel = 23;
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_UINT16, &channel);
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(&dict, &entry);
+
+       dbus_message_iter_open_container(&dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+       str = "ServiceRecord";
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &str);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT,
+                                       DBUS_TYPE_STRING_AS_STRING, &value);
+       record = g_strdup_printf(IAP_RECORD, IAP_UUID, channel);
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &record);
+       g_free(record);
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(&dict, &entry);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void register_profile_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               g_print("Failed to register profile\n");
+               return;
+       }
+
+       g_print("Profile registered\n");
+}
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       GDBusClient *client = user_data;
+       GDBusProxy *proxy;
+
+       g_print("Bluetooth connected\n");
+
+       proxy = g_dbus_proxy_new(client, "/org/bluez",
+                                       "org.bluez.ProfileManager1");
+       if (!proxy)
+               return;
+
+       g_dbus_register_interface(connection, IAP_PATH,
+                                       "org.bluez.Profile1",
+                                       methods, NULL, NULL, NULL, NULL);
+
+       g_dbus_proxy_method_call(proxy, "RegisterProfile", 
+                                       register_profile_setup,
+                                       register_profile_reply, NULL, NULL);
+
+       g_dbus_proxy_unref(proxy);
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       g_print("Bluetooth disconnected\n");
+
+       g_dbus_unregister_interface(connection, IAP_PATH,
+                                               "org.bluez.Profile1");
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+       case SIGTERM:
+               if (__terminated == 0)
+                       g_main_loop_quit(main_loop);
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { NULL },
+};
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       DBusConnection *dbus_conn;
+       GDBusClient *client;
+       guint signal;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               g_print("%s\n", VERSION);
+               exit(0);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+       dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+       signal = setup_signalfd();
+
+       client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+       g_dbus_client_set_connect_watch(client, connect_handler, client);
+       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+
+       g_main_loop_run(main_loop);
+
+       g_dbus_client_unref(client);
+
+       g_source_remove(signal);
+
+       dbus_connection_unref(dbus_conn);
+       g_main_loop_unref(main_loop);
+
+       return 0;
+}
diff --git a/profiles/input/device.c b/profiles/input/device.c
new file mode 100644 (file)
index 0000000..6523161
--- /dev/null
@@ -0,0 +1,990 @@
+/*
+ *
+ *  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 <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hidp.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+
+#include "lib/uuid.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+#include "../src/profile.h"
+#include "../src/service.h"
+#include "../src/storage.h"
+#include "../src/dbus-common.h"
+
+#include "device.h"
+#include "error.h"
+#include <btio/btio.h>
+
+#include "sdp-client.h"
+
+#define INPUT_INTERFACE "org.bluez.Input1"
+
+enum reconnect_mode_t {
+       RECONNECT_NONE = 0,
+       RECONNECT_DEVICE,
+       RECONNECT_HOST,
+       RECONNECT_ANY
+};
+
+struct input_device {
+       struct btd_service      *service;
+       struct btd_device       *device;
+       char                    *path;
+       bdaddr_t                src;
+       bdaddr_t                dst;
+       uint32_t                handle;
+       GIOChannel              *ctrl_io;
+       GIOChannel              *intr_io;
+       guint                   ctrl_watch;
+       guint                   intr_watch;
+       guint                   sec_watch;
+       struct hidp_connadd_req *req;
+       guint                   dc_id;
+       bool                    disable_sdp;
+       char                    *name;
+       enum reconnect_mode_t   reconnect_mode;
+       guint                   reconnect_timer;
+       uint32_t                reconnect_attempt;
+};
+
+static int idle_timeout = 0;
+
+void input_set_idle_timeout(int timeout)
+{
+       idle_timeout = timeout;
+}
+
+static void input_device_enter_reconnect_mode(struct input_device *idev);
+
+static void input_device_free(struct input_device *idev)
+{
+       if (idev->dc_id)
+               device_remove_disconnect_watch(idev->device, idev->dc_id);
+
+       btd_service_unref(idev->service);
+       btd_device_unref(idev->device);
+       g_free(idev->name);
+       g_free(idev->path);
+
+       if (idev->ctrl_watch > 0)
+               g_source_remove(idev->ctrl_watch);
+
+       if (idev->intr_watch > 0)
+               g_source_remove(idev->intr_watch);
+
+       if (idev->sec_watch > 0)
+               g_source_remove(idev->sec_watch);
+
+       if (idev->intr_io)
+               g_io_channel_unref(idev->intr_io);
+
+       if (idev->ctrl_io)
+               g_io_channel_unref(idev->ctrl_io);
+
+       if (idev->req) {
+               g_free(idev->req->rd_data);
+               g_free(idev->req);
+       }
+
+       if (idev->reconnect_timer > 0)
+               g_source_remove(idev->reconnect_timer);
+
+       g_free(idev);
+}
+
+static gboolean intr_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+       struct input_device *idev = data;
+       char address[18];
+
+       ba2str(&idev->dst, address);
+
+       DBG("Device %s disconnected", address);
+
+       /* Checking for ctrl_watch avoids a double g_io_channel_shutdown since
+        * it's likely that ctrl_watch_cb has been queued for dispatching in
+        * this mainloop iteration */
+       if ((cond & (G_IO_HUP | G_IO_ERR)) && idev->ctrl_watch)
+               g_io_channel_shutdown(chan, TRUE, NULL);
+
+       device_remove_disconnect_watch(idev->device, idev->dc_id);
+       idev->dc_id = 0;
+
+       idev->intr_watch = 0;
+
+       if (idev->intr_io) {
+               g_io_channel_unref(idev->intr_io);
+               idev->intr_io = NULL;
+       }
+
+       /* Close control channel */
+       if (idev->ctrl_io && !(cond & G_IO_NVAL))
+               g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
+
+       btd_service_disconnecting_complete(idev->service, 0);
+
+       /* Enter the auto-reconnect mode if needed */
+       input_device_enter_reconnect_mode(idev);
+
+       return FALSE;
+}
+
+static gboolean ctrl_watch_cb(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+       struct input_device *idev = data;
+       char address[18];
+
+       ba2str(&idev->dst, address);
+
+       DBG("Device %s disconnected", address);
+
+       /* Checking for intr_watch avoids a double g_io_channel_shutdown since
+        * it's likely that intr_watch_cb has been queued for dispatching in
+        * this mainloop iteration */
+       if ((cond & (G_IO_HUP | G_IO_ERR)) && idev->intr_watch)
+               g_io_channel_shutdown(chan, TRUE, NULL);
+
+       idev->ctrl_watch = 0;
+
+       if (idev->ctrl_io) {
+               g_io_channel_unref(idev->ctrl_io);
+               idev->ctrl_io = NULL;
+       }
+
+       /* Close interrupt channel */
+       if (idev->intr_io && !(cond & G_IO_NVAL))
+               g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
+
+       return FALSE;
+}
+
+static void epox_endian_quirk(unsigned char *data, int size)
+{
+       /* USAGE_PAGE (Keyboard)        05 07
+        * USAGE_MINIMUM (0)            19 00
+        * USAGE_MAXIMUM (65280)        2A 00 FF   <= must be FF 00
+        * LOGICAL_MINIMUM (0)          15 00
+        * LOGICAL_MAXIMUM (65280)      26 00 FF   <= must be FF 00
+        */
+       unsigned char pattern[] = { 0x05, 0x07, 0x19, 0x00, 0x2a, 0x00, 0xff,
+                                               0x15, 0x00, 0x26, 0x00, 0xff };
+       unsigned int i;
+
+       if (!data)
+               return;
+
+       for (i = 0; i < size - sizeof(pattern); i++) {
+               if (!memcmp(data + i, pattern, sizeof(pattern))) {
+                       data[i + 5] = 0xff;
+                       data[i + 6] = 0x00;
+                       data[i + 10] = 0xff;
+                       data[i + 11] = 0x00;
+               }
+       }
+}
+
+static int create_hid_dev_name(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+       char sdesc[sizeof(req->name)];
+
+       if (sdp_get_service_desc(rec, sdesc, sizeof(sdesc)) == 0) {
+               char pname[sizeof(req->name)];
+
+               if (sdp_get_provider_name(rec, pname, sizeof(pname)) == 0 &&
+                                               strncmp(sdesc, pname, 5) != 0)
+                       snprintf(req->name, sizeof(req->name), "%s %s", pname,
+                                                                       sdesc);
+               else
+                       snprintf(req->name, sizeof(req->name), "%s", sdesc);
+       } else {
+               return sdp_get_service_name(rec, req->name, sizeof(req->name));
+       }
+
+       return 0;
+}
+
+/* See HID profile specification v1.0, "7.11.6 HIDDescriptorList" for details
+ * on the attribute format. */
+static int extract_hid_desc_data(sdp_record_t *rec,
+                                               struct hidp_connadd_req *req)
+{
+       sdp_data_t *d;
+
+       d = sdp_data_get(rec, SDP_ATTR_HID_DESCRIPTOR_LIST);
+       if (!d)
+               goto invalid_desc;
+
+       if (!SDP_IS_SEQ(d->dtd))
+               goto invalid_desc;
+
+       /* First HIDDescriptor */
+       d = d->val.dataseq;
+       if (!SDP_IS_SEQ(d->dtd))
+               goto invalid_desc;
+
+       /* ClassDescriptorType */
+       d = d->val.dataseq;
+       if (d->dtd != SDP_UINT8)
+               goto invalid_desc;
+
+       /* ClassDescriptorData */
+       d = d->next;
+       if (!d || !SDP_IS_TEXT_STR(d->dtd))
+               goto invalid_desc;
+
+       req->rd_data = g_try_malloc0(d->unitSize);
+       if (req->rd_data) {
+               memcpy(req->rd_data, d->val.str, d->unitSize);
+               req->rd_size = d->unitSize;
+               epox_endian_quirk(req->rd_data, req->rd_size);
+       }
+
+       return 0;
+
+invalid_desc:
+       error("Missing or invalid HIDDescriptorList SDP attribute");
+       return -EINVAL;
+}
+
+static int extract_hid_record(sdp_record_t *rec, struct hidp_connadd_req *req)
+{
+       sdp_data_t *pdlist;
+       uint8_t attr_val;
+       int err;
+
+       err = create_hid_dev_name(rec, req);
+       if (err < 0)
+               DBG("No valid Service Name or Service Description found");
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_PARSER_VERSION);
+       req->parser = pdlist ? pdlist->val.uint16 : 0x0100;
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_DEVICE_SUBCLASS);
+       req->subclass = pdlist ? pdlist->val.uint8 : 0;
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_COUNTRY_CODE);
+       req->country = pdlist ? pdlist->val.uint8 : 0;
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_VIRTUAL_CABLE);
+       attr_val = pdlist ? pdlist->val.uint8 : 0;
+       if (attr_val)
+               req->flags |= (1 << HIDP_VIRTUAL_CABLE_UNPLUG);
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_BOOT_DEVICE);
+       attr_val = pdlist ? pdlist->val.uint8 : 0;
+       if (attr_val)
+               req->flags |= (1 << HIDP_BOOT_PROTOCOL_MODE);
+
+       err = extract_hid_desc_data(rec, req);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int ioctl_connadd(struct hidp_connadd_req *req)
+{
+       int ctl, err = 0;
+
+       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+       if (ctl < 0)
+               return -errno;
+
+       if (ioctl(ctl, HIDPCONNADD, req) < 0)
+               err = -errno;
+
+       close(ctl);
+
+       return err;
+}
+
+static gboolean encrypt_notify(GIOChannel *io, GIOCondition condition,
+                                                               gpointer data)
+{
+       struct input_device *idev = data;
+       int err;
+
+       DBG("");
+
+       err = ioctl_connadd(idev->req);
+       if (err < 0) {
+               error("ioctl_connadd(): %s (%d)", strerror(-err), -err);
+
+               if (idev->ctrl_io) {
+                       g_io_channel_shutdown(idev->ctrl_io, FALSE, NULL);
+                       g_io_channel_unref(idev->ctrl_io);
+                       idev->ctrl_io = NULL;
+               }
+
+               if (idev->intr_io) {
+                       g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
+                       g_io_channel_unref(idev->intr_io);
+                       idev->intr_io = NULL;
+               }
+       }
+
+       idev->sec_watch = 0;
+
+       g_free(idev->req->rd_data);
+       g_free(idev->req);
+       idev->req = NULL;
+
+       return FALSE;
+}
+
+static int hidp_add_connection(struct input_device *idev)
+{
+       struct hidp_connadd_req *req;
+       sdp_record_t *rec;
+       char src_addr[18], dst_addr[18];
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char handle[11], *str;
+       GError *gerr = NULL;
+       int err;
+
+       req = g_new0(struct hidp_connadd_req, 1);
+       req->ctrl_sock = g_io_channel_unix_get_fd(idev->ctrl_io);
+       req->intr_sock = g_io_channel_unix_get_fd(idev->intr_io);
+       req->flags     = 0;
+       req->idle_to   = idle_timeout;
+
+       ba2str(&idev->src, src_addr);
+       ba2str(&idev->dst, dst_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", src_addr,
+                                                               dst_addr);
+       filename[PATH_MAX] = '\0';
+       sprintf(handle, "0x%8.8X", idev->handle);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       str = g_key_file_get_string(key_file, "ServiceRecords", handle, NULL);
+       g_key_file_free(key_file);
+
+       if (!str) {
+               error("Rejected connection from unknown device %s", dst_addr);
+               err = -EPERM;
+               goto cleanup;
+       }
+
+       rec = record_from_string(str);
+       g_free(str);
+
+       err = extract_hid_record(rec, req);
+       sdp_record_free(rec);
+       if (err < 0) {
+               error("Could not parse HID SDP record: %s (%d)", strerror(-err),
+                                                                       -err);
+               goto cleanup;
+       }
+
+       req->vendor = btd_device_get_vendor(idev->device);
+       req->product = btd_device_get_product(idev->device);
+       req->version = btd_device_get_version(idev->device);
+
+       if (idev->name)
+               strncpy(req->name, idev->name, sizeof(req->name) - 1);
+
+       /* Encryption is mandatory for keyboards */
+       if (req->subclass & 0x40) {
+               if (!bt_io_set(idev->intr_io, &gerr,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
+                                       BT_IO_OPT_INVALID)) {
+                       error("btio: %s", gerr->message);
+                       g_error_free(gerr);
+                       err = -EFAULT;
+                       goto cleanup;
+               }
+
+               idev->req = req;
+               idev->sec_watch = g_io_add_watch(idev->intr_io, G_IO_OUT,
+                                                       encrypt_notify, idev);
+
+               return 0;
+       }
+
+       err = ioctl_connadd(req);
+
+cleanup:
+       g_free(req->rd_data);
+       g_free(req);
+
+       return err;
+}
+
+static int is_connected(struct input_device *idev)
+{
+       struct hidp_conninfo ci;
+       int ctl;
+
+       /* Standard HID */
+       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+       if (ctl < 0)
+               return 0;
+
+       memset(&ci, 0, sizeof(ci));
+       bacpy(&ci.bdaddr, &idev->dst);
+       if (ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) {
+               close(ctl);
+               return 0;
+       }
+
+       close(ctl);
+
+       if (ci.state != BT_CONNECTED)
+               return 0;
+       else
+               return 1;
+}
+
+static int connection_disconnect(struct input_device *idev, uint32_t flags)
+{
+       struct hidp_conndel_req req;
+       struct hidp_conninfo ci;
+       int ctl, err = 0;
+
+       if (!is_connected(idev))
+               return -ENOTCONN;
+
+       /* Standard HID disconnect */
+       if (idev->intr_io)
+               g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
+       if (idev->ctrl_io)
+               g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
+
+       ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HIDP);
+       if (ctl < 0) {
+               error("Can't open HIDP control socket");
+               return -errno;
+       }
+
+       memset(&ci, 0, sizeof(ci));
+       bacpy(&ci.bdaddr, &idev->dst);
+       if ((ioctl(ctl, HIDPGETCONNINFO, &ci) < 0) ||
+                               (ci.state != BT_CONNECTED)) {
+               err = -ENOTCONN;
+               goto fail;
+       }
+
+       memset(&req, 0, sizeof(req));
+       bacpy(&req.bdaddr, &idev->dst);
+       req.flags = flags;
+       if (ioctl(ctl, HIDPCONNDEL, &req) < 0) {
+               err = -errno;
+               error("Can't delete the HID device: %s(%d)",
+                               strerror(-err), -err);
+               goto fail;
+       }
+
+fail:
+       close(ctl);
+
+       return err;
+}
+
+static void disconnect_cb(struct btd_device *device, gboolean removal,
+                               void *user_data)
+{
+       struct input_device *idev = user_data;
+       int flags;
+
+       info("Input: disconnect %s", idev->path);
+
+       flags = removal ? (1 << HIDP_VIRTUAL_CABLE_UNPLUG) : 0;
+
+       connection_disconnect(idev, flags);
+}
+
+static int input_device_connected(struct input_device *idev)
+{
+       int err;
+
+       if (idev->intr_io == NULL || idev->ctrl_io == NULL)
+               return -ENOTCONN;
+
+       err = hidp_add_connection(idev);
+       if (err < 0)
+               return err;
+
+       idev->dc_id = device_add_disconnect_watch(idev->device, disconnect_cb,
+                                                       idev, NULL);
+
+       btd_service_connecting_complete(idev->service, 0);
+
+       return 0;
+}
+
+static void interrupt_connect_cb(GIOChannel *chan, GError *conn_err,
+                                                       gpointer user_data)
+{
+       struct input_device *idev = user_data;
+       int err;
+
+       if (conn_err) {
+               err = -EIO;
+               goto failed;
+       }
+
+       err = input_device_connected(idev);
+       if (err < 0)
+               goto failed;
+
+       idev->intr_watch = g_io_add_watch(idev->intr_io,
+                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                       intr_watch_cb, idev);
+
+       return;
+
+failed:
+       btd_service_connecting_complete(idev->service, err);
+
+       /* So we guarantee the interrupt channel is closed before the
+        * control channel (if we only do unref GLib will close it only
+        * after returning control to the mainloop */
+       if (!conn_err)
+               g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
+
+       g_io_channel_unref(idev->intr_io);
+       idev->intr_io = NULL;
+
+       if (idev->ctrl_io) {
+               g_io_channel_unref(idev->ctrl_io);
+               idev->ctrl_io = NULL;
+       }
+}
+
+static void control_connect_cb(GIOChannel *chan, GError *conn_err,
+                                                       gpointer user_data)
+{
+       struct input_device *idev = user_data;
+       GIOChannel *io;
+       GError *err = NULL;
+
+       if (conn_err) {
+               error("%s", conn_err->message);
+               goto failed;
+       }
+
+       /* Connect to the HID interrupt channel */
+       io = bt_io_connect(interrupt_connect_cb, idev,
+                               NULL, &err,
+                               BT_IO_OPT_SOURCE_BDADDR, &idev->src,
+                               BT_IO_OPT_DEST_BDADDR, &idev->dst,
+                               BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
+                               BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                               BT_IO_OPT_INVALID);
+       if (!io) {
+               error("%s", err->message);
+               g_error_free(err);
+               goto failed;
+       }
+
+       idev->intr_io = io;
+
+       idev->ctrl_watch = g_io_add_watch(idev->ctrl_io,
+                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                       ctrl_watch_cb, idev);
+
+       return;
+
+failed:
+       btd_service_connecting_complete(idev->service, -EIO);
+       g_io_channel_unref(idev->ctrl_io);
+       idev->ctrl_io = NULL;
+}
+
+static int dev_connect(struct input_device *idev)
+{
+       GError *err = NULL;
+       GIOChannel *io;
+
+       if (idev->disable_sdp)
+               bt_clear_cached_session(&idev->src, &idev->dst);
+
+       io = bt_io_connect(control_connect_cb, idev,
+                       NULL, &err,
+                       BT_IO_OPT_SOURCE_BDADDR, &idev->src,
+                       BT_IO_OPT_DEST_BDADDR, &idev->dst,
+                       BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
+                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                       BT_IO_OPT_INVALID);
+       idev->ctrl_io = io;
+
+       if (err == NULL)
+               return 0;
+
+       error("%s", err->message);
+       g_error_free(err);
+
+       return -EIO;
+}
+
+static gboolean input_device_auto_reconnect(gpointer user_data)
+{
+       struct input_device *idev = user_data;
+
+       DBG("path=%s, attempt=%d", idev->path, idev->reconnect_attempt);
+
+       /* Stop the recurrent reconnection attempts if the device is reconnected
+        * or is marked for removal. */
+       if (device_is_temporary(idev->device) ||
+                                       device_is_connected(idev->device))
+               return FALSE;
+
+       /* Only attempt an auto-reconnect for at most 3 minutes (6 * 30s). */
+       if (idev->reconnect_attempt >= 6)
+               return FALSE;
+
+       /* Check if the profile is already connected. */
+       if (idev->ctrl_io)
+               return FALSE;
+
+       if (is_connected(idev))
+               return FALSE;
+
+       idev->reconnect_attempt++;
+       dev_connect(idev);
+
+       return TRUE;
+}
+
+static const char * const _reconnect_mode_str[] = {
+       "none",
+       "device",
+       "host",
+       "any"
+};
+
+static const char *reconnect_mode_to_string(const enum reconnect_mode_t mode)
+{
+       return _reconnect_mode_str[mode];
+}
+
+static void input_device_enter_reconnect_mode(struct input_device *idev)
+{
+       DBG("path=%s reconnect_mode=%s", idev->path,
+                               reconnect_mode_to_string(idev->reconnect_mode));
+
+       /* Only attempt an auto-reconnect when the device is required to accept
+        * reconnections from the host. */
+       if (idev->reconnect_mode != RECONNECT_ANY &&
+                               idev->reconnect_mode != RECONNECT_HOST)
+               return;
+
+       /* If the device is temporary we are not required to reconnect with the
+        * device. This is likely the case of a removing device. */
+       if (device_is_temporary(idev->device) ||
+                                       device_is_connected(idev->device))
+               return;
+
+       if (idev->reconnect_timer > 0)
+               g_source_remove(idev->reconnect_timer);
+
+       DBG("registering auto-reconnect");
+       idev->reconnect_attempt = 0;
+       idev->reconnect_timer = g_timeout_add_seconds(30,
+                                       input_device_auto_reconnect, idev);
+
+}
+
+int input_device_connect(struct btd_service *service)
+{
+       struct input_device *idev;
+
+       DBG("");
+
+       idev = btd_service_get_user_data(service);
+
+       if (idev->ctrl_io)
+               return -EBUSY;
+
+       if (is_connected(idev))
+               return -EALREADY;
+
+       return dev_connect(idev);
+}
+
+int input_device_disconnect(struct btd_service *service)
+{
+       struct input_device *idev;
+       int err;
+
+       DBG("");
+
+       idev = btd_service_get_user_data(service);
+
+       err = connection_disconnect(idev, 0);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static bool 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;
+}
+
+static enum reconnect_mode_t hid_reconnection_mode(bool reconnect_initiate,
+                                               bool normally_connectable)
+{
+       if (!reconnect_initiate && !normally_connectable)
+               return RECONNECT_NONE;
+       else if (!reconnect_initiate && normally_connectable)
+               return RECONNECT_HOST;
+       else if (reconnect_initiate && !normally_connectable)
+               return RECONNECT_DEVICE;
+       else /* (reconnect_initiate && normally_connectable) */
+               return RECONNECT_ANY;
+}
+
+static void extract_hid_props(struct input_device *idev,
+                                       const sdp_record_t *rec)
+{
+       /* Extract HID connectability */
+       bool reconnect_initiate, normally_connectable;
+       sdp_data_t *pdlist;
+
+       /* HIDNormallyConnectable is optional and assumed FALSE
+       * if not present. */
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_RECONNECT_INITIATE);
+       reconnect_initiate = pdlist ? pdlist->val.uint8 : TRUE;
+
+       pdlist = sdp_data_get(rec, SDP_ATTR_HID_NORMALLY_CONNECTABLE);
+       normally_connectable = pdlist ? pdlist->val.uint8 : FALSE;
+
+       /* Update local values */
+       idev->reconnect_mode =
+               hid_reconnection_mode(reconnect_initiate, normally_connectable);
+}
+
+static struct input_device *input_device_new(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct btd_profile *p = btd_service_get_profile(service);
+       const char *path = device_get_path(device);
+       const sdp_record_t *rec = btd_device_get_record(device, p->remote_uuid);
+       struct btd_adapter *adapter = device_get_adapter(device);
+       struct input_device *idev;
+       char name[HCI_MAX_NAME_LENGTH + 1];
+
+       idev = g_new0(struct input_device, 1);
+       bacpy(&idev->src, adapter_get_address(adapter));
+       bacpy(&idev->dst, device_get_address(device));
+       idev->service = btd_service_ref(service);
+       idev->device = btd_device_ref(device);
+       idev->path = g_strdup(path);
+       idev->handle = rec->handle;
+       idev->disable_sdp = is_device_sdp_disable(rec);
+
+       device_get_name(device, name, HCI_MAX_NAME_LENGTH);
+       if (strlen(name) > 0)
+               idev->name = g_strdup(name);
+
+       /* Initialize device properties */
+       extract_hid_props(idev, rec);
+
+       return idev;
+}
+
+static gboolean property_get_reconnect_mode(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct input_device *idev = data;
+       const char *str_mode = reconnect_mode_to_string(idev->reconnect_mode);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str_mode);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable input_properties[] = {
+       { "ReconnectMode", "s", property_get_reconnect_mode },
+       { }
+};
+
+int input_device_register(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       const char *path = device_get_path(device);
+       struct input_device *idev;
+
+       DBG("%s", path);
+
+       idev = input_device_new(service);
+       if (!idev)
+               return -EINVAL;
+
+       if (g_dbus_register_interface(btd_get_dbus_connection(),
+                                       idev->path, INPUT_INTERFACE,
+                                       NULL, NULL,
+                                       input_properties, idev,
+                                       NULL) == FALSE) {
+               error("Unable to register %s interface", INPUT_INTERFACE);
+               input_device_free(idev);
+               return -EINVAL;
+       }
+
+       btd_service_set_user_data(service, idev);
+
+       return 0;
+}
+
+static struct input_device *find_device(const bdaddr_t *src,
+                                       const bdaddr_t *dst)
+{
+       struct btd_device *device;
+       struct btd_service *service;
+
+       device = adapter_find_device(adapter_find(src), dst);
+       if (device == NULL)
+               return NULL;
+
+       service = btd_device_get_service(device, HID_UUID);
+       if (service == NULL)
+               return NULL;
+
+       return btd_service_get_user_data(service);
+}
+
+void input_device_unregister(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       const char *path = device_get_path(device);
+       struct input_device *idev = btd_service_get_user_data(service);
+
+       DBG("%s", path);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               idev->path, INPUT_INTERFACE);
+
+       input_device_free(idev);
+}
+
+static int input_device_connadd(struct input_device *idev)
+{
+       int err;
+
+       err = input_device_connected(idev);
+       if (err < 0)
+               goto error;
+
+       return 0;
+
+error:
+       if (idev->ctrl_io) {
+               g_io_channel_shutdown(idev->ctrl_io, FALSE, NULL);
+               g_io_channel_unref(idev->ctrl_io);
+               idev->ctrl_io = NULL;
+       }
+       if (idev->intr_io) {
+               g_io_channel_shutdown(idev->intr_io, FALSE, NULL);
+               g_io_channel_unref(idev->intr_io);
+               idev->intr_io = NULL;
+       }
+
+       return err;
+}
+
+bool input_device_exists(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       if (find_device(src, dst))
+               return true;
+
+       return false;
+}
+
+int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
+                                                               GIOChannel *io)
+{
+       struct input_device *idev = find_device(src, dst);
+
+       DBG("idev %p psm %d", idev, psm);
+
+       if (!idev)
+               return -ENOENT;
+
+       switch (psm) {
+       case L2CAP_PSM_HIDP_CTRL:
+               if (idev->ctrl_io)
+                       return -EALREADY;
+               idev->ctrl_io = g_io_channel_ref(io);
+               idev->ctrl_watch = g_io_add_watch(idev->ctrl_io,
+                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                       ctrl_watch_cb, idev);
+               break;
+       case L2CAP_PSM_HIDP_INTR:
+               if (idev->intr_io)
+                       return -EALREADY;
+               idev->intr_io = g_io_channel_ref(io);
+               idev->intr_watch = g_io_add_watch(idev->intr_io,
+                                       G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                       intr_watch_cb, idev);
+               break;
+       }
+
+       if (idev->intr_io && idev->ctrl_io)
+               input_device_connadd(idev);
+
+       return 0;
+}
+
+int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst)
+{
+       struct input_device *idev = find_device(src, dst);
+
+       if (!idev)
+               return -ENOENT;
+
+       if (idev->intr_io)
+               g_io_channel_shutdown(idev->intr_io, TRUE, NULL);
+
+       if (idev->ctrl_io)
+               g_io_channel_shutdown(idev->ctrl_io, TRUE, NULL);
+
+       return 0;
+}
similarity index 62%
rename from input/device.h
rename to profiles/input/device.h
index 509a353..da2149c 100644 (file)
 struct input_device;
 struct input_conn;
 
-struct fake_input {
-       int             flags;
-       GIOChannel      *io;
-       int             uinput;         /* uinput socket */
-       int             rfcomm;         /* RFCOMM socket */
-       uint8_t         ch;             /* RFCOMM channel number */
-       gboolean        (*connect) (struct input_conn *iconn, GError **err);
-       int             (*disconnect) (struct input_conn *iconn);
-       void            *priv;
-       const struct input_device *idev;
-};
+void input_set_idle_timeout(int timeout);
 
-int fake_input_register(DBusConnection *conn, struct btd_device *device,
-                       const char *path, const char *uuid, uint8_t channel);
-int input_device_register(DBusConnection *conn, struct btd_device *device,
-                                       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_register(struct btd_service *service);
+void input_device_unregister(struct btd_service *service);
 
+bool input_device_exists(const bdaddr_t *src, const bdaddr_t *dst);
 int input_device_set_channel(const bdaddr_t *src, const bdaddr_t *dst, int psm,
                                                        GIOChannel *io);
 int input_device_close_channels(const bdaddr_t *src, const bdaddr_t *dst);
+
+int input_device_connect(struct btd_service *service);
+int input_device_disconnect(struct btd_service *service);
diff --git a/profiles/input/hog.c b/profiles/input/hog.c
new file mode 100644 (file)
index 0000000..4647fef
--- /dev/null
@@ -0,0 +1,941 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012  Nordic Semiconductor Inc.
+ *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include "uhid_copy.h"
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#include "lib/uuid.h"
+#include "src/adapter.h"
+#include "src/device.h"
+#include "src/profile.h"
+#include "src/service.h"
+
+#include "plugin.h"
+#include "suspend.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attio.h"
+#include "attrib/gatt.h"
+
+#define HOG_UUID               "00001812-0000-1000-8000-00805f9b34fb"
+
+#define HOG_INFO_UUID          0x2A4A
+#define HOG_REPORT_MAP_UUID    0x2A4B
+#define HOG_REPORT_UUID                0x2A4D
+#define HOG_PROTO_MODE_UUID    0x2A4E
+#define HOG_CONTROL_POINT_UUID 0x2A4C
+
+#define HOG_REPORT_TYPE_INPUT  1
+#define HOG_REPORT_TYPE_OUTPUT 2
+#define HOG_REPORT_TYPE_FEATURE        3
+
+#define HOG_PROTO_MODE_BOOT    0
+#define HOG_PROTO_MODE_REPORT  1
+
+#define UHID_DEVICE_FILE       "/dev/uhid"
+
+#define HOG_REPORT_MAP_MAX_SIZE        512
+#define HID_INFO_SIZE                  4
+
+struct hog_device {
+       uint16_t                id;
+       struct btd_device       *device;
+       GAttrib                 *attrib;
+       guint                   attioid;
+       struct gatt_primary     *hog_primary;
+       GSList                  *reports;
+       int                     uhid_fd;
+       gboolean                has_report_id;
+       guint                   uhid_watch_id;
+       uint16_t                bcdhid;
+       uint8_t                 bcountrycode;
+       uint16_t                proto_mode_handle;
+       uint16_t                ctrlpt_handle;
+       uint8_t                 flags;
+};
+
+struct report {
+       uint8_t                 id;
+       uint8_t                 type;
+       guint                   notifyid;
+       struct gatt_char        *decl;
+       struct hog_device       *hogdev;
+};
+
+struct disc_desc_cb_data {
+       uint16_t end;
+       gpointer data;
+};
+
+static gboolean suspend_supported = FALSE;
+static GSList *devices = NULL;
+
+static void report_value_cb(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct report *report = user_data;
+       struct hog_device *hogdev = report->hogdev;
+       struct uhid_event ev;
+       uint16_t report_size = len - 3;
+       uint8_t *buf;
+
+       if (len < 3) { /* 1-byte opcode + 2-byte handle */
+               error("Malformed ATT notification");
+               return;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_INPUT;
+       ev.u.input.size = MIN(report_size, UHID_DATA_MAX);
+
+       buf = ev.u.input.data;
+       if (hogdev->has_report_id) {
+               *buf = report->id;
+               buf++;
+               ev.u.input.size++;
+       }
+
+       memcpy(buf, &pdu[3], MIN(report_size, UHID_DATA_MAX));
+
+       if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+               error("uHID write failed: %s", strerror(errno));
+       else
+               DBG("Report from HoG device 0x%04X written to uHID fd %d",
+                                               hogdev->id, hogdev->uhid_fd);
+}
+
+static void report_ccc_written_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data)
+{
+       struct report *report = user_data;
+       struct hog_device *hogdev = report->hogdev;
+
+       if (status != 0) {
+               error("Write report characteristic descriptor failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       report->notifyid = g_attrib_register(hogdev->attrib,
+                                       ATT_OP_HANDLE_NOTIFY,
+                                       report->decl->value_handle,
+                                       report_value_cb, report, NULL);
+
+       DBG("Report characteristic descriptor written: notifications enabled");
+}
+
+static void write_ccc(uint16_t handle, gpointer user_data)
+{
+       struct report *report = user_data;
+       struct hog_device *hogdev = report->hogdev;
+       uint8_t value[] = { 0x01, 0x00 };
+
+       gatt_write_char(hogdev->attrib, handle, value, sizeof(value),
+                                       report_ccc_written_cb, report);
+}
+
+static void report_reference_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data)
+{
+       struct report *report = user_data;
+
+       if (status != 0) {
+               error("Read Report Reference descriptor failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (plen != 3) {
+               error("Malformed ATT read response");
+               return;
+       }
+
+       report->id = pdu[1];
+       report->type = pdu[2];
+       DBG("Report ID: 0x%02x Report type: 0x%02x", pdu[1], pdu[2]);
+}
+
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data);
+
+
+static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
+                                       guint16 len, gpointer user_data)
+{
+       struct disc_desc_cb_data *ddcb_data = user_data;
+       struct report *report;
+       struct hog_device *hogdev;
+       struct att_data_list *list = NULL;
+       GAttrib *attrib = NULL;
+       uint8_t format;
+       uint16_t handle = 0xffff;
+       uint16_t end = ddcb_data->end;
+       int i;
+
+       if (status == ATT_ECODE_ATTR_NOT_FOUND) {
+               DBG("Discover all characteristic descriptors finished");
+               goto done;
+       }
+
+       if (status != 0) {
+               error("Discover all characteristic descriptors failed: %s",
+                                                       att_ecode2str(status));
+               goto done;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               return;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       for (i = 0; i < list->num; i++) {
+               uint16_t uuid16;
+               uint8_t *value;
+
+               value = list->data[i];
+               handle = att_get_u16(value);
+               uuid16 = att_get_u16(&value[2]);
+
+               switch (uuid16) {
+               case GATT_CLIENT_CHARAC_CFG_UUID:
+                       report = ddcb_data->data;
+                       attrib = report->hogdev->attrib;
+                       write_ccc(handle, report);
+                       break;
+               case GATT_REPORT_REFERENCE:
+                       report = ddcb_data->data;
+                       attrib = report->hogdev->attrib;
+                       gatt_read_char(attrib, handle,
+                                               report_reference_cb, report);
+                       break;
+               case GATT_EXTERNAL_REPORT_REFERENCE:
+                       hogdev = ddcb_data->data;
+                       attrib = hogdev->attrib;
+                       gatt_read_char(attrib, handle,
+                                       external_report_reference_cb, hogdev);
+                       break;
+               }
+       }
+
+done:
+       att_data_list_free(list);
+
+       if (handle != 0xffff && handle < end)
+               gatt_discover_char_desc(attrib, handle + 1, end,
+                                       discover_descriptor_cb, ddcb_data);
+       else
+               g_free(ddcb_data);
+}
+
+static void discover_descriptor(GAttrib *attrib, uint16_t start, uint16_t end,
+                                                       gpointer user_data)
+{
+       struct disc_desc_cb_data *ddcb_data;
+
+       if (start > end)
+               return;
+
+       ddcb_data = g_new0(struct disc_desc_cb_data, 1);
+       ddcb_data->end = end;
+       ddcb_data->data = user_data;
+
+       gatt_discover_char_desc(attrib, start, end, discover_descriptor_cb,
+                                                               ddcb_data);
+}
+
+static void external_service_char_cb(GSList *chars, guint8 status,
+                                                       gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       struct gatt_primary *prim = hogdev->hog_primary;
+       struct report *report;
+       GSList *l;
+
+       if (status != 0) {
+               const char *str = att_ecode2str(status);
+               DBG("Discover external service characteristic failed: %s", str);
+               return;
+       }
+
+       for (l = chars; l; l = g_slist_next(l)) {
+               struct gatt_char *chr, *next;
+               uint16_t start, end;
+
+               chr = l->data;
+               next = l->next ? l->next->data : NULL;
+
+               DBG("0x%04x UUID: %s properties: %02x",
+                               chr->handle, chr->uuid, chr->properties);
+
+               report = g_new0(struct report, 1);
+               report->hogdev = hogdev;
+               report->decl = g_memdup(chr, sizeof(*chr));
+               hogdev->reports = g_slist_append(hogdev->reports, report);
+               start = chr->value_handle + 1;
+               end = (next ? next->handle - 1 : prim->range.end);
+               discover_descriptor(hogdev->attrib, start, end, report);
+       }
+}
+
+static void external_report_reference_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       uint16_t uuid16;
+       bt_uuid_t uuid;
+
+       if (status != 0) {
+               error("Read External Report Reference descriptor failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       if (plen != 3) {
+               error("Malformed ATT read response");
+               return;
+       }
+
+       uuid16 = att_get_u16(&pdu[1]);
+       DBG("External report reference read, external report characteristic "
+                                               "UUID: 0x%04x", uuid16);
+       bt_uuid16_create(&uuid, uuid16);
+       gatt_discover_char(hogdev->attrib, 0x00, 0xff, &uuid,
+                                       external_service_char_cb, hogdev);
+}
+
+static void report_map_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       uint8_t value[HOG_REPORT_MAP_MAX_SIZE];
+       struct uhid_event ev;
+       uint16_t vendor_src, vendor, product, version;
+       ssize_t vlen;
+       int i;
+
+       if (status != 0) {
+               error("Report Map read failed: %s", att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       if (vlen < 0) {
+               error("ATT protocol error");
+               return;
+       }
+
+       DBG("Report MAP:");
+       for (i = 0; i < vlen; i++) {
+               switch (value[i]) {
+               case 0x85:
+               case 0x86:
+               case 0x87:
+                       hogdev->has_report_id = TRUE;
+               }
+
+               if (i % 2 == 0) {
+                       if (i + 1 == vlen)
+                               DBG("\t %02x", value[i]);
+                       else
+                               DBG("\t %02x %02x", value[i], value[i + 1]);
+               }
+       }
+
+       vendor_src = btd_device_get_vendor_src(hogdev->device);
+       vendor = btd_device_get_vendor(hogdev->device);
+       product = btd_device_get_product(hogdev->device);
+       version = btd_device_get_version(hogdev->device);
+       DBG("DIS information: vendor_src=0x%X, vendor=0x%X, product=0x%X, "
+                       "version=0x%X", vendor_src, vendor, product, version);
+
+       /* create uHID device */
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_CREATE;
+       strcpy((char *) ev.u.create.name, "bluez-hog-device");
+       ev.u.create.vendor = vendor;
+       ev.u.create.product = product;
+       ev.u.create.version = version;
+       ev.u.create.country = hogdev->bcountrycode;
+       ev.u.create.bus = BUS_BLUETOOTH;
+       ev.u.create.rd_data = value;
+       ev.u.create.rd_size = vlen;
+
+       if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+               error("Failed to create uHID device: %s", strerror(errno));
+}
+
+static void info_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       uint8_t value[HID_INFO_SIZE];
+       ssize_t vlen;
+
+       if (status != 0) {
+               error("HID Information read failed: %s",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       if (vlen != 4) {
+               error("ATT protocol error");
+               return;
+       }
+
+       hogdev->bcdhid = att_get_u16(&value[0]);
+       hogdev->bcountrycode = value[2];
+       hogdev->flags = value[3];
+
+       DBG("bcdHID: 0x%04X bCountryCode: 0x%02X Flags: 0x%02X",
+                       hogdev->bcdhid, hogdev->bcountrycode, hogdev->flags);
+}
+
+static void proto_mode_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
+                                                       gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       uint8_t value;
+       ssize_t vlen;
+
+       if (status != 0) {
+               error("Protocol Mode characteristic read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, plen, &value, sizeof(value));
+       if (vlen < 0) {
+               error("ATT protocol error");
+               return;
+       }
+
+       if (value == HOG_PROTO_MODE_BOOT) {
+               uint8_t nval = HOG_PROTO_MODE_REPORT;
+
+               DBG("HoG device 0x%04X is operating in Boot Procotol Mode",
+                                                               hogdev->id);
+
+               gatt_write_cmd(hogdev->attrib, hogdev->proto_mode_handle, &nval,
+                                               sizeof(nval), NULL, NULL);
+       } else if (value == HOG_PROTO_MODE_REPORT)
+               DBG("HoG device 0x%04X is operating in Report Protocol Mode",
+                                                               hogdev->id);
+}
+
+static void char_discovered_cb(GSList *chars, guint8 status, gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       struct gatt_primary *prim = hogdev->hog_primary;
+       bt_uuid_t report_uuid, report_map_uuid, info_uuid;
+       bt_uuid_t proto_mode_uuid, ctrlpt_uuid;
+       struct report *report;
+       GSList *l;
+       uint16_t info_handle = 0, proto_mode_handle = 0;
+
+       if (status != 0) {
+               const char *str = att_ecode2str(status);
+               DBG("Discover all characteristics failed: %s", str);
+               return;
+       }
+
+       bt_uuid16_create(&report_uuid, HOG_REPORT_UUID);
+       bt_uuid16_create(&report_map_uuid, HOG_REPORT_MAP_UUID);
+       bt_uuid16_create(&info_uuid, HOG_INFO_UUID);
+       bt_uuid16_create(&proto_mode_uuid, HOG_PROTO_MODE_UUID);
+       bt_uuid16_create(&ctrlpt_uuid, HOG_CONTROL_POINT_UUID);
+
+       for (l = chars; l; l = g_slist_next(l)) {
+               struct gatt_char *chr, *next;
+               bt_uuid_t uuid;
+               uint16_t start, end;
+
+               chr = l->data;
+               next = l->next ? l->next->data : NULL;
+
+               DBG("0x%04x UUID: %s properties: %02x",
+                               chr->handle, chr->uuid, chr->properties);
+
+               bt_string_to_uuid(&uuid, chr->uuid);
+
+               start = chr->value_handle + 1;
+               end = (next ? next->handle - 1 : prim->range.end);
+
+               if (bt_uuid_cmp(&uuid, &report_uuid) == 0) {
+                       report = g_new0(struct report, 1);
+                       report->hogdev = hogdev;
+                       report->decl = g_memdup(chr, sizeof(*chr));
+                       hogdev->reports = g_slist_append(hogdev->reports,
+                                                               report);
+                       discover_descriptor(hogdev->attrib, start, end, report);
+               } else if (bt_uuid_cmp(&uuid, &report_map_uuid) == 0) {
+                       gatt_read_char(hogdev->attrib, chr->value_handle,
+                                               report_map_read_cb, hogdev);
+                       discover_descriptor(hogdev->attrib, start, end, hogdev);
+               } else if (bt_uuid_cmp(&uuid, &info_uuid) == 0)
+                       info_handle = chr->value_handle;
+               else if (bt_uuid_cmp(&uuid, &proto_mode_uuid) == 0)
+                       proto_mode_handle = chr->value_handle;
+               else if (bt_uuid_cmp(&uuid, &ctrlpt_uuid) == 0)
+                       hogdev->ctrlpt_handle = chr->value_handle;
+       }
+
+       if (proto_mode_handle) {
+               hogdev->proto_mode_handle = proto_mode_handle;
+               gatt_read_char(hogdev->attrib, proto_mode_handle,
+                                               proto_mode_read_cb, hogdev);
+       }
+
+       if (info_handle)
+               gatt_read_char(hogdev->attrib, info_handle, info_read_cb,
+                                                                       hogdev);
+}
+
+static void output_written_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data)
+{
+       if (status != 0) {
+               error("Write output report failed: %s", att_ecode2str(status));
+               return;
+       }
+}
+
+static int report_type_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct report *report = a;
+       uint8_t type = GPOINTER_TO_UINT(b);
+
+       return report->type - type;
+}
+
+static void forward_report(struct hog_device *hogdev,
+                                               struct uhid_event *ev)
+{
+       struct report *report;
+       GSList *l;
+       void *data;
+       int size;
+       guint type;
+
+       if (hogdev->has_report_id) {
+               data = ev->u.output.data + 1;
+               size = ev->u.output.size - 1;
+       } else {
+               data = ev->u.output.data;
+               size = ev->u.output.size;
+       }
+
+       switch (ev->type) {
+       case UHID_OUTPUT:
+               type = HOG_REPORT_TYPE_OUTPUT;
+               break;
+       case UHID_FEATURE:
+               type = HOG_REPORT_TYPE_FEATURE;
+               break;
+       default:
+               return;
+       }
+
+       l = g_slist_find_custom(hogdev->reports, GUINT_TO_POINTER(type),
+                                                       report_type_cmp);
+       if (!l)
+               return;
+
+       report = l->data;
+
+       DBG("Sending report type %d to device 0x%04X handle 0x%X", type,
+                               hogdev->id, report->decl->value_handle);
+
+       if (hogdev->attrib == NULL)
+               return;
+
+       if (report->decl->properties & ATT_CHAR_PROPER_WRITE)
+               gatt_write_char(hogdev->attrib, report->decl->value_handle,
+                               data, size, output_written_cb, hogdev);
+       else if (report->decl->properties & ATT_CHAR_PROPER_WRITE_WITHOUT_RESP)
+               gatt_write_cmd(hogdev->attrib, report->decl->value_handle,
+                                               data, size, NULL, NULL);
+}
+
+static gboolean uhid_event_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       struct uhid_event ev;
+       ssize_t bread;
+       int fd;
+
+       if (cond & (G_IO_ERR | G_IO_NVAL))
+               goto failed;
+
+       fd = g_io_channel_unix_get_fd(io);
+       memset(&ev, 0, sizeof(ev));
+
+       bread = read(fd, &ev, sizeof(ev));
+       if (bread < 0) {
+               int err = -errno;
+               DBG("uhid-dev read: %s(%d)", strerror(-err), -err);
+               goto failed;
+       }
+
+       DBG("uHID event type %d received", ev.type);
+
+       switch (ev.type) {
+       case UHID_START:
+       case UHID_STOP:
+               /* These are called to start and stop the underlying hardware.
+                * For HoG we open the channels before creating the device so
+                * the hardware is always ready. No need to handle these.
+                * Note that these are also called when the kernel switches
+                * between device-drivers loaded on the HID device. But we can
+                * simply keep the hardware alive during transitions and it
+                * works just fine.
+                * The kernel never destroys a device itself! Only an explicit
+                * UHID_DESTROY request can remove a device. */
+               break;
+       case UHID_OPEN:
+       case UHID_CLOSE:
+               /* OPEN/CLOSE are sent whenever user-space opens any interface
+                * provided by the kernel HID device. Whenever the open-count
+                * is non-zero we must be ready for I/O. As long as it is zero,
+                * we can decide to drop all I/O and put the device
+                * asleep This is optional, though. Moreover, some
+                * special device drivers are buggy in that regard, so
+                * maybe we just keep I/O always awake like HIDP in the
+                * kernel does. */
+               break;
+       case UHID_OUTPUT:
+       case UHID_FEATURE:
+               forward_report(hogdev, &ev);
+               break;
+       case UHID_OUTPUT_EV:
+               /* This is only sent by kernels prior to linux-3.11. It
+                * requires us to parse HID-descriptors in user-space to
+                * properly handle it. This is redundant as the kernel
+                * does it already. That's why newer kernels assemble
+                * the output-reports and send it to us via UHID_OUTPUT.
+                * We never implemented this, so we rely on users to use
+                * recent-enough kernels if they want this feature. No reason
+                * to implement this for older kernels. */
+               DBG("Unsupported uHID output event: type %d code %d value %d",
+                       ev.u.output_ev.type, ev.u.output_ev.code,
+                       ev.u.output_ev.value);
+               break;
+       default:
+               warn("unexpected uHID event");
+               break;
+       }
+
+       return TRUE;
+
+failed:
+       hogdev->uhid_watch_id = 0;
+       return FALSE;
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       struct gatt_primary *prim = hogdev->hog_primary;
+       GSList *l;
+
+       DBG("HoG connected");
+
+       hogdev->attrib = g_attrib_ref(attrib);
+
+       if (hogdev->reports == NULL) {
+               gatt_discover_char(hogdev->attrib, prim->range.start,
+                                               prim->range.end, NULL,
+                                               char_discovered_cb, hogdev);
+               return;
+       }
+
+       for (l = hogdev->reports; l; l = l->next) {
+               struct report *r = l->data;
+
+               r->notifyid = g_attrib_register(hogdev->attrib,
+                                       ATT_OP_HANDLE_NOTIFY,
+                                       r->decl->value_handle,
+                                       report_value_cb, r, NULL);
+       }
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct hog_device *hogdev = user_data;
+       GSList *l;
+
+       DBG("HoG disconnected");
+
+       for (l = hogdev->reports; l; l = l->next) {
+               struct report *r = l->data;
+
+               g_attrib_unregister(hogdev->attrib, r->notifyid);
+       }
+
+       g_attrib_unref(hogdev->attrib);
+       hogdev->attrib = NULL;
+}
+
+static struct hog_device *hog_new_device(struct btd_device *device,
+                                                               uint16_t id)
+{
+       struct hog_device *hogdev;
+
+       hogdev = g_try_new0(struct hog_device, 1);
+       if (!hogdev)
+               return NULL;
+
+       hogdev->id = id;
+       hogdev->device = btd_device_ref(device);
+
+       return hogdev;
+}
+
+static void report_free(void *data)
+{
+       struct report *report = data;
+       struct hog_device *hogdev = report->hogdev;
+
+       if (hogdev->attrib)
+               g_attrib_unregister(hogdev->attrib, report->notifyid);
+
+       g_free(report->decl);
+       g_free(report);
+}
+
+static void hog_free_device(struct hog_device *hogdev)
+{
+       btd_device_unref(hogdev->device);
+       g_slist_free_full(hogdev->reports, report_free);
+       g_attrib_unref(hogdev->attrib);
+       g_free(hogdev->hog_primary);
+       g_free(hogdev);
+}
+
+static struct hog_device *hog_register_device(struct btd_device *device,
+                                               struct gatt_primary *prim)
+{
+       struct hog_device *hogdev;
+       GIOCondition cond = G_IO_IN | G_IO_ERR | G_IO_NVAL;
+       GIOChannel *io;
+
+       hogdev = hog_new_device(device, prim->range.start);
+       if (!hogdev)
+               return NULL;
+
+       hogdev->uhid_fd = open(UHID_DEVICE_FILE, O_RDWR | O_CLOEXEC);
+       if (hogdev->uhid_fd < 0) {
+               error("Failed to open uHID device: %s(%d)", strerror(errno),
+                                                                       errno);
+               hog_free_device(hogdev);
+               return NULL;
+       }
+
+       io = g_io_channel_unix_new(hogdev->uhid_fd);
+       g_io_channel_set_encoding(io, NULL, NULL);
+       hogdev->uhid_watch_id = g_io_add_watch(io, cond, uhid_event_cb,
+                                                               hogdev);
+       g_io_channel_unref(io);
+
+       hogdev->hog_primary = g_memdup(prim, sizeof(*prim));
+
+       hogdev->attioid = btd_device_add_attio_callback(device,
+                                                       attio_connected_cb,
+                                                       attio_disconnected_cb,
+                                                       hogdev);
+
+       return hogdev;
+}
+
+static int hog_unregister_device(struct hog_device *hogdev)
+{
+       struct uhid_event ev;
+
+       btd_device_remove_attio_callback(hogdev->device, hogdev->attioid);
+
+       if (hogdev->uhid_watch_id) {
+               g_source_remove(hogdev->uhid_watch_id);
+               hogdev->uhid_watch_id = 0;
+       }
+
+       memset(&ev, 0, sizeof(ev));
+       ev.type = UHID_DESTROY;
+       if (write(hogdev->uhid_fd, &ev, sizeof(ev)) < 0)
+               error("Failed to destroy uHID device: %s", strerror(errno));
+
+       close(hogdev->uhid_fd);
+       hogdev->uhid_fd = -1;
+
+       hog_free_device(hogdev);
+
+       return 0;
+}
+
+static int set_control_point(struct hog_device *hogdev, gboolean suspend)
+{
+       uint8_t value = suspend ? 0x00 : 0x01;
+
+       if (hogdev->attrib == NULL)
+               return -ENOTCONN;
+
+       DBG("0x%4X HID Control Point: %s", hogdev->id, suspend ?
+                                               "Suspend" : "Exit Suspend");
+
+       if (hogdev->ctrlpt_handle == 0)
+               return -ENOTSUP;
+
+       gatt_write_cmd(hogdev->attrib, hogdev->ctrlpt_handle, &value,
+                                       sizeof(value), NULL, NULL);
+
+       return 0;
+}
+
+static void set_suspend(gpointer data, gpointer user_data)
+{
+       struct hog_device *hogdev = data;
+       gboolean suspend = GPOINTER_TO_INT(user_data);
+
+       set_control_point(hogdev, suspend);
+}
+
+static void suspend_callback(void)
+{
+       gboolean suspend = TRUE;
+
+       DBG("Suspending ...");
+
+       g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+}
+
+static void resume_callback(void)
+{
+       gboolean suspend = FALSE;
+
+       DBG("Resuming ...");
+
+       g_slist_foreach(devices, set_suspend, GINT_TO_POINTER(suspend));
+}
+
+static int hog_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       const char *path = device_get_path(device);
+       GSList *primaries, *l;
+
+       DBG("path %s", path);
+
+       primaries = btd_device_get_primaries(device);
+       if (primaries == NULL)
+               return -EINVAL;
+
+       for (l = primaries; l; l = g_slist_next(l)) {
+               struct gatt_primary *prim = l->data;
+               struct hog_device *hogdev;
+
+               if (strcmp(prim->uuid, HOG_UUID) != 0)
+                       continue;
+
+               hogdev = hog_register_device(device, prim);
+               if (hogdev == NULL)
+                       continue;
+
+               devices = g_slist_append(devices, hogdev);
+       }
+
+       return 0;
+}
+
+static void remove_device(gpointer a, gpointer b)
+{
+       struct hog_device *hogdev = a;
+       struct btd_device *device = b;
+
+       if (hogdev->device != device)
+               return;
+
+       devices = g_slist_remove(devices, hogdev);
+       hog_unregister_device(hogdev);
+}
+
+static void hog_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       const char *path = device_get_path(device);
+
+       DBG("path %s", path);
+
+       g_slist_foreach(devices, remove_device, device);
+}
+
+static struct btd_profile hog_profile = {
+       .name           = "input-hog",
+       .remote_uuid    = HOG_UUID,
+       .device_probe   = hog_probe,
+       .device_remove  = hog_remove,
+};
+
+static int hog_init(void)
+{
+       int err;
+
+       err = suspend_init(suspend_callback, resume_callback);
+       if (err < 0)
+               error("Loading suspend plugin failed: %s (%d)", strerror(-err),
+                                                                       -err);
+       else
+               suspend_supported = TRUE;
+
+       return btd_profile_register(&hog_profile);
+}
+
+static void hog_exit(void)
+{
+       if (suspend_supported)
+               suspend_exit();
+
+       btd_profile_unregister(&hog_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(hog, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                                       hog_init, hog_exit)
similarity index 100%
rename from input/input.conf
rename to profiles/input/input.conf
similarity index 53%
rename from input/main.c
rename to profiles/input/manager.c
index da09b86..689ccdd 100644 (file)
 #endif
 
 #include <errno.h>
+#include <stdbool.h>
 
 #include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
 
-#include <gdbus.h>
-
-#include "plugin.h"
 #include "log.h"
-#include "manager.h"
+#include "plugin.h"
+
+#include "lib/uuid.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+#include "../src/profile.h"
+#include "../src/service.h"
+
+#include "device.h"
+#include "server.h"
+
+static int hid_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       return server_start(adapter_get_address(adapter));
+}
+
+static void hid_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       server_stop(adapter_get_address(adapter));
+}
+
+static struct btd_profile input_profile = {
+       .name           = "input-hid",
+       .local_uuid     = HID_UUID,
+       .remote_uuid    = HID_UUID,
+
+       .auto_connect   = true,
+       .connect        = input_device_connect,
+       .disconnect     = input_device_disconnect,
+
+       .device_probe   = input_device_register,
+       .device_remove  = input_device_unregister,
+
+       .adapter_probe  = hid_server_probe,
+       .adapter_remove = hid_server_remove,
+};
 
 static GKeyFile *load_config_file(const char *file)
 {
@@ -43,7 +79,8 @@ static GKeyFile *load_config_file(const char *file)
        keyfile = g_key_file_new();
 
        if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
-               error("Parsing %s failed: %s", file, err->message);
+               if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+                       error("Parsing %s failed: %s", file, err->message);
                g_error_free(err);
                g_key_file_free(keyfile);
                return NULL;
@@ -52,23 +89,27 @@ static GKeyFile *load_config_file(const char *file)
        return keyfile;
 }
 
-static DBusConnection *connection;
-
 static int input_init(void)
 {
        GKeyFile *config;
-
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
+       GError *err = NULL;
 
        config = load_config_file(CONFIGDIR "/input.conf");
+       if (config) {
+               int idle_timeout;
+
+               idle_timeout = g_key_file_get_integer(config, "General",
+                                               "IdleTimeout", &err);
+               if (err) {
+                       DBG("input.conf: %s", err->message);
+                       g_error_free(err);
+               }
 
-       if (input_manager_init(connection, config) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
+               input_set_idle_timeout(idle_timeout * 60);
        }
 
+       btd_profile_register(&input_profile);
+
        if (config)
                g_key_file_free(config);
 
@@ -77,9 +118,7 @@ static int input_init(void)
 
 static void input_exit(void)
 {
-       input_manager_exit();
-
-       dbus_connection_unref(connection);
+       btd_profile_unregister(&input_profile);
 }
 
 BLUETOOTH_PLUGIN_DEFINE(input, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
similarity index 87%
rename from input/server.c
rename to profiles/input/server.c
index 86e2ac8..21d4562 100644 (file)
 #endif
 
 #include <unistd.h>
+#include <stdbool.h>
 #include <errno.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
-#include <bluetooth/uuid.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
 #include "log.h"
 
 #include "glib-helper.h"
-#include "btio.h"
-#include "adapter.h"
+#include "btio/btio.h"
+#include "lib/uuid.h"
+#include "../src/adapter.h"
+#include "../src/device.h"
+#include "../src/profile.h"
+
 #include "device.h"
 #include "server.h"
 
@@ -51,7 +55,7 @@ struct input_server {
        GIOChannel *confirm;
 };
 
-static gint server_cmp(gconstpointer s, gconstpointer user_data)
+static int server_cmp(gconstpointer s, gconstpointer user_data)
 {
        const struct input_server *server = s;
        const bdaddr_t *src = user_data;
@@ -72,7 +76,7 @@ static void connect_event_cb(GIOChannel *chan, GError *err, gpointer data)
                return;
        }
 
-       bt_io_get(chan, BT_IO_L2CAP, &gerr,
+       bt_io_get(chan, &gerr,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_PSM, &psm,
@@ -110,7 +114,7 @@ static void auth_callback(DBusError *derr, void *user_data)
        bdaddr_t src, dst;
        GError *err = NULL;
 
-       bt_io_get(server->confirm, BT_IO_L2CAP, &err,
+       bt_io_get(server->confirm, &err,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_INVALID);
@@ -150,9 +154,11 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
        bdaddr_t src, dst;
        GError *err = NULL;
        char addr[18];
-       int ret;
+       guint ret;
 
-       bt_io_get(chan, BT_IO_L2CAP, &err,
+       DBG("");
+
+       bt_io_get(chan, &err,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_INVALID);
@@ -162,12 +168,15 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
                goto drop;
        }
 
+       ba2str(&dst, addr);
+
        if (server->confirm) {
-               char address[18];
+               error("Refusing connection from %s: setup in progress", addr);
+               goto drop;
+       }
 
-               ba2str(&dst, address);
-               error("Refusing connection from %s: setup in progress",
-                                                               address);
+       if (!input_device_exists(&src, &dst)) {
+               error("Refusing connection from %s: unknown device", addr);
                goto drop;
        }
 
@@ -175,12 +184,10 @@ static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
 
        ret = btd_request_authorization(&src, &dst, HID_UUID,
                                        auth_callback, server);
-       if (ret == 0)
+       if (ret != 0)
                return;
 
-       ba2str(&src, addr);
-       error("input: authorization for %s failed: %s (%d)",
-                                               addr, strerror(-ret), ret);
+       error("input: authorization for device %s failed", addr);
 
        g_io_channel_unref(server->confirm);
        server->confirm = NULL;
@@ -198,7 +205,7 @@ int server_start(const bdaddr_t *src)
        server = g_new0(struct input_server, 1);
        bacpy(&server->src, src);
 
-       server->ctrl = bt_io_listen(BT_IO_L2CAP, connect_event_cb, NULL,
+       server->ctrl = bt_io_listen(connect_event_cb, NULL,
                                server, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, src,
                                BT_IO_OPT_PSM, L2CAP_PSM_HIDP_CTRL,
@@ -211,7 +218,7 @@ int server_start(const bdaddr_t *src)
                return -1;
        }
 
-       server->intr = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event_cb,
+       server->intr = bt_io_listen(NULL, confirm_event_cb,
                                server, NULL, &err,
                                BT_IO_OPT_SOURCE_BDADDR, src,
                                BT_IO_OPT_PSM, L2CAP_PSM_HIDP_INTR,
similarity index 100%
rename from input/server.h
rename to profiles/input/server.h
diff --git a/profiles/input/suspend-dummy.c b/profiles/input/suspend-dummy.c
new file mode 100644 (file)
index 0000000..75dd536
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Nordic Semiconductor Inc.
+ *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <unistd.h>
+
+#include <glib.h>
+
+#include "log.h"
+#include "suspend.h"
+
+#define HOG_SUSPEND_FIFO       "/tmp/hogsuspend"
+
+static suspend_event suspend_cb = NULL;
+static resume_event resume_cb = NULL;
+static guint watch = 0;
+
+static int fifo_open(void);
+
+static gboolean read_fifo(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+       char buffer[12];
+       gsize offset, left, bread;
+       GIOStatus iostatus;
+
+       if (cond & (G_IO_ERR | G_IO_HUP)) {
+               /*
+                * Both ends needs to be open simultaneously before proceeding
+                * any input or output operation. When the remote closes the
+                * channel, hup signal is received on this end.
+                */
+               fifo_open();
+               return FALSE;
+       }
+
+       offset = 0;
+       left = sizeof(buffer) - 1;
+       memset(buffer, 0, sizeof(buffer));
+
+       do {
+               iostatus = g_io_channel_read_chars(io, &buffer[offset], left,
+                                                               &bread, NULL);
+
+               offset += bread;
+               left -= bread;
+               if (left == 0)
+                       break;
+       } while (iostatus == G_IO_STATUS_NORMAL);
+
+       if (g_ascii_strncasecmp("suspend", buffer, 7) == 0)
+               suspend_cb();
+       else if (g_ascii_strncasecmp("resume", buffer, 6) == 0)
+               resume_cb();
+
+       return TRUE;
+}
+
+static int fifo_open(void)
+{
+       GIOCondition condition = G_IO_IN | G_IO_ERR | G_IO_HUP;
+       GIOChannel *fifoio;
+       int fd;
+
+       fd = open(HOG_SUSPEND_FIFO, O_RDONLY | O_NONBLOCK);
+       if (fd < 0) {
+               int err = -errno;
+               error("Can't open FIFO (%s): %s(%d)", HOG_SUSPEND_FIFO,
+                                                       strerror(-err), -err);
+               return err;
+       }
+
+       fifoio = g_io_channel_unix_new(fd);
+       g_io_channel_set_close_on_unref(fifoio, TRUE);
+
+       watch = g_io_add_watch(fifoio, condition, read_fifo, NULL);
+
+       g_io_channel_unref(fifoio);
+
+       return 0;
+}
+
+int suspend_init(suspend_event suspend, resume_event resume)
+{
+       struct stat st;
+       int ret;
+
+       DBG("");
+
+       suspend_cb = suspend;
+       resume_cb = resume;
+
+       if (stat(HOG_SUSPEND_FIFO, &st) == 0) {
+               if (!S_ISFIFO(st.st_mode)) {
+                       error("Unexpected non-FIFO %s file", HOG_SUSPEND_FIFO);
+                       return -EIO;
+               }
+
+               if (unlink(HOG_SUSPEND_FIFO) < 0) {
+                       int err = -errno;
+                       error("Failed to remove FIFO (%s): %s (%d)",
+                               HOG_SUSPEND_FIFO, strerror(-err), -err);
+                       return err;
+               }
+       }
+
+       if (mkfifo(HOG_SUSPEND_FIFO, S_IRUSR | S_IWUSR) < 0) {
+               int err = -errno;
+
+               error("Can't create FIFO (%s): %s (%d)", HOG_SUSPEND_FIFO,
+                                                       strerror(-err), -err);
+               return err;
+       }
+
+       DBG("Created suspend-dummy FIFO on %s", HOG_SUSPEND_FIFO);
+
+       ret = fifo_open();
+       if (ret < 0)
+               unlink(HOG_SUSPEND_FIFO);
+
+       return ret;
+}
+
+void suspend_exit(void)
+{
+       if (watch > 0) {
+               g_source_remove(watch);
+               watch = 0;
+       }
+
+       unlink(HOG_SUSPEND_FIFO);
+}
diff --git a/profiles/input/suspend.h b/profiles/input/suspend.h
new file mode 100644 (file)
index 0000000..bfee3cf
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Nordic Semiconductor Inc.
+ *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+typedef void (*suspend_event) (void);
+typedef void (*resume_event) (void);
+
+int suspend_init(suspend_event suspend, resume_event resume);
+void suspend_exit(void);
diff --git a/profiles/input/uhid_copy.h b/profiles/input/uhid_copy.h
new file mode 100644 (file)
index 0000000..381b062
--- /dev/null
@@ -0,0 +1,104 @@
+#ifndef __UHID_H_
+#define __UHID_H_
+
+/*
+ * User-space I/O driver support for HID subsystem
+ * Copyright (c) 2012 David Herrmann
+ */
+
+/*
+ * 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.
+ */
+
+/*
+ * Public header for user-space communication. We try to keep every structure
+ * aligned but to be safe we also use __attribute__((__packed__)). Therefore,
+ * the communication should be ABI compatible even between architectures.
+ */
+
+#include <linux/input.h>
+#include <linux/types.h>
+
+enum uhid_event_type {
+       UHID_CREATE,
+       UHID_DESTROY,
+       UHID_START,
+       UHID_STOP,
+       UHID_OPEN,
+       UHID_CLOSE,
+       UHID_OUTPUT,
+       UHID_OUTPUT_EV,
+       UHID_INPUT,
+       UHID_FEATURE,
+       UHID_FEATURE_ANSWER,
+};
+
+struct uhid_create_req {
+       __u8 name[128];
+       __u8 phys[64];
+       __u8 uniq[64];
+       __u8 *rd_data;
+       __u16 rd_size;
+
+       __u16 bus;
+       __u32 vendor;
+       __u32 product;
+       __u32 version;
+       __u32 country;
+} __attribute__((__packed__));
+
+#define UHID_DATA_MAX 4096
+
+enum uhid_report_type {
+       UHID_FEATURE_REPORT,
+       UHID_OUTPUT_REPORT,
+       UHID_INPUT_REPORT,
+};
+
+struct uhid_input_req {
+       __u8 data[UHID_DATA_MAX];
+       __u16 size;
+} __attribute__((__packed__));
+
+struct uhid_output_req {
+       __u8 data[UHID_DATA_MAX];
+       __u16 size;
+       __u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_output_ev_req {
+       __u16 type;
+       __u16 code;
+       __s32 value;
+} __attribute__((__packed__));
+
+struct uhid_feature_req {
+       __u32 id;
+       __u8 rnum;
+       __u8 rtype;
+} __attribute__((__packed__));
+
+struct uhid_feature_answer_req {
+       __u32 id;
+       __u16 err;
+       __u16 size;
+       __u8 data[UHID_DATA_MAX];
+};
+
+struct uhid_event {
+       __u32 type;
+
+       union {
+               struct uhid_create_req create;
+               struct uhid_input_req input;
+               struct uhid_output_req output;
+               struct uhid_output_ev_req output_ev;
+               struct uhid_feature_req feature;
+               struct uhid_feature_answer_req feature_answer;
+       } u;
+} __attribute__((__packed__));
+
+#endif /* __UHID_H_ */
similarity index 83%
rename from network/common.c
rename to profiles/network/common.c
index 4704072..0b291bd 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 #include <bluetooth/bnep.h>
-#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
 #include "log.h"
 #include "common.h"
+#include "lib/uuid.h"
 
 static int ctl;
 
@@ -65,16 +65,16 @@ uint16_t bnep_service_id(const char *svc)
        uint16_t id;
 
        /* Friendly service name */
-       for (i = 0; __svc[i].name; i++)
-               if (!strcasecmp(svc, __svc[i].name)) {
+       for (i = 0; __svc[i].name; i++) {
+               if (!strcasecmp(svc, __svc[i].name))
                        return __svc[i].id;
-               }
+       }
 
        /* UUID 128 string */
-       for (i = 0; __svc[i].uuid128; i++)
-               if (!strcasecmp(svc, __svc[i].uuid128)) {
+       for (i = 0; __svc[i].uuid128; i++) {
+               if (!strcasecmp(svc, __svc[i].uuid128))
                        return __svc[i].id;
-               }
+       }
 
        /* Try convert to HEX */
        id = strtol(svc, NULL, 16);
@@ -110,8 +110,13 @@ int bnep_init(void)
 
        if (ctl < 0) {
                int err = -errno;
-               error("Failed to open control socket: %s (%d)",
+
+               if (err == -EPROTONOSUPPORT)
+                       warn("kernel lacks bnep-protocol support");
+               else
+                       error("Failed to open control socket: %s (%d)",
                                                strerror(-err), -err);
+
                return err;
        }
 
@@ -124,7 +129,7 @@ int bnep_cleanup(void)
        return 0;
 }
 
-int bnep_kill_connection(bdaddr_t *dst)
+int bnep_kill_connection(const bdaddr_t *dst)
 {
        struct bnep_conndel_req req;
 
@@ -140,34 +145,6 @@ int bnep_kill_connection(bdaddr_t *dst)
        return 0;
 }
 
-int bnep_kill_all_connections(void)
-{
-       struct bnep_connlist_req req;
-       struct bnep_conninfo ci[7];
-       unsigned int i;
-       int err;
-
-       memset(&req, 0, sizeof(req));
-       req.cnum = 7;
-       req.ci   = ci;
-       if (ioctl(ctl, BNEPGETCONNLIST, &req)) {
-               err = -errno;
-               error("Failed to get connection list: %s (%d)",
-                                               strerror(-err), -err);
-               return err;
-       }
-
-       for (i = 0; i < req.cnum; i++) {
-               struct bnep_conndel_req del;
-
-               memset(&del, 0, sizeof(del));
-               memcpy(del.dst, ci[i].dst, ETH_ALEN);
-               del.flags = 0;
-               ioctl(ctl, BNEPCONNDEL, &del);
-       }
-       return 0;
-}
-
 int bnep_connadd(int sk, uint16_t role, char *dev)
 {
        struct bnep_connadd_req req;
@@ -240,13 +217,15 @@ int bnep_if_down(const char *devname)
 
 int bnep_add_to_bridge(const char *devname, const char *bridge)
 {
-       int ifindex = if_nametoindex(devname);
+       int ifindex;
        struct ifreq ifr;
        int sk, err;
 
        if (!devname || !bridge)
                return -EINVAL;
 
+       ifindex = if_nametoindex(devname);
+
        sk = socket(AF_INET, SOCK_STREAM, 0);
        if (sk < 0)
                return -1;
@@ -266,3 +245,32 @@ int bnep_add_to_bridge(const char *devname, const char *bridge)
 
        return 0;
 }
+
+int bnep_del_from_bridge(const char *devname, const char *bridge)
+{
+       int ifindex = if_nametoindex(devname);
+       struct ifreq ifr;
+       int sk, err;
+
+       if (!devname || !bridge)
+               return -EINVAL;
+
+       sk = socket(AF_INET, SOCK_STREAM, 0);
+       if (sk < 0)
+               return -1;
+
+       memset(&ifr, 0, sizeof(ifr));
+       strncpy(ifr.ifr_name, bridge, IFNAMSIZ - 1);
+       ifr.ifr_ifindex = ifindex;
+
+       err = ioctl(sk, SIOCBRDELIF, &ifr);
+
+       close(sk);
+
+       if (err < 0)
+               return err;
+
+       info("bridge %s: interface %s removed", bridge, devname);
+
+       return 0;
+}
similarity index 91%
rename from network/common.h
rename to profiles/network/common.h
index cb1f08a..9a8caac 100644 (file)
@@ -28,10 +28,10 @@ uint16_t bnep_service_id(const char *svc);
 const char *bnep_uuid(uint16_t id);
 const char *bnep_name(uint16_t id);
 
-int bnep_kill_connection(bdaddr_t *dst);
-int bnep_kill_all_connections(void);
+int bnep_kill_connection(const bdaddr_t *dst);
 
 int bnep_connadd(int sk, uint16_t role, char *dev);
 int bnep_if_up(const char *devname);
 int bnep_if_down(const char *devname);
 int bnep_add_to_bridge(const char *devname, const char *bridge);
+int bnep_del_from_bridge(const char *devname, const char *bridge);
similarity index 54%
rename from network/connection.c
rename to profiles/network/connection.c
index 544ec3a..960a1fe 100644 (file)
@@ -26,6 +26,7 @@
 #endif
 
 #include <stdio.h>
+#include <stdbool.h>
 #include <errno.h>
 #include <unistd.h>
 #include <netinet/in.h>
 #include <bluetooth/sdp.h>
 
 #include <glib.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
+#include <btio/btio.h>
 
 #include "log.h"
-#include "btio.h"
 #include "dbus-common.h"
 #include "adapter.h"
 #include "device.h"
+#include "profile.h"
+#include "service.h"
 
 #include "error.h"
 #include "common.h"
 #include "connection.h"
 
-#define NETWORK_PEER_INTERFACE "org.bluez.Network"
+#define NETWORK_PEER_INTERFACE "org.bluez.Network1"
 #define CON_SETUP_RETRIES      3
 #define CON_SETUP_TO           9
 
@@ -58,24 +61,21 @@ typedef enum {
 } conn_state;
 
 struct network_peer {
-       bdaddr_t        src;
-       bdaddr_t        dst;
-       char            *path;          /* D-Bus path */
        struct btd_device *device;
        GSList          *connections;
 };
 
 struct network_conn {
-       DBusMessage     *msg;
+       struct btd_service *service;
        char            dev[16];        /* Interface name */
        uint16_t        id;             /* Role: Service Class Identifier */
        conn_state      state;
        GIOChannel      *io;
-       guint           watch;          /* Disconnect watch */
        guint           dc_id;
        struct network_peer *peer;
        guint           attempt_cnt;
-       guint           timeout_source;
+       guint           timeout_source;
+       DBusMessage     *connect;
 };
 
 struct __service_16 {
@@ -83,27 +83,32 @@ struct __service_16 {
        uint16_t src;
 } __attribute__ ((packed));
 
-static DBusConnection *connection = NULL;
 static GSList *peers = NULL;
 
-static struct network_peer *find_peer(GSList *list, const char *path)
+static uint16_t get_service_id(struct btd_service *service)
+{
+       return bnep_service_id(btd_service_get_profile(service)->remote_uuid);
+}
+
+static struct network_peer *find_peer(GSList *list, struct btd_device *device)
 {
        for (; list; list = list->next) {
                struct network_peer *peer = list->data;
 
-               if (!strcmp(peer->path, path))
+               if (peer->device == device)
                        return peer;
        }
 
        return NULL;
 }
 
-static struct network_conn *find_connection(GSList *list, uint16_t id)
+static struct network_conn *find_connection_by_state(GSList *list,
+                                                       conn_state state)
 {
        for (; list; list = list->next) {
                struct network_conn *nc = list->data;
 
-               if (nc->id == id)
+               if (nc->state == state)
                        return nc;
        }
 
@@ -114,26 +119,19 @@ static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
                                gpointer data)
 {
        struct network_conn *nc = data;
+       DBusConnection *conn = btd_get_dbus_connection();
+       const char *path = device_get_path(nc->peer->device);
 
-       if (connection != NULL) {
-               gboolean connected = FALSE;
-               const char *property = "";
-               emit_property_changed(connection, nc->peer->path,
-                                       NETWORK_PEER_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &connected);
-               emit_property_changed(connection, nc->peer->path,
-                                       NETWORK_PEER_INTERFACE, "Interface",
-                                       DBUS_TYPE_STRING, &property);
-               emit_property_changed(connection, nc->peer->path,
-                                       NETWORK_PEER_INTERFACE, "UUID",
-                                       DBUS_TYPE_STRING, &property);
-               device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
-               nc->dc_id = 0;
-               if (nc->watch) {
-                       g_dbus_remove_watch(connection, nc->watch);
-                       nc->watch = 0;
-               }
-       }
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "Connected");
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "Interface");
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "UUID");
+       device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
+       nc->dc_id = 0;
+
+       btd_service_disconnecting_complete(nc->service, 0);
 
        info("%s disconnected", nc->dev);
 
@@ -145,24 +143,34 @@ static gboolean bnep_watchdog_cb(GIOChannel *chan, GIOCondition cond,
        return FALSE;
 }
 
-static void cancel_connection(struct network_conn *nc, const char *err_msg)
+static void local_connect_cb(struct network_conn *nc, int err)
 {
-       DBusMessage *reply;
+       DBusConnection *conn = btd_get_dbus_connection();
+       const char *pdev = nc->dev;
 
+       if (err < 0) {
+               DBusMessage *reply = btd_error_failed(nc->connect,
+                                                       strerror(-err));
+               g_dbus_send_message(conn, reply);
+       } else {
+               g_dbus_send_reply(conn, nc->connect, DBUS_TYPE_STRING, &pdev,
+                                                       DBUS_TYPE_INVALID);
+       }
+
+       dbus_message_unref(nc->connect);
+       nc->connect = NULL;
+}
+
+static void cancel_connection(struct network_conn *nc, int err)
+{
        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;
-       }
-
-       if (nc->msg && err_msg) {
-               reply = btd_error_failed(nc->msg, err_msg);
-               g_dbus_send_message(connection, reply);
-       }
+       btd_service_connecting_complete(nc->service, err);
+       if (nc->connect)
+               local_connect_cb(nc, err);
 
        g_io_channel_shutdown(nc->io, TRUE, NULL);
        g_io_channel_unref(nc->io);
@@ -177,9 +185,9 @@ static void connection_destroy(DBusConnection *conn, void *user_data)
 
        if (nc->state == CONNECTED) {
                bnep_if_down(nc->dev);
-               bnep_kill_connection(&nc->peer->dst);
+               bnep_kill_connection(device_get_address(nc->peer->device));
        } else if (nc->io)
-               cancel_connection(nc, NULL);
+               cancel_connection(nc, -EIO);
 }
 
 static void disconnect_cb(struct btd_device *device, gboolean removal,
@@ -187,7 +195,7 @@ static void disconnect_cb(struct btd_device *device, gboolean removal,
 {
        struct network_conn *nc = user_data;
 
-       info("Network: disconnect %s", nc->peer->path);
+       info("Network: disconnect %s", device_get_path(nc->peer->device));
 
        connection_destroy(NULL, user_data);
 }
@@ -201,14 +209,18 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        char pkt[BNEP_MTU];
        ssize_t r;
        int sk;
-       const char *pdev, *uuid;
-       gboolean connected;
+       const char *path;
+       DBusConnection *conn;
+
+       DBG("cond %u", cond);
 
        if (cond & G_IO_NVAL)
                return FALSE;
 
-       g_source_remove(nc->timeout_source);
-       nc->timeout_source = 0;
+       if (nc->timeout_source > 0) {
+               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");
@@ -263,23 +275,20 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        }
 
        bnep_if_up(nc->dev);
-       pdev = nc->dev;
-       uuid = bnep_uuid(nc->id);
 
-       g_dbus_send_reply(connection, nc->msg,
-                       DBUS_TYPE_STRING, &pdev,
-                       DBUS_TYPE_INVALID);
-
-       connected = TRUE;
-       emit_property_changed(connection, nc->peer->path,
-                               NETWORK_PEER_INTERFACE, "Connected",
-                               DBUS_TYPE_BOOLEAN, &connected);
-       emit_property_changed(connection, nc->peer->path,
-                               NETWORK_PEER_INTERFACE, "Interface",
-                               DBUS_TYPE_STRING, &pdev);
-       emit_property_changed(connection, nc->peer->path,
-                               NETWORK_PEER_INTERFACE, "UUID",
-                               DBUS_TYPE_STRING, &uuid);
+       btd_service_connecting_complete(nc->service, 0);
+       if (nc->connect)
+               local_connect_cb(nc, 0);
+
+       conn = btd_get_dbus_connection();
+       path = device_get_path(nc->peer->device);
+
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "Connected");
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "Interface");
+       g_dbus_emit_property_changed(conn, path,
+                                       NETWORK_PEER_INTERFACE, "UUID");
 
        nc->state = CONNECTED;
        nc->dc_id = device_add_disconnect_watch(nc->peer->device, disconnect_cb,
@@ -295,7 +304,7 @@ static gboolean bnep_setup_cb(GIOChannel *chan, GIOCondition cond,
        return FALSE;
 
 failed:
-       cancel_connection(nc, "bnep setup failed");
+       cancel_connection(nc, -EIO);
 
        return FALSE;
 }
@@ -307,6 +316,8 @@ static int bnep_send_conn_req(struct network_conn *nc)
        unsigned char pkt[BNEP_MTU];
        int fd;
 
+       DBG("");
+
        /* Send request */
        req = (void *) pkt;
        req->type = BNEP_CONTROL;
@@ -337,11 +348,11 @@ static gboolean bnep_conn_req_to(gpointer user_data)
                error("Too many bnep connection attempts");
        } else {
                error("bnep connection setup TO, retrying...");
-               if (!bnep_send_conn_req(nc))
+               if (bnep_send_conn_req(nc) == 0)
                        return TRUE;
        }
 
-       cancel_connection(nc, "bnep setup failed");
+       cancel_connection(nc, -ETIMEDOUT);
 
        return FALSE;
 }
@@ -351,14 +362,16 @@ static int bnep_connect(struct network_conn *nc)
        int err;
 
        nc->attempt_cnt = 0;
-       if ((err = bnep_send_conn_req(nc)))
+
+       err = bnep_send_conn_req(nc);
+       if (err < 0)
                return err;
 
        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);
+                                                       bnep_setup_cb, nc);
 
        return 0;
 }
@@ -366,93 +379,112 @@ static int bnep_connect(struct network_conn *nc)
 static void connect_cb(GIOChannel *chan, GError *err, gpointer data)
 {
        struct network_conn *nc = data;
-       const char *err_msg;
        int perr;
 
        if (err) {
                error("%s", err->message);
-               err_msg = err->message;
                goto failed;
        }
 
        perr = bnep_connect(nc);
        if (perr < 0) {
-               err_msg = strerror(-perr);
-               error("bnep connect(): %s (%d)", err_msg, -perr);
+               error("bnep connect(): %s (%d)", strerror(-perr), -perr);
                goto failed;
        }
 
        return;
 
 failed:
-       cancel_connection(nc, err_msg);
+       cancel_connection(nc, -EIO);
 }
 
-/* Connect and initiate BNEP session */
-static DBusMessage *connection_connect(DBusConnection *conn,
+static DBusMessage *local_connect(DBusConnection *conn,
                                                DBusMessage *msg, void *data)
 {
        struct network_peer *peer = data;
+       struct btd_service *service;
        struct network_conn *nc;
        const char *svc;
+       const char *uuid;
        uint16_t id;
-       GError *err = NULL;
+       int err;
 
        if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &svc,
                                                DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
+               return btd_error_invalid_args(msg);
 
        id = bnep_service_id(svc);
-       nc = find_connection(peer->connections, id);
-       if (!nc)
+       uuid = bnep_uuid(id);
+
+       if (uuid == NULL)
+               return btd_error_invalid_args(msg);
+
+       service = btd_device_get_service(peer->device, uuid);
+       if (service == NULL)
                return btd_error_not_supported(msg);
 
+       nc = btd_service_get_user_data(service);
+
+       if (nc->connect != NULL)
+               return btd_error_busy(msg);
+
+       err = connection_connect(nc->service);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       nc->connect = dbus_message_ref(msg);
+
+       return NULL;
+}
+
+/* Connect and initiate BNEP session */
+int connection_connect(struct btd_service *service)
+{
+       struct network_conn *nc = btd_service_get_user_data(service);
+       struct network_peer *peer = nc->peer;
+       uint16_t id = get_service_id(service);
+       GError *err = NULL;
+       const bdaddr_t *src;
+       const bdaddr_t *dst;
+
+       DBG("id %u", id);
+
        if (nc->state != DISCONNECTED)
-               return btd_error_already_connected(msg);
+               return -EALREADY;
 
-       nc->io = bt_io_connect(BT_IO_L2CAP, connect_cb, nc,
+       src = adapter_get_address(device_get_adapter(peer->device));
+       dst = device_get_address(peer->device);
+
+       nc->io = bt_io_connect(connect_cb, nc,
                                NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &peer->src,
-                               BT_IO_OPT_DEST_BDADDR, &peer->dst,
+                               BT_IO_OPT_SOURCE_BDADDR, src,
+                               BT_IO_OPT_DEST_BDADDR, 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);
-       if (!nc->io) {
-               DBusMessage *reply;
-               error("%s", err->message);
-               reply = btd_error_failed(msg, err->message);
-               g_error_free(err);
-               return reply;
-       }
+       if (!nc->io)
+               return -EIO;
 
        nc->state = CONNECTING;
-       nc->msg = dbus_message_ref(msg);
-       nc->watch = g_dbus_add_disconnect_watch(conn,
-                                               dbus_message_get_sender(msg),
-                                               connection_destroy,
-                                               nc, NULL);
 
-       return NULL;
+       return 0;
 }
 
-static DBusMessage *connection_cancel(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+int connection_disconnect(struct btd_service *service)
 {
-       struct network_conn *nc = data;
-       const char *owner = dbus_message_get_sender(nc->msg);
-       const char *caller = dbus_message_get_sender(msg);
+       struct network_conn *nc = btd_service_get_user_data(service);
 
-       if (!g_str_equal(owner, caller))
-               return btd_error_not_authorized(msg);
+       if (nc->state == DISCONNECTED)
+               return 0;
 
-       connection_destroy(conn, nc);
+       connection_destroy(NULL, nc);
 
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+       return 0;
 }
 
-static DBusMessage *connection_disconnect(DBusConnection *conn,
+static DBusMessage *local_disconnect(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
        struct network_peer *peer = data;
@@ -460,64 +492,85 @@ static DBusMessage *connection_disconnect(DBusConnection *conn,
 
        for (l = peer->connections; l; l = l->next) {
                struct network_conn *nc = l->data;
+               int err;
 
                if (nc->state == DISCONNECTED)
                        continue;
 
-               return connection_cancel(conn, msg, nc);
+               err = connection_disconnect(nc->service);
+               if (err < 0)
+                       return btd_error_failed(msg, strerror(-err));
+
+               return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
        }
 
        return btd_error_not_connected(msg);
 }
 
-static DBusMessage *connection_get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static gboolean
+network_property_get_connected(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
        struct network_peer *peer = data;
-       struct network_conn *nc = NULL;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
+       struct network_conn *nc;
        dbus_bool_t connected;
-       const char *property;
-       GSList *l;
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       nc = find_connection_by_state(peer->connections, CONNECTED);
+       connected = nc != NULL ? TRUE : FALSE;
 
-       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);
 
-       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);
+       return TRUE;
+}
 
-       /* Connected */
-       for (l = peer->connections; l; l = l->next) {
-               struct network_conn *tmp = l->data;
+static gboolean network_property_exists(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct network_peer *peer = data;
+       struct network_conn *nc;
 
-               if (tmp->state != CONNECTED)
-                       continue;
+       nc = find_connection_by_state(peer->connections, CONNECTED);
+       if (nc == NULL)
+               return FALSE;
 
-               nc = tmp;
-               break;
-       }
+       return TRUE;
+}
 
-       connected = nc ? TRUE : FALSE;
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
+static gboolean
+network_property_get_interface(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct network_peer *peer = data;
+       struct network_conn *nc;
+       const char *iface;
 
-       /* Interface */
-       property = nc ? nc->dev : "";
-       dict_append_entry(&dict, "Interface", DBUS_TYPE_STRING, &property);
+       nc = find_connection_by_state(peer->connections, CONNECTED);
+       if (nc == NULL)
+               return FALSE;
 
-       /* UUID */
-       property = nc ? bnep_uuid(nc->id) : "";
-       dict_append_entry(&dict, "UUID", DBUS_TYPE_STRING, &property);
+       iface = nc->dev;
 
-       dbus_message_iter_close_container(&iter, &dict);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &iface);
 
-       return reply;
+       return TRUE;
+}
+
+static gboolean network_property_get_uuid(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct network_peer *peer = data;
+       struct network_conn *nc;
+       const char *uuid;
+
+       nc = find_connection_by_state(peer->connections, CONNECTED);
+       if (nc == NULL)
+               return FALSE;
+
+       uuid = bnep_uuid(nc->id);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &uuid);
+
+       return TRUE;
 }
 
 static void connection_free(void *data)
@@ -527,17 +580,19 @@ static void connection_free(void *data)
        if (nc->dc_id)
                device_remove_disconnect_watch(nc->peer->device, nc->dc_id);
 
-       connection_destroy(connection, nc);
+       connection_destroy(NULL, nc);
+
+       if (nc->connect)
+               dbus_message_unref(nc->connect);
 
+       btd_service_unref(nc->service);
        g_free(nc);
-       nc = NULL;
 }
 
 static void peer_free(struct network_peer *peer)
 {
        g_slist_free_full(peer->connections, connection_free);
        btd_device_unref(peer->device);
-       g_free(peer->path);
        g_free(peer);
 }
 
@@ -546,7 +601,7 @@ static void path_unregister(void *data)
        struct network_peer *peer = data;
 
        DBG("Unregistered interface %s on path %s",
-               NETWORK_PEER_INTERFACE, peer->path);
+               NETWORK_PEER_INTERFACE, device_get_path(peer->device));
 
        peers = g_slist_remove(peers, peer);
        peer_free(peer);
@@ -554,58 +609,57 @@ static void path_unregister(void *data)
 
 static const GDBusMethodTable connection_methods[] = {
        { GDBUS_ASYNC_METHOD("Connect",
-                       NULL, NULL, connection_connect) },
+                               GDBUS_ARGS({"uuid", "s"}),
+                               GDBUS_ARGS({"interface", "s"}),
+                               local_connect) },
        { GDBUS_METHOD("Disconnect",
-                       NULL, NULL, connection_disconnect) },
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       connection_get_properties) },
+                       NULL, NULL, local_disconnect) },
        { }
 };
 
-static const GDBusSignalTable connection_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+static const GDBusPropertyTable connection_properties[] = {
+       { "Connected", "b", network_property_get_connected },
+       { "Interface", "s", network_property_get_interface, NULL,
+                                               network_property_exists },
+       { "UUID", "s", network_property_get_uuid, NULL,
+                                               network_property_exists },
        { }
 };
 
-void connection_unregister(const char *path, uint16_t id)
+void connection_unregister(struct btd_service *service)
 {
-       struct network_peer *peer;
-       struct network_conn *nc;
+       struct btd_device *device = btd_service_get_device(service);
+       struct network_conn *conn = btd_service_get_user_data(service);
+       struct network_peer *peer = conn->peer;
+       uint16_t id = get_service_id(service);
 
-       peer = find_peer(peers, path);
-       if (!peer)
-               return;
+       DBG("%s id %u", device_get_path(device), id);
 
-       nc = find_connection(peer->connections, id);
-       if (!nc)
-               return;
+       peer->connections = g_slist_remove(peer->connections, conn);
+       connection_free(conn);
 
-       peer->connections = g_slist_remove(peer->connections, nc);
-       connection_free(nc);
-       if (peer->connections)
+       if (peer->connections != NULL)
                return;
 
-       g_dbus_unregister_interface(connection, path, NETWORK_PEER_INTERFACE);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               device_get_path(device),
+                                               NETWORK_PEER_INTERFACE);
 }
 
-static struct network_peer *create_peer(struct btd_device *device,
-                                       const char *path, bdaddr_t *src,
-                                       bdaddr_t *dst)
+static struct network_peer *create_peer(struct btd_device *device)
 {
        struct network_peer *peer;
+       const char *path;
 
        peer = g_new0(struct network_peer, 1);
        peer->device = btd_device_ref(device);
-       peer->path = g_strdup(path);
-       bacpy(&peer->src, src);
-       bacpy(&peer->dst, dst);
 
-       if (g_dbus_register_interface(connection, path,
+       path = device_get_path(device);
+
+       if (g_dbus_register_interface(btd_get_dbus_connection(), path,
                                        NETWORK_PEER_INTERFACE,
                                        connection_methods,
-                                       connection_signals, NULL,
+                                       NULL, connection_properties,
                                        peer, path_unregister) == FALSE) {
                error("D-Bus failed to register %s interface",
                        NETWORK_PEER_INTERFACE);
@@ -619,48 +673,36 @@ static struct network_peer *create_peer(struct btd_device *device,
        return peer;
 }
 
-int connection_register(struct btd_device *device, const char *path,
-                       bdaddr_t *src, bdaddr_t *dst, uint16_t id)
+int connection_register(struct btd_service *service)
 {
+       struct btd_device *device = btd_service_get_device(service);
        struct network_peer *peer;
        struct network_conn *nc;
+       uint16_t id = get_service_id(service);
 
-       if (!path)
-               return -EINVAL;
+       DBG("%s id %u", device_get_path(device), id);
 
-       peer = find_peer(peers, path);
+       peer = find_peer(peers, device);
        if (!peer) {
-               peer = create_peer(device, path, src, dst);
+               peer = create_peer(device);
                if (!peer)
                        return -1;
                peers = g_slist_append(peers, peer);
        }
 
-       nc = find_connection(peer->connections, id);
-       if (nc)
-               return 0;
-
        nc = g_new0(struct network_conn, 1);
        nc->id = id;
        memset(nc->dev, 0, sizeof(nc->dev));
        strcpy(nc->dev, "bnep%d");
+       nc->service = btd_service_ref(service);
        nc->state = DISCONNECTED;
        nc->peer = peer;
 
-       peer->connections = g_slist_append(peer->connections, nc);
+       btd_service_set_user_data(service, nc);
 
-       return 0;
-}
+       DBG("id %u registered", id);
 
-int connection_init(DBusConnection *conn)
-{
-       connection = dbus_connection_ref(conn);
+       peer->connections = g_slist_append(peer->connections, nc);
 
        return 0;
 }
-
-void connection_exit(void)
-{
-       dbus_connection_unref(connection);
-       connection = NULL;
-}
diff --git a/profiles/network/connection.h b/profiles/network/connection.h
new file mode 100644 (file)
index 0000000..4a8b43b
--- /dev/null
@@ -0,0 +1,27 @@
+/*
+ *
+ *  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
+ *
+ */
+
+int connection_register(struct btd_service *service);
+void connection_unregister(struct btd_service *service);
+int connection_connect(struct btd_service *service);
+int connection_disconnect(struct btd_service *service);
diff --git a/profiles/network/manager.c b/profiles/network/manager.c
new file mode 100644 (file)
index 0000000..ab4224d
--- /dev/null
@@ -0,0 +1,213 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <errno.h>
+#include <stdbool.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/bnep.h>
+#include <bluetooth/sdp.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "log.h"
+#include "plugin.h"
+
+#include "lib/uuid.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "common.h"
+#include "connection.h"
+#include "server.h"
+
+static gboolean conf_security = TRUE;
+
+static void read_config(const char *file)
+{
+       GKeyFile *keyfile;
+       GError *err = NULL;
+
+       keyfile = g_key_file_new();
+
+       if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
+               g_clear_error(&err);
+               goto done;
+       }
+
+       conf_security = !g_key_file_get_boolean(keyfile, "General",
+                                               "DisableSecurity", &err);
+       if (err) {
+               DBG("%s: %s", file, err->message);
+               g_clear_error(&err);
+       }
+
+done:
+       g_key_file_free(keyfile);
+
+       DBG("Config options: Security=%s",
+                               conf_security ? "true" : "false");
+}
+
+static int panu_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       return server_register(adapter, BNEP_SVC_PANU);
+}
+
+static void panu_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       server_unregister(adapter, BNEP_SVC_PANU);
+}
+
+static int gn_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       return server_register(adapter, BNEP_SVC_GN);
+}
+
+static void gn_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       server_unregister(adapter, BNEP_SVC_GN);
+}
+
+static int nap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       return server_register(adapter, BNEP_SVC_NAP);
+}
+
+static void nap_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       server_unregister(adapter, BNEP_SVC_NAP);
+}
+
+static struct btd_profile panu_profile = {
+       .name           = "network-panu",
+       .local_uuid     = NAP_UUID,
+       .remote_uuid    = PANU_UUID,
+       .device_probe   = connection_register,
+       .device_remove  = connection_unregister,
+       .connect        = connection_connect,
+       .disconnect     = connection_disconnect,
+       .adapter_probe  = panu_server_probe,
+       .adapter_remove = panu_server_remove,
+};
+
+static struct btd_profile gn_profile = {
+       .name           = "network-gn",
+       .local_uuid     = PANU_UUID,
+       .remote_uuid    = GN_UUID,
+       .device_probe   = connection_register,
+       .device_remove  = connection_unregister,
+       .connect        = connection_connect,
+       .disconnect     = connection_disconnect,
+       .adapter_probe  = gn_server_probe,
+       .adapter_remove = gn_server_remove,
+};
+
+static struct btd_profile nap_profile = {
+       .name           = "network-nap",
+       .local_uuid     = PANU_UUID,
+       .remote_uuid    = NAP_UUID,
+       .device_probe   = connection_register,
+       .device_remove  = connection_unregister,
+       .connect        = connection_connect,
+       .disconnect     = connection_disconnect,
+       .adapter_probe  = nap_server_probe,
+       .adapter_remove = nap_server_remove,
+};
+
+static int network_init(void)
+{
+       int err;
+
+       read_config(CONFIGDIR "/network.conf");
+
+       err = bnep_init();
+       if (err) {
+               if (err == -EPROTONOSUPPORT)
+                       err = -ENOSYS;
+               return err;
+       }
+
+       /*
+        * 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.
+        */
+
+       if (server_init(conf_security) < 0)
+               return -1;
+
+       btd_profile_register(&panu_profile);
+       btd_profile_register(&gn_profile);
+       btd_profile_register(&nap_profile);
+
+       return 0;
+}
+
+static void network_exit(void)
+{
+       server_exit();
+
+       btd_profile_unregister(&panu_profile);
+       btd_profile_unregister(&gn_profile);
+       btd_profile_unregister(&nap_profile);
+
+       bnep_cleanup();
+}
+
+BLUETOOTH_PLUGIN_DEFINE(network, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, network_init, network_exit)
similarity index 82%
rename from network/server.c
rename to profiles/network/server.c
index 480c7e2..7b784e5 100644 (file)
 #include <bluetooth/bnep.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
 #include <netinet/in.h>
 
 #include <glib.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
+#include <btio/btio.h>
 
+#include "lib/uuid.h"
 #include "../src/dbus-common.h"
 #include "../src/adapter.h"
 
 #include "log.h"
 #include "error.h"
 #include "sdpd.h"
-#include "btio.h"
 
 #include "common.h"
 #include "server.h"
 
-#define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer"
+#define NETWORK_SERVER_INTERFACE "org.bluez.NetworkServer1"
 #define SETUP_TIMEOUT          1
 
 /* Pending Authorization */
 struct network_session {
        bdaddr_t        dst;            /* Remote Bluetooth Address */
+       char            dev[16];        /* Interface name */
        GIOChannel      *io;            /* Pending connect channel */
        guint           watch;          /* BNEP socket watch */
 };
@@ -71,7 +72,6 @@ struct network_adapter {
 /* Main server structure */
 struct network_server {
        bdaddr_t        src;            /* Bluetooth Local Address */
-       char            *iface;         /* DBus interface */
        char            *name;          /* Server service name */
        char            *bridge;        /* Bridge name */
        uint32_t        record_id;      /* Service record id */
@@ -81,7 +81,6 @@ struct network_server {
        guint           watch_id;       /* Client service watch */
 };
 
-static DBusConnection *connection = NULL;
 static GSList *adapters = NULL;
 static gboolean security = TRUE;
 
@@ -110,6 +109,22 @@ static struct network_server *find_server(GSList *list, uint16_t id)
        return NULL;
 }
 
+static struct network_server *find_server_by_uuid(GSList *list,
+                                                       const char *uuid)
+{
+       for (; list; list = list->next) {
+               struct network_server *ns = list->data;
+
+               if (strcasecmp(uuid, bnep_uuid(ns->id)) == 0)
+                       return ns;
+
+               if (strcasecmp(uuid, bnep_name(ns->id)) == 0)
+                       return ns;
+       }
+
+       return NULL;
+}
+
 static sdp_record_t *server_record_new(const char *name, uint16_t id)
 {
        sdp_list_t *svclass, *pfseq, *apseq, *root, *aproto;
@@ -272,6 +287,8 @@ static int server_connadd(struct network_server *ns,
 
        bnep_if_up(devname);
 
+       strncpy(session->dev, devname, sizeof(devname));
+
        ns->sessions = g_slist_append(ns->sessions, session);
 
        return 0;
@@ -301,7 +318,10 @@ static uint16_t bnep_setup_chk(uint16_t dst_role, uint16_t src_role)
 static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
                                uint16_t *dst_role, uint16_t *src_role)
 {
+       const uint8_t bt_base[] = { 0x00, 0x00, 0x10, 0x00, 0x80, 0x00,
+                               0x00, 0x80, 0x5F, 0x9B, 0x34, 0xFB };
        uint8_t *dest, *source;
+       uint32_t val;
 
        dest = req->service;
        source = req->service + req->uuid_size;
@@ -311,16 +331,33 @@ static uint16_t bnep_setup_decode(struct bnep_setup_conn_req *req,
                *dst_role = bt_get_be16(dest);
                *src_role = bt_get_be16(source);
                break;
-       case 4: /* UUID32 */
        case 16: /* UUID128 */
-               *dst_role = bt_get_be32(dest);
-               *src_role = bt_get_be32(source);
+               /* Check that the bytes in the UUID, except the service ID
+                * itself, are correct. The service ID is checked in
+                * bnep_setup_chk(). */
+               if (memcmp(&dest[4], bt_base, sizeof(bt_base)) != 0)
+                       return BNEP_CONN_INVALID_DST;
+               if (memcmp(&source[4], bt_base, sizeof(bt_base)) != 0)
+                       return BNEP_CONN_INVALID_SRC;
+
+               /* Intentional no-break */
+
+       case 4: /* UUID32 */
+               val = bt_get_be32(dest);
+               if (val > 0xffff)
+                       return BNEP_CONN_INVALID_DST;
+               *dst_role = val;
+
+               val = bt_get_be32(source);
+               if (val > 0xffff)
+                       return BNEP_CONN_INVALID_SRC;
+               *src_role = val;
                break;
        default:
                return BNEP_CONN_INVALID_SVC;
        }
 
-       return 0;
+       return BNEP_SUCCESS;
 }
 
 static void session_free(void *data)
@@ -402,6 +439,8 @@ static gboolean bnep_setup(GIOChannel *chan,
        if (rsp)
                goto reply;
 
+       rsp = BNEP_CONN_NOT_ALLOWED;
+
        ns = find_server(na->servers, dst_role);
        if (!ns) {
                error("Server unavailable: (0x%x)", dst_role);
@@ -476,12 +515,12 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
 {
        struct network_adapter *na = user_data;
        struct network_server *ns;
-       int perr;
        bdaddr_t src, dst;
        char address[18];
        GError *err = NULL;
+       guint ret;
 
-       bt_io_get(chan, BT_IO_L2CAP, &err,
+       bt_io_get(chan, &err,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_DEST, address,
@@ -513,11 +552,10 @@ static void confirm_event(GIOChannel *chan, gpointer user_data)
        bacpy(&na->setup->dst, &dst);
        na->setup->io = g_io_channel_ref(chan);
 
-       perr = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
+       ret = btd_request_authorization(&src, &dst, BNEP_SVC_UUID,
                                        auth_cb, na);
-       if (perr < 0) {
-               error("Refusing connect from %s: %s (%d)", address,
-                               strerror(-perr), -perr);
+       if (ret == 0) {
+               error("Refusing connect from %s", address);
                setup_destroy(na);
                goto drop;
        }
@@ -528,18 +566,15 @@ drop:
        g_io_channel_shutdown(chan, TRUE, NULL);
 }
 
-int server_init(DBusConnection *conn, gboolean secure)
+int server_init(gboolean secure)
 {
        security = secure;
-       connection = dbus_connection_ref(conn);
 
        return 0;
 }
 
 void server_exit(void)
 {
-       dbus_connection_unref(connection);
-       connection = NULL;
 }
 
 static uint32_t register_server_record(struct network_server *ns)
@@ -552,7 +587,7 @@ static uint32_t register_server_record(struct network_server *ns)
                return 0;
        }
 
-       if (add_record_to_server(&ns->src, record) < 0) {
+       if (adapter_service_add(ns->na->adapter, record) < 0) {
                error("Failed to register service record");
                sdp_record_free(record);
                return 0;
@@ -563,14 +598,37 @@ static uint32_t register_server_record(struct network_server *ns)
        return record->handle;
 }
 
+static void server_remove_sessions(struct network_server *ns)
+{
+       GSList *list;
+
+       for (list = ns->sessions; list; list = list->next) {
+               struct network_session *session = list->data;
+
+               if (*session->dev == '\0')
+                       continue;
+
+               bnep_del_from_bridge(session->dev, ns->bridge);
+               bnep_if_down(session->dev);
+
+               bnep_kill_connection(&session->dst);
+       }
+
+       g_slist_free_full(ns->sessions, session_free);
+
+       ns->sessions = NULL;
+}
+
 static void server_disconnect(DBusConnection *conn, void *user_data)
 {
        struct network_server *ns = user_data;
 
+       server_remove_sessions(ns);
+
        ns->watch_id = 0;
 
        if (ns->record_id) {
-               remove_record_from_server(ns->record_id);
+               adapter_service_remove(ns->na->adapter, ns->record_id);
                ns->record_id = 0;
        }
 
@@ -581,15 +639,17 @@ static void server_disconnect(DBusConnection *conn, void *user_data)
 static DBusMessage *register_server(DBusConnection *conn,
                                DBusMessage *msg, void *data)
 {
-       struct network_server *ns = data;
+       struct network_adapter *na = data;
+       struct network_server *ns;
        DBusMessage *reply;
        const char *uuid, *bridge;
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
                                DBUS_TYPE_STRING, &bridge, DBUS_TYPE_INVALID))
-               return NULL;
+               return btd_error_invalid_args(msg);
 
-       if (g_strcmp0(uuid, "nap"))
+       ns = find_server_by_uuid(na->servers, uuid);
+       if (ns == NULL)
                return btd_error_failed(msg, "Invalid UUID");
 
        if (ns->record_id)
@@ -616,15 +676,17 @@ static DBusMessage *register_server(DBusConnection *conn,
 static DBusMessage *unregister_server(DBusConnection *conn,
                                        DBusMessage *msg, void *data)
 {
-       struct network_server *ns = data;
+       struct network_adapter *na = data;
+       struct network_server *ns;
        DBusMessage *reply;
        const char *uuid;
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &uuid,
                                                        DBUS_TYPE_INVALID))
-               return NULL;
+               return btd_error_invalid_args(msg);
 
-       if (g_strcmp0(uuid, "nap"))
+       ns = find_server_by_uuid(na->servers, uuid);
+       if (!ns)
                return btd_error_failed(msg, "Invalid UUID");
 
        reply = dbus_message_new_method_return(msg);
@@ -650,37 +712,33 @@ static void adapter_free(struct network_adapter *na)
        g_free(na);
 }
 
-static void server_free(struct network_server *ns)
+static void server_free(void *data)
 {
+       struct network_server *ns = data;
+
        if (!ns)
                return;
 
-       /* FIXME: Missing release/free all bnepX interfaces */
+       server_remove_sessions(ns);
+
        if (ns->record_id)
-               remove_record_from_server(ns->record_id);
+               adapter_service_remove(ns->na->adapter, ns->record_id);
 
-       g_free(ns->iface);
+       g_dbus_remove_watch(btd_get_dbus_connection(), ns->watch_id);
        g_free(ns->name);
        g_free(ns->bridge);
 
-       g_slist_free_full(ns->sessions, session_free);
-
        g_free(ns);
 }
 
 static void path_unregister(void *data)
 {
-       struct network_server *ns = data;
-       struct network_adapter *na = ns->na;
+       struct network_adapter *na = data;
 
        DBG("Unregistered interface %s on path %s",
-               ns->iface, adapter_get_path(na->adapter));
+               NETWORK_SERVER_INTERFACE, adapter_get_path(na->adapter));
 
-       na->servers = g_slist_remove(na->servers, ns);
-       server_free(ns);
-
-       if (na->servers)
-               return;
+       g_slist_free_full(na->servers, server_free);
 
        adapters = g_slist_remove(adapters, na);
        adapter_free(na);
@@ -700,16 +758,14 @@ static struct network_adapter *create_adapter(struct btd_adapter *adapter)
 {
        struct network_adapter *na;
        GError *err = NULL;
-       bdaddr_t src;
 
        na = g_new0(struct network_adapter, 1);
        na->adapter = btd_adapter_ref(adapter);
 
-       adapter_get_address(adapter, &src);
-
-       na->io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event, na,
+       na->io = bt_io_listen(NULL, confirm_event, na,
                                NULL, &err,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               adapter_get_address(adapter),
                                BT_IO_OPT_PSM, BNEP_PSM,
                                BT_IO_OPT_OMTU, BNEP_MTU,
                                BT_IO_OPT_IMTU, BNEP_MTU,
@@ -726,7 +782,7 @@ static struct network_adapter *create_adapter(struct btd_adapter *adapter)
        return na;
 }
 
-int server_register(struct btd_adapter *adapter)
+int server_register(struct btd_adapter *adapter, uint16_t id)
 {
        struct network_adapter *na;
        struct network_server *ns;
@@ -740,42 +796,46 @@ int server_register(struct btd_adapter *adapter)
                adapters = g_slist_append(adapters, na);
        }
 
-       ns = find_server(na->servers, BNEP_SVC_NAP);
+       ns = find_server(na->servers, id);
        if (ns)
                return 0;
 
        ns = g_new0(struct network_server, 1);
 
-       ns->iface = g_strdup(NETWORK_SERVER_INTERFACE);
        ns->name = g_strdup("Network service");
 
        path = adapter_get_path(adapter);
 
-       if (!g_dbus_register_interface(connection, path, ns->iface,
+       if (g_slist_length(na->servers) > 0)
+               goto done;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       path, NETWORK_SERVER_INTERFACE,
                                        server_methods, NULL, NULL,
-                                       ns, path_unregister)) {
+                                       na, path_unregister)) {
                error("D-Bus failed to register %s interface",
-                               ns->iface);
+                                               NETWORK_SERVER_INTERFACE);
                server_free(ns);
                return -1;
        }
 
-       adapter_get_address(adapter, &ns->src);
-       ns->id = BNEP_SVC_NAP;
+       DBG("Registered interface %s on path %s", NETWORK_SERVER_INTERFACE,
+                                                                       path);
+
+done:
+       bacpy(&ns->src, adapter_get_address(adapter));
+       ns->id = id;
        ns->na = na;
        ns->record_id = 0;
        na->servers = g_slist_append(na->servers, ns);
 
-       DBG("Registered interface %s on path %s", ns->iface, path);
-
        return 0;
 }
 
-int server_unregister(struct btd_adapter *adapter)
+int server_unregister(struct btd_adapter *adapter, uint16_t id)
 {
        struct network_adapter *na;
        struct network_server *ns;
-       uint16_t id = BNEP_SVC_NAP;
 
        na = find_adapter(adapters, adapter);
        if (!na)
@@ -785,8 +845,15 @@ int server_unregister(struct btd_adapter *adapter)
        if (!ns)
                return -EINVAL;
 
-       g_dbus_unregister_interface(connection, adapter_get_path(adapter),
-                                       ns->iface);
+       na->servers = g_slist_remove(na->servers, ns);
+       server_free(ns);
+
+       if (g_slist_length(na->servers) > 0)
+               return 0;
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               NETWORK_SERVER_INTERFACE);
 
        return 0;
 }
similarity index 84%
rename from network/server.h
rename to profiles/network/server.h
index 6351f6d..2edd342 100644 (file)
@@ -21,7 +21,7 @@
  *
  */
 
-int server_init(DBusConnection *conn, gboolean secure);
+int server_init(gboolean secure);
 void server_exit(void);
-int server_register(struct btd_adapter *adapter);
-int server_unregister(struct btd_adapter *adapter);
+int server_register(struct btd_adapter *adapter, uint16_t id);
+int server_unregister(struct btd_adapter *adapter, uint16_t id);
similarity index 91%
rename from proximity/immalert.c
rename to profiles/proximity/immalert.c
index 1540b61..2f8d4e7 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <adapter.h>
 
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
+#include "lib/uuid.h"
 #include "log.h"
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
-#include "gatt-service.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/att-database.h"
+#include "attrib/gatt-service.h"
 #include "attrib-server.h"
 #include "device.h"
+#include "profile.h"
 #include "attio.h"
 #include "dbus-common.h"
 #include "reporter.h"
@@ -46,7 +49,6 @@
 
 struct imm_alert_adapter {
        struct btd_adapter *adapter;
-       DBusConnection *conn;
        GSList *connected_devices;
 };
 
@@ -125,21 +127,18 @@ const char *imm_alert_get_level(struct btd_device *device)
 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);
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                       PROXIMITY_REPORTER_INTERFACE, "ImmediateAlertLevel");
 }
 
 static void imm_alert_remove_condev(struct connected_device *condev)
@@ -233,7 +232,7 @@ set_error:
        return ATT_ECODE_IO;
 }
 
-void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
+void imm_alert_register(struct btd_adapter *adapter)
 {
        gboolean svc_added;
        bt_uuid_t uuid;
@@ -243,7 +242,6 @@ void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
 
        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);
 
@@ -251,7 +249,7 @@ void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn)
        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_UUID16, ALERT_LEVEL_CHR_UUID,
                                GATT_OPT_CHR_PROPS,
                                        ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
                                GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
@@ -283,7 +281,6 @@ void imm_alert_unregister(struct btd_adapter *adapter)
 
        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);
similarity index 92%
rename from proximity/immalert.h
rename to profiles/proximity/immalert.h
index dd28eaa..1a09fa9 100644 (file)
@@ -21,6 +21,6 @@
  *
  */
 
-void imm_alert_register(struct btd_adapter *adapter, DBusConnection *conn);
+void imm_alert_register(struct btd_adapter *adapter);
 void imm_alert_unregister(struct btd_adapter *adapter);
 const char *imm_alert_get_level(struct btd_device *device);
similarity index 92%
rename from proximity/linkloss.c
rename to profiles/proximity/linkloss.c
index 14403cb..a7ed96c 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <adapter.h>
 
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
+#include "lib/uuid.h"
 #include "log.h"
-#include "att-database.h"
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "gatt-service.h"
+#include "attrib/att-database.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/gatt-service.h"
 #include "attrib-server.h"
 #include "device.h"
+#include "profile.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;
 };
 
@@ -128,7 +128,6 @@ const char *link_loss_get_alert_level(struct btd_device *device)
 
 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)
@@ -139,9 +138,8 @@ static void link_loss_emit_alert_signal(struct connected_device *condev)
 
        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);
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                       PROXIMITY_REPORTER_INTERFACE, "LinkLossAlertLevel");
 }
 
 static uint8_t link_loss_alert_lvl_read(struct attribute *a,
@@ -275,7 +273,7 @@ set_error:
        return ATT_ECODE_IO;
 }
 
-void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn)
+void link_loss_register(struct btd_adapter *adapter)
 {
        gboolean svc_added;
        bt_uuid_t uuid;
@@ -285,7 +283,6 @@ void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn)
 
        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);
 
@@ -293,7 +290,7 @@ void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn)
        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_UUID16, ALERT_LEVEL_CHR_UUID,
                        GATT_OPT_CHR_PROPS,
                                ATT_CHAR_PROPER_READ | ATT_CHAR_PROPER_WRITE,
                        GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
@@ -331,7 +328,6 @@ void link_loss_unregister(struct btd_adapter *adapter)
 
        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);
similarity index 92%
rename from proximity/linkloss.h
rename to profiles/proximity/linkloss.h
index a7d83d0..0447def 100644 (file)
@@ -21,6 +21,6 @@
  *
  */
 
-void link_loss_register(struct btd_adapter *adapter, DBusConnection *conn);
+void link_loss_register(struct btd_adapter *adapter);
 void link_loss_unregister(struct btd_adapter *adapter);
 const char *link_loss_get_alert_level(struct btd_device *device);
similarity index 79%
rename from proximity/main.c
rename to profiles/proximity/main.c
index 3d5d9b2..46468d2 100644 (file)
 #include <errno.h>
 #include <stdint.h>
 #include <glib.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 #include "plugin.h"
 #include "manager.h"
 #include "hcid.h"
 
-static DBusConnection *connection = NULL;
 static GKeyFile *config = NULL;
 
 static GKeyFile *open_config_file(const char *file)
@@ -49,7 +48,8 @@ static GKeyFile *open_config_file(const char *file)
        g_key_file_set_list_separator(keyfile, ',');
 
        if (!g_key_file_load_from_file(keyfile, file, 0, &gerr)) {
-               error("Parsing %s failed: %s", file, gerr->message);
+               if (!g_error_matches(gerr, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+                       error("Parsing %s failed: %s", file, gerr->message);
                g_error_free(gerr);
                g_key_file_free(keyfile);
                return NULL;
@@ -60,35 +60,20 @@ 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)
-               return -EIO;
-
        config = open_config_file(CONFIGDIR "/proximity.conf");
 
-       if (proximity_manager_init(connection, config) < 0) {
-               dbus_connection_unref(connection);
+       if (proximity_manager_init(config) < 0)
                return -EIO;
-       }
 
        return 0;
 }
 
 static void proximity_exit(void)
 {
-       if (!main_opts.gatt_enabled)
-               return;
-
        if (config)
                g_key_file_free(config);
 
        proximity_manager_exit();
-       dbus_connection_unref(connection);
 }
 
 BLUETOOTH_PLUGIN_DEFINE(proximity, VERSION,
diff --git a/profiles/proximity/manager.c b/profiles/proximity/manager.c
new file mode 100644 (file)
index 0000000..7dab23f
--- /dev/null
@@ -0,0 +1,192 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
+#include "monitor.h"
+#include "reporter.h"
+#include "manager.h"
+
+static struct enabled enabled  = {
+       .linkloss = TRUE,
+       .pathloss = TRUE,
+       .findme = TRUE,
+};
+
+static int monitor_linkloss_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *linkloss;
+
+       linkloss = btd_device_get_primary(device, LINK_LOSS_UUID);
+       if (linkloss == NULL)
+               return -1;
+
+       return monitor_register_linkloss(device, &enabled, linkloss);
+}
+
+static int monitor_immediate_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *immediate;
+
+       immediate = btd_device_get_primary(device, IMMEDIATE_ALERT_UUID);
+       if (immediate == NULL)
+               return -1;
+
+       return monitor_register_immediate(device, &enabled, immediate);
+}
+
+static int monitor_txpower_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *txpower;
+
+       txpower = btd_device_get_primary(device, TX_POWER_UUID);
+       if (txpower == NULL)
+               return -1;
+
+       return monitor_register_txpower(device, &enabled, txpower);
+}
+
+static void monitor_linkloss_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       monitor_unregister_linkloss(device);
+}
+
+static void monitor_immediate_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       monitor_unregister_immediate(device);
+}
+
+static void monitor_txpower_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       monitor_unregister_txpower(device);
+}
+
+static struct btd_profile pxp_monitor_linkloss_profile = {
+       .name           = "proximity-linkloss",
+       .remote_uuid    = LINK_LOSS_UUID,
+       .device_probe   = monitor_linkloss_probe,
+       .device_remove  = monitor_linkloss_remove,
+};
+
+static struct btd_profile pxp_monitor_immediate_profile = {
+       .name           = "proximity-immediate",
+       .remote_uuid    = IMMEDIATE_ALERT_UUID,
+       .device_probe   = monitor_immediate_probe,
+       .device_remove  = monitor_immediate_remove,
+};
+
+static struct btd_profile pxp_monitor_txpower_profile = {
+       .name           = "proximity-txpower",
+       .remote_uuid    = TX_POWER_UUID,
+       .device_probe   = monitor_txpower_probe,
+       .device_remove  = monitor_txpower_remove,
+};
+
+static struct btd_profile pxp_reporter_profile = {
+       .name           = "Proximity Reporter GATT Driver",
+       .remote_uuid    = GATT_UUID,
+       .device_probe   = reporter_device_probe,
+       .device_remove  = reporter_device_remove,
+
+       .adapter_probe  = reporter_adapter_probe,
+       .adapter_remove = reporter_adapter_remove,
+};
+
+static void load_config_file(GKeyFile *config)
+{
+       char **list;
+       int i;
+
+       if (config == NULL)
+               return;
+
+       list = g_key_file_get_string_list(config, "General", "Disable",
+                                                               NULL, NULL);
+       for (i = 0; list && list[i] != NULL; i++) {
+               if (g_str_equal(list[i], "FindMe"))
+                       enabled.findme = FALSE;
+               else if (g_str_equal(list[i], "LinkLoss"))
+                       enabled.linkloss = FALSE;
+               else if (g_str_equal(list[i], "PathLoss"))
+                       enabled.pathloss = FALSE;
+       }
+
+       g_strfreev(list);
+}
+
+int proximity_manager_init(GKeyFile *config)
+{
+       load_config_file(config);
+
+       if (btd_profile_register(&pxp_monitor_linkloss_profile) < 0)
+               goto fail;
+
+       if (btd_profile_register(&pxp_monitor_immediate_profile) < 0)
+               goto fail;
+
+       if (btd_profile_register(&pxp_monitor_txpower_profile) < 0)
+               goto fail;
+
+       if (btd_profile_register(&pxp_reporter_profile) < 0)
+               goto fail;
+
+       return 0;
+
+fail:
+       proximity_manager_exit();
+
+       return -1;
+}
+
+void proximity_manager_exit(void)
+{
+       btd_profile_unregister(&pxp_reporter_profile);
+       btd_profile_unregister(&pxp_monitor_txpower_profile);
+       btd_profile_unregister(&pxp_monitor_immediate_profile);
+       btd_profile_unregister(&pxp_monitor_linkloss_profile);
+}
similarity index 93%
rename from proximity/manager.h
rename to profiles/proximity/manager.h
index b0fe7c8..e65c31d 100644 (file)
@@ -22,5 +22,5 @@
  *
  */
 
-int proximity_manager_init(DBusConnection *conn, GKeyFile *conf);
+int proximity_manager_init(GKeyFile *conf);
 void proximity_manager_exit(void);
similarity index 53%
rename from proximity/monitor.c
rename to profiles/proximity/monitor.c
index 98dbcd1..eaa5b0d 100644 (file)
 
 #include <errno.h>
 #include <fcntl.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <sys/stat.h>
+#include <glib.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
 
+#include "lib/uuid.h"
 #include "dbus-common.h"
 #include "adapter.h"
 #include "device.h"
 #include "error.h"
 #include "log.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
 #include "attio.h"
 #include "monitor.h"
 #include "textfile.h"
 
-#define PROXIMITY_INTERFACE "org.bluez.ProximityMonitor"
+#define PROXIMITY_INTERFACE "org.bluez.ProximityMonitor1"
 
 #define ALERT_LEVEL_CHR_UUID 0x2A06
 #define POWER_LEVEL_CHR_UUID 0x2A07
 
 #define IMMEDIATE_TIMEOUT      5
+#define TX_POWER_SIZE          1
 
 enum {
        ALERT_NONE = 0,
@@ -65,7 +68,6 @@ enum {
 struct monitor {
        struct btd_device *device;
        GAttrib *attrib;
-       DBusConnection *conn;
        struct att_range *linkloss;
        struct att_range *txpower;
        struct att_range *immediate;
@@ -82,51 +84,76 @@ struct monitor {
        guint attioid;
 };
 
-static inline int create_filename(char *buf, size_t size,
-                               const bdaddr_t *bdaddr, const char *name)
+static GSList *monitors = NULL;
+
+static struct monitor *find_monitor(struct btd_device *device)
 {
-       char addr[18];
+       GSList *l;
+
+       for (l = monitors; l; l = l->next) {
+               struct monitor *monitor = l->data;
 
-       ba2str(bdaddr, addr);
+               if (monitor->device == device)
+                       return monitor;
+       }
 
-       return create_name(buf, size, STORAGEDIR, addr, name);
+       return NULL;
 }
 
-static int write_proximity_config(bdaddr_t *sba, bdaddr_t *dba,
-                                       const char *alert, const char *level)
+static void write_proximity_config(struct btd_device *device, const char *alert,
+                                       const char *level)
 {
-       char filename[PATH_MAX + 1], addr[18], key[38];
-
-       create_filename(filename, PATH_MAX, sba, "proximity");
+       char *filename;
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
+
+       filename = btd_device_get_storage_path(device, "proximity");
+       if (!filename) {
+               warn("Unable to get proximity storage path for device");
+               return;
+       }
 
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       ba2str(dba, addr);
+       if (level)
+               g_key_file_set_string(key_file, alert, "Level", level);
+       else
+               g_key_file_remove_group(key_file, alert, NULL);
 
-       snprintf(key, sizeof(key), "%17s#%s", addr, alert);
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-       return textfile_put(filename, key, level);
+       g_free(data);
+       g_free(filename);
+       g_key_file_free(key_file);
 }
 
-static char *read_proximity_config(bdaddr_t *sba, bdaddr_t *dba,
-                                                       const char *alert)
+static char *read_proximity_config(struct btd_device *device, const char *alert)
 {
-       char filename[PATH_MAX + 1], addr[18], key[38];
-       char *str, *strnew;
+       char *filename;
+       GKeyFile *key_file;
+       char *str;
 
-       create_filename(filename, PATH_MAX, sba, "proximity");
+       filename = btd_device_get_storage_path(device, "proximity");
+       if (!filename) {
+               warn("Unable to get proximity storage path for device");
+               return NULL;
+       }
 
-       ba2str(dba, addr);
-       snprintf(key, sizeof(key), "%17s#%s", addr, alert);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       str = textfile_caseget(filename, key);
-       if (str == NULL)
-               return NULL;
+       str = g_key_file_get_string(key_file, alert, "Level", NULL);
 
-       strnew = g_strdup(str);
-       free(str);
+       g_free(filename);
+       g_key_file_free(key_file);
 
-       return strnew;
+       return str;
 }
 
 static uint8_t str2level(const char *level)
@@ -159,9 +186,8 @@ static void linkloss_written(guint8 status, const guint8 *pdu, guint16 plen,
 
        DBG("Link Loss Alert Level written");
 
-       emit_property_changed(monitor->conn, path,
-                               PROXIMITY_INTERFACE, "LinkLossAlertLevel",
-                               DBUS_TYPE_STRING, &monitor->linklosslevel);
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                               PROXIMITY_INTERFACE, "LinkLossAlertLevel");
 }
 
 static void char_discovered_cb(GSList *characteristics, guint8 status,
@@ -211,21 +237,22 @@ static int write_alert_level(struct monitor *monitor)
 static void tx_power_read_cb(guint8 status, const guint8 *pdu, guint16 plen,
                                                        gpointer user_data)
 {
-       uint8_t value[ATT_MAX_MTU];
-       int vlen;
+       uint8_t value[TX_POWER_SIZE];
+       ssize_t vlen;
 
        if (status != 0) {
                DBG("Tx Power Level read failed: %s", att_ecode2str(status));
                return;
        }
 
-       if (!dec_read_resp(pdu, plen, value, &vlen)) {
+       vlen = dec_read_resp(pdu, plen, value, sizeof(value));
+       if (vlen < 0) {
                DBG("Protocol error");
                return;
        }
 
        if (vlen != 1) {
-               DBG("Invalid length for TX Power value: %d", vlen);
+               DBG("Invalid length for TX Power value: %zd", vlen);
                return;
        }
 
@@ -248,7 +275,7 @@ static void tx_power_handle_cb(GSList *characteristics, guint8 status,
 
        DBG("Tx Power handle: 0x%04x", monitor->txpowerhandle);
 
-       gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0,
+       gatt_read_char(monitor->attrib, monitor->txpowerhandle,
                                                        tx_power_read_cb, monitor);
 }
 
@@ -258,7 +285,7 @@ static void read_tx_power(struct monitor *monitor)
        bt_uuid_t uuid;
 
        if (monitor->txpowerhandle != 0) {
-               gatt_read_char(monitor->attrib, monitor->txpowerhandle, 0,
+               gatt_read_char(monitor->attrib, monitor->txpowerhandle,
                                                tx_power_read_cb, monitor);
                return;
        }
@@ -287,9 +314,10 @@ static gboolean immediate_timeout(gpointer user_data)
 
        g_free(monitor->immediatelevel);
        monitor->immediatelevel = g_strdup("none");
-       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
-                                       "ImmediateAlertLevel", DBUS_TYPE_STRING,
-                                       &monitor->immediatelevel);
+
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                               PROXIMITY_INTERFACE, "ImmediateAlertLevel");
 
        return FALSE;
 }
@@ -302,9 +330,9 @@ static void immediate_written(gpointer user_data)
        g_free(monitor->fallbacklevel);
        monitor->fallbacklevel = NULL;
 
-       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
-                               "ImmediateAlertLevel",
-                               DBUS_TYPE_STRING, &monitor->immediatelevel);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                               PROXIMITY_INTERFACE, "ImmediateAlertLevel");
 
        monitor->immediateto = g_timeout_add_seconds(IMMEDIATE_TIMEOUT,
                                                immediate_timeout, monitor);
@@ -388,9 +416,9 @@ static void attio_disconnected_cb(gpointer user_data)
 
        g_free(monitor->immediatelevel);
        monitor->immediatelevel = g_strdup("none");
-       emit_property_changed(monitor->conn, path, PROXIMITY_INTERFACE,
-                                       "ImmediateAlertLevel", DBUS_TYPE_STRING,
-                                       &monitor->immediatelevel);
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(), path,
+                               PROXIMITY_INTERFACE, "ImmediateAlertLevel");
 }
 
 static gboolean level_is_valid(const char *level)
@@ -400,43 +428,103 @@ static gboolean level_is_valid(const char *level)
                        g_str_equal("high", level));
 }
 
-static DBusMessage *set_link_loss_alert(DBusConnection *conn, DBusMessage *msg,
-                                               const char *level, void *data)
+static gboolean property_get_link_loss_level(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
        struct monitor *monitor = data;
-       struct btd_device *device = monitor->device;
-       bdaddr_t sba, dba;
 
-       if (!level_is_valid(level))
-               return btd_error_invalid_args(msg);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                               &monitor->linklosslevel);
+
+       return TRUE;
+}
+
+static void property_set_link_loss_level(const GDBusPropertyTable *property,
+               DBusMessageIter *iter, GDBusPendingPropertySet id, void *data)
+{
+       struct monitor *monitor = data;
+       const char *level;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &level);
+
+       if (!level_is_valid(level)) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
 
        if (g_strcmp0(monitor->linklosslevel, level) == 0)
-               return dbus_message_new_method_return(msg);
+               goto done;
 
        g_free(monitor->linklosslevel);
        monitor->linklosslevel = g_strdup(level);
 
-       adapter_get_address(device_get_adapter(device), &sba);
-       device_get_address(device, &dba, NULL);
-
-       write_proximity_config(&sba, &dba, "LinkLossAlertLevel", level);
+       write_proximity_config(monitor->device, "LinkLossAlertLevel", level);
 
        if (monitor->attrib)
                write_alert_level(monitor);
 
-       return dbus_message_new_method_return(msg);
+done:
+       g_dbus_pending_property_success(id);
+}
+
+static gboolean property_exists_link_loss_level(
+                               const GDBusPropertyTable *property, void *data)
+{
+       struct monitor *monitor = data;
+
+       if (!monitor->enabled.linkloss)
+               return FALSE;
+
+       return TRUE;
 }
 
-static DBusMessage *set_immediate_alert(DBusConnection *conn, DBusMessage *msg,
-                                               const char *level, void *data)
+static gboolean property_get_immediate_alert_level(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
        struct monitor *monitor = data;
 
-       if (!level_is_valid(level))
-               return btd_error_invalid_args(msg);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                               &monitor->immediatelevel);
+
+       return TRUE;
+}
+
+static void property_set_immediate_alert_level(
+               const GDBusPropertyTable *property, DBusMessageIter *iter,
+               GDBusPendingPropertySet id, void *data)
+{
+       struct monitor *monitor = data;
+       struct btd_device *device = monitor->device;
+       const char *level;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &level);
+
+       if (!level_is_valid(level)) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
 
        if (g_strcmp0(monitor->immediatelevel, level) == 0)
-               return dbus_message_new_method_return(msg);
+               goto done;
 
        if (monitor->immediateto) {
                g_source_remove(monitor->immediateto);
@@ -456,109 +544,60 @@ static DBusMessage *set_immediate_alert(DBusConnection *conn, DBusMessage *msg,
         * when the Proximity Monitor starts.
         */
        if (monitor->attioid == 0)
-               monitor->attioid = btd_device_add_attio_callback(monitor->device,
+               monitor->attioid = btd_device_add_attio_callback(device,
                                                        attio_connected_cb,
                                                        attio_disconnected_cb,
                                                        monitor);
        else if (monitor->attrib)
                write_immediate_alert(monitor);
 
-       return dbus_message_new_method_return(msg);
+done:
+       g_dbus_pending_property_success(id);
 }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static gboolean property_exists_immediate_alert_level(
+                               const GDBusPropertyTable *property, void *data)
 {
        struct monitor *monitor = data;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       DBusMessage *reply;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
 
-       if (monitor->enabled.linkloss)
-               dict_append_entry(&dict, "LinkLossAlertLevel",
-                               DBUS_TYPE_STRING, &monitor->linklosslevel);
-
-       if (monitor->enabled.findme || monitor->enabled.pathloss)
-               dict_append_entry(&dict, "ImmediateAlertLevel",
-                               DBUS_TYPE_STRING, &monitor->immediatelevel);
-
-       if (monitor->enabled.pathloss)
-               dict_append_entry(&dict, "SignalLevel",
-                               DBUS_TYPE_STRING, &monitor->signallevel);
-
-       dbus_message_iter_close_container(&iter, &dict);
+       if (!(monitor->enabled.findme || monitor->enabled.pathloss))
+               return FALSE;
 
-       return reply;
+       return TRUE;
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static gboolean property_get_signal_level(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
        struct monitor *monitor = data;
-       const char *property;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *level;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
 
-       dbus_message_iter_recurse(&iter, &sub);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                               &monitor->signallevel);
 
-       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&sub, &level);
-
-       if (g_str_equal("ImmediateAlertLevel", property)) {
-               if (monitor->enabled.findme == FALSE &&
-                               monitor->enabled.pathloss == FALSE)
-                       return btd_error_not_available(msg);
+       return TRUE;
+}
 
-               return set_immediate_alert(conn, msg, level, data);
-       } else if (g_str_equal("LinkLossAlertLevel", property)) {
-               if (monitor->enabled.linkloss == FALSE)
-                       return btd_error_not_available(msg);
+static gboolean property_exists_signal_level(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct monitor *monitor = data;
 
-               return set_link_loss_alert(conn, msg, level, data);
-       }
+       if (!monitor->enabled.pathloss)
+               return FALSE;
 
-       return btd_error_invalid_args(msg);
+       return TRUE;
 }
 
-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 const GDBusSignalTable monitor_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+static const GDBusPropertyTable monitor_device_properties[] = {
+       { "LinkLossAlertLevel", "s", property_get_link_loss_level,
+                                       property_set_link_loss_level,
+                                       property_exists_link_loss_level },
+       { "ImmediateAlertLevel", "s", property_get_immediate_alert_level,
+                                       property_set_immediate_alert_level,
+                                       property_exists_immediate_alert_level },
+       { "SignalLevel", "s", property_get_signal_level, NULL,
+                                       property_exists_signal_level },
        { }
 };
 
@@ -566,102 +605,214 @@ static void monitor_destroy(gpointer user_data)
 {
        struct monitor *monitor = user_data;
 
-       if (monitor->immediateto)
-               g_source_remove(monitor->immediateto);
-
-       if (monitor->attioid)
-               btd_device_remove_attio_callback(monitor->device,
-                                               monitor->attioid);
-       if (monitor->attrib)
-               g_attrib_unref(monitor->attrib);
-
-       dbus_connection_unref(monitor->conn);
        btd_device_unref(monitor->device);
-       g_free(monitor->linkloss);
-       g_free(monitor->immediate);
-       g_free(monitor->txpower);
        g_free(monitor->linklosslevel);
        g_free(monitor->immediatelevel);
        g_free(monitor->signallevel);
        g_free(monitor);
+
+       monitors = g_slist_remove(monitors, monitor);
 }
 
-int monitor_register(DBusConnection *conn, struct btd_device *device,
-               struct gatt_primary *linkloss, struct gatt_primary *txpower,
-               struct gatt_primary *immediate, struct enabled *enabled)
+static struct monitor *register_monitor(struct btd_device *device)
 {
        const char *path = device_get_path(device);
        struct monitor *monitor;
-       bdaddr_t sba, dba;
        char *level;
 
-       adapter_get_address(device_get_adapter(device), &sba);
-       device_get_address(device, &dba, NULL);
+       monitor = find_monitor(device);
+       if (monitor != NULL)
+               return monitor;
 
-       level = read_proximity_config(&sba, &dba, "LinkLossAlertLevel");
+       level = read_proximity_config(device, "LinkLossAlertLevel");
 
        monitor = g_new0(struct monitor, 1);
        monitor->device = btd_device_ref(device);
-       monitor->conn = dbus_connection_ref(conn);
        monitor->linklosslevel = (level ? : g_strdup("high"));
        monitor->signallevel = g_strdup("unknown");
        monitor->immediatelevel = g_strdup("none");
 
-       if (g_dbus_register_interface(conn, path,
+       monitors = g_slist_append(monitors, monitor);
+
+       if (g_dbus_register_interface(btd_get_dbus_connection(), path,
                                PROXIMITY_INTERFACE,
-                               monitor_methods, monitor_signals,
-                               NULL, monitor, monitor_destroy) == FALSE) {
+                               NULL, NULL, monitor_device_properties,
+                               monitor, monitor_destroy) == FALSE) {
                error("D-Bus failed to register %s interface",
                                                PROXIMITY_INTERFACE);
                monitor_destroy(monitor);
-               return -1;
+               return NULL;
        }
 
        DBG("Registered interface %s on path %s", PROXIMITY_INTERFACE, path);
 
-       if (linkloss && enabled->linkloss) {
-               monitor->linkloss = g_new0(struct att_range, 1);
-               monitor->linkloss->start = linkloss->range.start;
-               monitor->linkloss->end = linkloss->range.end;
-
-               monitor->enabled.linkloss = TRUE;
-       }
-
-       if (immediate) {
-               if (txpower && enabled->pathloss) {
-                       monitor->txpower = g_new0(struct att_range, 1);
-                       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->range.start;
-                       monitor->immediate->end = immediate->range.end;
-               }
+       return monitor;
+}
 
-               monitor->enabled.findme = enabled->findme;
-       }
+static void update_monitor(struct monitor *monitor)
+{
+       if (monitor->txpower != NULL && monitor->immediate != NULL)
+               monitor->enabled.pathloss = TRUE;
+       else
+               monitor->enabled.pathloss = FALSE;
 
        DBG("Link Loss: %s, Path Loss: %s, FindMe: %s",
                                monitor->enabled.linkloss ? "TRUE" : "FALSE",
                                monitor->enabled.pathloss ? "TRUE" : "FALSE",
                                monitor->enabled.findme ? "TRUE" : "FALSE");
 
-       if (monitor->enabled.linkloss || monitor->enabled.pathloss)
-               monitor->attioid = btd_device_add_attio_callback(device,
+       if (!monitor->enabled.linkloss && !monitor->enabled.pathloss)
+               return;
+
+       if (monitor->attioid != 0)
+               return;
+
+       monitor->attioid = btd_device_add_attio_callback(monitor->device,
                                                        attio_connected_cb,
                                                        attio_disconnected_cb,
                                                        monitor);
+}
+
+int monitor_register_linkloss(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *linkloss)
+{
+       struct monitor *monitor;
+
+       if (!enabled->linkloss)
+               return 0;
+
+       monitor = register_monitor(device);
+       if (monitor == NULL)
+               return -1;
+
+       monitor->linkloss = g_new0(struct att_range, 1);
+       monitor->linkloss->start = linkloss->range.start;
+       monitor->linkloss->end = linkloss->range.end;
+       monitor->enabled.linkloss = TRUE;
+
+       update_monitor(monitor);
+
+       return 0;
+}
+
+int monitor_register_txpower(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *txpower)
+{
+       struct monitor *monitor;
+
+       if (!enabled->pathloss)
+               return 0;
+
+       monitor = register_monitor(device);
+       if (monitor == NULL)
+               return -1;
+
+       monitor->txpower = g_new0(struct att_range, 1);
+       monitor->txpower->start = txpower->range.start;
+       monitor->txpower->end = txpower->range.end;
+
+       update_monitor(monitor);
+
+       return 0;
+}
+
+int monitor_register_immediate(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *immediate)
+{
+       struct monitor *monitor;
+
+       if (!enabled->pathloss && !enabled->findme)
+               return 0;
+
+       monitor = register_monitor(device);
+       if (monitor == NULL)
+               return -1;
+
+       monitor->immediate = g_new0(struct att_range, 1);
+       monitor->immediate->start = immediate->range.start;
+       monitor->immediate->end = immediate->range.end;
+       monitor->enabled.findme = enabled->findme;
+
+       update_monitor(monitor);
 
        return 0;
 }
 
-void monitor_unregister(DBusConnection *conn, struct btd_device *device)
+static void cleanup_monitor(struct monitor *monitor)
 {
+       struct btd_device *device = monitor->device;
        const char *path = device_get_path(device);
 
-       g_dbus_unregister_interface(conn, path, PROXIMITY_INTERFACE);
+       if (monitor->immediate != NULL || monitor->txpower != NULL)
+               return;
+
+       if (monitor->immediateto != 0) {
+               g_source_remove(monitor->immediateto);
+               monitor->immediateto = 0;
+       }
+
+       if (monitor->linkloss != NULL)
+               return;
+
+       if (monitor->attioid != 0) {
+               btd_device_remove_attio_callback(device, monitor->attioid);
+               monitor->attioid = 0;
+       }
+
+       if (monitor->attrib != NULL) {
+               g_attrib_unref(monitor->attrib);
+               monitor->attrib = NULL;
+       }
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(), path,
+                                                       PROXIMITY_INTERFACE);
+}
+
+void monitor_unregister_linkloss(struct btd_device *device)
+{
+       struct monitor *monitor;
+
+       monitor = find_monitor(device);
+       if (monitor == NULL)
+               return;
+
+       g_free(monitor->linkloss);
+       monitor->linkloss = NULL;
+       monitor->enabled.linkloss = FALSE;
+
+       cleanup_monitor(monitor);
+}
+
+void monitor_unregister_txpower(struct btd_device *device)
+{
+       struct monitor *monitor;
+
+       monitor = find_monitor(device);
+       if (monitor == NULL)
+               return;
+
+       g_free(monitor->txpower);
+       monitor->txpower = NULL;
+       monitor->enabled.pathloss = FALSE;
+
+       cleanup_monitor(monitor);
+}
+
+void monitor_unregister_immediate(struct btd_device *device)
+{
+       struct monitor *monitor;
+
+       monitor = find_monitor(device);
+       if (monitor == NULL)
+               return;
+
+       g_free(monitor->immediate);
+       monitor->immediate = NULL;
+       monitor->enabled.findme = FALSE;
+       monitor->enabled.pathloss = FALSE;
+
+       cleanup_monitor(monitor);
 }
similarity index 63%
rename from proximity/monitor.h
rename to profiles/proximity/monitor.h
index b71363d..d9a40c6 100644 (file)
@@ -28,7 +28,16 @@ struct enabled {
        gboolean findme;
 };
 
-int monitor_register(DBusConnection *conn, struct btd_device *device,
-               struct gatt_primary *linkloss, struct gatt_primary *txpower,
-               struct gatt_primary *immediate, struct enabled *enabled);
-void monitor_unregister(DBusConnection *conn, struct btd_device *device);
+int monitor_register_linkloss(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *linkloss);
+int monitor_register_txpower(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *txpower);
+int monitor_register_immediate(struct btd_device *device,
+                                               struct enabled *enabled,
+                                               struct gatt_primary *immediate);
+
+void monitor_unregister_linkloss(struct btd_device *device);
+void monitor_unregister_txpower(struct btd_device *device);
+void monitor_unregister_immediate(struct btd_device *device);
similarity index 66%
rename from proximity/reporter.c
rename to profiles/proximity/reporter.c
index 607de2b..dbb593a 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+#include <errno.h>
+
 #include <glib.h>
-#include <bluetooth/uuid.h>
 #include <adapter.h>
-#include <errno.h>
 
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 
+#include "lib/uuid.h"
 #include "dbus-common.h"
 #include "error.h"
 #include "device.h"
+#include "profile.h"
+#include "service.h"
 #include "hcid.h"
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/att-database.h"
 #include "attrib-server.h"
 #include "reporter.h"
 #include "linkloss.h"
 #include "immalert.h"
 
-#define BLUEZ_SERVICE "org.bluez"
-
 struct reporter_adapter {
-       DBusConnection *conn;
        struct btd_adapter *adapter;
        GSList *devices;
 };
@@ -139,56 +140,36 @@ static void register_tx_power(struct btd_adapter *adapter)
        g_assert(h - start_handle == svc_size);
 }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+static gboolean property_get_link_loss_level(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       DBusMessage *reply = NULL;
-       const char *linkloss_level, *immalert_level;
        struct btd_device *device = data;
+       const char *level;
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       linkloss_level = link_loss_get_alert_level(device);
-       immalert_level = imm_alert_get_level(device);
+       level = link_loss_get_alert_level(device);
 
-       dbus_message_iter_init_append(reply, &iter);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &level);
 
-       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;
+       return TRUE;
+}
 
-       dict_append_entry(&dict, "LinkLossAlertLevel", DBUS_TYPE_STRING,
-                                                       &linkloss_level);
-       dict_append_entry(&dict, "ImmediateAlertLevel", DBUS_TYPE_STRING,
-                                                       &immalert_level);
+static gboolean property_get_immediate_alert_level(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       const char *level;
 
-       if (!dbus_message_iter_close_container(&iter, &dict))
-               goto err;
+       level = imm_alert_get_level(device);
 
-       return reply;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &level);
 
-err:
-       if (reply)
-               dbus_message_unref(reply);
-       return btd_error_failed(msg, "not enough memory");
+       return TRUE;
 }
 
-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 const GDBusPropertyTable reporter_device_properties[] = {
+       { "LinkLossAlertLevel", "s", property_get_link_loss_level },
+       { "ImmediateAlertLevel", "s", property_get_immediate_alert_level },
        { }
 };
 
@@ -200,7 +181,7 @@ static void unregister_reporter_device(gpointer data, gpointer user_data)
 
        DBG("unregister on device %s", path);
 
-       g_dbus_unregister_interface(radapter->conn, path,
+       g_dbus_unregister_interface(btd_get_dbus_connection(), path,
                                        PROXIMITY_REPORTER_INTERFACE);
 
        radapter->devices = g_slist_remove(radapter->devices, device);
@@ -214,17 +195,18 @@ static void register_reporter_device(struct btd_device *device,
 
        DBG("register on device %s", path);
 
-       g_dbus_register_interface(radapter->conn, path,
+       g_dbus_register_interface(btd_get_dbus_connection(), path,
                                        PROXIMITY_REPORTER_INTERFACE,
-                                       reporter_methods, reporter_signals,
-                                       NULL, device, NULL);
+                                       NULL, NULL, reporter_device_properties,
+                                       device, NULL);
 
        btd_device_ref(device);
        radapter->devices = g_slist_prepend(radapter->devices, device);
 }
 
-static int reporter_device_probe(struct btd_device *device, GSList *uuids)
+int reporter_device_probe(struct btd_service *service)
 {
+       struct btd_device *device = btd_service_get_device(service);
        struct reporter_adapter *radapter;
        struct btd_adapter *adapter = device_get_adapter(device);
 
@@ -233,11 +215,13 @@ static int reporter_device_probe(struct btd_device *device, GSList *uuids)
                return -1;
 
        register_reporter_device(device, radapter);
+
        return 0;
 }
 
-static void reporter_device_remove(struct btd_device *device)
+void reporter_device_remove(struct btd_service *service)
 {
+       struct btd_device *device = btd_service_get_device(service);
        struct reporter_adapter *radapter;
        struct btd_adapter *adapter = device_get_adapter(device);
 
@@ -248,37 +232,16 @@ static void reporter_device_remove(struct btd_device *device)
        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)
+int reporter_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter)
 {
        struct reporter_adapter *radapter;
-       DBusConnection *conn;
-
-       if (!main_opts.gatt_enabled) {
-               DBG("GATT is disabled");
-               return -ENOTSUP;
-       }
-
-       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);
+       link_loss_register(adapter);
        register_tx_power(adapter);
-       imm_alert_register(adapter, radapter->conn);
-
-       btd_register_device_driver(&reporter_device_driver);
+       imm_alert_register(adapter);
 
        reporter_adapters = g_slist_prepend(reporter_adapters, radapter);
        DBG("Proximity Reporter for adapter %p", adapter);
@@ -286,20 +249,18 @@ int reporter_init(struct btd_adapter *adapter)
        return 0;
 }
 
-void reporter_exit(struct btd_adapter *adapter)
+void reporter_adapter_remove(struct btd_profile *p,
+                                               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);
similarity index 81%
rename from proximity/reporter.h
rename to profiles/proximity/reporter.h
index 5ae0eb2..a8e1aac 100644 (file)
@@ -22,7 +22,7 @@
  *
  */
 
-#define PROXIMITY_REPORTER_INTERFACE "org.bluez.ProximityReporter"
+#define PROXIMITY_REPORTER_INTERFACE "org.bluez.ProximityReporter1"
 
 #define IMMEDIATE_ALERT_SVC_UUID       0x1802
 #define LINK_LOSS_SVC_UUID             0x1803
@@ -36,7 +36,11 @@ enum {
        HIGH_ALERT = 0x02,
 };
 
-int reporter_init(struct btd_adapter *adapter);
-void reporter_exit(struct btd_adapter *adapter);
+void reporter_device_remove(struct btd_service *service);
+int reporter_device_probe(struct btd_service *service);
+
+int reporter_adapter_probe(struct btd_profile *p, struct btd_adapter *adapter);
+void reporter_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter);
 
 const char *get_alert_level_string(uint8_t level);
similarity index 79%
rename from sap/main.c
rename to profiles/sap/main.c
index c9c90bd..8cc9533 100644 (file)
 #endif
 
 #include <errno.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 #include "plugin.h"
 #include "manager.h"
 
-static DBusConnection *connection;
-
 static int sap_init(void)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-
-       if (!connection)
-               return -EIO;
-
-       if (sap_manager_init(connection) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
-       }
-
-       return 0;
+       return sap_manager_init();
 }
 
 static void sap_exit(void)
 {
        sap_manager_exit();
-
-       dbus_connection_unref(connection);
 }
 
 BLUETOOTH_PLUGIN_DEFINE(sap, VERSION,
similarity index 59%
rename from sap/manager.c
rename to profiles/sap/manager.c
index 9fa9c56..bfb81a5 100644 (file)
 #include <config.h>
 #endif
 
+#include <stdbool.h>
+
 #include "log.h"
 #include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
 
 #include "manager.h"
 #include "server.h"
 
-static DBusConnection *connection = NULL;
-
-static int sap_server_probe(struct btd_adapter *adapter)
+static int sap_server_probe(struct btd_profile *p, struct btd_adapter *adapter)
 {
-       const char *path = adapter_get_path(adapter);
-       bdaddr_t src;
-
-       DBG("path %s", path);
+       DBG("path %s", adapter_get_path(adapter));
 
-       adapter_get_address(adapter, &src);
-
-       return sap_server_register(path, &src);
+       return sap_server_register(adapter);
 }
 
-static void sap_server_remove(struct btd_adapter *adapter)
+static void sap_server_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
 {
        const char *path = adapter_get_path(adapter);
 
@@ -51,33 +50,20 @@ static void sap_server_remove(struct btd_adapter *adapter)
        sap_server_unregister(path);
 }
 
-static struct btd_adapter_driver sap_server_driver = {
-       .name   = "sap-server",
-       .probe  = sap_server_probe,
-       .remove = sap_server_remove,
+static struct btd_profile sap_profile = {
+       .name           = "sap-server",
+       .adapter_probe  = sap_server_probe,
+       .adapter_remove = sap_server_remove,
 };
 
-int sap_manager_init(DBusConnection *conn)
+int sap_manager_init(void)
 {
-       connection = dbus_connection_ref(conn);
-
-       if (sap_server_init(connection) < 0) {
-               error("Can't init SAP server");
-               dbus_connection_unref(conn);
-               return -1;
-       }
-
-       btd_register_adapter_driver(&sap_server_driver);
+       btd_profile_register(&sap_profile);
 
        return 0;
 }
 
 void sap_manager_exit(void)
 {
-       btd_unregister_adapter_driver(&sap_server_driver);
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-
-       sap_server_exit();
+       btd_profile_unregister(&sap_profile);
 }
similarity index 95%
rename from sap/manager.h
rename to profiles/sap/manager.h
index e08c882..6601a03 100644 (file)
@@ -18,5 +18,5 @@
  *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
  */
 
-int sap_manager_init(DBusConnection *conn);
+int sap_manager_init(void);
 void sap_manager_exit(void);
similarity index 73%
rename from sap/sap-dummy.c
rename to profiles/sap/sap-dummy.c
index 7ea4e92..47dedf7 100644 (file)
 #endif
 
 #include <glib.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
+#include <stdint.h>
 
+#include "dbus-common.h"
+#include "error.h"
 #include "log.h"
 #include "sap.h"
 
-#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest"
+#define SAP_DUMMY_IFACE "org.bluez.SimAccessTest1"
 #define SAP_DUMMY_PATH "/org/bluez/test"
 
 enum {
@@ -42,7 +45,7 @@ enum {
        SIM_MISSING      = 0x03
 };
 
-static DBusConnection *connection = NULL;
+static unsigned int init_cnt = 0;
 
 static int sim_card_conn_status = SIM_DISCONNECTED;
 static void *sap_data = NULL; /* SAP server private data. */
@@ -54,34 +57,30 @@ void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
        DBG("status: %d", sim_card_conn_status);
 
        if (sim_card_conn_status != SIM_DISCONNECTED) {
-               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
-                                                               maxmsgsize);
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED);
                return;
        }
 
        if (max_msg_size_supported > maxmsgsize) {
-               sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL,
-                                               max_msg_size_supported);
+               sap_connect_rsp(sap_device, SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL);
                return;
        }
 
        if (max_msg_size_supported < maxmsgsize) {
                sap_connect_rsp(sap_device,
-                               SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
-                               max_msg_size_supported);
+                                       SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED);
                return;
        }
 
        if (ongoing_call_status) {
-               sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL,
-                                               max_msg_size_supported);
+               sap_connect_rsp(sap_device, SAP_STATUS_OK_ONGOING_CALL);
                return;
        }
 
        sim_card_conn_status = SIM_CONNECTED;
        sap_data = sap_device;
 
-       sap_connect_rsp(sap_device, SAP_STATUS_OK, maxmsgsize);
+       sap_connect_rsp(sap_device, SAP_STATUS_OK);
        sap_status_ind(sap_device, SAP_STATUS_CHANGE_CARD_RESET);
 }
 
@@ -105,18 +104,24 @@ void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
 
        DBG("status: %d", sim_card_conn_status);
 
-       if (sim_card_conn_status == SIM_MISSING)
+       switch (sim_card_conn_status) {
+       case SIM_MISSING:
                sap_transfer_apdu_rsp(sap_device,
                                SAP_RESULT_ERROR_CARD_REMOVED, NULL, 0);
-       else if (sim_card_conn_status == SIM_POWERED_OFF)
+               break;
+       case SIM_POWERED_OFF:
                sap_transfer_apdu_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
                                                                NULL, 0);
-       else if (sim_card_conn_status != SIM_CONNECTED)
+               break;
+       case SIM_DISCONNECTED:
                sap_transfer_apdu_rsp(sap_device,
-                       SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
-       else
+                               SAP_RESULT_ERROR_NOT_ACCESSIBLE, NULL, 0);
+               break;
+       case SIM_CONNECTED:
                sap_transfer_apdu_rsp(sap_device, SAP_RESULT_OK,
-                                               (uint8_t *)&apdu, sizeof(apdu));
+                                               (uint8_t *)apdu, sizeof(apdu));
+               break;
+       }
 }
 
 void sap_transfer_atr_req(void *sap_device)
@@ -125,36 +130,46 @@ void sap_transfer_atr_req(void *sap_device)
 
        DBG("status: %d", sim_card_conn_status);
 
-       if (sim_card_conn_status == SIM_MISSING)
+       switch (sim_card_conn_status) {
+       case SIM_MISSING:
                sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED,
                                                                NULL, 0);
-       else if (sim_card_conn_status == SIM_POWERED_OFF)
+               break;
+       case SIM_POWERED_OFF:
                sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF,
                                                                NULL, 0);
-       else if (sim_card_conn_status != SIM_CONNECTED)
+               break;
+       case SIM_DISCONNECTED:
                sap_transfer_atr_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON,
                                                                NULL, 0);
-       else
+               break;
+       case SIM_CONNECTED:
                sap_transfer_atr_rsp(sap_device, SAP_RESULT_OK,
-                                               (uint8_t *)&atr, sizeof(atr));
+                                               (uint8_t *)atr, sizeof(atr));
+               break;
+       }
 }
 
 void sap_power_sim_off_req(void *sap_device)
 {
        DBG("status: %d", sim_card_conn_status);
 
-       if (sim_card_conn_status == SIM_MISSING) {
+       switch (sim_card_conn_status) {
+       case SIM_MISSING:
                sap_power_sim_off_rsp(sap_device,
                                        SAP_RESULT_ERROR_CARD_REMOVED);
-       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               break;
+       case SIM_POWERED_OFF:
                sap_power_sim_off_rsp(sap_device,
                                        SAP_RESULT_ERROR_POWERED_OFF);
-       } else if (sim_card_conn_status != SIM_CONNECTED) {
-               sap_power_sim_off_rsp(sap_device,
-                                       SAP_RESULT_ERROR_NO_REASON);
-       } else {
+               break;
+       case SIM_DISCONNECTED:
+               sap_power_sim_off_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+               break;
+       case SIM_CONNECTED:
                sap_power_sim_off_rsp(sap_device, SAP_RESULT_OK);
                sim_card_conn_status = SIM_POWERED_OFF;
+               break;
        }
 }
 
@@ -162,19 +177,22 @@ void sap_power_sim_on_req(void *sap_device)
 {
        DBG("status: %d", sim_card_conn_status);
 
-       if (sim_card_conn_status == SIM_MISSING) {
+       switch (sim_card_conn_status) {
+       case SIM_MISSING:
                sap_power_sim_on_rsp(sap_device,
                                        SAP_RESULT_ERROR_CARD_REMOVED);
-       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               break;
+       case SIM_POWERED_OFF:
                sap_power_sim_on_rsp(sap_device, SAP_RESULT_OK);
                sim_card_conn_status = SIM_CONNECTED;
-               return;
-       } else if (sim_card_conn_status != SIM_CONNECTED) {
+               break;
+       case SIM_DISCONNECTED:
                sap_power_sim_on_rsp(sap_device,
                                        SAP_RESULT_ERROR_NOT_ACCESSIBLE);
-       } else {
-               sap_power_sim_on_rsp(sap_device,
-                                       SAP_RESULT_ERROR_NO_REASON);
+               break;
+       case SIM_CONNECTED:
+               sap_power_sim_on_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
+               break;
        }
 }
 
@@ -182,14 +200,19 @@ void sap_reset_sim_req(void *sap_device)
 {
        DBG("status: %d", sim_card_conn_status);
 
-       if (sim_card_conn_status == SIM_MISSING) {
+       switch (sim_card_conn_status) {
+       case SIM_MISSING:
                sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_CARD_REMOVED);
-       } else if (sim_card_conn_status == SIM_POWERED_OFF) {
+               break;
+       case SIM_POWERED_OFF:
                sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_POWERED_OFF);
-       } else if (sim_card_conn_status != SIM_CONNECTED) {
+               break;
+       case SIM_DISCONNECTED:
                sap_reset_sim_rsp(sap_device, SAP_RESULT_ERROR_NO_REASON);
-       } else {
+               break;
+       case SIM_CONNECTED:
                sap_reset_sim_rsp(sap_device, SAP_RESULT_OK);
+               break;
        }
 }
 
@@ -212,12 +235,6 @@ void sap_set_transport_protocol_req(void *sap_device,
        sap_transport_protocol_rsp(sap_device, SAP_RESULT_NOT_SUPPORTED);
 }
 
-static inline DBusMessage *invalid_args(DBusMessage *msg)
-{
-       return g_dbus_create_error(msg, "org.bluez.Error.InvalidArguments",
-                                       "Invalid arguments in method call");
-}
-
 static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
                                                void *data)
 {
@@ -225,7 +242,7 @@ static DBusMessage *ongoing_call(DBusConnection *conn, DBusMessage *msg,
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_BOOLEAN, &ongoing,
                                                DBUS_TYPE_INVALID))
-               return invalid_args(msg);
+               return btd_error_invalid_args(msg);
 
        if (ongoing_call_status && !ongoing) {
                /* An ongoing call has finished. Continue connection.*/
@@ -247,12 +264,12 @@ static DBusMessage *max_msg_size(DBusConnection *conn, DBusMessage *msg,
        dbus_uint32_t size;
 
        if (sim_card_conn_status == SIM_CONNECTED)
-               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+               return btd_error_failed(msg,
                                "Can't change msg size when connected.");
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &size,
                                                        DBUS_TYPE_INVALID))
-               return invalid_args(msg);
+               return btd_error_invalid_args(msg);
 
        max_msg_size_supported = size;
 
@@ -265,8 +282,7 @@ static DBusMessage *disconnect_immediate(DBusConnection *conn, DBusMessage *msg,
                                                void *data)
 {
        if (sim_card_conn_status == SIM_DISCONNECTED)
-               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
-                               "Already disconnected.");
+               return btd_error_failed(msg, "Already disconnected.");
 
        sim_card_conn_status = SIM_DISCONNECTED;
        sap_disconnect_ind(sap_data, SAP_DISCONNECTION_TYPE_IMMEDIATE);
@@ -282,12 +298,12 @@ static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
        DBG("status %d", sim_card_conn_status);
 
        if (sim_card_conn_status != SIM_CONNECTED)
-               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
+               return btd_error_failed(msg,
                                "Can't change msg size when not connected.");
 
        if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_UINT32, &status,
                                                        DBUS_TYPE_INVALID))
-               return invalid_args(msg);
+               return btd_error_invalid_args(msg);
 
        switch (status) {
        case 0: /* card removed */
@@ -309,8 +325,8 @@ static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
                break;
 
        default:
-               return g_dbus_create_error(msg, "org.bluez.Error.Failed",
-                               "Unknown card status. Use 0, 1 or 2.");
+               return btd_error_failed(msg,
+                                       "Unknown card status. Use 0, 1 or 2.");
        }
 
        DBG("Card status changed to %d", status);
@@ -319,15 +335,15 @@ static DBusMessage *card_status(DBusConnection *conn, DBusMessage *msg,
 }
 
 static const GDBusMethodTable dummy_methods[] = {
-       { GDBUS_METHOD("OngoingCall",
+       { GDBUS_EXPERIMENTAL_METHOD("OngoingCall",
                                GDBUS_ARGS({ "ongoing", "b" }), NULL,
                                ongoing_call) },
-       { GDBUS_METHOD("MaxMessageSize",
+       { GDBUS_EXPERIMENTAL_METHOD("MaxMessageSize",
                                GDBUS_ARGS({ "size", "u" }), NULL,
                                max_msg_size) },
-       { GDBUS_METHOD("DisconnectImmediate", NULL, NULL,
+       { GDBUS_EXPERIMENTAL_METHOD("DisconnectImmediate", NULL, NULL,
                                disconnect_immediate) },
-       { GDBUS_METHOD("CardStatus",
+       { GDBUS_EXPERIMENTAL_METHOD("CardStatus",
                                GDBUS_ARGS({ "status", "" }), NULL,
                                card_status) },
        { }
@@ -335,15 +351,13 @@ static const GDBusMethodTable dummy_methods[] = {
 
 int sap_init(void)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       if (init_cnt++)
+               return 0;
 
-       if (g_dbus_register_interface(connection, SAP_DUMMY_PATH,
+       if (g_dbus_register_interface(btd_get_dbus_connection(), SAP_DUMMY_PATH,
                                SAP_DUMMY_IFACE, dummy_methods, NULL, NULL,
                                NULL, NULL) == FALSE) {
-               error("sap-dummy interface %s init failed on path %s",
-                                       SAP_DUMMY_IFACE, SAP_DUMMY_PATH);
-               dbus_connection_unref(connection);
-               connection = NULL;
+               init_cnt--;
                return -1;
        }
 
@@ -352,9 +366,9 @@ int sap_init(void)
 
 void sap_exit(void)
 {
-       g_dbus_unregister_interface(connection, SAP_DUMMY_PATH,
-                                                       SAP_DUMMY_IFACE);
+       if (--init_cnt)
+               return;
 
-       dbus_connection_unref(connection);
-       connection = NULL;
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       SAP_DUMMY_PATH, SAP_DUMMY_IFACE);
 }
similarity index 94%
rename from sap/sap-u8500.c
rename to profiles/sap/sap-u8500.c
index 2920cc7..39169a0 100644 (file)
  *  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 <fcntl.h>
 #define STE_SIMD_SOCK  "/dev/socket/catd_a"
 #define STE_CLIENT_TAG 0x0000
 
-#ifdef STE_SAP_DEBUG
-#define DBG_VERBOSE(fmt, arg...) DBG(fmt, arg)
-#else
-#define DBG_VERBOSE(fmt...)
-#endif
-
 #define sap_error(fmt, arg...) do { \
        error("STE U8500 SAP: " fmt, ## arg); \
        } while (0)
@@ -264,7 +262,7 @@ static int send_message(GIOChannel *io, void *buf, size_t size)
 {
        gsize written;
 
-       DBG_VERBOSE("io %p, size %zu", io, size);
+       SAP_VDBG("io %p, size %zu", io, size);
 
        if (g_io_channel_write_chars(io, buf, size, &written, NULL) !=
                                                        G_IO_STATUS_NORMAL)
@@ -280,7 +278,7 @@ static int send_request(GIOChannel *io, uint16_t id,
        struct ste_message *msg;
        size_t size = sizeof(*msg);
 
-       DBG_VERBOSE("io %p", io);
+       SAP_VDBG("io %p", io);
 
        if (param)
                size += param->len;
@@ -319,16 +317,16 @@ static void recv_status(uint32_t status)
 
 static void recv_card_status(uint32_t status, uint8_t *param)
 {
-       uint32_t *card_status;
+       uint32_t card_status;
        uint8_t result;
        uint8_t iccrs;
 
        if (status != STE_STATUS_OK)
                return;
 
-       card_status = (uint32_t *)param;
+       memcpy(&card_status, param, sizeof(card_status));
 
-       if (get_sap_reader_status(*card_status, &iccrs) < 0)
+       if (get_sap_reader_status(card_status, &iccrs) < 0)
                result = SAP_RESULT_ERROR_NO_REASON;
        else
                result = get_sap_result(STE_GET_STATUS_MSG, status);
@@ -385,8 +383,7 @@ static void recv_sim_ready(void)
        sap_info("sim is ready. Try to connect again");
 
        if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
-               sap_connect_rsp(u8500.sap_data, SAP_STATUS_CONNECTION_FAILED,
-                                                               SAP_BUF_SIZE);
+               sap_connect_rsp(u8500.sap_data, SAP_STATUS_CONNECTION_FAILED);
                simd_close();
        }
 }
@@ -396,21 +393,18 @@ static void recv_connect_rsp(uint32_t status)
        switch (status) {
        case STE_STATUS_OK:
                if (u8500.state != STE_SIM_BUSY)
-                       sap_connect_rsp(u8500.sap_data,
-                                       SAP_STATUS_OK, 0);
+                       sap_connect_rsp(u8500.sap_data, SAP_STATUS_OK);
                break;
        case STE_STATUS_BUSY_CALL:
                if (u8500.state != STE_SIM_BUSY) {
                        sap_connect_rsp(u8500.sap_data,
-                               SAP_STATUS_OK_ONGOING_CALL,
-                               SAP_BUF_SIZE);
+                                               SAP_STATUS_OK_ONGOING_CALL);
 
                        u8500.state = STE_SIM_BUSY;
                }
                break;
        default:
-               sap_connect_rsp(u8500.sap_data,
-                               SAP_STATUS_CONNECTION_FAILED, 0);
+               sap_connect_rsp(u8500.sap_data, SAP_STATUS_CONNECTION_FAILED);
                simd_close();
                break;
        }
@@ -421,7 +415,7 @@ static void recv_response(struct ste_message *msg)
        uint32_t status;
        uint8_t *param;
 
-       DBG_VERBOSE("msg_id 0x%x", msg->id);
+       SAP_VDBG("msg_id 0x%x", msg->id);
 
        if (msg->id == STE_END_SAP_RSP) {
                sap_disconnect_rsp(u8500.sap_data);
@@ -430,10 +424,10 @@ static void recv_response(struct ste_message *msg)
        }
 
        param = msg->payload;
-       status = *(uint32_t *)param;
+       memcpy(&status, param, sizeof(status));
        param += sizeof(status);
 
-       DBG_VERBOSE("status 0x%x", status);
+       SAP_VDBG("status 0x%x", status);
 
        switch (msg->id) {
        case STE_START_SAP_RSP:
@@ -487,7 +481,7 @@ static int recv_message(void *buf, size_t size)
        struct ste_message *msg = buf;
 
        do {
-               DBG_VERBOSE("size %zu msg->len %u.", size, msg->len);
+               SAP_VDBG("size %zu msg->len %u.", size, msg->len);
 
                if (size < sizeof(*msg)) {
                        sap_error("invalid message received (%zu bytes)", size);
@@ -608,13 +602,12 @@ void sap_connect_req(void *sap_device, uint16_t maxmsgsize)
        sap_info("connect request");
 
        if (simd_connect(sap_device) < 0) {
-               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED, 0);
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED);
                return;
        }
 
        if (send_request(u8500.io, STE_START_SAP_REQ, NULL) < 0) {
-               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED,
-                                                               SAP_BUF_SIZE);
+               sap_connect_rsp(sap_device, SAP_STATUS_CONNECTION_FAILED);
                simd_close();
        }
 }
@@ -646,7 +639,7 @@ void sap_transfer_apdu_req(void *sap_device, struct sap_parameter *param)
 {
        uint8_t result;
 
-       DBG_VERBOSE("sap_device %p param %p", sap_device, param);
+       SAP_VDBG("sap_device %p param %p", sap_device, param);
 
        if (u8500.state != STE_ENABLED) {
                result = get_sap_result(STE_SEND_APDU_MSG, STE_STATUS_FAILURE);
similarity index 96%
rename from sap/sap.h
rename to profiles/sap/sap.h
index 1dbb235..16c333a 100644 (file)
--- a/sap/sap.h
 #include <stdint.h>
 #include <glib.h>
 
+#ifdef SAP_DEBUG
+#define SAP_VDBG(fmt, arg...) DBG(fmt, arg)
+#else
+#define SAP_VDBG(fmt...)
+#endif
+
 #define SAP_VERSION 0x0101
 
 /* Connection Status - SAP v1.1 section 5.2.2 */
@@ -40,8 +46,7 @@ enum sap_status {
 /* Disconnection Type - SAP v1.1 section 5.2.3 */
 enum sap_disconnection_type {
        SAP_DISCONNECTION_TYPE_GRACEFUL         = 0x00,
-       SAP_DISCONNECTION_TYPE_IMMEDIATE        = 0x01,
-       SAP_DISCONNECTION_TYPE_CLIENT           = 0xFF
+       SAP_DISCONNECTION_TYPE_IMMEDIATE        = 0x01
 };
 
 /* Result codes - SAP v1.1 section 5.2.4 */
@@ -157,7 +162,7 @@ void sap_set_transport_protocol_req(void *sap_device,
                                        struct sap_parameter *param);
 
 /*SAP responses to SAP requests. Implemented by server.c */
-int sap_connect_rsp(void *sap_device, uint8_t status, uint16_t maxmsgsize);
+int sap_connect_rsp(void *sap_device, uint8_t status);
 int sap_disconnect_rsp(void *sap_device);
 int sap_transfer_apdu_rsp(void *sap_device, uint8_t result,
                                uint8_t *sap_apdu_resp, uint16_t length);
@@ -168,7 +173,6 @@ int sap_power_sim_on_rsp(void *sap_device, uint8_t result);
 int sap_reset_sim_rsp(void *sap_device, uint8_t result);
 int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
                                                uint8_t status);
-int sap_error_rsp(void *sap_device);
 int sap_transport_protocol_rsp(void *sap_device, uint8_t result);
 
 /* Event indication. Implemented by server.c*/
similarity index 74%
rename from sap/server.c
rename to profiles/sap/server.c
index f5d19c4..63314a7 100644 (file)
 #include <glib.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
 
+#include "lib/uuid.h"
+#include "btio/btio.h"
 #include "adapter.h"
-#include "btio.h"
 #include "sdpd.h"
 #include "log.h"
 #include "error.h"
 #include "sap.h"
 #include "server.h"
 
-#define SAP_SERVER_INTERFACE   "org.bluez.SimAccess"
+#define SAP_SERVER_INTERFACE   "org.bluez.SimAccess1"
 #define SAP_SERVER_CHANNEL     8
 
 #define PADDING4(x) ((4 - ((x) & 0x03)) & 0x03)
 #define PARAMETER_SIZE(x) (sizeof(struct sap_parameter) + x + PADDING4(x))
 
 #define SAP_NO_REQ 0xFF
+#define SAP_DISCONNECTION_TYPE_CLIENT 0xFF
 
 #define SAP_TIMER_GRACEFUL_DISCONNECT 30
 #define SAP_TIMER_NO_ACTIVITY 30
@@ -72,17 +73,14 @@ struct sap_connection {
 };
 
 struct sap_server {
-       char *path;
+       struct btd_adapter *adapter;
        uint32_t record_id;
        GIOChannel *listen_io;
        struct sap_connection *conn;
 };
 
-static DBusConnection *connection;
-static struct sap_server *server;
-
-static void start_guard_timer(struct sap_connection *conn, guint interval);
-static void stop_guard_timer(struct sap_connection *conn);
+static void start_guard_timer(struct sap_server *server, guint interval);
+static void stop_guard_timer(struct sap_server *server);
 static gboolean guard_timeout(gpointer data);
 
 static size_t add_result_parameter(uint8_t result,
@@ -243,10 +241,7 @@ static int send_message(struct sap_connection *conn, void *buf, size_t size)
        GError *gerr = NULL;
        GIOStatus gstatus;
 
-       if (!conn || !buf)
-               return -EINVAL;
-
-       DBG("conn %p, size %zu", conn, size);
+       SAP_VDBG("conn %p, size %zu", conn, size);
 
        gstatus = g_io_channel_write_chars(conn->io, buf, size, &written,
                                                                        &gerr);
@@ -266,9 +261,8 @@ static int send_message(struct sap_connection *conn, void *buf, size_t size)
        return written;
 }
 
-static int disconnect_ind(void *sap_device, uint8_t disc_type)
+static int disconnect_ind(struct sap_connection *conn, uint8_t disc_type)
 {
-       struct sap_connection *conn = sap_device;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -286,13 +280,27 @@ static int disconnect_ind(void *sap_device, uint8_t disc_type)
        *param->val = disc_type;
        size += PARAMETER_SIZE(SAP_PARAM_ID_DISCONNECT_IND_LEN);
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
-static void connect_req(struct sap_connection *conn,
+static int sap_error_rsp(struct sap_connection *conn)
+{
+       struct sap_message msg;
+
+       memset(&msg, 0, sizeof(msg));
+       msg.id = SAP_ERROR_RESP;
+
+       error("SAP error (state %d pr 0x%02x).", conn->state,
+                                                       conn->processing_req);
+
+       return send_message(conn, &msg, sizeof(msg));
+}
+
+static void connect_req(struct sap_server *server,
                                struct sap_parameter *param)
 {
-       uint16_t maxmsgsize, *val;
+       struct sap_connection *conn = server->conn;
+       uint16_t maxmsgsize;
 
        DBG("conn %p state %d", conn, conn->state);
 
@@ -302,10 +310,9 @@ static void connect_req(struct sap_connection *conn,
        if (conn->state != SAP_STATE_DISCONNECTED)
                goto error_rsp;
 
-       stop_guard_timer(conn);
+       stop_guard_timer(server);
 
-       val = (uint16_t *) &param->val;
-       maxmsgsize = ntohs(*val);
+       maxmsgsize = bt_get_be16(&param->val);
 
        DBG("Connect MaxMsgSize: 0x%04x", maxmsgsize);
 
@@ -313,10 +320,9 @@ static void connect_req(struct sap_connection *conn,
 
        if (maxmsgsize <= SAP_BUF_SIZE) {
                conn->processing_req = SAP_CONNECT_REQ;
-               sap_connect_req(conn, maxmsgsize);
+               sap_connect_req(server, maxmsgsize);
        } else {
-               sap_connect_rsp(conn, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED,
-                                                               SAP_BUF_SIZE);
+               sap_connect_rsp(server, SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED);
        }
 
        return;
@@ -325,8 +331,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
+static int disconnect_req(struct sap_server *server, uint8_t disc_type)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d disc_type 0x%02x", conn, conn->state, disc_type);
 
        switch (disc_type) {
@@ -342,7 +350,8 @@ static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
 
                        disconnect_ind(conn, disc_type);
                        /* Timer will disconnect if client won't do.*/
-                       start_guard_timer(conn, SAP_TIMER_GRACEFUL_DISCONNECT);
+                       start_guard_timer(server,
+                                       SAP_TIMER_GRACEFUL_DISCONNECT);
                }
 
                return 0;
@@ -358,9 +367,9 @@ static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
                        conn->state = SAP_STATE_IMMEDIATE_DISCONNECT;
                        conn->processing_req = SAP_NO_REQ;
 
-                       stop_guard_timer(conn);
+                       stop_guard_timer(server);
                        disconnect_ind(conn, disc_type);
-                       sap_disconnect_req(conn, 0);
+                       sap_disconnect_req(server, 0);
                }
 
                return 0;
@@ -375,8 +384,8 @@ static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
                conn->state = SAP_STATE_CLIENT_DISCONNECT;
                conn->processing_req = SAP_NO_REQ;
 
-               stop_guard_timer(conn);
-               sap_disconnect_req(conn, 0);
+               stop_guard_timer(server);
+               sap_disconnect_req(server, 0);
 
                return 0;
 
@@ -386,10 +395,12 @@ static int disconnect_req(struct sap_connection *conn, uint8_t disc_type)
        }
 }
 
-static void transfer_apdu_req(struct sap_connection *conn,
+static void transfer_apdu_req(struct sap_server *server,
                                        struct sap_parameter *param)
 {
-       DBG("conn %p state %d", conn, conn->state);
+       struct sap_connection *conn = server->conn;
+
+       SAP_VDBG("conn %p state %d", conn, conn->state);
 
        if (!param)
                goto error_rsp;
@@ -404,7 +415,7 @@ static void transfer_apdu_req(struct sap_connection *conn,
                goto error_rsp;
 
        conn->processing_req = SAP_TRANSFER_APDU_REQ;
-       sap_transfer_apdu_req(conn, param);
+       sap_transfer_apdu_req(server, param);
 
        return;
 
@@ -412,8 +423,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void transfer_atr_req(struct sap_connection *conn)
+static void transfer_atr_req(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d", conn, conn->state);
 
        if (conn->state != SAP_STATE_CONNECTED)
@@ -423,7 +436,7 @@ static void transfer_atr_req(struct sap_connection *conn)
                goto error_rsp;
 
        conn->processing_req = SAP_TRANSFER_ATR_REQ;
-       sap_transfer_atr_req(conn);
+       sap_transfer_atr_req(server);
 
        return;
 
@@ -431,8 +444,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void power_sim_off_req(struct sap_connection *conn)
+static void power_sim_off_req(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d", conn, conn->state);
 
        if (conn->state != SAP_STATE_CONNECTED)
@@ -442,7 +457,7 @@ static void power_sim_off_req(struct sap_connection *conn)
                goto error_rsp;
 
        conn->processing_req = SAP_POWER_SIM_OFF_REQ;
-       sap_power_sim_off_req(conn);
+       sap_power_sim_off_req(server);
 
        return;
 
@@ -450,8 +465,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void power_sim_on_req(struct sap_connection *conn)
+static void power_sim_on_req(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d", conn, conn->state);
 
        if (conn->state != SAP_STATE_CONNECTED)
@@ -461,7 +478,7 @@ static void power_sim_on_req(struct sap_connection *conn)
                goto error_rsp;
 
        conn->processing_req = SAP_POWER_SIM_ON_REQ;
-       sap_power_sim_on_req(conn);
+       sap_power_sim_on_req(server);
 
        return;
 
@@ -469,8 +486,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void reset_sim_req(struct sap_connection *conn)
+static void reset_sim_req(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d", conn, conn->state);
 
        if (conn->state != SAP_STATE_CONNECTED)
@@ -480,7 +499,7 @@ static void reset_sim_req(struct sap_connection *conn)
                goto error_rsp;
 
        conn->processing_req = SAP_RESET_SIM_REQ;
-       sap_reset_sim_req(conn);
+       sap_reset_sim_req(server);
 
        return;
 
@@ -488,8 +507,10 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void transfer_card_reader_status_req(struct sap_connection *conn)
+static void transfer_card_reader_status_req(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p state %d", conn, conn->state);
 
        if (conn->state != SAP_STATE_CONNECTED)
@@ -499,7 +520,7 @@ static void transfer_card_reader_status_req(struct sap_connection *conn)
                goto error_rsp;
 
        conn->processing_req = SAP_TRANSFER_CARD_READER_STATUS_REQ;
-       sap_transfer_card_reader_status_req(conn);
+       sap_transfer_card_reader_status_req(server);
 
        return;
 
@@ -507,9 +528,11 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void set_transport_protocol_req(struct sap_connection *conn,
+static void set_transport_protocol_req(struct sap_server *server,
                                        struct sap_parameter *param)
 {
+       struct sap_connection *conn = server->conn;
+
        if (!param)
                goto error_rsp;
 
@@ -522,7 +545,7 @@ static void set_transport_protocol_req(struct sap_connection *conn,
                goto error_rsp;
 
        conn->processing_req = SAP_SET_TRANSPORT_PROTOCOL_REQ;
-       sap_set_transport_protocol_req(conn, param);
+       sap_set_transport_protocol_req(server, param);
 
        return;
 
@@ -530,20 +553,24 @@ error_rsp:
        sap_error_rsp(conn);
 }
 
-static void start_guard_timer(struct sap_connection *conn, guint interval)
+static void start_guard_timer(struct sap_server *server, guint interval)
 {
+       struct sap_connection *conn = server->conn;
+
        if (!conn)
                return;
 
        if (!conn->timer_id)
                conn->timer_id = g_timeout_add_seconds(interval, guard_timeout,
-                                                                       conn);
+                                                               server);
        else
                error("Timer is already active.");
 }
 
-static void stop_guard_timer(struct sap_connection *conn)
+static void stop_guard_timer(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        if (conn  && conn->timer_id) {
                g_source_remove(conn->timer_id);
                conn->timer_id = 0;
@@ -552,7 +579,8 @@ static void stop_guard_timer(struct sap_connection *conn)
 
 static gboolean guard_timeout(gpointer data)
 {
-       struct sap_connection *conn = data;
+       struct sap_server *server = data;
+       struct sap_connection *conn = server->conn;
 
        if (!conn)
                return FALSE;
@@ -570,13 +598,14 @@ static gboolean guard_timeout(gpointer data)
                if (conn->io) {
                        g_io_channel_shutdown(conn->io, TRUE, NULL);
                        g_io_channel_unref(conn->io);
+                       conn->io = NULL;
                }
                break;
 
        case SAP_STATE_GRACEFUL_DISCONNECT:
                /* Client didn't disconnect SAP connection in fixed time,
                 * so close SAP connection immediately. */
-               disconnect_req(conn, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+               disconnect_req(server, SAP_DISCONNECTION_TYPE_IMMEDIATE);
                break;
 
        default:
@@ -587,20 +616,19 @@ static gboolean guard_timeout(gpointer data)
        return FALSE;
 }
 
-static void sap_set_connected(struct sap_connection *conn)
+static void sap_set_connected(struct sap_server *server)
 {
-       gboolean connected = TRUE;
-
-       emit_property_changed(connection, server->path,
-                                       SAP_SERVER_INTERFACE,
-               "Connected", DBUS_TYPE_BOOLEAN, &connected);
+       server->conn->state = SAP_STATE_CONNECTED;
 
-       conn->state = SAP_STATE_CONNECTED;
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       adapter_get_path(server->adapter),
+                                       SAP_SERVER_INTERFACE, "Connected");
 }
 
-int sap_connect_rsp(void *sap_device, uint8_t status, uint16_t maxmsgsize)
+int sap_connect_rsp(void *sap_device, uint8_t status)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -625,40 +653,42 @@ int sap_connect_rsp(void *sap_device, uint8_t status, uint16_t maxmsgsize)
        *param->val = status;
        size += PARAMETER_SIZE(SAP_PARAM_ID_CONN_STATUS_LEN);
 
-       /* Add MaxMsgSize */
-       if (maxmsgsize) {
-               uint16_t *len;
 
+       switch (status) {
+       case SAP_STATUS_OK:
+               sap_set_connected(server);
+               break;
+       case SAP_STATUS_OK_ONGOING_CALL:
+               DBG("ongoing call. Wait for reset indication!");
+               conn->state = SAP_STATE_CONNECT_MODEM_BUSY;
+               break;
+       case SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED: /* Add MaxMsgSize */
                msg->nparam++;
                param = (struct sap_parameter *) &buf[size];
                param->id = SAP_PARAM_ID_MAX_MSG_SIZE;
                param->len = htons(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
-               len = (uint16_t *) &param->val;
-               *len = htons(maxmsgsize);
+               bt_put_be16(SAP_BUF_SIZE, &param->val);
                size += PARAMETER_SIZE(SAP_PARAM_ID_MAX_MSG_SIZE_LEN);
-       }
 
-       if (status == SAP_STATUS_OK) {
-               sap_set_connected(conn);
-       } else if (status == SAP_STATUS_OK_ONGOING_CALL) {
-               DBG("ongoing call. Wait for reset indication!");
-               conn->state = SAP_STATE_CONNECT_MODEM_BUSY;
-       } else {
+               /* fall */
+       default:
                conn->state = SAP_STATE_DISCONNECTED;
 
                /* Timer will shutdown channel if client doesn't send
                 * CONNECT_REQ or doesn't shutdown channel itself.*/
-               start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+               start_guard_timer(server, SAP_TIMER_NO_ACTIVITY);
+               break;
        }
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_disconnect_rsp(void *sap_device)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        struct sap_message msg;
 
        if (!conn)
@@ -675,9 +705,9 @@ int sap_disconnect_rsp(void *sap_device)
                conn->processing_req = SAP_NO_REQ;
 
                /* Timer will close channel if client doesn't do it.*/
-               start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+               start_guard_timer(server, SAP_TIMER_NO_ACTIVITY);
 
-               return send_message(sap_device, &msg, sizeof(msg));
+               return send_message(conn, &msg, sizeof(msg));
 
        case SAP_STATE_IMMEDIATE_DISCONNECT:
                conn->state = SAP_STATE_DISCONNECTED;
@@ -686,6 +716,7 @@ int sap_disconnect_rsp(void *sap_device)
                if (conn->io) {
                        g_io_channel_shutdown(conn->io, TRUE, NULL);
                        g_io_channel_unref(conn->io);
+                       conn->io = NULL;
                }
 
                return 0;
@@ -700,7 +731,8 @@ int sap_disconnect_rsp(void *sap_device)
 int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
                                        uint16_t length)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -709,7 +741,7 @@ int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
        if (!conn)
                return -EINVAL;
 
-       DBG("state %d pr 0x%02x", conn->state, conn->processing_req);
+       SAP_VDBG("state %d pr 0x%02x", conn->state, conn->processing_req);
 
        if (conn->processing_req != SAP_TRANSFER_APDU_REQ)
                return 0;
@@ -739,13 +771,14 @@ int sap_transfer_apdu_rsp(void *sap_device, uint8_t result, uint8_t *apdu,
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_transfer_atr_rsp(void *sap_device, uint8_t result, uint8_t *atr,
                                        uint16_t length)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -784,12 +817,13 @@ int sap_transfer_atr_rsp(void *sap_device, uint8_t result, uint8_t *atr,
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_power_sim_off_rsp(void *sap_device, uint8_t result)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        size_t size = sizeof(struct sap_message);
@@ -809,12 +843,13 @@ int sap_power_sim_off_rsp(void *sap_device, uint8_t result)
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_power_sim_on_rsp(void *sap_device, uint8_t result)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        size_t size = sizeof(struct sap_message);
@@ -834,12 +869,13 @@ int sap_power_sim_on_rsp(void *sap_device, uint8_t result)
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_reset_sim_rsp(void *sap_device, uint8_t result)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        size_t size = sizeof(struct sap_message);
@@ -860,13 +896,14 @@ int sap_reset_sim_rsp(void *sap_device, uint8_t result)
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
                                                uint8_t status)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -898,12 +935,13 @@ int sap_transfer_card_reader_status_rsp(void *sap_device, uint8_t result,
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
+       return send_message(conn, buf, size);
 }
 
 int sap_transport_protocol_rsp(void *sap_device, uint8_t result)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        size_t size = sizeof(struct sap_message);
@@ -924,26 +962,13 @@ int sap_transport_protocol_rsp(void *sap_device, uint8_t result)
 
        conn->processing_req = SAP_NO_REQ;
 
-       return send_message(sap_device, buf, size);
-}
-
-int sap_error_rsp(void *sap_device)
-{
-       struct sap_message msg;
-       struct sap_connection *conn = sap_device;
-
-       memset(&msg, 0, sizeof(msg));
-       msg.id = SAP_ERROR_RESP;
-
-       error("SAP error (state %d pr 0x%02x).", conn->state,
-                                                       conn->processing_req);
-
-       return send_message(conn, &msg, sizeof(msg));
+       return send_message(conn, buf, size);
 }
 
 int sap_status_ind(void *sap_device, uint8_t status_change)
 {
-       struct sap_connection *conn = sap_device;
+       struct sap_server *server = sap_device;
+       struct sap_connection *conn = server->conn;
        char buf[SAP_BUF_SIZE];
        struct sap_message *msg = (struct sap_message *) buf;
        struct sap_parameter *param = (struct sap_parameter *) msg->param;
@@ -955,37 +980,45 @@ int sap_status_ind(void *sap_device, uint8_t status_change)
        DBG("state %d pr 0x%02x sc 0x%02x", conn->state, conn->processing_req,
                                                                status_change);
 
-       /* Might be need to change state to connected after ongoing call.*/
-       if (conn->state == SAP_STATE_CONNECT_MODEM_BUSY &&
-                       status_change == SAP_STATUS_CHANGE_CARD_RESET)
-               sap_set_connected(conn);
-
-       if (conn->state != SAP_STATE_CONNECTED &&
-                       conn->state != SAP_STATE_GRACEFUL_DISCONNECT)
-               return 0;
+       switch (conn->state) {
+       case SAP_STATE_CONNECT_MODEM_BUSY:
+               if (status_change != SAP_STATUS_CHANGE_CARD_RESET)
+                       break;
+
+               /* Change state to connected after ongoing call ended */
+               sap_set_connected(server);
+               /* fall */
+       case SAP_STATE_CONNECTED:
+       case SAP_STATE_GRACEFUL_DISCONNECT:
+               memset(buf, 0, sizeof(buf));
+               msg->id = SAP_STATUS_IND;
+               msg->nparam = 0x01;
 
-       memset(buf, 0, sizeof(buf));
-       msg->id = SAP_STATUS_IND;
-       msg->nparam = 0x01;
+               /* Add status change. */
+               param->id  = SAP_PARAM_ID_STATUS_CHANGE;
+               param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+               *param->val = status_change;
+               size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
 
-       /* Add status change. */
-       param->id  = SAP_PARAM_ID_STATUS_CHANGE;
-       param->len = htons(SAP_PARAM_ID_STATUS_CHANGE_LEN);
-       *param->val = status_change;
-       size += PARAMETER_SIZE(SAP_PARAM_ID_STATUS_CHANGE_LEN);
+               return send_message(conn, buf, size);
+       case SAP_STATE_DISCONNECTED:
+       case SAP_STATE_CONNECT_IN_PROGRESS:
+       case SAP_STATE_IMMEDIATE_DISCONNECT:
+       case SAP_STATE_CLIENT_DISCONNECT:
+               break;
+       }
 
-       return send_message(sap_device, buf, size);
+       return 0;
 }
 
 int sap_disconnect_ind(void *sap_device, uint8_t disc_type)
 {
-       struct sap_connection *conn = sap_device;
-
-       return disconnect_req(conn, SAP_DISCONNECTION_TYPE_IMMEDIATE);
+       return disconnect_req(sap_device, SAP_DISCONNECTION_TYPE_IMMEDIATE);
 }
 
-static int handle_cmd(struct sap_connection *conn, void *buf, size_t size)
+static int handle_cmd(struct sap_server *server, void *buf, size_t size)
 {
+       struct sap_connection *conn = server->conn;
        struct sap_message *msg = buf;
 
        if (!conn)
@@ -1003,31 +1036,31 @@ static int handle_cmd(struct sap_connection *conn, void *buf, size_t size)
 
        switch (msg->id) {
        case SAP_CONNECT_REQ:
-               connect_req(conn, msg->param);
+               connect_req(server, msg->param);
                return 0;
        case SAP_DISCONNECT_REQ:
-               disconnect_req(conn, SAP_DISCONNECTION_TYPE_CLIENT);
+               disconnect_req(server, SAP_DISCONNECTION_TYPE_CLIENT);
                return 0;
        case SAP_TRANSFER_APDU_REQ:
-               transfer_apdu_req(conn, msg->param);
+               transfer_apdu_req(server, msg->param);
                return 0;
        case SAP_TRANSFER_ATR_REQ:
-               transfer_atr_req(conn);
+               transfer_atr_req(server);
                return 0;
        case SAP_POWER_SIM_OFF_REQ:
-               power_sim_off_req(conn);
+               power_sim_off_req(server);
                return 0;
        case SAP_POWER_SIM_ON_REQ:
-               power_sim_on_req(conn);
+               power_sim_on_req(server);
                return 0;
        case SAP_RESET_SIM_REQ:
-               reset_sim_req(conn);
+               reset_sim_req(server);
                return 0;
        case SAP_TRANSFER_CARD_READER_STATUS_REQ:
-               transfer_card_reader_status_req(conn);
+               transfer_card_reader_status_req(server);
                return 0;
        case SAP_SET_TRANSPORT_PROTOCOL_REQ:
-               set_transport_protocol_req(conn, msg->param);
+               set_transport_protocol_req(server, msg->param);
                return 0;
        default:
                DBG("Unknown SAP message id 0x%02x.", msg->id);
@@ -1040,8 +1073,10 @@ error_rsp:
        return -EBADMSG;
 }
 
-static void sap_conn_remove(struct sap_connection *conn)
+static void sap_server_remove_conn(struct sap_server *server)
 {
+       struct sap_connection *conn = server->conn;
+
        DBG("conn %p", conn);
 
        if (!conn)
@@ -1052,21 +1087,18 @@ static void sap_conn_remove(struct sap_connection *conn)
                g_io_channel_unref(conn->io);
        }
 
-       conn->io = NULL;
        g_free(conn);
        server->conn = NULL;
 }
 
 static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
 {
-       struct sap_connection *conn = data;
-
        char buf[SAP_BUF_SIZE];
        size_t bytes_read = 0;
        GError *gerr = NULL;
        GIOStatus gstatus;
 
-       DBG("conn %p io %p", conn, io);
+       SAP_VDBG("conn %p io %p", conn, io);
 
        if (cond & G_IO_NVAL) {
                DBG("ERR (G_IO_NVAL) on rfcomm socket.");
@@ -1092,7 +1124,7 @@ static gboolean sap_io_cb(GIOChannel *io, GIOCondition cond, gpointer data)
                return TRUE;
        }
 
-       if (handle_cmd(conn, buf, bytes_read) < 0)
+       if (handle_cmd(data, buf, bytes_read) < 0)
                error("SAP protocol processing failure.");
 
        return TRUE;
@@ -1100,34 +1132,36 @@ 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;
+       struct sap_server *server = data;
+       struct sap_connection *conn = server->conn;
 
        DBG("conn %p", conn);
 
        if (!conn || !conn->io)
                return;
 
-       stop_guard_timer(conn);
+       stop_guard_timer(server);
 
        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);
+                               conn->state != SAP_STATE_CONNECT_MODEM_BUSY)
+               g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                       adapter_get_path(server->adapter),
+                                       SAP_SERVER_INTERFACE,
+                                       "Connected");
 
        if (conn->state == SAP_STATE_CONNECT_IN_PROGRESS ||
                        conn->state == SAP_STATE_CONNECT_MODEM_BUSY ||
                        conn->state == SAP_STATE_CONNECTED ||
                        conn->state == SAP_STATE_GRACEFUL_DISCONNECT)
-               sap_disconnect_req(NULL, 1);
+               sap_disconnect_req(server, 1);
 
-       sap_conn_remove(conn);
+       sap_server_remove_conn(server);
 }
 
 static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
 {
-       struct sap_connection *conn = data;
+       struct sap_server *server = data;
+       struct sap_connection *conn = server->conn;
 
        DBG("conn %p, io %p", conn, io);
 
@@ -1136,16 +1170,17 @@ static void sap_connect_cb(GIOChannel *io, GError *gerr, gpointer data)
 
        /* Timer will shutdown the channel in case of lack of client
           activity */
-       start_guard_timer(conn, SAP_TIMER_NO_ACTIVITY);
+       start_guard_timer(server, SAP_TIMER_NO_ACTIVITY);
 
        g_io_add_watch_full(io, G_PRIORITY_DEFAULT,
                        G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL,
-                       sap_io_cb, conn, sap_io_destroy);
+                       sap_io_cb, server, sap_io_destroy);
 }
 
 static void connect_auth_cb(DBusError *derr, void *data)
 {
-       struct sap_connection *conn = data;
+       struct sap_server *server = data;
+       struct sap_connection *conn = server->conn;
        GError *gerr = NULL;
 
        DBG("conn %p", conn);
@@ -1155,14 +1190,14 @@ static void connect_auth_cb(DBusError *derr, void *data)
 
        if (derr && dbus_error_is_set(derr)) {
                error("Access has been denied (%s)", derr->message);
-               sap_conn_remove(conn);
+               sap_server_remove_conn(server);
                return;
        }
 
-       if (!bt_io_accept(conn->io, sap_connect_cb, conn, NULL, &gerr)) {
+       if (!bt_io_accept(conn->io, sap_connect_cb, server, NULL, &gerr)) {
                error("bt_io_accept: %s", gerr->message);
                g_error_free(gerr);
-               sap_conn_remove(conn);
+               sap_server_remove_conn(server);
                return;
        }
 
@@ -1171,11 +1206,12 @@ static void connect_auth_cb(DBusError *derr, void *data)
 
 static void connect_confirm_cb(GIOChannel *io, gpointer data)
 {
+       struct sap_server *server = data;
        struct sap_connection *conn = server->conn;
        GError *gerr = NULL;
        bdaddr_t src, dst;
        char dstaddr[18];
-       int err;
+       guint ret;
 
        DBG("conn %p io %p", conn, io);
 
@@ -1202,112 +1238,98 @@ static void connect_confirm_cb(GIOChannel *io, gpointer data)
        conn->io = g_io_channel_ref(io);
        conn->state = SAP_STATE_DISCONNECTED;
 
-       bt_io_get(io, BT_IO_RFCOMM, &gerr,
+       bt_io_get(io, &gerr,
                        BT_IO_OPT_SOURCE_BDADDR, &src,
                        BT_IO_OPT_DEST_BDADDR, &dst,
                        BT_IO_OPT_INVALID);
        if (gerr) {
                error("%s", gerr->message);
                g_error_free(gerr);
-               sap_conn_remove(conn);
+               sap_server_remove_conn(server);
                return;
        }
 
        ba2str(&dst, dstaddr);
 
-       err = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
-                                                                       conn);
-       if (err < 0) {
-               error("Authorization failure (err %d)", err);
-               sap_conn_remove(conn);
+       ret = btd_request_authorization(&src, &dst, SAP_UUID, connect_auth_cb,
+                                                               server);
+       if (ret == 0) {
+               error("Authorization failure");
+               sap_server_remove_conn(server);
                return;
        }
 
        DBG("Authorizing incoming SAP connection from %s", dstaddr);
 }
 
-static inline DBusMessage *message_failed(DBusMessage *msg,
-                                       const char *description)
-{
-       return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed", "%s",
-                                                               description);
-}
-
 static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
                                                                void *data)
 {
        struct sap_server *server = data;
 
        if (!server)
-               return message_failed(msg, "Server internal error.");
+               return btd_error_failed(msg, "Server internal error.");
 
        DBG("conn %p", server->conn);
 
        if (!server->conn)
-               return message_failed(msg, "Client already disconnected");
+               return btd_error_failed(msg, "Client already disconnected");
 
-       if (disconnect_req(server->conn, SAP_DISCONNECTION_TYPE_GRACEFUL) < 0)
-               return g_dbus_create_error(msg, ERROR_INTERFACE ".Failed",
-                                       "There is no active connection");
+       if (disconnect_req(server, SAP_DISCONNECTION_TYPE_GRACEFUL) < 0)
+               return btd_error_failed(msg, "There is no active connection");
 
        return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *get_properties(DBusConnection *c,
-                               DBusMessage *msg, void *data)
+static gboolean server_property_get_connected(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct sap_connection *conn = data;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
+       struct sap_server *server = data;
+       struct sap_connection *conn = server->conn;
        dbus_bool_t connected;
 
-       if (!conn)
-               return message_failed(msg, "Server internal error.");
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       if (!conn) {
+               connected = FALSE;
+               goto append;
+       }
 
        connected = (conn->state == SAP_STATE_CONNECTED ||
                                conn->state == SAP_STATE_GRACEFUL_DISCONNECT);
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN, &connected);
 
-       dbus_message_iter_close_container(&iter, &dict);
+append:
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &connected);
 
-       return reply;
+       return TRUE;
 }
 
 static const GDBusMethodTable server_methods[] = {
-       { GDBUS_METHOD("GetProperties",
-                       NULL, GDBUS_ARGS({ "properties", "a{sv}" }),
-                       get_properties) },
        { GDBUS_METHOD("Disconnect", NULL, NULL, disconnect) },
        { }
 };
 
-static const GDBusSignalTable server_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
+static const GDBusPropertyTable server_properties[] = {
+       { "Connected", "b", server_property_get_connected },
        { }
 };
 
-static void server_free(struct sap_server *server)
+static void server_remove(struct sap_server *server)
 {
        if (!server)
                return;
 
-       sap_conn_remove(server->conn);
-       g_free(server->path);
+       sap_server_remove_conn(server);
+
+       adapter_service_remove(server->adapter, server->record_id);
+
+       if (server->listen_io) {
+               g_io_channel_shutdown(server->listen_io, TRUE, NULL);
+               g_io_channel_unref(server->listen_io);
+               server->listen_io = NULL;
+       }
+
+       btd_adapter_unref(server->adapter);
        g_free(server);
-       server = NULL;
 }
 
 static void destroy_sap_interface(void *data)
@@ -1315,47 +1337,42 @@ static void destroy_sap_interface(void *data)
        struct sap_server *server = data;
 
        DBG("Unregistered interface %s on path %s", SAP_SERVER_INTERFACE,
-                                                               server->path);
+                                       adapter_get_path(server->adapter));
 
-       server_free(server);
+       server_remove(server);
 }
 
-int sap_server_register(const char *path, bdaddr_t *src)
+int sap_server_register(struct btd_adapter *adapter)
 {
        sdp_record_t *record = NULL;
        GError *gerr = NULL;
        GIOChannel *io;
+       struct sap_server *server;
 
        if (sap_init() < 0) {
                error("Sap driver initialization failed.");
                return -1;
        }
 
-       server = g_try_new0(struct sap_server, 1);
-       if (!server) {
-               sap_exit();
-               return -ENOMEM;
-       }
-
-       server->path = g_strdup(path);
-
        record = create_sap_record(SAP_SERVER_CHANNEL);
        if (!record) {
                error("Creating SAP SDP record failed.");
                goto sdp_err;
        }
 
-       if (add_record_to_server(src, record) < 0) {
+       if (adapter_service_add(adapter, record) < 0) {
                error("Adding SAP SDP record to the SDP server failed.");
                sdp_record_free(record);
                goto sdp_err;
        }
 
+       server = g_new0(struct sap_server, 1);
+       server->adapter = btd_adapter_ref(adapter);
        server->record_id = record->handle;
 
-       io = bt_io_listen(BT_IO_RFCOMM, NULL, connect_confirm_cb, server,
+       io = bt_io_listen(NULL, connect_confirm_cb, server,
                        NULL, &gerr,
-                       BT_IO_OPT_SOURCE_BDADDR, src,
+                       BT_IO_OPT_SOURCE_BDADDR, adapter_get_address(adapter),
                        BT_IO_OPT_CHANNEL, SAP_SERVER_CHANNEL,
                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_HIGH,
                        BT_IO_OPT_MASTER, TRUE,
@@ -1365,62 +1382,36 @@ int sap_server_register(const char *path, bdaddr_t *src)
                g_error_free(gerr);
                goto server_err;
        }
-
-       DBG("Listen socket 0x%02x", g_io_channel_unix_get_fd(io));
-
        server->listen_io = io;
-       server->conn = NULL;
 
-       if (!g_dbus_register_interface(connection, path, SAP_SERVER_INTERFACE,
-                                       server_methods, server_signals, NULL,
-                                       server, destroy_sap_interface)) {
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(server->adapter),
+                                       SAP_SERVER_INTERFACE,
+                                       server_methods, NULL,
+                                       server_properties, server,
+                                       destroy_sap_interface)) {
                error("D-Bus failed to register %s interface",
                                                        SAP_SERVER_INTERFACE);
                goto server_err;
        }
 
+       DBG("server %p, listen socket 0x%02x", server,
+                                               g_io_channel_unix_get_fd(io));
+
        return 0;
 
 server_err:
-       remove_record_from_server(server->record_id);
+       server_remove(server);
 sdp_err:
-       server_free(server);
        sap_exit();
 
        return -1;
 }
 
-int sap_server_unregister(const char *path)
+void sap_server_unregister(const char *path)
 {
-       if (!server)
-               return -EINVAL;
-
-       remove_record_from_server(server->record_id);
-
-       if (server->conn)
-               sap_conn_remove(server->conn);
-
-       if (server->listen_io) {
-               g_io_channel_shutdown(server->listen_io, TRUE, NULL);
-               g_io_channel_unref(server->listen_io);
-               server->listen_io = NULL;
-       }
-
-       g_dbus_unregister_interface(connection, path, SAP_SERVER_INTERFACE);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                               path, SAP_SERVER_INTERFACE);
 
        sap_exit();
-
-       return 0;
-}
-
-int sap_server_init(DBusConnection *conn)
-{
-       connection = dbus_connection_ref(conn);
-       return 0;
-}
-
-void sap_server_exit(void)
-{
-       dbus_connection_unref(connection);
-       connection = NULL;
 }
similarity index 82%
rename from deviceinfo/manager.h
rename to profiles/sap/server.h
index 0f742ca..d7e674a 100644 (file)
@@ -1,8 +1,7 @@
 /*
- *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2012 Texas Instruments, Inc.
+ *  Copyright (C) 2010 ST-Ericsson SA
  *
  *  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
@@ -17,8 +16,9 @@
  *  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);
+#include <gdbus/gdbus.h>
+
+int sap_server_register(struct btd_adapter *adapter);
+void sap_server_unregister(const char *path);
diff --git a/profiles/scanparam/scan.c b/profiles/scanparam/scan.c
new file mode 100644 (file)
index 0000000..0236af6
--- /dev/null
@@ -0,0 +1,282 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Nordic Semiconductor Inc.
+ *  Copyright (C) 2012  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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 <stdbool.h>
+#include <errno.h>
+
+#include "lib/uuid.h"
+#include "log.h"
+#include "plugin.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "attrib/att.h"
+#include "attrib/gattrib.h"
+#include "attrib/gatt.h"
+#include "attio.h"
+
+#define SCAN_PARAMETERS_UUID           "00001813-0000-1000-8000-00805f9b34fb"
+
+#define SCAN_INTERVAL_WIN_UUID         0x2A4F
+#define SCAN_REFRESH_UUID              0x2A31
+
+#define SCAN_INTERVAL          0x0060
+#define SCAN_WINDOW            0x0030
+#define SERVER_REQUIRES_REFRESH        0x00
+
+struct scan {
+       struct btd_device *device;
+       GAttrib *attrib;
+       struct att_range range;
+       guint attioid;
+       uint16_t interval;
+       uint16_t window;
+       uint16_t iwhandle;
+       uint16_t refresh_handle;
+       guint refresh_cb_id;
+};
+
+static void write_scan_params(GAttrib *attrib, uint16_t handle)
+{
+       uint8_t value[4];
+
+       att_put_u16(SCAN_INTERVAL, &value[0]);
+       att_put_u16(SCAN_WINDOW, &value[2]);
+
+       gatt_write_cmd(attrib, handle, value, sizeof(value), NULL, NULL);
+}
+
+static void refresh_value_cb(const uint8_t *pdu, uint16_t len,
+                                               gpointer user_data)
+{
+       struct scan *scan = user_data;
+
+       DBG("Server requires refresh: %d", pdu[3]);
+
+       if (pdu[3] == SERVER_REQUIRES_REFRESH)
+               write_scan_params(scan->attrib, scan->iwhandle);
+}
+
+static void ccc_written_cb(guint8 status, const guint8 *pdu,
+                                       guint16 plen, gpointer user_data)
+{
+       struct scan *scan = user_data;
+
+       if (status != 0) {
+               error("Write Scan Refresh CCC failed: %s",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       DBG("Scan Refresh: notification enabled");
+
+       scan->refresh_cb_id = g_attrib_register(scan->attrib,
+                               ATT_OP_HANDLE_NOTIFY, scan->refresh_handle,
+                               refresh_value_cb, scan, NULL);
+}
+
+static void discover_descriptor_cb(guint8 status, const guint8 *pdu,
+                                       guint16 len, gpointer user_data)
+{
+       struct scan *scan = user_data;
+       struct att_data_list *list;
+       uint8_t *ptr;
+       uint16_t uuid16, handle;
+       uint8_t value[2];
+       uint8_t format;
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               return;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       ptr = list->data[0];
+       handle = att_get_u16(ptr);
+       uuid16 = att_get_u16(&ptr[2]);
+
+       if (uuid16 != GATT_CLIENT_CHARAC_CFG_UUID)
+               goto done;
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+       gatt_write_char(scan->attrib, handle, value, sizeof(value),
+                                               ccc_written_cb, user_data);
+done:
+       att_data_list_free(list);
+}
+
+static void refresh_discovered_cb(GSList *chars, guint8 status,
+                                               gpointer user_data)
+{
+       struct scan *scan = user_data;
+       struct gatt_char *chr;
+       uint16_t start, end;
+
+       if (status) {
+               error("Scan Refresh %s", att_ecode2str(status));
+               return;
+       }
+
+       if (!chars) {
+               DBG("Scan Refresh not supported");
+               return;
+       }
+
+       chr = chars->data;
+
+       DBG("Scan Refresh handle: 0x%04x", chr->value_handle);
+
+       start = chr->value_handle + 1;
+       end = scan->range.end;
+
+       if (start > end)
+               return;
+
+       scan->refresh_handle = chr->value_handle;
+
+       gatt_discover_char_desc(scan->attrib, start, end,
+                                       discover_descriptor_cb, user_data);
+}
+
+static void iwin_discovered_cb(GSList *chars, guint8 status,
+                                               gpointer user_data)
+{
+       struct scan *scan = user_data;
+       struct gatt_char *chr;
+
+       if (status) {
+               error("Discover Scan Interval Window: %s",
+                                               att_ecode2str(status));
+               return;
+       }
+
+       chr = chars->data;
+       scan->iwhandle = chr->value_handle;
+
+       DBG("Scan Interval Window handle: 0x%04x", scan->iwhandle);
+
+       write_scan_params(scan->attrib, scan->iwhandle);
+}
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct scan *scan = user_data;
+       bt_uuid_t iwin_uuid, refresh_uuid;
+
+       scan->attrib = g_attrib_ref(attrib);
+
+       if (scan->iwhandle) {
+               write_scan_params(scan->attrib, scan->iwhandle);
+               return;
+       }
+
+       bt_uuid16_create(&iwin_uuid, SCAN_INTERVAL_WIN_UUID);
+       bt_uuid16_create(&refresh_uuid, SCAN_REFRESH_UUID);
+
+       gatt_discover_char(scan->attrib, scan->range.start, scan->range.end,
+                                       &iwin_uuid, iwin_discovered_cb, scan);
+
+       gatt_discover_char(scan->attrib, scan->range.start, scan->range.end,
+                               &refresh_uuid, refresh_discovered_cb, scan);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct scan *scan = user_data;
+
+       g_attrib_unref(scan->attrib);
+       scan->attrib = NULL;
+}
+
+static int scan_register(struct btd_service *service, struct gatt_primary *prim)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct scan *scan;
+
+       scan = g_new0(struct scan, 1);
+       scan->device = btd_device_ref(device);
+       scan->range = prim->range;
+       scan->attioid = btd_device_add_attio_callback(device,
+                                                       attio_connected_cb,
+                                                       attio_disconnected_cb,
+                                                       scan);
+
+       btd_service_set_user_data(service, scan);
+
+       return 0;
+}
+
+static void scan_param_remove(struct btd_service *service)
+{
+       struct scan *scan = btd_service_get_user_data(service);
+
+       if (scan->attrib != NULL && scan->refresh_cb_id > 0)
+               g_attrib_unregister(scan->attrib, scan->refresh_cb_id);
+
+       btd_device_remove_attio_callback(scan->device, scan->attioid);
+       btd_device_unref(scan->device);
+       g_attrib_unref(scan->attrib);
+       g_free(scan);
+}
+
+static int scan_param_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *prim;
+
+       DBG("Probing Scan Parameters");
+
+       prim = btd_device_get_primary(device, SCAN_PARAMETERS_UUID);
+       if (!prim)
+               return -EINVAL;
+
+       return scan_register(service, prim);
+}
+
+static struct btd_profile scan_profile = {
+       .name = "Scan Parameters Client Driver",
+       .remote_uuid = SCAN_PARAMETERS_UUID,
+       .device_probe = scan_param_probe,
+       .device_remove = scan_param_remove,
+};
+
+static int scan_param_init(void)
+{
+       return btd_profile_register(&scan_profile);
+}
+
+static void scan_param_exit(void)
+{
+       btd_profile_unregister(&scan_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(scanparam, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       scan_param_init, scan_param_exit)
diff --git a/profiles/thermometer/thermometer.c b/profiles/thermometer/thermometer.c
new file mode 100644 (file)
index 0000000..bd8413d
--- /dev/null
@@ -0,0 +1,1335 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdbool.h>
+#include <errno.h>
+
+#include <gdbus/gdbus.h>
+
+#include "lib/uuid.h"
+#include "plugin.h"
+#include "dbus-common.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+#include "error.h"
+#include "log.h"
+#include "attrib/gattrib.h"
+#include "attio.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+
+#define THERMOMETER_INTERFACE          "org.bluez.Thermometer1"
+#define THERMOMETER_MANAGER_INTERFACE  "org.bluez.ThermometerManager1"
+#define THERMOMETER_WATCHER_INTERFACE  "org.bluez.ThermometerWatcher1"
+
+/* Temperature measurement flag fields */
+#define TEMP_UNITS             0x01
+#define TEMP_TIME_STAMP                0x02
+#define TEMP_TYPE              0x04
+
+#define FLOAT_MAX_MANTISSA     16777216 /* 2^24 */
+
+#define VALID_RANGE_DESC_SIZE  4
+#define TEMPERATURE_TYPE_SIZE  1
+#define MEASUREMENT_INTERVAL_SIZE      2
+
+struct thermometer_adapter {
+       struct btd_adapter      *adapter;
+       GSList                  *devices;
+       GSList                  *fwatchers;     /* Final measurements */
+       GSList                  *iwatchers;     /* Intermediate measurements */
+};
+
+struct thermometer {
+       struct btd_device               *dev;           /* Device reference */
+       struct thermometer_adapter      *tadapter;
+       GAttrib                         *attrib;        /* GATT connection */
+       struct att_range                *svc_range;     /* Thermometer range */
+       guint                           attioid;        /* Att watcher id */
+       /* attio id for Temperature Measurement value indications */
+       guint                           attio_measurement_id;
+       /* attio id for Intermediate Temperature value notifications */
+       guint                           attio_intermediate_id;
+       /* attio id for Measurement Interval value indications */
+       guint                           attio_interval_id;
+       gboolean                        intermediate;
+       uint8_t                         type;
+       uint16_t                        interval;
+       uint16_t                        max;
+       uint16_t                        min;
+       gboolean                        has_type;
+       gboolean                        has_interval;
+
+       uint16_t                        measurement_ccc_handle;
+       uint16_t                        intermediate_ccc_handle;
+       uint16_t                        interval_val_handle;
+};
+
+struct characteristic {
+       struct thermometer      *t;     /* Thermometer where the char belongs */
+       char                    uuid[MAX_LEN_UUID_STR + 1];
+};
+
+struct watcher {
+       struct thermometer_adapter      *tadapter;
+       guint                           id;
+       char                            *srv;
+       char                            *path;
+};
+
+struct measurement {
+       struct thermometer      *t;
+       int16_t                 exp;
+       int32_t                 mant;
+       uint64_t                time;
+       gboolean                suptime;
+       char                    *unit;
+       char                    *type;
+       char                    *value;
+};
+
+struct tmp_interval_data {
+       struct thermometer      *thermometer;
+       uint16_t                interval;
+};
+
+static GSList *thermometer_adapters = NULL;
+
+static const char * const temp_type[] = {
+       "<reserved>",
+       "armpit",
+       "body",
+       "ear",
+       "finger",
+       "intestines",
+       "mouth",
+       "rectum",
+       "toe",
+       "tympanum"
+};
+
+static const char *temptype2str(uint8_t value)
+{
+        if (value > 0 && value < G_N_ELEMENTS(temp_type))
+               return temp_type[value];
+
+       error("Temperature type %d reserved for future use", value);
+       return NULL;
+}
+
+static void destroy_watcher(gpointer user_data)
+{
+       struct watcher *watcher = user_data;
+
+       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(btd_get_dbus_connection(), watcher->id);
+}
+
+static void destroy_thermometer(gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       if (t->attioid > 0)
+               btd_device_remove_attio_callback(t->dev, t->attioid);
+
+       if (t->attrib != NULL) {
+               g_attrib_unregister(t->attrib, t->attio_measurement_id);
+               g_attrib_unregister(t->attrib, t->attio_intermediate_id);
+               g_attrib_unregister(t->attrib, t->attio_interval_id);
+               g_attrib_unref(t->attrib);
+       }
+
+       btd_device_unref(t->dev);
+       g_free(t->svc_range);
+       g_free(t);
+}
+
+static void destroy_thermometer_adapter(gpointer user_data)
+{
+       struct thermometer_adapter *tadapter = user_data;
+
+       if (tadapter->devices != NULL)
+               g_slist_free_full(tadapter->devices, destroy_thermometer);
+
+       if (tadapter->fwatchers != NULL)
+               g_slist_free_full(tadapter->fwatchers, remove_watcher);
+
+       g_free(tadapter);
+}
+
+static int cmp_adapter(gconstpointer a, gconstpointer b)
+{
+       const struct thermometer_adapter *tadapter = a;
+       const struct btd_adapter *adapter = b;
+
+       if (adapter == tadapter->adapter)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_device(gconstpointer a, gconstpointer b)
+{
+       const struct thermometer *t = a;
+       const struct btd_device *dev = b;
+
+       if (dev == t->dev)
+               return 0;
+
+       return -1;
+}
+
+static int cmp_watcher(gconstpointer a, gconstpointer b)
+{
+       const struct watcher *watcher = a;
+       const struct watcher *match = b;
+       int ret;
+
+       ret = g_strcmp0(watcher->srv, match->srv);
+       if (ret != 0)
+               return ret;
+
+       return g_strcmp0(watcher->path, match->path);
+}
+
+static struct thermometer_adapter *
+find_thermometer_adapter(struct btd_adapter *adapter)
+{
+       GSList *l = g_slist_find_custom(thermometer_adapters, adapter,
+                                                               cmp_adapter);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static void change_property(struct thermometer *t, const char *name,
+                                                       gpointer value) {
+       if (g_strcmp0(name, "Intermediate") == 0) {
+               gboolean *intermediate = value;
+               if (t->intermediate == *intermediate)
+                       return;
+
+               t->intermediate = *intermediate;
+       } else if (g_strcmp0(name, "Interval") == 0) {
+               uint16_t *interval = value;
+               if (t->has_interval && t->interval == *interval)
+                       return;
+
+               t->has_interval = TRUE;
+               t->interval = *interval;
+       } else if (g_strcmp0(name, "Maximum") == 0) {
+               uint16_t *max = value;
+               if (t->max == *max)
+                       return;
+
+               t->max = *max;
+       } else if (g_strcmp0(name, "Minimum") == 0) {
+               uint16_t *min = value;
+               if (t->min == *min)
+                       return;
+
+               t->min = *min;
+       } else {
+               DBG("%s is not a thermometer property", name);
+               return;
+       }
+
+       g_dbus_emit_property_changed(btd_get_dbus_connection(),
+                                               device_get_path(t->dev),
+                                               THERMOMETER_INTERFACE, name);
+}
+
+static void update_watcher(gpointer data, gpointer user_data)
+{
+       struct watcher *w = data;
+       struct measurement *m = user_data;
+       const char *path = device_get_path(m->t->dev);
+       DBusMessageIter iter;
+       DBusMessageIter dict;
+       DBusMessage *msg;
+
+       msg = dbus_message_new_method_call(w->srv, w->path,
+                               THERMOMETER_WATCHER_INTERFACE,
+                               "MeasurementReceived");
+       if (msg == NULL)
+               return;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH , &path);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
+       dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
+       dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
+
+       if (m->suptime)
+               dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
+
+       dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
+       dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       dbus_message_set_no_reply(msg, TRUE);
+       g_dbus_send_message(btd_get_dbus_connection(), msg);
+}
+
+static void recv_measurement(struct thermometer *t, struct measurement *m)
+{
+       GSList *wlist;
+
+       m->t = t;
+
+       if (g_strcmp0(m->value, "intermediate") == 0)
+               wlist = t->tadapter->iwatchers;
+       else
+               wlist = t->tadapter->fwatchers;
+
+       g_slist_foreach(wlist, update_watcher, m);
+}
+
+static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
+                                               uint16_t len, gboolean final)
+{
+       struct measurement m;
+       const char *type = NULL;
+       uint8_t flags;
+       uint32_t raw;
+
+       /* skip opcode and handle */
+       pdu += 3;
+       len -= 3;
+
+       if (len < 1) {
+               DBG("Mandatory flags are not provided");
+               return;
+       }
+
+       memset(&m, 0, sizeof(m));
+
+       flags = *pdu;
+
+       if (flags & TEMP_UNITS)
+               m.unit = "fahrenheit";
+       else
+               m.unit = "celsius";
+
+       pdu++;
+       len--;
+
+       if (len < 4) {
+               DBG("Mandatory temperature measurement value is not provided");
+               return;
+       }
+
+       raw = att_get_u32(pdu);
+       m.mant = raw & 0x00FFFFFF;
+       m.exp = ((int32_t) raw) >> 24;
+
+       if (m.mant & 0x00800000) {
+               /* convert to C2 negative value */
+               m.mant = m.mant - FLOAT_MAX_MANTISSA;
+       }
+
+       pdu += 4;
+       len -= 4;
+
+       if (flags & TEMP_TIME_STAMP) {
+               struct tm ts;
+               time_t time;
+
+               if (len < 7) {
+                       DBG("Time stamp is not provided");
+                       return;
+               }
+
+               ts.tm_year = att_get_u16(pdu) - 1900;
+               ts.tm_mon = *(pdu + 2) - 1;
+               ts.tm_mday = *(pdu + 3);
+               ts.tm_hour = *(pdu + 4);
+               ts.tm_min = *(pdu + 5);
+               ts.tm_sec = *(pdu + 6);
+               ts.tm_isdst = -1;
+
+               time = mktime(&ts);
+               m.time = (uint64_t) time;
+               m.suptime = TRUE;
+
+               pdu += 7;
+               len -= 7;
+       }
+
+       if (flags & TEMP_TYPE) {
+               if (len < 1) {
+                       DBG("Temperature type is not provided");
+                       return;
+               }
+
+               type = temptype2str(*pdu);
+       } else if (t->has_type) {
+               type = temptype2str(t->type);
+       }
+
+       m.type = g_strdup(type);
+       m.value = final ? "final" : "intermediate";
+
+       recv_measurement(t, &m);
+       g_free(m.type);
+}
+
+
+static void measurement_ind_handler(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       uint8_t *opdu;
+       uint16_t olen;
+       size_t plen;
+
+       if (len < 3) {
+               DBG("Bad pdu received");
+               return;
+       }
+
+       proc_measurement(t, pdu, len, TRUE);
+
+       opdu = g_attrib_get_buffer(t->attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
+
+       if (olen > 0)
+               g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
+
+static void intermediate_notify_handler(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       if (len < 3) {
+               DBG("Bad pdu received");
+               return;
+       }
+
+       proc_measurement(t, pdu, len, FALSE);
+}
+
+static void interval_ind_handler(const uint8_t *pdu, uint16_t len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       uint16_t interval;
+       uint8_t *opdu;
+       uint16_t olen;
+       size_t plen;
+
+       if (len < 5) {
+               DBG("Bad pdu received");
+               return;
+       }
+
+       interval = att_get_u16(pdu + 3);
+       change_property(t, "Interval", &interval);
+
+       opdu = g_attrib_get_buffer(t->attrib, &plen);
+       olen = enc_confirmation(opdu, plen);
+
+       if (olen > 0)
+               g_attrib_send(t->attrib, 0, opdu, olen, NULL, NULL, NULL);
+}
+
+static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       uint8_t value[VALID_RANGE_DESC_SIZE];
+       uint16_t max, min;
+       ssize_t vlen;
+
+       if (status != 0) {
+               DBG("Valid Range descriptor read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, value, sizeof(value));
+       if (vlen < 0) {
+               DBG("Protocol error\n");
+               return;
+       }
+
+       if (vlen < 4) {
+               DBG("Invalid range received");
+               return;
+       }
+
+       min = att_get_u16(&value[0]);
+       max = att_get_u16(&value[2]);
+
+       if (min == 0 || min > max) {
+               DBG("Invalid range");
+               return;
+       }
+
+       change_property(t, "Maximum", &max);
+       change_property(t, "Minimum", &min);
+}
+
+static void write_ccc_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 characteristic *ch, uint16_t uuid,
+                                                               uint16_t handle)
+{
+       uint8_t atval[2];
+       uint16_t val;
+       char *msg;
+
+       if (uuid == GATT_CHARAC_VALID_RANGE_UUID) {
+               if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0)
+                       gatt_read_char(ch->t->attrib, handle,
+                                               valid_range_desc_cb, ch->t);
+               return;
+       }
+
+       if (uuid != GATT_CLIENT_CHARAC_CFG_UUID)
+               return;
+
+       if (g_strcmp0(ch->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
+               ch->t->measurement_ccc_handle = handle;
+
+               if (g_slist_length(ch->t->tadapter->fwatchers) == 0) {
+                       val = 0x0000;
+                       msg = g_strdup("Disable Temperature Measurement ind");
+               } else {
+                       val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+                       msg = g_strdup("Enable Temperature Measurement ind");
+               }
+       } else if (g_strcmp0(ch->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+               ch->t->intermediate_ccc_handle = handle;
+
+               if (g_slist_length(ch->t->tadapter->iwatchers) == 0) {
+                       val = 0x0000;
+                       msg = g_strdup("Disable Intermediate Temperature noti");
+               } else {
+                       val = GATT_CLIENT_CHARAC_CFG_NOTIF_BIT;
+                       msg = g_strdup("Enable Intermediate Temperature noti");
+               }
+       } else if (g_strcmp0(ch->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+               val = GATT_CLIENT_CHARAC_CFG_IND_BIT;
+               msg = g_strdup("Enable Measurement Interval indication");
+       } else {
+               return;
+       }
+
+       att_put_u16(val, atval);
+       gatt_write_char(ch->t->attrib, handle, atval, sizeof(atval),
+                                                       write_ccc_cb, msg);
+}
+
+static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct characteristic *ch = user_data;
+       struct att_data_list *list = NULL;
+       uint8_t format;
+       int i;
+
+       if (status != 0) {
+               error("Discover all characteristic descriptors failed [%s]: %s",
+                                       ch->uuid, att_ecode2str(status));
+               goto done;
+       }
+
+       list = dec_find_info_resp(pdu, len, &format);
+       if (list == NULL)
+               goto done;
+
+       if (format != ATT_FIND_INFO_RESP_FMT_16BIT)
+               goto done;
+
+       for (i = 0; i < list->num; i++) {
+               uint8_t *value;
+               uint16_t handle, uuid;
+
+               value = list->data[i];
+               handle = att_get_u16(value);
+               uuid = att_get_u16(value + 2);
+
+               process_thermometer_desc(ch, uuid, handle);
+       }
+
+done:
+       if (list != NULL)
+               att_data_list_free(list);
+       g_free(ch);
+}
+
+static void discover_desc(struct thermometer *t, struct gatt_char *c,
+                                               struct gatt_char *c_next)
+{
+       struct characteristic *ch;
+       uint16_t start, end;
+
+       start = c->value_handle + 1;
+
+       if (c_next != NULL) {
+               if (start == c_next->handle)
+                       return;
+               end = c_next->handle - 1;
+       } else if (c->value_handle != t->svc_range->end) {
+               end = t->svc_range->end;
+       } else {
+               return;
+       }
+
+       ch = g_new0(struct characteristic, 1);
+       ch->t = t;
+       memcpy(ch->uuid, c->uuid, sizeof(c->uuid));
+
+       gatt_discover_char_desc(t->attrib, start, end, discover_desc_cb, ch);
+}
+
+static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       uint8_t value[TEMPERATURE_TYPE_SIZE];
+       ssize_t vlen;
+
+       if (status != 0) {
+               DBG("Temperature Type value read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, value, sizeof(value));
+       if (vlen < 0) {
+               DBG("Protocol error.");
+               return;
+       }
+
+       if (vlen != 1) {
+               DBG("Invalid length for Temperature type");
+               return;
+       }
+
+       t->has_type = TRUE;
+       t->type = value[0];
+}
+
+static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       uint8_t value[MEASUREMENT_INTERVAL_SIZE];
+       uint16_t interval;
+       ssize_t vlen;
+
+       if (status != 0) {
+               DBG("Measurement Interval value read failed: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       vlen = dec_read_resp(pdu, len, value, sizeof(value));
+       if (vlen < 0) {
+               DBG("Protocol error\n");
+               return;
+       }
+
+       if (vlen < 2) {
+               DBG("Invalid Interval received");
+               return;
+       }
+
+       interval = att_get_u16(&value[0]);
+       change_property(t, "Interval", &interval);
+}
+
+static void process_thermometer_char(struct thermometer *t,
+                               struct gatt_char *c, struct gatt_char *c_next)
+{
+       if (g_strcmp0(c->uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
+               gboolean intermediate = TRUE;
+               change_property(t, "Intermediate", &intermediate);
+
+               t->attio_intermediate_id = g_attrib_register(t->attrib,
+                                       ATT_OP_HANDLE_NOTIFY, c->value_handle,
+                                       intermediate_notify_handler, t, NULL);
+
+               discover_desc(t, c, c_next);
+       } else if (g_strcmp0(c->uuid, TEMPERATURE_MEASUREMENT_UUID) == 0) {
+
+               t->attio_measurement_id = g_attrib_register(t->attrib,
+                                       ATT_OP_HANDLE_IND, c->value_handle,
+                                       measurement_ind_handler, t, NULL);
+
+               discover_desc(t, c, c_next);
+       } else if (g_strcmp0(c->uuid, TEMPERATURE_TYPE_UUID) == 0) {
+               gatt_read_char(t->attrib, c->value_handle,
+                                                       read_temp_type_cb, t);
+       } else if (g_strcmp0(c->uuid, MEASUREMENT_INTERVAL_UUID) == 0) {
+               bool need_desc = false;
+
+               gatt_read_char(t->attrib, c->value_handle, read_interval_cb, t);
+
+               if (c->properties & ATT_CHAR_PROPER_WRITE) {
+                       t->interval_val_handle = c->value_handle;
+                       need_desc = true;
+               }
+
+               if (c->properties & ATT_CHAR_PROPER_INDICATE) {
+                       t->attio_interval_id = g_attrib_register(t->attrib,
+                                       ATT_OP_HANDLE_IND, c->value_handle,
+                                       interval_ind_handler, t, NULL);
+                       need_desc = true;
+               }
+
+               if (need_desc)
+                       discover_desc(t, c, c_next);
+       }
+}
+
+static void configure_thermometer_cb(GSList *characteristics, guint8 status,
+                                                       gpointer user_data)
+{
+       struct thermometer *t = user_data;
+       GSList *l;
+
+       if (status != 0) {
+               error("Discover thermometer characteristics: %s",
+                                                       att_ecode2str(status));
+               return;
+       }
+
+       for (l = characteristics; l; l = l->next) {
+               struct gatt_char *c = l->data;
+               struct gatt_char *c_next = (l->next ? l->next->data : NULL);
+
+               process_thermometer_char(t, c, c_next);
+       }
+}
+
+static void write_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
+                                                       gpointer user_data)
+{
+       struct tmp_interval_data *data = user_data;
+
+       if (status != 0) {
+               error("Interval Write Request failed %s",
+                                                       att_ecode2str(status));
+               goto done;
+       }
+
+       if (!dec_write_resp(pdu, len)) {
+               error("Interval Write Request: protocol error");
+               goto done;
+       }
+
+       change_property(data->thermometer, "Interval", &data->interval);
+
+done:
+       g_free(user_data);
+}
+
+static void enable_final_measurement(gpointer data, gpointer user_data)
+{
+       struct thermometer *t = data;
+       uint16_t handle = t->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (t->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_IND_BIT, value);
+       msg = g_strdup("Enable Temperature Measurement indications");
+
+       gatt_write_char(t->attrib, handle, value, sizeof(value),
+                                                       write_ccc_cb, msg);
+}
+
+static void enable_intermediate_measurement(gpointer data, gpointer user_data)
+{
+       struct thermometer *t = data;
+       uint16_t handle = t->intermediate_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (t->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(GATT_CLIENT_CHARAC_CFG_NOTIF_BIT, value);
+       msg = g_strdup("Enable Intermediate Temperature notifications");
+
+       gatt_write_char(t->attrib, handle, value, sizeof(value),
+                                                       write_ccc_cb, msg);
+}
+
+static void disable_final_measurement(gpointer data, gpointer user_data)
+{
+       struct thermometer *t = data;
+       uint16_t handle = t->measurement_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (t->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(0x0000, value);
+       msg = g_strdup("Disable Temperature Measurement indications");
+
+       gatt_write_char(t->attrib, handle, value, sizeof(value),
+                                                       write_ccc_cb, msg);
+}
+
+static void disable_intermediate_measurement(gpointer data, gpointer user_data)
+{
+       struct thermometer *t = data;
+       uint16_t handle = t->intermediate_ccc_handle;
+       uint8_t value[2];
+       char *msg;
+
+       if (t->attrib == NULL || !handle)
+               return;
+
+       att_put_u16(0x0000, value);
+       msg = g_strdup("Disable Intermediate Temperature notifications");
+
+       gatt_write_char(t->attrib, handle, value, sizeof(value),
+                                                       write_ccc_cb, msg);
+}
+
+static void remove_int_watcher(struct thermometer_adapter *tadapter,
+                                                       struct watcher *w)
+{
+       if (!g_slist_find(tadapter->iwatchers, w))
+               return;
+
+       tadapter->iwatchers = g_slist_remove(tadapter->iwatchers, w);
+
+       if (g_slist_length(tadapter->iwatchers) == 0)
+               g_slist_foreach(tadapter->devices,
+                                       disable_intermediate_measurement, 0);
+}
+
+static void watcher_exit(DBusConnection *conn, void *user_data)
+{
+       struct watcher *watcher = user_data;
+       struct thermometer_adapter *tadapter = watcher->tadapter;
+
+       DBG("Thermometer watcher %s disconnected", watcher->path);
+
+       remove_int_watcher(tadapter, watcher);
+
+       tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher);
+       g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+
+       if (g_slist_length(tadapter->fwatchers) == 0)
+               g_slist_foreach(tadapter->devices,
+                                       disable_final_measurement, 0);
+}
+
+static struct watcher *find_watcher(GSList *list, const char *sender,
+                                                       const char *path)
+{
+       struct watcher *match;
+       GSList *l;
+
+       match = g_new0(struct watcher, 1);
+       match->srv = g_strdup(sender);
+       match->path = g_strdup(path);
+
+       l = g_slist_find_custom(list, match, cmp_watcher);
+       destroy_watcher(match);
+
+       if (l != NULL)
+               return l->data;
+
+       return NULL;
+}
+
+static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer_adapter *tadapter = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(tadapter->fwatchers, sender, path);
+       if (watcher != NULL)
+               return btd_error_already_exists(msg);
+
+       DBG("Thermometer watcher %s registered", path);
+
+       watcher = g_new0(struct watcher, 1);
+       watcher->srv = g_strdup(sender);
+       watcher->path = g_strdup(path);
+       watcher->tadapter = tadapter;
+       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
+                                               watcher, destroy_watcher);
+
+       if (g_slist_length(tadapter->fwatchers) == 0)
+               g_slist_foreach(tadapter->devices, enable_final_measurement, 0);
+
+       tadapter->fwatchers = g_slist_prepend(tadapter->fwatchers, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer_adapter *tadapter = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(tadapter->fwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       DBG("Thermometer watcher %s unregistered", path);
+
+       remove_int_watcher(tadapter, watcher);
+
+       tadapter->fwatchers = g_slist_remove(tadapter->fwatchers, watcher);
+       g_dbus_remove_watch(btd_get_dbus_connection(), watcher->id);
+
+       if (g_slist_length(tadapter->fwatchers) == 0)
+               g_slist_foreach(tadapter->devices,
+                                       disable_final_measurement, 0);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer_adapter *ta = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(ta->fwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       if (find_watcher(ta->iwatchers, sender, path))
+               return btd_error_already_exists(msg);
+
+       DBG("Intermediate measurement watcher %s registered", path);
+
+       if (g_slist_length(ta->iwatchers) == 0)
+               g_slist_foreach(ta->devices,
+                                       enable_intermediate_measurement, 0);
+
+       ta->iwatchers = g_slist_prepend(ta->iwatchers, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       const char *sender = dbus_message_get_sender(msg);
+       struct thermometer_adapter *ta = data;
+       struct watcher *watcher;
+       char *path;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       watcher = find_watcher(ta->iwatchers, sender, path);
+       if (watcher == NULL)
+               return btd_error_does_not_exist(msg);
+
+       DBG("Intermediate measurement %s unregistered", path);
+
+       remove_int_watcher(ta, watcher);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static gboolean property_get_intermediate(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct thermometer *t = data;
+       dbus_bool_t val;
+
+       val = !!t->intermediate;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
+
+       return TRUE;
+}
+
+static gboolean property_get_interval(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct thermometer *t = data;
+
+       if (!t->has_interval)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->interval);
+
+       return TRUE;
+}
+
+static void property_set_interval(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter,
+                                       GDBusPendingPropertySet id, void *data)
+{
+       struct thermometer *t = data;
+       struct tmp_interval_data *interval_data;
+       uint16_t val;
+       uint8_t atval[2];
+
+       if (t->interval_val_handle == 0) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".NotSupported",
+                                       "Operation is not supported");
+               return;
+       }
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT16) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &val);
+
+       if (val < t->min || val > t->max) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       att_put_u16(val, &atval[0]);
+
+       interval_data = g_new0(struct tmp_interval_data, 1);
+       interval_data->thermometer = t;
+       interval_data->interval = val;
+       gatt_write_char(t->attrib, t->interval_val_handle, atval, sizeof(atval),
+                                       write_interval_cb, interval_data);
+
+       g_dbus_pending_property_success(id);
+}
+
+static gboolean property_exists_interval(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct thermometer *t = data;
+
+       return t->has_interval;
+}
+
+static gboolean property_get_maximum(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct thermometer *t = data;
+
+       if (!t->has_interval)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->max);
+
+       return TRUE;
+}
+
+static gboolean property_get_minimum(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct thermometer *t = data;
+
+       if (!t->has_interval)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &t->min);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable thermometer_properties[] = {
+       { "Intermediate", "b", property_get_intermediate },
+       { "Interval", "q", property_get_interval, property_set_interval,
+                                               property_exists_interval },
+       { "Maximum", "q", property_get_maximum, NULL,
+                                               property_exists_interval },
+       { "Minimum", "q", property_get_minimum, NULL,
+                                               property_exists_interval },
+       { }
+};
+
+static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       t->attrib = g_attrib_ref(attrib);
+
+       gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
+                                       NULL, configure_thermometer_cb, t);
+}
+
+static void attio_disconnected_cb(gpointer user_data)
+{
+       struct thermometer *t = user_data;
+
+       DBG("GATT Disconnected");
+
+       if (t->attio_measurement_id > 0) {
+               g_attrib_unregister(t->attrib, t->attio_measurement_id);
+               t->attio_measurement_id = 0;
+       }
+
+       if (t->attio_intermediate_id > 0) {
+               g_attrib_unregister(t->attrib, t->attio_intermediate_id);
+               t->attio_intermediate_id = 0;
+       }
+
+       if (t->attio_interval_id > 0) {
+               g_attrib_unregister(t->attrib, t->attio_interval_id);
+               t->attio_interval_id = 0;
+       }
+
+       g_attrib_unref(t->attrib);
+       t->attrib = NULL;
+}
+
+static int thermometer_register(struct btd_device *device,
+                                               struct gatt_primary *tattr)
+{
+       const char *path = device_get_path(device);
+       struct thermometer *t;
+       struct btd_adapter *adapter;
+       struct thermometer_adapter *tadapter;
+
+       adapter = device_get_adapter(device);
+
+       tadapter = find_thermometer_adapter(adapter);
+
+       if (tadapter == NULL)
+               return -1;
+
+       t = g_new0(struct thermometer, 1);
+       t->dev = btd_device_ref(device);
+       t->tadapter = tadapter;
+       t->svc_range = g_new0(struct att_range, 1);
+       t->svc_range->start = tattr->range.start;
+       t->svc_range->end = tattr->range.end;
+
+       tadapter->devices = g_slist_prepend(tadapter->devices, t);
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                               path, THERMOMETER_INTERFACE,
+                               NULL, NULL, thermometer_properties,
+                               t, destroy_thermometer)) {
+               error("D-Bus failed to register %s interface",
+                                                       THERMOMETER_INTERFACE);
+               destroy_thermometer(t);
+               return -EIO;
+       }
+
+       t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
+                                               attio_disconnected_cb, t);
+       return 0;
+}
+
+static void thermometer_unregister(struct btd_device *device)
+{
+       struct thermometer *t;
+       struct btd_adapter *adapter;
+       struct thermometer_adapter *tadapter;
+       GSList *l;
+
+       adapter = device_get_adapter(device);
+
+       tadapter = find_thermometer_adapter(adapter);
+
+       if (tadapter == NULL)
+               return;
+
+       l = g_slist_find_custom(tadapter->devices, device, cmp_device);
+       if (l == NULL)
+               return;
+
+       t = l->data;
+
+       tadapter->devices = g_slist_remove(tadapter->devices, t);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                               device_get_path(t->dev), THERMOMETER_INTERFACE);
+}
+
+static const GDBusMethodTable thermometer_manager_methods[] = {
+       { 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 int thermometer_adapter_register(struct btd_adapter *adapter)
+{
+       struct thermometer_adapter *tadapter;
+
+       tadapter = g_new0(struct thermometer_adapter, 1);
+       tadapter->adapter = adapter;
+
+       if (!g_dbus_register_interface(btd_get_dbus_connection(),
+                                               adapter_get_path(adapter),
+                                               THERMOMETER_MANAGER_INTERFACE,
+                                               thermometer_manager_methods,
+                                               NULL, NULL, tadapter,
+                                               destroy_thermometer_adapter)) {
+               error("D-Bus failed to register %s interface",
+                                               THERMOMETER_MANAGER_INTERFACE);
+               destroy_thermometer_adapter(tadapter);
+               return -EIO;
+       }
+
+       thermometer_adapters = g_slist_prepend(thermometer_adapters, tadapter);
+
+       return 0;
+}
+
+static void thermometer_adapter_unregister(struct btd_adapter *adapter)
+{
+       struct thermometer_adapter *tadapter;
+
+       tadapter = find_thermometer_adapter(adapter);
+       if (tadapter == NULL)
+               return;
+
+       thermometer_adapters = g_slist_remove(thermometer_adapters, tadapter);
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                                       adapter_get_path(tadapter->adapter),
+                                       THERMOMETER_MANAGER_INTERFACE);
+}
+
+static int thermometer_device_probe(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+       struct gatt_primary *tattr;
+
+       tattr = btd_device_get_primary(device, HEALTH_THERMOMETER_UUID);
+       if (tattr == NULL)
+               return -EINVAL;
+
+       return thermometer_register(device, tattr);
+}
+
+static void thermometer_device_remove(struct btd_service *service)
+{
+       struct btd_device *device = btd_service_get_device(service);
+
+       thermometer_unregister(device);
+}
+
+static int thermometer_adapter_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       return thermometer_adapter_register(adapter);
+}
+
+static void thermometer_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       thermometer_adapter_unregister(adapter);
+}
+
+static struct btd_profile thermometer_profile = {
+       .name           = "Health Thermometer GATT driver",
+       .remote_uuid    = HEALTH_THERMOMETER_UUID,
+       .device_probe   = thermometer_device_probe,
+       .device_remove  = thermometer_device_remove,
+       .adapter_probe  = thermometer_adapter_probe,
+       .adapter_remove = thermometer_adapter_remove
+};
+
+static int thermometer_init(void)
+{
+       return btd_profile_register(&thermometer_profile);
+}
+
+static void thermometer_exit(void)
+{
+       btd_profile_unregister(&thermometer_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                                       thermometer_init, thermometer_exit)
diff --git a/profiles/time/server.c b/profiles/time/server.c
new file mode 100644 (file)
index 0000000..178d4d2
--- /dev/null
@@ -0,0 +1,278 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Nokia Corporation
+ *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <time.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <adapter.h>
+#include <device.h>
+#include <profile.h>
+#include <plugin.h>
+
+#include "lib/uuid.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/att-database.h"
+#include "attrib-server.h"
+#include "attrib/gatt-service.h"
+#include "log.h"
+
+#define CURRENT_TIME_SVC_UUID          0x1805
+#define REF_TIME_UPDATE_SVC_UUID       0x1806
+
+#define LOCAL_TIME_INFO_CHR_UUID       0x2A0F
+#define TIME_UPDATE_CTRL_CHR_UUID      0x2A16
+#define TIME_UPDATE_STAT_CHR_UUID      0x2A17
+#define CT_TIME_CHR_UUID               0x2A2B
+
+enum {
+       UPDATE_RESULT_SUCCESSFUL = 0,
+       UPDATE_RESULT_CANCELED = 1,
+       UPDATE_RESULT_NO_CONN = 2,
+       UPDATE_RESULT_ERROR = 3,
+       UPDATE_RESULT_TIMEOUT = 4,
+       UPDATE_RESULT_NOT_ATTEMPTED = 5,
+};
+
+enum {
+       UPDATE_STATE_IDLE = 0,
+       UPDATE_STATE_PENDING = 1,
+};
+
+enum {
+       GET_REFERENCE_UPDATE = 1,
+       CANCEL_REFERENCE_UPDATE = 2,
+};
+
+static int encode_current_time(uint8_t value[10])
+{
+       struct timespec tp;
+       struct tm tm;
+
+       if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
+               int err = -errno;
+
+               error("clock_gettime: %s", strerror(-err));
+               return err;
+       }
+
+       if (localtime_r(&tp.tv_sec, &tm) == NULL) {
+               error("localtime_r() failed");
+               /* localtime_r() does not set errno */
+               return -EINVAL;
+       }
+
+       att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
+       value[2] = tm.tm_mon + 1; /* Month */
+       value[3] = tm.tm_mday; /* Day */
+       value[4] = tm.tm_hour; /* Hours */
+       value[5] = tm.tm_min; /* Minutes */
+       value[6] = tm.tm_sec; /* Seconds */
+       value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
+       /* From Time Profile spec: "The number of 1/256 fractions of a second."
+        * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
+        * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
+       value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
+       value[9] = 0x00; /* Adjust Reason */
+
+       return 0;
+}
+
+static uint8_t current_time_read(struct attribute *a,
+                                struct btd_device *device, gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value[10];
+
+       if (encode_current_time(value) < 0)
+               return ATT_ECODE_IO;
+
+       attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static uint8_t local_time_info_read(struct attribute *a,
+                               struct btd_device *device, gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value[2];
+
+       DBG("a=%p", a);
+
+       tzset();
+
+       /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
+        * format (offset from UTC in number of 15 minutes increments). */
+       value[0] = (uint8_t) (-1 * timezone / (60 * 15));
+
+       /* FIXME: POSIX "daylight" variable only indicates whether there
+        * is DST for the local time or not. The offset is unknown. */
+       value[1] = daylight ? 0xff : 0x00;
+
+       attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static gboolean register_current_time_service(struct btd_adapter *adapter)
+{
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, CURRENT_TIME_SVC_UUID);
+
+       /* Current Time service */
+       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+                               /* CT Time characteristic */
+                               GATT_OPT_CHR_UUID16, CT_TIME_CHR_UUID,
+                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
+                                                       ATT_CHAR_PROPER_NOTIFY,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               current_time_read, adapter,
+
+                               /* Local Time Information characteristic */
+                               GATT_OPT_CHR_UUID16, LOCAL_TIME_INFO_CHR_UUID,
+                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               local_time_info_read, adapter,
+
+                               GATT_OPT_INVALID);
+}
+
+static uint8_t time_update_control(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       DBG("handle 0x%04x", a->handle);
+
+       if (a->len != 1)
+               DBG("Invalid control point value size: %zu", a->len);
+
+       switch (a->data[0]) {
+       case GET_REFERENCE_UPDATE:
+               DBG("Get Reference Update");
+               break;
+       case CANCEL_REFERENCE_UPDATE:
+               DBG("Cancel Reference Update");
+               break;
+       default:
+               DBG("Unknown command: 0x%02x", a->data[0]);
+       }
+
+       return 0;
+}
+
+static uint8_t time_update_status(struct attribute *a,
+                                               struct btd_device *device,
+                                               gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       uint8_t value[2];
+
+       DBG("handle 0x%04x", a->handle);
+
+       value[0] = UPDATE_STATE_IDLE;
+       value[1] = UPDATE_RESULT_SUCCESSFUL;
+       attrib_db_update(adapter, a->handle, NULL, value, sizeof(value), NULL);
+
+       return 0;
+}
+
+static gboolean register_ref_time_update_service(struct btd_adapter *adapter)
+{
+       bt_uuid_t uuid;
+
+       bt_uuid16_create(&uuid, REF_TIME_UPDATE_SVC_UUID);
+
+       /* Reference Time Update service */
+       return gatt_service_add(adapter, GATT_PRIM_SVC_UUID, &uuid,
+                               /* Time Update control point */
+                               GATT_OPT_CHR_UUID16, TIME_UPDATE_CTRL_CHR_UUID,
+                               GATT_OPT_CHR_PROPS,
+                                       ATT_CHAR_PROPER_WRITE_WITHOUT_RESP,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_WRITE,
+                                               time_update_control, adapter,
+
+                               /* Time Update status */
+                               GATT_OPT_CHR_UUID16, TIME_UPDATE_STAT_CHR_UUID,
+                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
+                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
+                                               time_update_status, adapter,
+
+                               GATT_OPT_INVALID);
+}
+
+static int time_server_init(struct btd_profile *p, struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+
+       if (!register_current_time_service(adapter)) {
+               error("Current Time Service could not be registered");
+               return -EIO;
+       }
+
+       if (!register_ref_time_update_service(adapter)) {
+               error("Reference Time Update Service could not be registered");
+               return -EIO;
+       }
+
+       return 0;
+}
+
+static void time_server_exit(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       const char *path = adapter_get_path(adapter);
+
+       DBG("path %s", path);
+}
+
+struct btd_profile time_profile = {
+       .name           = "gatt-time-server",
+       .adapter_probe  = time_server_init,
+       .adapter_remove = time_server_exit,
+};
+
+static int time_init(void)
+{
+       return btd_profile_register(&time_profile);
+}
+
+static void time_exit(void)
+{
+       btd_profile_unregister(&time_profile);
+}
+
+BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
+                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
+                       time_init, time_exit)
diff --git a/proximity/manager.c b/proximity/manager.c
deleted file mode 100644 (file)
index f2e49a6..0000000
+++ /dev/null
@@ -1,150 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <gdbus.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "monitor.h"
-#include "reporter.h"
-#include "manager.h"
-
-static DBusConnection *connection = NULL;
-
-static struct enabled enabled  = {
-       .linkloss = TRUE,
-       .pathloss = TRUE,
-       .findme = TRUE,
-};
-
-static gint primary_uuid_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct gatt_primary *prim = a;
-       const char *uuid = b;
-
-       return g_strcmp0(prim->uuid, uuid);
-}
-
-static int attio_device_probe(struct btd_device *device, GSList *uuids)
-{
-       struct gatt_primary *linkloss, *txpower, *immediate;
-       GSList *l, *primaries;
-
-       primaries = btd_device_get_primaries(device);
-
-       l = g_slist_find_custom(primaries, IMMEDIATE_ALERT_UUID,
-                       primary_uuid_cmp);
-       immediate = (l ? l->data : NULL);
-
-       l = g_slist_find_custom(primaries, TX_POWER_UUID, primary_uuid_cmp);
-       txpower = (l ? l->data : NULL);
-
-       l = g_slist_find_custom(primaries, LINK_LOSS_UUID, primary_uuid_cmp);
-       linkloss = (l ? l->data : NULL);
-
-       return monitor_register(connection, device, linkloss, txpower,
-                                                       immediate, &enabled);
-}
-
-static void attio_device_remove(struct btd_device *device)
-{
-       monitor_unregister(connection, device);
-}
-
-static struct btd_device_driver monitor_driver = {
-       .name = "Proximity GATT 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;
-       int i;
-
-       if (config == NULL)
-               return;
-
-       list = g_key_file_get_string_list(config, "General", "Disable",
-                                                               NULL, NULL);
-       for (i = 0; list && list[i] != NULL; i++) {
-               if (g_str_equal(list[i], "FindMe"))
-                       enabled.findme = FALSE;
-               else if (g_str_equal(list[i], "LinkLoss"))
-                       enabled.linkloss = FALSE;
-               else if (g_str_equal(list[i], "PathLoss"))
-                       enabled.pathloss = FALSE;
-       }
-
-       g_strfreev(list);
-}
-
-int proximity_manager_init(DBusConnection *conn, GKeyFile *config)
-{
-       int ret;
-
-       load_config_file(config);
-
-       connection = dbus_connection_ref(conn);
-
-       ret = btd_register_device_driver(&monitor_driver);
-       if (ret < 0)
-               goto fail_monitor;
-
-       ret = btd_register_adapter_driver(&reporter_server_driver);
-       if (ret < 0)
-               goto fail_reporter;
-
-       return 0;
-
-fail_reporter:
-       btd_unregister_device_driver(&monitor_driver);
-
-fail_monitor:
-       dbus_connection_unref(connection);
-       return ret;
-}
-
-void proximity_manager_exit(void)
-{
-       btd_unregister_device_driver(&monitor_driver);
-       btd_unregister_adapter_driver(&reporter_server_driver);
-       dbus_connection_unref(connection);
-}
diff --git a/sap/server.h b/sap/server.h
deleted file mode 100644 (file)
index ef2b7b8..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2010 ST-Ericsson SA
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- */
-
-#include <gdbus.h>
-
-int sap_server_init(DBusConnection *conn);
-void sap_server_exit(void);
-int sap_server_register(const char *path, bdaddr_t *src);
-int sap_server_unregister(const char *path);
diff --git a/sbc/formats.h b/sbc/formats.h
deleted file mode 100644 (file)
index 3050b25..0000000
+++ /dev/null
@@ -1,55 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  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 <byteswap.h>
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define COMPOSE_ID(a,b,c,d)    ((a) | ((b)<<8) | ((c)<<16) | ((d)<<24))
-#define LE_SHORT(v)            (v)
-#define LE_INT(v)              (v)
-#define BE_SHORT(v)            bswap_16(v)
-#define BE_INT(v)              bswap_32(v)
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define COMPOSE_ID(a,b,c,d)    ((d) | ((c)<<8) | ((b)<<16) | ((a)<<24))
-#define LE_SHORT(v)            bswap_16(v)
-#define LE_INT(v)              bswap_32(v)
-#define BE_SHORT(v)            (v)
-#define BE_INT(v)              (v)
-#else
-#error "Wrong endian"
-#endif
-
-#define AU_MAGIC               COMPOSE_ID('.','s','n','d')
-
-#define AU_FMT_ULAW            1
-#define AU_FMT_LIN8            2
-#define AU_FMT_LIN16           3
-
-struct au_header {
-       uint32_t magic;         /* '.snd' */
-       uint32_t hdr_size;      /* size of header (min 24) */
-       uint32_t data_size;     /* size of data */
-       uint32_t encoding;      /* see to AU_FMT_XXXX */
-       uint32_t sample_rate;   /* sample rate */
-       uint32_t channels;      /* number of channels (voices) */
-};
diff --git a/sbc/sbc.c b/sbc/sbc.c
deleted file mode 100644 (file)
index c5015ab..0000000
--- a/sbc/sbc.c
+++ /dev/null
@@ -1,1241 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/* todo items:
-
-  use a log2 table for byte integer scale factors calculation (sum log2 results
-  for high and low bytes) fill bitpool by 16 bits instead of one at a time in
-  bits allocation/bitpool generation port to the dsp
-
-*/
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <stdlib.h>
-#include <sys/types.h>
-#include <limits.h>
-
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc.h"
-#include "sbc_primitives.h"
-
-#define SBC_SYNCWORD   0x9C
-
-/* This structure contains an unpacked SBC frame.
-   Yes, there is probably quite some unused space herein */
-struct sbc_frame {
-       uint8_t frequency;
-       uint8_t block_mode;
-       uint8_t blocks;
-       enum {
-               MONO            = SBC_MODE_MONO,
-               DUAL_CHANNEL    = SBC_MODE_DUAL_CHANNEL,
-               STEREO          = SBC_MODE_STEREO,
-               JOINT_STEREO    = SBC_MODE_JOINT_STEREO
-       } mode;
-       uint8_t channels;
-       enum {
-               LOUDNESS        = SBC_AM_LOUDNESS,
-               SNR             = SBC_AM_SNR
-       } allocation;
-       uint8_t subband_mode;
-       uint8_t subbands;
-       uint8_t bitpool;
-       uint16_t codesize;
-       uint8_t length;
-
-       /* bit number x set means joint stereo has been used in subband x */
-       uint8_t joint;
-
-       /* only the lower 4 bits of every element are to be used */
-       uint32_t SBC_ALIGNED scale_factor[2][8];
-
-       /* raw integer subband samples in the frame */
-       int32_t SBC_ALIGNED sb_sample_f[16][2][8];
-
-       /* modified subband samples */
-       int32_t SBC_ALIGNED sb_sample[16][2][8];
-
-       /* original pcm audio samples */
-       int16_t SBC_ALIGNED pcm_sample[2][16*8];
-};
-
-struct sbc_decoder_state {
-       int subbands;
-       int32_t V[2][170];
-       int offset[2][16];
-};
-
-/*
- * Calculates the CRC-8 of the first len bits in data
- */
-static const uint8_t crc_table[256] = {
-       0x00, 0x1D, 0x3A, 0x27, 0x74, 0x69, 0x4E, 0x53,
-       0xE8, 0xF5, 0xD2, 0xCF, 0x9C, 0x81, 0xA6, 0xBB,
-       0xCD, 0xD0, 0xF7, 0xEA, 0xB9, 0xA4, 0x83, 0x9E,
-       0x25, 0x38, 0x1F, 0x02, 0x51, 0x4C, 0x6B, 0x76,
-       0x87, 0x9A, 0xBD, 0xA0, 0xF3, 0xEE, 0xC9, 0xD4,
-       0x6F, 0x72, 0x55, 0x48, 0x1B, 0x06, 0x21, 0x3C,
-       0x4A, 0x57, 0x70, 0x6D, 0x3E, 0x23, 0x04, 0x19,
-       0xA2, 0xBF, 0x98, 0x85, 0xD6, 0xCB, 0xEC, 0xF1,
-       0x13, 0x0E, 0x29, 0x34, 0x67, 0x7A, 0x5D, 0x40,
-       0xFB, 0xE6, 0xC1, 0xDC, 0x8F, 0x92, 0xB5, 0xA8,
-       0xDE, 0xC3, 0xE4, 0xF9, 0xAA, 0xB7, 0x90, 0x8D,
-       0x36, 0x2B, 0x0C, 0x11, 0x42, 0x5F, 0x78, 0x65,
-       0x94, 0x89, 0xAE, 0xB3, 0xE0, 0xFD, 0xDA, 0xC7,
-       0x7C, 0x61, 0x46, 0x5B, 0x08, 0x15, 0x32, 0x2F,
-       0x59, 0x44, 0x63, 0x7E, 0x2D, 0x30, 0x17, 0x0A,
-       0xB1, 0xAC, 0x8B, 0x96, 0xC5, 0xD8, 0xFF, 0xE2,
-       0x26, 0x3B, 0x1C, 0x01, 0x52, 0x4F, 0x68, 0x75,
-       0xCE, 0xD3, 0xF4, 0xE9, 0xBA, 0xA7, 0x80, 0x9D,
-       0xEB, 0xF6, 0xD1, 0xCC, 0x9F, 0x82, 0xA5, 0xB8,
-       0x03, 0x1E, 0x39, 0x24, 0x77, 0x6A, 0x4D, 0x50,
-       0xA1, 0xBC, 0x9B, 0x86, 0xD5, 0xC8, 0xEF, 0xF2,
-       0x49, 0x54, 0x73, 0x6E, 0x3D, 0x20, 0x07, 0x1A,
-       0x6C, 0x71, 0x56, 0x4B, 0x18, 0x05, 0x22, 0x3F,
-       0x84, 0x99, 0xBE, 0xA3, 0xF0, 0xED, 0xCA, 0xD7,
-       0x35, 0x28, 0x0F, 0x12, 0x41, 0x5C, 0x7B, 0x66,
-       0xDD, 0xC0, 0xE7, 0xFA, 0xA9, 0xB4, 0x93, 0x8E,
-       0xF8, 0xE5, 0xC2, 0xDF, 0x8C, 0x91, 0xB6, 0xAB,
-       0x10, 0x0D, 0x2A, 0x37, 0x64, 0x79, 0x5E, 0x43,
-       0xB2, 0xAF, 0x88, 0x95, 0xC6, 0xDB, 0xFC, 0xE1,
-       0x5A, 0x47, 0x60, 0x7D, 0x2E, 0x33, 0x14, 0x09,
-       0x7F, 0x62, 0x45, 0x58, 0x0B, 0x16, 0x31, 0x2C,
-       0x97, 0x8A, 0xAD, 0xB0, 0xE3, 0xFE, 0xD9, 0xC4
-};
-
-static uint8_t sbc_crc8(const uint8_t *data, size_t len)
-{
-       uint8_t crc = 0x0f;
-       size_t i;
-       uint8_t octet;
-
-       for (i = 0; i < len / 8; i++)
-               crc = crc_table[crc ^ data[i]];
-
-       octet = data[i];
-       for (i = 0; i < len % 8; i++) {
-               char bit = ((octet ^ crc) & 0x80) >> 7;
-
-               crc = ((crc & 0x7f) << 1) ^ (bit ? 0x1d : 0);
-
-               octet = octet << 1;
-       }
-
-       return crc;
-}
-
-/*
- * Code straight from the spec to calculate the bits array
- * Takes a pointer to the frame in question, a pointer to the bits array and
- * the sampling frequency (as 2 bit integer)
- */
-static SBC_ALWAYS_INLINE void sbc_calculate_bits_internal(
-               const struct sbc_frame *frame, int (*bits)[8], int subbands)
-{
-       uint8_t sf = frame->frequency;
-
-       if (frame->mode == MONO || frame->mode == DUAL_CHANNEL) {
-               int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
-               int ch, sb;
-
-               for (ch = 0; ch < frame->channels; ch++) {
-                       max_bitneed = 0;
-                       if (frame->allocation == SNR) {
-                               for (sb = 0; sb < subbands; sb++) {
-                                       bitneed[ch][sb] = frame->scale_factor[ch][sb];
-                                       if (bitneed[ch][sb] > max_bitneed)
-                                               max_bitneed = bitneed[ch][sb];
-                               }
-                       } else {
-                               for (sb = 0; sb < subbands; sb++) {
-                                       if (frame->scale_factor[ch][sb] == 0)
-                                               bitneed[ch][sb] = -5;
-                                       else {
-                                               if (subbands == 4)
-                                                       loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
-                                               else
-                                                       loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
-                                               if (loudness > 0)
-                                                       bitneed[ch][sb] = loudness / 2;
-                                               else
-                                                       bitneed[ch][sb] = loudness;
-                                       }
-                                       if (bitneed[ch][sb] > max_bitneed)
-                                               max_bitneed = bitneed[ch][sb];
-                               }
-                       }
-
-                       bitcount = 0;
-                       slicecount = 0;
-                       bitslice = max_bitneed + 1;
-                       do {
-                               bitslice--;
-                               bitcount += slicecount;
-                               slicecount = 0;
-                               for (sb = 0; sb < subbands; sb++) {
-                                       if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
-                                               slicecount++;
-                                       else if (bitneed[ch][sb] == bitslice + 1)
-                                               slicecount += 2;
-                               }
-                       } while (bitcount + slicecount < frame->bitpool);
-
-                       if (bitcount + slicecount == frame->bitpool) {
-                               bitcount += slicecount;
-                               bitslice--;
-                       }
-
-                       for (sb = 0; sb < subbands; sb++) {
-                               if (bitneed[ch][sb] < bitslice + 2)
-                                       bits[ch][sb] = 0;
-                               else {
-                                       bits[ch][sb] = bitneed[ch][sb] - bitslice;
-                                       if (bits[ch][sb] > 16)
-                                               bits[ch][sb] = 16;
-                               }
-                       }
-
-                       for (sb = 0; bitcount < frame->bitpool &&
-                                                       sb < subbands; sb++) {
-                               if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
-                                       bits[ch][sb]++;
-                                       bitcount++;
-                               } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
-                                       bits[ch][sb] = 2;
-                                       bitcount += 2;
-                               }
-                       }
-
-                       for (sb = 0; bitcount < frame->bitpool &&
-                                                       sb < subbands; sb++) {
-                               if (bits[ch][sb] < 16) {
-                                       bits[ch][sb]++;
-                                       bitcount++;
-                               }
-                       }
-
-               }
-
-       } else if (frame->mode == STEREO || frame->mode == JOINT_STEREO) {
-               int bitneed[2][8], loudness, max_bitneed, bitcount, slicecount, bitslice;
-               int ch, sb;
-
-               max_bitneed = 0;
-               if (frame->allocation == SNR) {
-                       for (ch = 0; ch < 2; ch++) {
-                               for (sb = 0; sb < subbands; sb++) {
-                                       bitneed[ch][sb] = frame->scale_factor[ch][sb];
-                                       if (bitneed[ch][sb] > max_bitneed)
-                                               max_bitneed = bitneed[ch][sb];
-                               }
-                       }
-               } else {
-                       for (ch = 0; ch < 2; ch++) {
-                               for (sb = 0; sb < subbands; sb++) {
-                                       if (frame->scale_factor[ch][sb] == 0)
-                                               bitneed[ch][sb] = -5;
-                                       else {
-                                               if (subbands == 4)
-                                                       loudness = frame->scale_factor[ch][sb] - sbc_offset4[sf][sb];
-                                               else
-                                                       loudness = frame->scale_factor[ch][sb] - sbc_offset8[sf][sb];
-                                               if (loudness > 0)
-                                                       bitneed[ch][sb] = loudness / 2;
-                                               else
-                                                       bitneed[ch][sb] = loudness;
-                                       }
-                                       if (bitneed[ch][sb] > max_bitneed)
-                                               max_bitneed = bitneed[ch][sb];
-                               }
-                       }
-               }
-
-               bitcount = 0;
-               slicecount = 0;
-               bitslice = max_bitneed + 1;
-               do {
-                       bitslice--;
-                       bitcount += slicecount;
-                       slicecount = 0;
-                       for (ch = 0; ch < 2; ch++) {
-                               for (sb = 0; sb < subbands; sb++) {
-                                       if ((bitneed[ch][sb] > bitslice + 1) && (bitneed[ch][sb] < bitslice + 16))
-                                               slicecount++;
-                                       else if (bitneed[ch][sb] == bitslice + 1)
-                                               slicecount += 2;
-                               }
-                       }
-               } while (bitcount + slicecount < frame->bitpool);
-
-               if (bitcount + slicecount == frame->bitpool) {
-                       bitcount += slicecount;
-                       bitslice--;
-               }
-
-               for (ch = 0; ch < 2; ch++) {
-                       for (sb = 0; sb < subbands; sb++) {
-                               if (bitneed[ch][sb] < bitslice + 2) {
-                                       bits[ch][sb] = 0;
-                               } else {
-                                       bits[ch][sb] = bitneed[ch][sb] - bitslice;
-                                       if (bits[ch][sb] > 16)
-                                               bits[ch][sb] = 16;
-                               }
-                       }
-               }
-
-               ch = 0;
-               sb = 0;
-               while (bitcount < frame->bitpool) {
-                       if ((bits[ch][sb] >= 2) && (bits[ch][sb] < 16)) {
-                               bits[ch][sb]++;
-                               bitcount++;
-                       } else if ((bitneed[ch][sb] == bitslice + 1) && (frame->bitpool > bitcount + 1)) {
-                               bits[ch][sb] = 2;
-                               bitcount += 2;
-                       }
-                       if (ch == 1) {
-                               ch = 0;
-                               sb++;
-                               if (sb >= subbands)
-                                       break;
-                       } else
-                               ch = 1;
-               }
-
-               ch = 0;
-               sb = 0;
-               while (bitcount < frame->bitpool) {
-                       if (bits[ch][sb] < 16) {
-                               bits[ch][sb]++;
-                               bitcount++;
-                       }
-                       if (ch == 1) {
-                               ch = 0;
-                               sb++;
-                               if (sb >= subbands)
-                                       break;
-                       } else
-                               ch = 1;
-               }
-
-       }
-
-}
-
-static void sbc_calculate_bits(const struct sbc_frame *frame, int (*bits)[8])
-{
-       if (frame->subbands == 4)
-               sbc_calculate_bits_internal(frame, bits, 4);
-       else
-               sbc_calculate_bits_internal(frame, bits, 8);
-}
-
-/*
- * Unpacks a SBC frame at the beginning of the stream in data,
- * which has at most len bytes into frame.
- * Returns the length in bytes of the packed frame, or a negative
- * value on error. The error codes are:
- *
- *  -1   Data stream too short
- *  -2   Sync byte incorrect
- *  -3   CRC8 incorrect
- *  -4   Bitpool value out of bounds
- */
-static int sbc_unpack_frame(const uint8_t *data, struct sbc_frame *frame,
-                                                               size_t len)
-{
-       unsigned int consumed;
-       /* Will copy the parts of the header that are relevant to crc
-        * calculation here */
-       uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-       int crc_pos = 0;
-       int32_t temp;
-
-       uint32_t audio_sample;
-       int ch, sb, blk, bit;   /* channel, subband, block and bit standard
-                                  counters */
-       int bits[2][8];         /* bits distribution */
-       uint32_t levels[2][8];  /* levels derived from that */
-
-       if (len < 4)
-               return -1;
-
-       if (data[0] != SBC_SYNCWORD)
-               return -2;
-
-       frame->frequency = (data[1] >> 6) & 0x03;
-
-       frame->block_mode = (data[1] >> 4) & 0x03;
-       switch (frame->block_mode) {
-       case SBC_BLK_4:
-               frame->blocks = 4;
-               break;
-       case SBC_BLK_8:
-               frame->blocks = 8;
-               break;
-       case SBC_BLK_12:
-               frame->blocks = 12;
-               break;
-       case SBC_BLK_16:
-               frame->blocks = 16;
-               break;
-       }
-
-       frame->mode = (data[1] >> 2) & 0x03;
-       switch (frame->mode) {
-       case MONO:
-               frame->channels = 1;
-               break;
-       case DUAL_CHANNEL:      /* fall-through */
-       case STEREO:
-       case JOINT_STEREO:
-               frame->channels = 2;
-               break;
-       }
-
-       frame->allocation = (data[1] >> 1) & 0x01;
-
-       frame->subband_mode = (data[1] & 0x01);
-       frame->subbands = frame->subband_mode ? 8 : 4;
-
-       frame->bitpool = data[2];
-
-       if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
-                       frame->bitpool > 16 * frame->subbands)
-               return -4;
-
-       if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
-                       frame->bitpool > 32 * frame->subbands)
-               return -4;
-
-       /* data[3] is crc, we're checking it later */
-
-       consumed = 32;
-
-       crc_header[0] = data[1];
-       crc_header[1] = data[2];
-       crc_pos = 16;
-
-       if (frame->mode == JOINT_STEREO) {
-               if (len * 8 < consumed + frame->subbands)
-                       return -1;
-
-               frame->joint = 0x00;
-               for (sb = 0; sb < frame->subbands - 1; sb++)
-                       frame->joint |= ((data[4] >> (7 - sb)) & 0x01) << sb;
-               if (frame->subbands == 4)
-                       crc_header[crc_pos / 8] = data[4] & 0xf0;
-               else
-                       crc_header[crc_pos / 8] = data[4];
-
-               consumed += frame->subbands;
-               crc_pos += frame->subbands;
-       }
-
-       if (len * 8 < consumed + (4 * frame->subbands * frame->channels))
-               return -1;
-
-       for (ch = 0; ch < frame->channels; ch++) {
-               for (sb = 0; sb < frame->subbands; sb++) {
-                       /* FIXME assert(consumed % 4 == 0); */
-                       frame->scale_factor[ch][sb] =
-                               (data[consumed >> 3] >> (4 - (consumed & 0x7))) & 0x0F;
-                       crc_header[crc_pos >> 3] |=
-                               frame->scale_factor[ch][sb] << (4 - (crc_pos & 0x7));
-
-                       consumed += 4;
-                       crc_pos += 4;
-               }
-       }
-
-       if (data[3] != sbc_crc8(crc_header, crc_pos))
-               return -3;
-
-       sbc_calculate_bits(frame, bits);
-
-       for (ch = 0; ch < frame->channels; ch++) {
-               for (sb = 0; sb < frame->subbands; sb++)
-                       levels[ch][sb] = (1 << bits[ch][sb]) - 1;
-       }
-
-       for (blk = 0; blk < frame->blocks; blk++) {
-               for (ch = 0; ch < frame->channels; ch++) {
-                       for (sb = 0; sb < frame->subbands; sb++) {
-                               uint32_t shift;
-
-                               if (levels[ch][sb] == 0) {
-                                       frame->sb_sample[blk][ch][sb] = 0;
-                                       continue;
-                               }
-
-                               shift = frame->scale_factor[ch][sb] +
-                                               1 + SBCDEC_FIXED_EXTRA_BITS;
-
-                               audio_sample = 0;
-                               for (bit = 0; bit < bits[ch][sb]; bit++) {
-                                       if (consumed > len * 8)
-                                               return -1;
-
-                                       if ((data[consumed >> 3] >> (7 - (consumed & 0x7))) & 0x01)
-                                               audio_sample |= 1 << (bits[ch][sb] - bit - 1);
-
-                                       consumed++;
-                               }
-
-                               frame->sb_sample[blk][ch][sb] = (int32_t)
-                                       (((((uint64_t) audio_sample << 1) | 1) << shift) /
-                                       levels[ch][sb]) - (1 << shift);
-                       }
-               }
-       }
-
-       if (frame->mode == JOINT_STEREO) {
-               for (blk = 0; blk < frame->blocks; blk++) {
-                       for (sb = 0; sb < frame->subbands; sb++) {
-                               if (frame->joint & (0x01 << sb)) {
-                                       temp = frame->sb_sample[blk][0][sb] +
-                                               frame->sb_sample[blk][1][sb];
-                                       frame->sb_sample[blk][1][sb] =
-                                               frame->sb_sample[blk][0][sb] -
-                                               frame->sb_sample[blk][1][sb];
-                                       frame->sb_sample[blk][0][sb] = temp;
-                               }
-                       }
-               }
-       }
-
-       if ((consumed & 0x7) != 0)
-               consumed += 8 - (consumed & 0x7);
-
-       return consumed >> 3;
-}
-
-static void sbc_decoder_init(struct sbc_decoder_state *state,
-                                       const struct sbc_frame *frame)
-{
-       int i, ch;
-
-       memset(state->V, 0, sizeof(state->V));
-       state->subbands = frame->subbands;
-
-       for (ch = 0; ch < 2; ch++)
-               for (i = 0; i < frame->subbands * 2; i++)
-                       state->offset[ch][i] = (10 * i + 10);
-}
-
-static SBC_ALWAYS_INLINE int16_t sbc_clip16(int32_t s)
-{
-       if (s > 0x7FFF)
-               return 0x7FFF;
-       else if (s < -0x8000)
-               return -0x8000;
-       else
-               return s;
-}
-
-static inline void sbc_synthesize_four(struct sbc_decoder_state *state,
-                               struct sbc_frame *frame, int ch, int blk)
-{
-       int i, k, idx;
-       int32_t *v = state->V[ch];
-       int *offset = state->offset[ch];
-
-       for (i = 0; i < 8; i++) {
-               /* Shifting */
-               offset[i]--;
-               if (offset[i] < 0) {
-                       offset[i] = 79;
-                       memcpy(v + 80, v, 9 * sizeof(*v));
-               }
-
-               /* Distribute the new matrix value to the shifted position */
-               v[offset[i]] = SCALE4_STAGED1(
-                       MULA(synmatrix4[i][0], frame->sb_sample[blk][ch][0],
-                       MULA(synmatrix4[i][1], frame->sb_sample[blk][ch][1],
-                       MULA(synmatrix4[i][2], frame->sb_sample[blk][ch][2],
-                       MUL (synmatrix4[i][3], frame->sb_sample[blk][ch][3])))));
-       }
-
-       /* Compute the samples */
-       for (idx = 0, i = 0; i < 4; i++, idx += 5) {
-               k = (i + 4) & 0xf;
-
-               /* Store in output, Q0 */
-               frame->pcm_sample[ch][blk * 4 + i] = sbc_clip16(SCALE4_STAGED1(
-                       MULA(v[offset[i] + 0], sbc_proto_4_40m0[idx + 0],
-                       MULA(v[offset[k] + 1], sbc_proto_4_40m1[idx + 0],
-                       MULA(v[offset[i] + 2], sbc_proto_4_40m0[idx + 1],
-                       MULA(v[offset[k] + 3], sbc_proto_4_40m1[idx + 1],
-                       MULA(v[offset[i] + 4], sbc_proto_4_40m0[idx + 2],
-                       MULA(v[offset[k] + 5], sbc_proto_4_40m1[idx + 2],
-                       MULA(v[offset[i] + 6], sbc_proto_4_40m0[idx + 3],
-                       MULA(v[offset[k] + 7], sbc_proto_4_40m1[idx + 3],
-                       MULA(v[offset[i] + 8], sbc_proto_4_40m0[idx + 4],
-                       MUL( v[offset[k] + 9], sbc_proto_4_40m1[idx + 4]))))))))))));
-       }
-}
-
-static inline void sbc_synthesize_eight(struct sbc_decoder_state *state,
-                               struct sbc_frame *frame, int ch, int blk)
-{
-       int i, j, k, idx;
-       int *offset = state->offset[ch];
-
-       for (i = 0; i < 16; i++) {
-               /* Shifting */
-               offset[i]--;
-               if (offset[i] < 0) {
-                       offset[i] = 159;
-                       for (j = 0; j < 9; j++)
-                               state->V[ch][j + 160] = state->V[ch][j];
-               }
-
-               /* Distribute the new matrix value to the shifted position */
-               state->V[ch][offset[i]] = SCALE8_STAGED1(
-                       MULA(synmatrix8[i][0], frame->sb_sample[blk][ch][0],
-                       MULA(synmatrix8[i][1], frame->sb_sample[blk][ch][1],
-                       MULA(synmatrix8[i][2], frame->sb_sample[blk][ch][2],
-                       MULA(synmatrix8[i][3], frame->sb_sample[blk][ch][3],
-                       MULA(synmatrix8[i][4], frame->sb_sample[blk][ch][4],
-                       MULA(synmatrix8[i][5], frame->sb_sample[blk][ch][5],
-                       MULA(synmatrix8[i][6], frame->sb_sample[blk][ch][6],
-                       MUL( synmatrix8[i][7], frame->sb_sample[blk][ch][7])))))))));
-       }
-
-       /* Compute the samples */
-       for (idx = 0, i = 0; i < 8; i++, idx += 5) {
-               k = (i + 8) & 0xf;
-
-               /* Store in output, Q0 */
-               frame->pcm_sample[ch][blk * 8 + i] = sbc_clip16(SCALE8_STAGED1(
-                       MULA(state->V[ch][offset[i] + 0], sbc_proto_8_80m0[idx + 0],
-                       MULA(state->V[ch][offset[k] + 1], sbc_proto_8_80m1[idx + 0],
-                       MULA(state->V[ch][offset[i] + 2], sbc_proto_8_80m0[idx + 1],
-                       MULA(state->V[ch][offset[k] + 3], sbc_proto_8_80m1[idx + 1],
-                       MULA(state->V[ch][offset[i] + 4], sbc_proto_8_80m0[idx + 2],
-                       MULA(state->V[ch][offset[k] + 5], sbc_proto_8_80m1[idx + 2],
-                       MULA(state->V[ch][offset[i] + 6], sbc_proto_8_80m0[idx + 3],
-                       MULA(state->V[ch][offset[k] + 7], sbc_proto_8_80m1[idx + 3],
-                       MULA(state->V[ch][offset[i] + 8], sbc_proto_8_80m0[idx + 4],
-                       MUL( state->V[ch][offset[k] + 9], sbc_proto_8_80m1[idx + 4]))))))))))));
-       }
-}
-
-static int sbc_synthesize_audio(struct sbc_decoder_state *state,
-                                               struct sbc_frame *frame)
-{
-       int ch, blk;
-
-       switch (frame->subbands) {
-       case 4:
-               for (ch = 0; ch < frame->channels; ch++) {
-                       for (blk = 0; blk < frame->blocks; blk++)
-                               sbc_synthesize_four(state, frame, ch, blk);
-               }
-               return frame->blocks * 4;
-
-       case 8:
-               for (ch = 0; ch < frame->channels; ch++) {
-                       for (blk = 0; blk < frame->blocks; blk++)
-                               sbc_synthesize_eight(state, frame, ch, blk);
-               }
-               return frame->blocks * 8;
-
-       default:
-               return -EIO;
-       }
-}
-
-static int sbc_analyze_audio(struct sbc_encoder_state *state,
-                                               struct sbc_frame *frame)
-{
-       int ch, blk;
-       int16_t *x;
-
-       switch (frame->subbands) {
-       case 4:
-               for (ch = 0; ch < frame->channels; ch++) {
-                       x = &state->X[ch][state->position - 16 +
-                                                       frame->blocks * 4];
-                       for (blk = 0; blk < frame->blocks; blk += 4) {
-                               state->sbc_analyze_4b_4s(
-                                       x,
-                                       frame->sb_sample_f[blk][ch],
-                                       frame->sb_sample_f[blk + 1][ch] -
-                                       frame->sb_sample_f[blk][ch]);
-                               x -= 16;
-                       }
-               }
-               return frame->blocks * 4;
-
-       case 8:
-               for (ch = 0; ch < frame->channels; ch++) {
-                       x = &state->X[ch][state->position - 32 +
-                                                       frame->blocks * 8];
-                       for (blk = 0; blk < frame->blocks; blk += 4) {
-                               state->sbc_analyze_4b_8s(
-                                       x,
-                                       frame->sb_sample_f[blk][ch],
-                                       frame->sb_sample_f[blk + 1][ch] -
-                                       frame->sb_sample_f[blk][ch]);
-                               x -= 32;
-                       }
-               }
-               return frame->blocks * 8;
-
-       default:
-               return -EIO;
-       }
-}
-
-/* Supplementary bitstream writing macros for 'sbc_pack_frame' */
-
-#define PUT_BITS(data_ptr, bits_cache, bits_count, v, n)               \
-       do {                                                            \
-               bits_cache = (v) | (bits_cache << (n));                 \
-               bits_count += (n);                                      \
-               if (bits_count >= 16) {                                 \
-                       bits_count -= 8;                                \
-                       *data_ptr++ = (uint8_t)                         \
-                               (bits_cache >> bits_count);             \
-                       bits_count -= 8;                                \
-                       *data_ptr++ = (uint8_t)                         \
-                               (bits_cache >> bits_count);             \
-               }                                                       \
-       } while (0)
-
-#define FLUSH_BITS(data_ptr, bits_cache, bits_count)                   \
-       do {                                                            \
-               while (bits_count >= 8) {                               \
-                       bits_count -= 8;                                \
-                       *data_ptr++ = (uint8_t)                         \
-                               (bits_cache >> bits_count);             \
-               }                                                       \
-               if (bits_count > 0)                                     \
-                       *data_ptr++ = (uint8_t)                         \
-                               (bits_cache << (8 - bits_count));       \
-       } while (0)
-
-/*
- * Packs the SBC frame from frame into the memory at data. At most len
- * bytes will be used, should more memory be needed an appropriate
- * error code will be returned. Returns the length of the packed frame
- * on success or a negative value on error.
- *
- * The error codes are:
- * -1 Not enough memory reserved
- * -2 Unsupported sampling rate
- * -3 Unsupported number of blocks
- * -4 Unsupported number of subbands
- * -5 Bitpool value out of bounds
- * -99 not implemented
- */
-
-static SBC_ALWAYS_INLINE ssize_t sbc_pack_frame_internal(uint8_t *data,
-                                       struct sbc_frame *frame, size_t len,
-                                       int frame_subbands, int frame_channels,
-                                       int joint)
-{
-       /* Bitstream writer starts from the fourth byte */
-       uint8_t *data_ptr = data + 4;
-       uint32_t bits_cache = 0;
-       uint32_t bits_count = 0;
-
-       /* Will copy the header parts for CRC-8 calculation here */
-       uint8_t crc_header[11] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
-       int crc_pos = 0;
-
-       uint32_t audio_sample;
-
-       int ch, sb, blk;        /* channel, subband, block and bit counters */
-       int bits[2][8];         /* bits distribution */
-       uint32_t levels[2][8];  /* levels are derived from that */
-       uint32_t sb_sample_delta[2][8];
-
-       data[0] = SBC_SYNCWORD;
-
-       data[1] = (frame->frequency & 0x03) << 6;
-
-       data[1] |= (frame->block_mode & 0x03) << 4;
-
-       data[1] |= (frame->mode & 0x03) << 2;
-
-       data[1] |= (frame->allocation & 0x01) << 1;
-
-       switch (frame_subbands) {
-       case 4:
-               /* Nothing to do */
-               break;
-       case 8:
-               data[1] |= 0x01;
-               break;
-       default:
-               return -4;
-               break;
-       }
-
-       data[2] = frame->bitpool;
-
-       if ((frame->mode == MONO || frame->mode == DUAL_CHANNEL) &&
-                       frame->bitpool > frame_subbands << 4)
-               return -5;
-
-       if ((frame->mode == STEREO || frame->mode == JOINT_STEREO) &&
-                       frame->bitpool > frame_subbands << 5)
-               return -5;
-
-       /* Can't fill in crc yet */
-
-       crc_header[0] = data[1];
-       crc_header[1] = data[2];
-       crc_pos = 16;
-
-       if (frame->mode == JOINT_STEREO) {
-               PUT_BITS(data_ptr, bits_cache, bits_count,
-                       joint, frame_subbands);
-               crc_header[crc_pos >> 3] = joint;
-               crc_pos += frame_subbands;
-       }
-
-       for (ch = 0; ch < frame_channels; ch++) {
-               for (sb = 0; sb < frame_subbands; sb++) {
-                       PUT_BITS(data_ptr, bits_cache, bits_count,
-                               frame->scale_factor[ch][sb] & 0x0F, 4);
-                       crc_header[crc_pos >> 3] <<= 4;
-                       crc_header[crc_pos >> 3] |= frame->scale_factor[ch][sb] & 0x0F;
-                       crc_pos += 4;
-               }
-       }
-
-       /* align the last crc byte */
-       if (crc_pos % 8)
-               crc_header[crc_pos >> 3] <<= 8 - (crc_pos % 8);
-
-       data[3] = sbc_crc8(crc_header, crc_pos);
-
-       sbc_calculate_bits(frame, bits);
-
-       for (ch = 0; ch < frame_channels; ch++) {
-               for (sb = 0; sb < frame_subbands; sb++) {
-                       levels[ch][sb] = ((1 << bits[ch][sb]) - 1) <<
-                               (32 - (frame->scale_factor[ch][sb] +
-                                       SCALE_OUT_BITS + 2));
-                       sb_sample_delta[ch][sb] = (uint32_t) 1 <<
-                               (frame->scale_factor[ch][sb] +
-                                       SCALE_OUT_BITS + 1);
-               }
-       }
-
-       for (blk = 0; blk < frame->blocks; blk++) {
-               for (ch = 0; ch < frame_channels; ch++) {
-                       for (sb = 0; sb < frame_subbands; sb++) {
-
-                               if (bits[ch][sb] == 0)
-                                       continue;
-
-                               audio_sample = ((uint64_t) levels[ch][sb] *
-                                       (sb_sample_delta[ch][sb] +
-                                       frame->sb_sample_f[blk][ch][sb])) >> 32;
-
-                               PUT_BITS(data_ptr, bits_cache, bits_count,
-                                       audio_sample, bits[ch][sb]);
-                       }
-               }
-       }
-
-       FLUSH_BITS(data_ptr, bits_cache, bits_count);
-
-       return data_ptr - data;
-}
-
-static ssize_t sbc_pack_frame(uint8_t *data, struct sbc_frame *frame, size_t len,
-                                                               int joint)
-{
-       if (frame->subbands == 4) {
-               if (frame->channels == 1)
-                       return sbc_pack_frame_internal(
-                               data, frame, len, 4, 1, joint);
-               else
-                       return sbc_pack_frame_internal(
-                               data, frame, len, 4, 2, joint);
-       } else {
-               if (frame->channels == 1)
-                       return sbc_pack_frame_internal(
-                               data, frame, len, 8, 1, joint);
-               else
-                       return sbc_pack_frame_internal(
-                               data, frame, len, 8, 2, joint);
-       }
-}
-
-static void sbc_encoder_init(struct sbc_encoder_state *state,
-                                       const struct sbc_frame *frame)
-{
-       memset(&state->X, 0, sizeof(state->X));
-       state->position = (SBC_X_BUFFER_SIZE - frame->subbands * 9) & ~7;
-
-       sbc_init_primitives(state);
-}
-
-struct sbc_priv {
-       int init;
-       struct SBC_ALIGNED sbc_frame frame;
-       struct SBC_ALIGNED sbc_decoder_state dec_state;
-       struct SBC_ALIGNED sbc_encoder_state enc_state;
-};
-
-static void sbc_set_defaults(sbc_t *sbc, unsigned long flags)
-{
-       sbc->frequency = SBC_FREQ_44100;
-       sbc->mode = SBC_MODE_STEREO;
-       sbc->subbands = SBC_SB_8;
-       sbc->blocks = SBC_BLK_16;
-       sbc->bitpool = 32;
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-       sbc->endian = SBC_LE;
-#elif __BYTE_ORDER == __BIG_ENDIAN
-       sbc->endian = SBC_BE;
-#else
-#error "Unknown byte order"
-#endif
-}
-
-int sbc_init(sbc_t *sbc, unsigned long flags)
-{
-       if (!sbc)
-               return -EIO;
-
-       memset(sbc, 0, sizeof(sbc_t));
-
-       sbc->priv_alloc_base = malloc(sizeof(struct sbc_priv) + SBC_ALIGN_MASK);
-       if (!sbc->priv_alloc_base)
-               return -ENOMEM;
-
-       sbc->priv = (void *) (((uintptr_t) sbc->priv_alloc_base +
-                       SBC_ALIGN_MASK) & ~((uintptr_t) SBC_ALIGN_MASK));
-
-       memset(sbc->priv, 0, sizeof(struct sbc_priv));
-
-       sbc_set_defaults(sbc, flags);
-
-       return 0;
-}
-
-ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len)
-{
-       return sbc_decode(sbc, input, input_len, NULL, 0, NULL);
-}
-
-ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
-                       void *output, size_t output_len, size_t *written)
-{
-       struct sbc_priv *priv;
-       char *ptr;
-       int i, ch, framelen, samples;
-
-       if (!sbc || !input)
-               return -EIO;
-
-       priv = sbc->priv;
-
-       framelen = sbc_unpack_frame(input, &priv->frame, input_len);
-
-       if (!priv->init) {
-               sbc_decoder_init(&priv->dec_state, &priv->frame);
-               priv->init = 1;
-
-               sbc->frequency = priv->frame.frequency;
-               sbc->mode = priv->frame.mode;
-               sbc->subbands = priv->frame.subband_mode;
-               sbc->blocks = priv->frame.block_mode;
-               sbc->allocation = priv->frame.allocation;
-               sbc->bitpool = priv->frame.bitpool;
-
-               priv->frame.codesize = sbc_get_codesize(sbc);
-               priv->frame.length = framelen;
-       } else if (priv->frame.bitpool != sbc->bitpool) {
-               priv->frame.length = framelen;
-               sbc->bitpool = priv->frame.bitpool;
-       }
-
-       if (!output)
-               return framelen;
-
-       if (written)
-               *written = 0;
-
-       if (framelen <= 0)
-               return framelen;
-
-       samples = sbc_synthesize_audio(&priv->dec_state, &priv->frame);
-
-       ptr = output;
-
-       if (output_len < (size_t) (samples * priv->frame.channels * 2))
-               samples = output_len / (priv->frame.channels * 2);
-
-       for (i = 0; i < samples; i++) {
-               for (ch = 0; ch < priv->frame.channels; ch++) {
-                       int16_t s;
-                       s = priv->frame.pcm_sample[ch][i];
-
-                       if (sbc->endian == SBC_BE) {
-                               *ptr++ = (s & 0xff00) >> 8;
-                               *ptr++ = (s & 0x00ff);
-                       } else {
-                               *ptr++ = (s & 0x00ff);
-                               *ptr++ = (s & 0xff00) >> 8;
-                       }
-               }
-       }
-
-       if (written)
-               *written = samples * priv->frame.channels * 2;
-
-       return framelen;
-}
-
-ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
-                       void *output, size_t output_len, ssize_t *written)
-{
-       struct sbc_priv *priv;
-       int samples;
-       ssize_t framelen;
-       int (*sbc_enc_process_input)(int position,
-                       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-                       int nsamples, int nchannels);
-
-       if (!sbc || !input)
-               return -EIO;
-
-       priv = sbc->priv;
-
-       if (written)
-               *written = 0;
-
-       if (!priv->init) {
-               priv->frame.frequency = sbc->frequency;
-               priv->frame.mode = sbc->mode;
-               priv->frame.channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
-               priv->frame.allocation = sbc->allocation;
-               priv->frame.subband_mode = sbc->subbands;
-               priv->frame.subbands = sbc->subbands ? 8 : 4;
-               priv->frame.block_mode = sbc->blocks;
-               priv->frame.blocks = 4 + (sbc->blocks * 4);
-               priv->frame.bitpool = sbc->bitpool;
-               priv->frame.codesize = sbc_get_codesize(sbc);
-               priv->frame.length = sbc_get_frame_length(sbc);
-
-               sbc_encoder_init(&priv->enc_state, &priv->frame);
-               priv->init = 1;
-       } else if (priv->frame.bitpool != sbc->bitpool) {
-               priv->frame.length = sbc_get_frame_length(sbc);
-               priv->frame.bitpool = sbc->bitpool;
-       }
-
-       /* input must be large enough to encode a complete frame */
-       if (input_len < priv->frame.codesize)
-               return 0;
-
-       /* output must be large enough to receive the encoded frame */
-       if (!output || output_len < priv->frame.length)
-               return -ENOSPC;
-
-       /* Select the needed input data processing function and call it */
-       if (priv->frame.subbands == 8) {
-               if (sbc->endian == SBC_BE)
-                       sbc_enc_process_input =
-                               priv->enc_state.sbc_enc_process_input_8s_be;
-               else
-                       sbc_enc_process_input =
-                               priv->enc_state.sbc_enc_process_input_8s_le;
-       } else {
-               if (sbc->endian == SBC_BE)
-                       sbc_enc_process_input =
-                               priv->enc_state.sbc_enc_process_input_4s_be;
-               else
-                       sbc_enc_process_input =
-                               priv->enc_state.sbc_enc_process_input_4s_le;
-       }
-
-       priv->enc_state.position = sbc_enc_process_input(
-               priv->enc_state.position, (const uint8_t *) input,
-               priv->enc_state.X, priv->frame.subbands * priv->frame.blocks,
-               priv->frame.channels);
-
-       samples = sbc_analyze_audio(&priv->enc_state, &priv->frame);
-
-       if (priv->frame.mode == JOINT_STEREO) {
-               int j = priv->enc_state.sbc_calc_scalefactors_j(
-                       priv->frame.sb_sample_f, priv->frame.scale_factor,
-                       priv->frame.blocks, priv->frame.subbands);
-               framelen = sbc_pack_frame(output, &priv->frame, output_len, j);
-       } else {
-               priv->enc_state.sbc_calc_scalefactors(
-                       priv->frame.sb_sample_f, priv->frame.scale_factor,
-                       priv->frame.blocks, priv->frame.channels,
-                       priv->frame.subbands);
-               framelen = sbc_pack_frame(output, &priv->frame, output_len, 0);
-       }
-
-       if (written)
-               *written = framelen;
-
-       return samples * priv->frame.channels * 2;
-}
-
-void sbc_finish(sbc_t *sbc)
-{
-       if (!sbc)
-               return;
-
-       free(sbc->priv_alloc_base);
-
-       memset(sbc, 0, sizeof(sbc_t));
-}
-
-size_t sbc_get_frame_length(sbc_t *sbc)
-{
-       int ret;
-       uint8_t subbands, channels, blocks, joint, bitpool;
-       struct sbc_priv *priv;
-
-       priv = sbc->priv;
-       if (priv->init && priv->frame.bitpool == sbc->bitpool)
-               return priv->frame.length;
-
-       subbands = sbc->subbands ? 8 : 4;
-       blocks = 4 + (sbc->blocks * 4);
-       channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
-       joint = sbc->mode == SBC_MODE_JOINT_STEREO ? 1 : 0;
-       bitpool = sbc->bitpool;
-
-       ret = 4 + (4 * subbands * channels) / 8;
-       /* This term is not always evenly divide so we round it up */
-       if (channels == 1)
-               ret += ((blocks * channels * bitpool) + 7) / 8;
-       else
-               ret += (((joint ? subbands : 0) + blocks * bitpool) + 7) / 8;
-
-       return ret;
-}
-
-unsigned sbc_get_frame_duration(sbc_t *sbc)
-{
-       uint8_t subbands, blocks;
-       uint16_t frequency;
-       struct sbc_priv *priv;
-
-       priv = sbc->priv;
-       if (!priv->init) {
-               subbands = sbc->subbands ? 8 : 4;
-               blocks = 4 + (sbc->blocks * 4);
-       } else {
-               subbands = priv->frame.subbands;
-               blocks = priv->frame.blocks;
-       }
-
-       switch (sbc->frequency) {
-       case SBC_FREQ_16000:
-               frequency = 16000;
-               break;
-
-       case SBC_FREQ_32000:
-               frequency = 32000;
-               break;
-
-       case SBC_FREQ_44100:
-               frequency = 44100;
-               break;
-
-       case SBC_FREQ_48000:
-               frequency = 48000;
-               break;
-       default:
-               return 0;
-       }
-
-       return (1000000 * blocks * subbands) / frequency;
-}
-
-size_t sbc_get_codesize(sbc_t *sbc)
-{
-       uint16_t subbands, channels, blocks;
-       struct sbc_priv *priv;
-
-       priv = sbc->priv;
-       if (!priv->init) {
-               subbands = sbc->subbands ? 8 : 4;
-               blocks = 4 + (sbc->blocks * 4);
-               channels = sbc->mode == SBC_MODE_MONO ? 1 : 2;
-       } else {
-               subbands = priv->frame.subbands;
-               blocks = priv->frame.blocks;
-               channels = priv->frame.channels;
-       }
-
-       return subbands * blocks * channels * 2;
-}
-
-const char *sbc_get_implementation_info(sbc_t *sbc)
-{
-       struct sbc_priv *priv;
-
-       if (!sbc)
-               return NULL;
-
-       priv = sbc->priv;
-       if (!priv)
-               return NULL;
-
-       return priv->enc_state.implementation_info;
-}
-
-int sbc_reinit(sbc_t *sbc, unsigned long flags)
-{
-       struct sbc_priv *priv;
-
-       if (!sbc || !sbc->priv)
-               return -EIO;
-
-       priv = sbc->priv;
-
-       if (priv->init == 1)
-               memset(sbc->priv, 0, sizeof(struct sbc_priv));
-
-       sbc_set_defaults(sbc, flags);
-
-       return 0;
-}
diff --git a/sbc/sbc.h b/sbc/sbc.h
deleted file mode 100644 (file)
index f7ec99d..0000000
--- a/sbc/sbc.h
+++ /dev/null
@@ -1,113 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifndef __SBC_H
-#define __SBC_H
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include <stdint.h>
-#include <sys/types.h>
-
-/* sampling frequency */
-#define SBC_FREQ_16000         0x00
-#define SBC_FREQ_32000         0x01
-#define SBC_FREQ_44100         0x02
-#define SBC_FREQ_48000         0x03
-
-/* blocks */
-#define SBC_BLK_4              0x00
-#define SBC_BLK_8              0x01
-#define SBC_BLK_12             0x02
-#define SBC_BLK_16             0x03
-
-/* channel mode */
-#define SBC_MODE_MONO          0x00
-#define SBC_MODE_DUAL_CHANNEL  0x01
-#define SBC_MODE_STEREO                0x02
-#define SBC_MODE_JOINT_STEREO  0x03
-
-/* allocation method */
-#define SBC_AM_LOUDNESS                0x00
-#define SBC_AM_SNR             0x01
-
-/* subbands */
-#define SBC_SB_4               0x00
-#define SBC_SB_8               0x01
-
-/* Data endianness */
-#define SBC_LE                 0x00
-#define SBC_BE                 0x01
-
-struct sbc_struct {
-       unsigned long flags;
-
-       uint8_t frequency;
-       uint8_t blocks;
-       uint8_t subbands;
-       uint8_t mode;
-       uint8_t allocation;
-       uint8_t bitpool;
-       uint8_t endian;
-
-       void *priv;
-       void *priv_alloc_base;
-};
-
-typedef struct sbc_struct sbc_t;
-
-int sbc_init(sbc_t *sbc, unsigned long flags);
-int sbc_reinit(sbc_t *sbc, unsigned long flags);
-
-ssize_t sbc_parse(sbc_t *sbc, const void *input, size_t input_len);
-
-/* Decodes ONE input block into ONE output block */
-ssize_t sbc_decode(sbc_t *sbc, const void *input, size_t input_len,
-                       void *output, size_t output_len, size_t *written);
-
-/* Encodes ONE input block into ONE output block */
-ssize_t sbc_encode(sbc_t *sbc, const void *input, size_t input_len,
-                       void *output, size_t output_len, ssize_t *written);
-
-/* Returns the output block size in bytes */
-size_t sbc_get_frame_length(sbc_t *sbc);
-
-/* Returns the time one input/output block takes to play in msec*/
-unsigned sbc_get_frame_duration(sbc_t *sbc);
-
-/* Returns the input block size in bytes */
-size_t sbc_get_codesize(sbc_t *sbc);
-
-const char *sbc_get_implementation_info(sbc_t *sbc);
-void sbc_finish(sbc_t *sbc);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __SBC_H */
diff --git a/sbc/sbc_math.h b/sbc/sbc_math.h
deleted file mode 100644 (file)
index 5476860..0000000
+++ /dev/null
@@ -1,61 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2008  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#define fabs(x) ((x) < 0 ? -(x) : (x))
-/* C does not provide an explicit arithmetic shift right but this will
-   always be correct and every compiler *should* generate optimal code */
-#define ASR(val, bits) ((-2 >> 1 == -1) ? \
-                ((int32_t)(val)) >> (bits) : ((int32_t) (val)) / (1 << (bits)))
-
-#define SCALE_SPROTO4_TBL      12
-#define SCALE_SPROTO8_TBL      14
-#define SCALE_NPROTO4_TBL      11
-#define SCALE_NPROTO8_TBL      11
-#define SCALE4_STAGED1_BITS    15
-#define SCALE4_STAGED2_BITS    16
-#define SCALE8_STAGED1_BITS    15
-#define SCALE8_STAGED2_BITS    16
-
-typedef int32_t sbc_fixed_t;
-
-#define SCALE4_STAGED1(src) ASR(src, SCALE4_STAGED1_BITS)
-#define SCALE4_STAGED2(src) ASR(src, SCALE4_STAGED2_BITS)
-#define SCALE8_STAGED1(src) ASR(src, SCALE8_STAGED1_BITS)
-#define SCALE8_STAGED2(src) ASR(src, SCALE8_STAGED2_BITS)
-
-#define SBC_FIXED_0(val) { val = 0; }
-#define MUL(a, b)        ((a) * (b))
-#if defined(__arm__) && (!defined(__thumb__) || defined(__thumb2__))
-#define MULA(a, b, res) ({                             \
-               int tmp = res;                  \
-               __asm__(                                \
-                       "mla %0, %2, %3, %0"            \
-                       : "=&r" (tmp)                   \
-                       : "0" (tmp), "r" (a), "r" (b)); \
-               tmp; })
-#else
-#define MULA(a, b, res)  ((a) * (b) + (res))
-#endif
diff --git a/sbc/sbc_primitives.c b/sbc/sbc_primitives.c
deleted file mode 100644 (file)
index ad780d0..0000000
+++ /dev/null
@@ -1,554 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include <string.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives.h"
-#include "sbc_primitives_mmx.h"
-#include "sbc_primitives_iwmmxt.h"
-#include "sbc_primitives_neon.h"
-#include "sbc_primitives_armv6.h"
-
-/*
- * A reference C code of analysis filter with SIMD-friendly tables
- * reordering and code layout. This code can be used to develop platform
- * specific SIMD optimizations. Also it may be used as some kind of test
- * for compiler autovectorization capabilities (who knows, if the compiler
- * is very good at this stuff, hand optimized assembly may be not strictly
- * needed for some platform).
- *
- * Note: It is also possible to make a simple variant of analysis filter,
- * which needs only a single constants table without taking care about
- * even/odd cases. This simple variant of filter can be implemented without
- * input data permutation. The only thing that would be lost is the
- * possibility to use pairwise SIMD multiplications. But for some simple
- * CPU cores without SIMD extensions it can be useful. If anybody is
- * interested in implementing such variant of a filter, sourcecode from
- * bluez versions 4.26/4.27 can be used as a reference and the history of
- * the changes in git repository done around that time may be worth checking.
- */
-
-static inline void sbc_analyze_four_simd(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       FIXED_A t1[4];
-       FIXED_T t2[4];
-       int hop = 0;
-
-       /* rounding coefficient */
-       t1[0] = t1[1] = t1[2] = t1[3] =
-               (FIXED_A) 1 << (SBC_PROTO_FIXED4_SCALE - 1);
-
-       /* low pass polyphase filter */
-       for (hop = 0; hop < 40; hop += 8) {
-               t1[0] += (FIXED_A) in[hop] * consts[hop];
-               t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
-               t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
-               t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
-               t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
-               t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
-               t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
-               t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
-       }
-
-       /* scaling */
-       t2[0] = t1[0] >> SBC_PROTO_FIXED4_SCALE;
-       t2[1] = t1[1] >> SBC_PROTO_FIXED4_SCALE;
-       t2[2] = t1[2] >> SBC_PROTO_FIXED4_SCALE;
-       t2[3] = t1[3] >> SBC_PROTO_FIXED4_SCALE;
-
-       /* do the cos transform */
-       t1[0]  = (FIXED_A) t2[0] * consts[40 + 0];
-       t1[0] += (FIXED_A) t2[1] * consts[40 + 1];
-       t1[1]  = (FIXED_A) t2[0] * consts[40 + 2];
-       t1[1] += (FIXED_A) t2[1] * consts[40 + 3];
-       t1[2]  = (FIXED_A) t2[0] * consts[40 + 4];
-       t1[2] += (FIXED_A) t2[1] * consts[40 + 5];
-       t1[3]  = (FIXED_A) t2[0] * consts[40 + 6];
-       t1[3] += (FIXED_A) t2[1] * consts[40 + 7];
-
-       t1[0] += (FIXED_A) t2[2] * consts[40 + 8];
-       t1[0] += (FIXED_A) t2[3] * consts[40 + 9];
-       t1[1] += (FIXED_A) t2[2] * consts[40 + 10];
-       t1[1] += (FIXED_A) t2[3] * consts[40 + 11];
-       t1[2] += (FIXED_A) t2[2] * consts[40 + 12];
-       t1[2] += (FIXED_A) t2[3] * consts[40 + 13];
-       t1[3] += (FIXED_A) t2[2] * consts[40 + 14];
-       t1[3] += (FIXED_A) t2[3] * consts[40 + 15];
-
-       out[0] = t1[0] >>
-               (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
-       out[1] = t1[1] >>
-               (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
-       out[2] = t1[2] >>
-               (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
-       out[3] = t1[3] >>
-               (SBC_COS_TABLE_FIXED4_SCALE - SCALE_OUT_BITS);
-}
-
-static inline void sbc_analyze_eight_simd(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       FIXED_A t1[8];
-       FIXED_T t2[8];
-       int i, hop;
-
-       /* rounding coefficient */
-       t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] =
-               (FIXED_A) 1 << (SBC_PROTO_FIXED8_SCALE-1);
-
-       /* low pass polyphase filter */
-       for (hop = 0; hop < 80; hop += 16) {
-               t1[0] += (FIXED_A) in[hop] * consts[hop];
-               t1[0] += (FIXED_A) in[hop + 1] * consts[hop + 1];
-               t1[1] += (FIXED_A) in[hop + 2] * consts[hop + 2];
-               t1[1] += (FIXED_A) in[hop + 3] * consts[hop + 3];
-               t1[2] += (FIXED_A) in[hop + 4] * consts[hop + 4];
-               t1[2] += (FIXED_A) in[hop + 5] * consts[hop + 5];
-               t1[3] += (FIXED_A) in[hop + 6] * consts[hop + 6];
-               t1[3] += (FIXED_A) in[hop + 7] * consts[hop + 7];
-               t1[4] += (FIXED_A) in[hop + 8] * consts[hop + 8];
-               t1[4] += (FIXED_A) in[hop + 9] * consts[hop + 9];
-               t1[5] += (FIXED_A) in[hop + 10] * consts[hop + 10];
-               t1[5] += (FIXED_A) in[hop + 11] * consts[hop + 11];
-               t1[6] += (FIXED_A) in[hop + 12] * consts[hop + 12];
-               t1[6] += (FIXED_A) in[hop + 13] * consts[hop + 13];
-               t1[7] += (FIXED_A) in[hop + 14] * consts[hop + 14];
-               t1[7] += (FIXED_A) in[hop + 15] * consts[hop + 15];
-       }
-
-       /* scaling */
-       t2[0] = t1[0] >> SBC_PROTO_FIXED8_SCALE;
-       t2[1] = t1[1] >> SBC_PROTO_FIXED8_SCALE;
-       t2[2] = t1[2] >> SBC_PROTO_FIXED8_SCALE;
-       t2[3] = t1[3] >> SBC_PROTO_FIXED8_SCALE;
-       t2[4] = t1[4] >> SBC_PROTO_FIXED8_SCALE;
-       t2[5] = t1[5] >> SBC_PROTO_FIXED8_SCALE;
-       t2[6] = t1[6] >> SBC_PROTO_FIXED8_SCALE;
-       t2[7] = t1[7] >> SBC_PROTO_FIXED8_SCALE;
-
-
-       /* do the cos transform */
-       t1[0] = t1[1] = t1[2] = t1[3] = t1[4] = t1[5] = t1[6] = t1[7] = 0;
-
-       for (i = 0; i < 4; i++) {
-               t1[0] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 0];
-               t1[0] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 1];
-               t1[1] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 2];
-               t1[1] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 3];
-               t1[2] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 4];
-               t1[2] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 5];
-               t1[3] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 6];
-               t1[3] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 7];
-               t1[4] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 8];
-               t1[4] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 9];
-               t1[5] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 10];
-               t1[5] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 11];
-               t1[6] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 12];
-               t1[6] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 13];
-               t1[7] += (FIXED_A) t2[i * 2 + 0] * consts[80 + i * 16 + 14];
-               t1[7] += (FIXED_A) t2[i * 2 + 1] * consts[80 + i * 16 + 15];
-       }
-
-       for (i = 0; i < 8; i++)
-               out[i] = t1[i] >>
-                       (SBC_COS_TABLE_FIXED8_SCALE - SCALE_OUT_BITS);
-}
-
-static inline void sbc_analyze_4b_4s_simd(int16_t *x,
-                                               int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_four_simd(x + 12, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_simd(x + 8, out, analysis_consts_fixed4_simd_even);
-       out += out_stride;
-       sbc_analyze_four_simd(x + 4, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_simd(x + 0, out, analysis_consts_fixed4_simd_even);
-}
-
-static inline void sbc_analyze_4b_8s_simd(int16_t *x,
-                                         int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_eight_simd(x + 24, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_simd(x + 16, out, analysis_consts_fixed8_simd_even);
-       out += out_stride;
-       sbc_analyze_eight_simd(x + 8, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_simd(x + 0, out, analysis_consts_fixed8_simd_even);
-}
-
-static inline int16_t unaligned16_be(const uint8_t *ptr)
-{
-       return (int16_t) ((ptr[0] << 8) | ptr[1]);
-}
-
-static inline int16_t unaligned16_le(const uint8_t *ptr)
-{
-       return (int16_t) (ptr[0] | (ptr[1] << 8));
-}
-
-/*
- * Internal helper functions for input data processing. In order to get
- * optimal performance, it is important to have "nsamples", "nchannels"
- * and "big_endian" arguments used with this inline function as compile
- * time constants.
- */
-
-static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s4_internal(
-       int position,
-       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-       int nsamples, int nchannels, int big_endian)
-{
-       /* handle X buffer wraparound */
-       if (position < nsamples) {
-               if (nchannels > 0)
-                       memcpy(&X[0][SBC_X_BUFFER_SIZE - 40], &X[0][position],
-                                                       36 * sizeof(int16_t));
-               if (nchannels > 1)
-                       memcpy(&X[1][SBC_X_BUFFER_SIZE - 40], &X[1][position],
-                                                       36 * sizeof(int16_t));
-               position = SBC_X_BUFFER_SIZE - 40;
-       }
-
-       #define PCM(i) (big_endian ? \
-               unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
-
-       /* copy/permutate audio samples */
-       while ((nsamples -= 8) >= 0) {
-               position -= 8;
-               if (nchannels > 0) {
-                       int16_t *x = &X[0][position];
-                       x[0]  = PCM(0 + 7 * nchannels);
-                       x[1]  = PCM(0 + 3 * nchannels);
-                       x[2]  = PCM(0 + 6 * nchannels);
-                       x[3]  = PCM(0 + 4 * nchannels);
-                       x[4]  = PCM(0 + 0 * nchannels);
-                       x[5]  = PCM(0 + 2 * nchannels);
-                       x[6]  = PCM(0 + 1 * nchannels);
-                       x[7]  = PCM(0 + 5 * nchannels);
-               }
-               if (nchannels > 1) {
-                       int16_t *x = &X[1][position];
-                       x[0]  = PCM(1 + 7 * nchannels);
-                       x[1]  = PCM(1 + 3 * nchannels);
-                       x[2]  = PCM(1 + 6 * nchannels);
-                       x[3]  = PCM(1 + 4 * nchannels);
-                       x[4]  = PCM(1 + 0 * nchannels);
-                       x[5]  = PCM(1 + 2 * nchannels);
-                       x[6]  = PCM(1 + 1 * nchannels);
-                       x[7]  = PCM(1 + 5 * nchannels);
-               }
-               pcm += 16 * nchannels;
-       }
-       #undef PCM
-
-       return position;
-}
-
-static SBC_ALWAYS_INLINE int sbc_encoder_process_input_s8_internal(
-       int position,
-       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-       int nsamples, int nchannels, int big_endian)
-{
-       /* handle X buffer wraparound */
-       if (position < nsamples) {
-               if (nchannels > 0)
-                       memcpy(&X[0][SBC_X_BUFFER_SIZE - 72], &X[0][position],
-                                                       72 * sizeof(int16_t));
-               if (nchannels > 1)
-                       memcpy(&X[1][SBC_X_BUFFER_SIZE - 72], &X[1][position],
-                                                       72 * sizeof(int16_t));
-               position = SBC_X_BUFFER_SIZE - 72;
-       }
-
-       #define PCM(i) (big_endian ? \
-               unaligned16_be(pcm + (i) * 2) : unaligned16_le(pcm + (i) * 2))
-
-       /* copy/permutate audio samples */
-       while ((nsamples -= 16) >= 0) {
-               position -= 16;
-               if (nchannels > 0) {
-                       int16_t *x = &X[0][position];
-                       x[0]  = PCM(0 + 15 * nchannels);
-                       x[1]  = PCM(0 + 7 * nchannels);
-                       x[2]  = PCM(0 + 14 * nchannels);
-                       x[3]  = PCM(0 + 8 * nchannels);
-                       x[4]  = PCM(0 + 13 * nchannels);
-                       x[5]  = PCM(0 + 9 * nchannels);
-                       x[6]  = PCM(0 + 12 * nchannels);
-                       x[7]  = PCM(0 + 10 * nchannels);
-                       x[8]  = PCM(0 + 11 * nchannels);
-                       x[9]  = PCM(0 + 3 * nchannels);
-                       x[10] = PCM(0 + 6 * nchannels);
-                       x[11] = PCM(0 + 0 * nchannels);
-                       x[12] = PCM(0 + 5 * nchannels);
-                       x[13] = PCM(0 + 1 * nchannels);
-                       x[14] = PCM(0 + 4 * nchannels);
-                       x[15] = PCM(0 + 2 * nchannels);
-               }
-               if (nchannels > 1) {
-                       int16_t *x = &X[1][position];
-                       x[0]  = PCM(1 + 15 * nchannels);
-                       x[1]  = PCM(1 + 7 * nchannels);
-                       x[2]  = PCM(1 + 14 * nchannels);
-                       x[3]  = PCM(1 + 8 * nchannels);
-                       x[4]  = PCM(1 + 13 * nchannels);
-                       x[5]  = PCM(1 + 9 * nchannels);
-                       x[6]  = PCM(1 + 12 * nchannels);
-                       x[7]  = PCM(1 + 10 * nchannels);
-                       x[8]  = PCM(1 + 11 * nchannels);
-                       x[9]  = PCM(1 + 3 * nchannels);
-                       x[10] = PCM(1 + 6 * nchannels);
-                       x[11] = PCM(1 + 0 * nchannels);
-                       x[12] = PCM(1 + 5 * nchannels);
-                       x[13] = PCM(1 + 1 * nchannels);
-                       x[14] = PCM(1 + 4 * nchannels);
-                       x[15] = PCM(1 + 2 * nchannels);
-               }
-               pcm += 32 * nchannels;
-       }
-       #undef PCM
-
-       return position;
-}
-
-/*
- * Input data processing functions. The data is endian converted if needed,
- * channels are deintrleaved and audio samples are reordered for use in
- * SIMD-friendly analysis filter function. The results are put into "X"
- * array, getting appended to the previous data (or it is better to say
- * prepended, as the buffer is filled from top to bottom). Old data is
- * discarded when neededed, but availability of (10 * nrof_subbands)
- * contiguous samples is always guaranteed for the input to the analysis
- * filter. This is achieved by copying a sufficient part of old data
- * to the top of the buffer on buffer wraparound.
- */
-
-static int sbc_enc_process_input_4s_le(int position,
-               const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-               int nsamples, int nchannels)
-{
-       if (nchannels > 1)
-               return sbc_encoder_process_input_s4_internal(
-                       position, pcm, X, nsamples, 2, 0);
-       else
-               return sbc_encoder_process_input_s4_internal(
-                       position, pcm, X, nsamples, 1, 0);
-}
-
-static int sbc_enc_process_input_4s_be(int position,
-               const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-               int nsamples, int nchannels)
-{
-       if (nchannels > 1)
-               return sbc_encoder_process_input_s4_internal(
-                       position, pcm, X, nsamples, 2, 1);
-       else
-               return sbc_encoder_process_input_s4_internal(
-                       position, pcm, X, nsamples, 1, 1);
-}
-
-static int sbc_enc_process_input_8s_le(int position,
-               const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-               int nsamples, int nchannels)
-{
-       if (nchannels > 1)
-               return sbc_encoder_process_input_s8_internal(
-                       position, pcm, X, nsamples, 2, 0);
-       else
-               return sbc_encoder_process_input_s8_internal(
-                       position, pcm, X, nsamples, 1, 0);
-}
-
-static int sbc_enc_process_input_8s_be(int position,
-               const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-               int nsamples, int nchannels)
-{
-       if (nchannels > 1)
-               return sbc_encoder_process_input_s8_internal(
-                       position, pcm, X, nsamples, 2, 1);
-       else
-               return sbc_encoder_process_input_s8_internal(
-                       position, pcm, X, nsamples, 1, 1);
-}
-
-/* Supplementary function to count the number of leading zeros */
-
-static inline int sbc_clz(uint32_t x)
-{
-#ifdef __GNUC__
-       return __builtin_clz(x);
-#else
-       /* TODO: this should be replaced with something better if good
-        * performance is wanted when using compilers other than gcc */
-       int cnt = 0;
-       while (x) {
-               cnt++;
-               x >>= 1;
-       }
-       return 32 - cnt;
-#endif
-}
-
-static void sbc_calc_scalefactors(
-       int32_t sb_sample_f[16][2][8],
-       uint32_t scale_factor[2][8],
-       int blocks, int channels, int subbands)
-{
-       int ch, sb, blk;
-       for (ch = 0; ch < channels; ch++) {
-               for (sb = 0; sb < subbands; sb++) {
-                       uint32_t x = 1 << SCALE_OUT_BITS;
-                       for (blk = 0; blk < blocks; blk++) {
-                               int32_t tmp = fabs(sb_sample_f[blk][ch][sb]);
-                               if (tmp != 0)
-                                       x |= tmp - 1;
-                       }
-                       scale_factor[ch][sb] = (31 - SCALE_OUT_BITS) -
-                               sbc_clz(x);
-               }
-       }
-}
-
-static int sbc_calc_scalefactors_j(
-       int32_t sb_sample_f[16][2][8],
-       uint32_t scale_factor[2][8],
-       int blocks, int subbands)
-{
-       int blk, joint = 0;
-       int32_t tmp0, tmp1;
-       uint32_t x, y;
-
-       /* last subband does not use joint stereo */
-       int sb = subbands - 1;
-       x = 1 << SCALE_OUT_BITS;
-       y = 1 << SCALE_OUT_BITS;
-       for (blk = 0; blk < blocks; blk++) {
-               tmp0 = fabs(sb_sample_f[blk][0][sb]);
-               tmp1 = fabs(sb_sample_f[blk][1][sb]);
-               if (tmp0 != 0)
-                       x |= tmp0 - 1;
-               if (tmp1 != 0)
-                       y |= tmp1 - 1;
-       }
-       scale_factor[0][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(x);
-       scale_factor[1][sb] = (31 - SCALE_OUT_BITS) - sbc_clz(y);
-
-       /* the rest of subbands can use joint stereo */
-       while (--sb >= 0) {
-               int32_t sb_sample_j[16][2];
-               x = 1 << SCALE_OUT_BITS;
-               y = 1 << SCALE_OUT_BITS;
-               for (blk = 0; blk < blocks; blk++) {
-                       tmp0 = sb_sample_f[blk][0][sb];
-                       tmp1 = sb_sample_f[blk][1][sb];
-                       sb_sample_j[blk][0] = ASR(tmp0, 1) + ASR(tmp1, 1);
-                       sb_sample_j[blk][1] = ASR(tmp0, 1) - ASR(tmp1, 1);
-                       tmp0 = fabs(tmp0);
-                       tmp1 = fabs(tmp1);
-                       if (tmp0 != 0)
-                               x |= tmp0 - 1;
-                       if (tmp1 != 0)
-                               y |= tmp1 - 1;
-               }
-               scale_factor[0][sb] = (31 - SCALE_OUT_BITS) -
-                       sbc_clz(x);
-               scale_factor[1][sb] = (31 - SCALE_OUT_BITS) -
-                       sbc_clz(y);
-               x = 1 << SCALE_OUT_BITS;
-               y = 1 << SCALE_OUT_BITS;
-               for (blk = 0; blk < blocks; blk++) {
-                       tmp0 = fabs(sb_sample_j[blk][0]);
-                       tmp1 = fabs(sb_sample_j[blk][1]);
-                       if (tmp0 != 0)
-                               x |= tmp0 - 1;
-                       if (tmp1 != 0)
-                               y |= tmp1 - 1;
-               }
-               x = (31 - SCALE_OUT_BITS) - sbc_clz(x);
-               y = (31 - SCALE_OUT_BITS) - sbc_clz(y);
-
-               /* decide whether to use joint stereo for this subband */
-               if ((scale_factor[0][sb] + scale_factor[1][sb]) > x + y) {
-                       joint |= 1 << (subbands - 1 - sb);
-                       scale_factor[0][sb] = x;
-                       scale_factor[1][sb] = y;
-                       for (blk = 0; blk < blocks; blk++) {
-                               sb_sample_f[blk][0][sb] = sb_sample_j[blk][0];
-                               sb_sample_f[blk][1][sb] = sb_sample_j[blk][1];
-                       }
-               }
-       }
-
-       /* bitmask with the information about subbands using joint stereo */
-       return joint;
-}
-
-/*
- * Detect CPU features and setup function pointers
- */
-void sbc_init_primitives(struct sbc_encoder_state *state)
-{
-       /* Default implementation for analyze functions */
-       state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_simd;
-       state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_simd;
-
-       /* Default implementation for input reordering / deinterleaving */
-       state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le;
-       state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be;
-       state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le;
-       state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be;
-
-       /* Default implementation for scale factors calculation */
-       state->sbc_calc_scalefactors = sbc_calc_scalefactors;
-       state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j;
-       state->implementation_info = "Generic C";
-
-       /* X86/AMD64 optimizations */
-#ifdef SBC_BUILD_WITH_MMX_SUPPORT
-       sbc_init_primitives_mmx(state);
-#endif
-
-       /* ARM optimizations */
-#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
-       sbc_init_primitives_armv6(state);
-#endif
-#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
-       sbc_init_primitives_iwmmxt(state);
-#endif
-#ifdef SBC_BUILD_WITH_NEON_SUPPORT
-       sbc_init_primitives_neon(state);
-#endif
-}
diff --git a/sbc/sbc_primitives.h b/sbc/sbc_primitives.h
deleted file mode 100644 (file)
index 17ad4f7..0000000
+++ /dev/null
@@ -1,80 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifndef __SBC_PRIMITIVES_H
-#define __SBC_PRIMITIVES_H
-
-#define SCALE_OUT_BITS 15
-#define SBC_X_BUFFER_SIZE 328
-
-#ifdef __GNUC__
-#define SBC_ALWAYS_INLINE inline __attribute__((always_inline))
-#else
-#define SBC_ALWAYS_INLINE inline
-#endif
-
-struct sbc_encoder_state {
-       int position;
-       int16_t SBC_ALIGNED X[2][SBC_X_BUFFER_SIZE];
-       /* Polyphase analysis filter for 4 subbands configuration,
-        * it handles 4 blocks at once */
-       void (*sbc_analyze_4b_4s)(int16_t *x, int32_t *out, int out_stride);
-       /* Polyphase analysis filter for 8 subbands configuration,
-        * it handles 4 blocks at once */
-       void (*sbc_analyze_4b_8s)(int16_t *x, int32_t *out, int out_stride);
-       /* Process input data (deinterleave, endian conversion, reordering),
-        * depending on the number of subbands and input data byte order */
-       int (*sbc_enc_process_input_4s_le)(int position,
-                       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-                       int nsamples, int nchannels);
-       int (*sbc_enc_process_input_4s_be)(int position,
-                       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-                       int nsamples, int nchannels);
-       int (*sbc_enc_process_input_8s_le)(int position,
-                       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-                       int nsamples, int nchannels);
-       int (*sbc_enc_process_input_8s_be)(int position,
-                       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-                       int nsamples, int nchannels);
-       /* Scale factors calculation */
-       void (*sbc_calc_scalefactors)(int32_t sb_sample_f[16][2][8],
-                       uint32_t scale_factor[2][8],
-                       int blocks, int channels, int subbands);
-       /* Scale factors calculation with joint stereo support */
-       int (*sbc_calc_scalefactors_j)(int32_t sb_sample_f[16][2][8],
-                       uint32_t scale_factor[2][8],
-                       int blocks, int subbands);
-       const char *implementation_info;
-};
-
-/*
- * Initialize pointers to the functions which are the basic "building bricks"
- * of SBC codec. Best implementation is selected based on target CPU
- * capabilities.
- */
-void sbc_init_primitives(struct sbc_encoder_state *encoder_state);
-
-#endif
diff --git a/sbc/sbc_primitives_armv6.c b/sbc/sbc_primitives_armv6.c
deleted file mode 100644 (file)
index b321272..0000000
+++ /dev/null
@@ -1,299 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives_armv6.h"
-
-/*
- * ARMv6 optimizations. The instructions are scheduled for ARM11 pipeline.
- */
-
-#ifdef SBC_BUILD_WITH_ARMV6_SUPPORT
-
-static void __attribute__((naked)) sbc_analyze_four_armv6()
-{
-       /* r0 = in, r1 = out, r2 = consts */
-       __asm__ volatile (
-               "push   {r1, r4-r7, lr}\n"
-               "push   {r8-r11}\n"
-               "ldrd   r4,  r5,  [r0, #0]\n"
-               "ldrd   r6,  r7,  [r2, #0]\n"
-               "ldrd   r8,  r9,  [r0, #16]\n"
-               "ldrd   r10, r11, [r2, #16]\n"
-               "mov    r14, #0x8000\n"
-               "smlad  r3,  r4,  r6,  r14\n"
-               "smlad  r12, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r0, #32]\n"
-               "ldrd   r6,  r7,  [r2, #32]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #48]\n"
-               "ldrd   r10, r11, [r2, #48]\n"
-               "smlad  r3,  r4,  r6,  r3\n"
-               "smlad  r12, r5,  r7,  r12\n"
-               "ldrd   r4,  r5,  [r0, #64]\n"
-               "ldrd   r6,  r7,  [r2, #64]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #8]\n"
-               "ldrd   r10, r11, [r2, #8]\n"
-               "smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
-               "smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
-               "ldrd   r4,  r5,  [r0, #24]\n"
-               "ldrd   r6,  r7,  [r2, #24]\n"
-               "pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
-               "smlad  r12, r8,  r10, r14\n"
-               "smlad  r14, r9,  r11, r14\n"
-               "ldrd   r8,  r9,  [r0, #40]\n"
-               "ldrd   r10, r11, [r2, #40]\n"
-               "smlad  r12, r4,  r6,  r12\n"
-               "smlad  r14, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r0, #56]\n"
-               "ldrd   r6,  r7,  [r2, #56]\n"
-               "smlad  r12, r8,  r10, r12\n"
-               "smlad  r14, r9,  r11, r14\n"
-               "ldrd   r8,  r9,  [r0, #72]\n"
-               "ldrd   r10, r11, [r2, #72]\n"
-               "smlad  r12, r4,  r6,  r12\n"
-               "smlad  r14, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r2, #80]\n"    /* start loading cos table */
-               "smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
-               "smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
-               "ldrd   r6,  r7,  [r2, #88]\n"
-               "ldrd   r8,  r9,  [r2, #96]\n"
-               "ldrd   r10, r11, [r2, #104]\n"   /* cos table fully loaded */
-               "pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
-               "smuad  r4,  r3,  r4\n"
-               "smuad  r5,  r3,  r5\n"
-               "smlad  r4,  r12, r8,  r4\n"
-               "smlad  r5,  r12, r9,  r5\n"
-               "smuad  r6,  r3,  r6\n"
-               "smuad  r7,  r3,  r7\n"
-               "smlad  r6,  r12, r10, r6\n"
-               "smlad  r7,  r12, r11, r7\n"
-               "pop    {r8-r11}\n"
-               "stmia  r1, {r4, r5, r6, r7}\n"
-               "pop    {r1, r4-r7, pc}\n"
-       );
-}
-
-#define sbc_analyze_four(in, out, consts) \
-       ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
-               sbc_analyze_four_armv6)((in), (out), (consts))
-
-static void __attribute__((naked)) sbc_analyze_eight_armv6()
-{
-       /* r0 = in, r1 = out, r2 = consts */
-       __asm__ volatile (
-               "push   {r1, r4-r7, lr}\n"
-               "push   {r8-r11}\n"
-               "ldrd   r4,  r5,  [r0, #24]\n"
-               "ldrd   r6,  r7,  [r2, #24]\n"
-               "ldrd   r8,  r9,  [r0, #56]\n"
-               "ldrd   r10, r11, [r2, #56]\n"
-               "mov    r14, #0x8000\n"
-               "smlad  r3,  r4,  r6,  r14\n"
-               "smlad  r12, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r0, #88]\n"
-               "ldrd   r6,  r7,  [r2, #88]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #120]\n"
-               "ldrd   r10, r11, [r2, #120]\n"
-               "smlad  r3,  r4,  r6,  r3\n"
-               "smlad  r12, r5,  r7,  r12\n"
-               "ldrd   r4,  r5,  [r0, #152]\n"
-               "ldrd   r6,  r7,  [r2, #152]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #16]\n"
-               "ldrd   r10, r11, [r2, #16]\n"
-               "smlad  r3,  r4,  r6,  r3\n"      /* t1[6] is done */
-               "smlad  r12, r5,  r7,  r12\n"     /* t1[7] is done */
-               "ldrd   r4,  r5,  [r0, #48]\n"
-               "ldrd   r6,  r7,  [r2, #48]\n"
-               "pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[6] and t1[7] */
-               "str    r3,  [sp, #-4]!\n"        /* save to stack */
-               "smlad  r3,  r8,  r10, r14\n"
-               "smlad  r12, r9,  r11, r14\n"
-               "ldrd   r8,  r9,  [r0, #80]\n"
-               "ldrd   r10, r11, [r2, #80]\n"
-               "smlad  r3,  r4,  r6,  r3\n"
-               "smlad  r12, r5,  r7,  r12\n"
-               "ldrd   r4,  r5,  [r0, #112]\n"
-               "ldrd   r6,  r7,  [r2, #112]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #144]\n"
-               "ldrd   r10, r11, [r2, #144]\n"
-               "smlad  r3,  r4,  r6,  r3\n"
-               "smlad  r12, r5,  r7,  r12\n"
-               "ldrd   r4,  r5,  [r0, #0]\n"
-               "ldrd   r6,  r7,  [r2, #0]\n"
-               "smlad  r3,  r8,  r10, r3\n"      /* t1[4] is done */
-               "smlad  r12, r9,  r11, r12\n"     /* t1[5] is done */
-               "ldrd   r8,  r9,  [r0, #32]\n"
-               "ldrd   r10, r11, [r2, #32]\n"
-               "pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[4] and t1[5] */
-               "str    r3,  [sp, #-4]!\n"        /* save to stack */
-               "smlad  r3,  r4,  r6,  r14\n"
-               "smlad  r12, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r0, #64]\n"
-               "ldrd   r6,  r7,  [r2, #64]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #96]\n"
-               "ldrd   r10, r11, [r2, #96]\n"
-               "smlad  r3,  r4,  r6,  r3\n"
-               "smlad  r12, r5,  r7,  r12\n"
-               "ldrd   r4,  r5,  [r0, #128]\n"
-               "ldrd   r6,  r7,  [r2, #128]\n"
-               "smlad  r3,  r8,  r10, r3\n"
-               "smlad  r12, r9,  r11, r12\n"
-               "ldrd   r8,  r9,  [r0, #8]\n"
-               "ldrd   r10, r11, [r2, #8]\n"
-               "smlad  r3,  r4,  r6,  r3\n"      /* t1[0] is done */
-               "smlad  r12, r5,  r7,  r12\n"     /* t1[1] is done */
-               "ldrd   r4,  r5,  [r0, #40]\n"
-               "ldrd   r6,  r7,  [r2, #40]\n"
-               "pkhtb  r3,  r12, r3, asr #16\n"  /* combine t1[0] and t1[1] */
-               "smlad  r12, r8,  r10, r14\n"
-               "smlad  r14, r9,  r11, r14\n"
-               "ldrd   r8,  r9,  [r0, #72]\n"
-               "ldrd   r10, r11, [r2, #72]\n"
-               "smlad  r12, r4,  r6,  r12\n"
-               "smlad  r14, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r0, #104]\n"
-               "ldrd   r6,  r7,  [r2, #104]\n"
-               "smlad  r12, r8,  r10, r12\n"
-               "smlad  r14, r9,  r11, r14\n"
-               "ldrd   r8,  r9,  [r0, #136]\n"
-               "ldrd   r10, r11, [r2, #136]!\n"
-               "smlad  r12, r4,  r6,  r12\n"
-               "smlad  r14, r5,  r7,  r14\n"
-               "ldrd   r4,  r5,  [r2, #(160 - 136 + 0)]\n"
-               "smlad  r12, r8,  r10, r12\n"     /* t1[2] is done */
-               "smlad  r14, r9,  r11, r14\n"     /* t1[3] is done */
-               "ldrd   r6,  r7,  [r2, #(160 - 136 + 8)]\n"
-               "smuad  r4,  r3,  r4\n"
-               "smuad  r5,  r3,  r5\n"
-               "pkhtb  r12, r14, r12, asr #16\n" /* combine t1[2] and t1[3] */
-                                                 /* r3  = t2[0:1] */
-                                                 /* r12 = t2[2:3] */
-               "pop    {r0, r14}\n"              /* t2[4:5], t2[6:7] */
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 32)]\n"
-               "smuad  r6,  r3,  r6\n"
-               "smuad  r7,  r3,  r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 40)]\n"
-               "smlad  r4,  r12, r8,  r4\n"
-               "smlad  r5,  r12, r9,  r5\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 64)]\n"
-               "smlad  r6,  r12, r10, r6\n"
-               "smlad  r7,  r12, r11, r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 72)]\n"
-               "smlad  r4,  r0,  r8,  r4\n"
-               "smlad  r5,  r0,  r9,  r5\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 96)]\n"
-               "smlad  r6,  r0,  r10, r6\n"
-               "smlad  r7,  r0,  r11, r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 104)]\n"
-               "smlad  r4,  r14, r8,  r4\n"
-               "smlad  r5,  r14, r9,  r5\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 0)]\n"
-               "smlad  r6,  r14, r10, r6\n"
-               "smlad  r7,  r14, r11, r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 16 + 8)]\n"
-               "stmia  r1!, {r4, r5}\n"
-               "smuad  r4,  r3,  r8\n"
-               "smuad  r5,  r3,  r9\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 32)]\n"
-               "stmia  r1!, {r6, r7}\n"
-               "smuad  r6,  r3,  r10\n"
-               "smuad  r7,  r3,  r11\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 16 + 40)]\n"
-               "smlad  r4,  r12, r8,  r4\n"
-               "smlad  r5,  r12, r9,  r5\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 64)]\n"
-               "smlad  r6,  r12, r10, r6\n"
-               "smlad  r7,  r12, r11, r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 16 + 72)]\n"
-               "smlad  r4,  r0,  r8,  r4\n"
-               "smlad  r5,  r0,  r9,  r5\n"
-               "ldrd   r8,  r9,  [r2, #(160 - 136 + 16 + 96)]\n"
-               "smlad  r6,  r0,  r10, r6\n"
-               "smlad  r7,  r0,  r11, r7\n"
-               "ldrd   r10, r11, [r2, #(160 - 136 + 16 + 104)]\n"
-               "smlad  r4,  r14, r8,  r4\n"
-               "smlad  r5,  r14, r9,  r5\n"
-               "smlad  r6,  r14, r10, r6\n"
-               "smlad  r7,  r14, r11, r7\n"
-               "pop    {r8-r11}\n"
-               "stmia  r1!, {r4, r5, r6, r7}\n"
-               "pop    {r1, r4-r7, pc}\n"
-       );
-}
-
-#define sbc_analyze_eight(in, out, consts) \
-       ((void (*)(int16_t *, int32_t *, const FIXED_T*)) \
-               sbc_analyze_eight_armv6)((in), (out), (consts))
-
-static void sbc_analyze_4b_4s_armv6(int16_t *x, int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_four(x + 12, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four(x + 8, out, analysis_consts_fixed4_simd_even);
-       out += out_stride;
-       sbc_analyze_four(x + 4, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four(x + 0, out, analysis_consts_fixed4_simd_even);
-}
-
-static void sbc_analyze_4b_8s_armv6(int16_t *x, int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_eight(x + 24, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight(x + 16, out, analysis_consts_fixed8_simd_even);
-       out += out_stride;
-       sbc_analyze_eight(x + 8, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight(x + 0, out, analysis_consts_fixed8_simd_even);
-}
-
-void sbc_init_primitives_armv6(struct sbc_encoder_state *state)
-{
-       state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_armv6;
-       state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_armv6;
-       state->implementation_info = "ARMv6 SIMD";
-}
-
-#endif
diff --git a/sbc/sbc_primitives_armv6.h b/sbc/sbc_primitives_armv6.h
deleted file mode 100644 (file)
index 6a9efe5..0000000
+++ /dev/null
@@ -1,52 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifndef __SBC_PRIMITIVES_ARMV6_H
-#define __SBC_PRIMITIVES_ARMV6_H
-
-#include "sbc_primitives.h"
-
-#if defined(__ARM_ARCH_6__) || defined(__ARM_ARCH_6J__) || \
-       defined(__ARM_ARCH_6K__) || defined(__ARM_ARCH_6Z__) || \
-       defined(__ARM_ARCH_6ZK__) || defined(__ARM_ARCH_6T2__) || \
-       defined(__ARM_ARCH_6M__) || defined(__ARM_ARCH_7__) || \
-       defined(__ARM_ARCH_7A__) || defined(__ARM_ARCH_7R__) || \
-       defined(__ARM_ARCH_7M__)
-#define SBC_HAVE_ARMV6 1
-#endif
-
-#if !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15) && \
-       defined(__GNUC__) && defined(SBC_HAVE_ARMV6) && \
-       defined(__ARM_EABI__) && !defined(__ARM_NEON__) && \
-       (!defined(__thumb__) || defined(__thumb2__))
-
-#define SBC_BUILD_WITH_ARMV6_SUPPORT
-
-void sbc_init_primitives_armv6(struct sbc_encoder_state *encoder_state);
-
-#endif
-
-#endif
diff --git a/sbc/sbc_primitives_iwmmxt.c b/sbc/sbc_primitives_iwmmxt.c
deleted file mode 100644 (file)
index e0bd060..0000000
+++ /dev/null
@@ -1,304 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives_iwmmxt.h"
-
-/*
- * IWMMXT optimizations
- */
-
-#ifdef SBC_BUILD_WITH_IWMMXT_SUPPORT
-
-static inline void sbc_analyze_four_iwmmxt(const int16_t *in, int32_t *out,
-                                       const FIXED_T *consts)
-{
-       __asm__ volatile (
-               "wldrd        wr0, [%0]\n"
-               "tbcstw       wr4, %2\n"
-               "wldrd        wr2, [%1]\n"
-               "wldrd        wr1, [%0, #8]\n"
-               "wldrd        wr3, [%1, #8]\n"
-               "wmadds       wr0, wr2, wr0\n"
-               " wldrd       wr6, [%0, #16]\n"
-               "wmadds       wr1, wr3, wr1\n"
-               " wldrd       wr7, [%0, #24]\n"
-               "waddwss      wr0, wr0, wr4\n"
-               " wldrd       wr8, [%1, #16]\n"
-               "waddwss      wr1, wr1, wr4\n"
-               " wldrd       wr9, [%1, #24]\n"
-               " wmadds      wr6, wr8, wr6\n"
-               "  wldrd      wr2, [%0, #32]\n"
-               " wmadds      wr7, wr9, wr7\n"
-               "  wldrd      wr3, [%0, #40]\n"
-               " waddwss     wr0, wr6, wr0\n"
-               "  wldrd      wr4, [%1, #32]\n"
-               " waddwss     wr1, wr7, wr1\n"
-               "  wldrd      wr5, [%1, #40]\n"
-               "  wmadds     wr2, wr4, wr2\n"
-               "wldrd        wr6, [%0, #48]\n"
-               "  wmadds     wr3, wr5, wr3\n"
-               "wldrd        wr7, [%0, #56]\n"
-               "  waddwss    wr0, wr2, wr0\n"
-               "wldrd        wr8, [%1, #48]\n"
-               "  waddwss    wr1, wr3, wr1\n"
-               "wldrd        wr9, [%1, #56]\n"
-               "wmadds       wr6, wr8, wr6\n"
-               " wldrd       wr2, [%0, #64]\n"
-               "wmadds       wr7, wr9, wr7\n"
-               " wldrd       wr3, [%0, #72]\n"
-               "waddwss      wr0, wr6, wr0\n"
-               " wldrd       wr4, [%1, #64]\n"
-               "waddwss      wr1, wr7, wr1\n"
-               " wldrd       wr5, [%1, #72]\n"
-               " wmadds      wr2, wr4, wr2\n"
-               "tmcr       wcgr0, %4\n"
-               " wmadds      wr3, wr5, wr3\n"
-               " waddwss     wr0, wr2, wr0\n"
-               " waddwss     wr1, wr3, wr1\n"
-               "\n"
-               "wsrawg       wr0, wr0, wcgr0\n"
-               " wldrd       wr4, [%1, #80]\n"
-               "wsrawg       wr1, wr1, wcgr0\n"
-               " wldrd       wr5, [%1, #88]\n"
-               "wpackwss     wr0, wr0, wr0\n"
-               " wldrd       wr6, [%1, #96]\n"
-               "wpackwss     wr1, wr1, wr1\n"
-               "wmadds       wr2, wr5, wr0\n"
-               " wldrd       wr7, [%1, #104]\n"
-               "wmadds       wr0, wr4, wr0\n"
-               "\n"
-               " wmadds      wr3, wr7, wr1\n"
-               " wmadds      wr1, wr6, wr1\n"
-               " waddwss     wr2, wr3, wr2\n"
-               " waddwss     wr0, wr1, wr0\n"
-               "\n"
-               "wstrd        wr0, [%3]\n"
-               "wstrd        wr2, [%3, #8]\n"
-               :
-               : "r" (in), "r" (consts),
-                       "r" (1 << (SBC_PROTO_FIXED4_SCALE - 1)), "r" (out),
-                       "r" (SBC_PROTO_FIXED4_SCALE)
-               : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
-                 "wr8", "wr9", "wcgr0", "memory");
-}
-
-static inline void sbc_analyze_eight_iwmmxt(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       __asm__ volatile (
-               "wldrd        wr0, [%0]\n"
-               "tbcstw       wr15, %2\n"
-               "wldrd        wr1, [%0, #8]\n"
-               "wldrd        wr2, [%0, #16]\n"
-               "wldrd        wr3, [%0, #24]\n"
-               "wldrd        wr4, [%1]\n"
-               "wldrd        wr5, [%1, #8]\n"
-               "wldrd        wr6, [%1, #16]\n"
-               "wldrd        wr7, [%1, #24]\n"
-               "wmadds       wr0, wr0, wr4\n"
-               " wldrd       wr8, [%1, #32]\n"
-               "wmadds       wr1, wr1, wr5\n"
-               " wldrd       wr9, [%1, #40]\n"
-               "wmadds       wr2, wr2, wr6\n"
-               " wldrd      wr10, [%1, #48]\n"
-               "wmadds       wr3, wr3, wr7\n"
-               " wldrd      wr11, [%1, #56]\n"
-               "waddwss      wr0, wr0, wr15\n"
-               " wldrd       wr4, [%0, #32]\n"
-               "waddwss      wr1, wr1, wr15\n"
-               " wldrd       wr5, [%0, #40]\n"
-               "waddwss      wr2, wr2, wr15\n"
-               " wldrd       wr6, [%0, #48]\n"
-               "waddwss      wr3, wr3, wr15\n"
-               " wldrd       wr7, [%0, #56]\n"
-               " wmadds      wr4, wr4, wr8\n"
-               "  wldrd     wr12, [%0, #64]\n"
-               " wmadds      wr5, wr5, wr9\n"
-               "  wldrd     wr13, [%0, #72]\n"
-               " wmadds      wr6, wr6, wr10\n"
-               "  wldrd     wr14, [%0, #80]\n"
-               " wmadds      wr7, wr7, wr11\n"
-               "  wldrd     wr15, [%0, #88]\n"
-               " waddwss     wr0, wr4, wr0\n"
-               "  wldrd      wr8, [%1, #64]\n"
-               " waddwss     wr1, wr5, wr1\n"
-               "  wldrd      wr9, [%1, #72]\n"
-               " waddwss     wr2, wr6, wr2\n"
-               "  wldrd     wr10, [%1, #80]\n"
-               " waddwss     wr3, wr7, wr3\n"
-               "  wldrd     wr11, [%1, #88]\n"
-               "  wmadds    wr12, wr12, wr8\n"
-               "wldrd        wr4, [%0, #96]\n"
-               "  wmadds    wr13, wr13, wr9\n"
-               "wldrd        wr5, [%0, #104]\n"
-               "  wmadds    wr14, wr14, wr10\n"
-               "wldrd        wr6, [%0, #112]\n"
-               "  wmadds    wr15, wr15, wr11\n"
-               "wldrd        wr7, [%0, #120]\n"
-               "  waddwss    wr0, wr12, wr0\n"
-               "wldrd        wr8, [%1, #96]\n"
-               "  waddwss    wr1, wr13, wr1\n"
-               "wldrd        wr9, [%1, #104]\n"
-               "  waddwss    wr2, wr14, wr2\n"
-               "wldrd       wr10, [%1, #112]\n"
-               "  waddwss    wr3, wr15, wr3\n"
-               "wldrd       wr11, [%1, #120]\n"
-               "wmadds       wr4, wr4, wr8\n"
-               " wldrd      wr12, [%0, #128]\n"
-               "wmadds       wr5, wr5, wr9\n"
-               " wldrd      wr13, [%0, #136]\n"
-               "wmadds       wr6, wr6, wr10\n"
-               " wldrd      wr14, [%0, #144]\n"
-               "wmadds       wr7, wr7, wr11\n"
-               " wldrd      wr15, [%0, #152]\n"
-               "waddwss      wr0, wr4, wr0\n"
-               " wldrd       wr8, [%1, #128]\n"
-               "waddwss      wr1, wr5, wr1\n"
-               " wldrd       wr9, [%1, #136]\n"
-               "waddwss      wr2, wr6, wr2\n"
-               " wldrd      wr10, [%1, #144]\n"
-               " waddwss     wr3, wr7, wr3\n"
-               " wldrd     wr11, [%1, #152]\n"
-               " wmadds     wr12, wr12, wr8\n"
-               "tmcr       wcgr0, %4\n"
-               " wmadds     wr13, wr13, wr9\n"
-               " wmadds     wr14, wr14, wr10\n"
-               " wmadds     wr15, wr15, wr11\n"
-               " waddwss     wr0, wr12, wr0\n"
-               " waddwss     wr1, wr13, wr1\n"
-               " waddwss     wr2, wr14, wr2\n"
-               " waddwss     wr3, wr15, wr3\n"
-               "\n"
-               "wsrawg       wr0, wr0, wcgr0\n"
-               "wsrawg       wr1, wr1, wcgr0\n"
-               "wsrawg       wr2, wr2, wcgr0\n"
-               "wsrawg       wr3, wr3, wcgr0\n"
-               "\n"
-               "wpackwss     wr0, wr0, wr0\n"
-               "wpackwss     wr1, wr1, wr1\n"
-               " wldrd       wr4, [%1, #160]\n"
-               "wpackwss     wr2, wr2, wr2\n"
-               " wldrd       wr5, [%1, #168]\n"
-               "wpackwss     wr3, wr3, wr3\n"
-               "  wldrd      wr6, [%1, #192]\n"
-               " wmadds      wr4, wr4, wr0\n"
-               "  wldrd      wr7, [%1, #200]\n"
-               " wmadds      wr5, wr5, wr0\n"
-               "   wldrd     wr8, [%1, #224]\n"
-               "  wmadds     wr6, wr6, wr1\n"
-               "   wldrd     wr9, [%1, #232]\n"
-               "  wmadds     wr7, wr7, wr1\n"
-               "  waddwss    wr4, wr6, wr4\n"
-               "  waddwss    wr5, wr7, wr5\n"
-               "   wmadds    wr8, wr8, wr2\n"
-               "wldrd        wr6, [%1, #256]\n"
-               "   wmadds    wr9, wr9, wr2\n"
-               "wldrd        wr7, [%1, #264]\n"
-               "waddwss      wr4, wr8, wr4\n"
-               "   waddwss   wr5, wr9, wr5\n"
-               "wmadds       wr6, wr6, wr3\n"
-               "wmadds       wr7, wr7, wr3\n"
-               "waddwss      wr4, wr6, wr4\n"
-               "waddwss      wr5, wr7, wr5\n"
-               "\n"
-               "wstrd        wr4, [%3]\n"
-               "wstrd        wr5, [%3, #8]\n"
-               "\n"
-               "wldrd        wr6, [%1, #176]\n"
-               "wldrd        wr5, [%1, #184]\n"
-               "wmadds       wr5, wr5, wr0\n"
-               "wldrd        wr8, [%1, #208]\n"
-               "wmadds       wr0, wr6, wr0\n"
-               "wldrd        wr9, [%1, #216]\n"
-               "wmadds       wr9, wr9, wr1\n"
-               "wldrd        wr6, [%1, #240]\n"
-               "wmadds       wr1, wr8, wr1\n"
-               "wldrd        wr7, [%1, #248]\n"
-               "waddwss      wr0, wr1, wr0\n"
-               "waddwss      wr5, wr9, wr5\n"
-               "wmadds       wr7, wr7, wr2\n"
-               "wldrd        wr8, [%1, #272]\n"
-               "wmadds       wr2, wr6, wr2\n"
-               "wldrd        wr9, [%1, #280]\n"
-               "waddwss      wr0, wr2, wr0\n"
-               "waddwss      wr5, wr7, wr5\n"
-               "wmadds       wr9, wr9, wr3\n"
-               "wmadds       wr3, wr8, wr3\n"
-               "waddwss      wr0, wr3, wr0\n"
-               "waddwss      wr5, wr9, wr5\n"
-               "\n"
-               "wstrd        wr0, [%3, #16]\n"
-               "wstrd        wr5, [%3, #24]\n"
-               :
-               : "r" (in), "r" (consts),
-                       "r" (1 << (SBC_PROTO_FIXED8_SCALE - 1)), "r" (out),
-                       "r" (SBC_PROTO_FIXED8_SCALE)
-               : "wr0", "wr1", "wr2", "wr3", "wr4", "wr5", "wr6", "wr7",
-                 "wr8", "wr9", "wr10", "wr11", "wr12", "wr13", "wr14", "wr15",
-                 "wcgr0", "memory");
-}
-
-static inline void sbc_analyze_4b_4s_iwmmxt(int16_t *x, int32_t *out,
-                                               int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_four_iwmmxt(x + 12, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_iwmmxt(x + 8, out, analysis_consts_fixed4_simd_even);
-       out += out_stride;
-       sbc_analyze_four_iwmmxt(x + 4, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_iwmmxt(x + 0, out, analysis_consts_fixed4_simd_even);
-}
-
-static inline void sbc_analyze_4b_8s_iwmmxt(int16_t *x, int32_t *out,
-                                               int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_eight_iwmmxt(x + 24, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_iwmmxt(x + 16, out, analysis_consts_fixed8_simd_even);
-       out += out_stride;
-       sbc_analyze_eight_iwmmxt(x + 8, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_iwmmxt(x + 0, out, analysis_consts_fixed8_simd_even);
-}
-
-void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *state)
-{
-       state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_iwmmxt;
-       state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_iwmmxt;
-       state->implementation_info = "IWMMXT";
-}
-
-#endif
diff --git a/sbc/sbc_primitives_mmx.c b/sbc/sbc_primitives_mmx.c
deleted file mode 100644 (file)
index 27e9a56..0000000
+++ /dev/null
@@ -1,375 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives_mmx.h"
-
-/*
- * MMX optimizations
- */
-
-#ifdef SBC_BUILD_WITH_MMX_SUPPORT
-
-static inline void sbc_analyze_four_mmx(const int16_t *in, int32_t *out,
-                                       const FIXED_T *consts)
-{
-       static const SBC_ALIGNED int32_t round_c[2] = {
-               1 << (SBC_PROTO_FIXED4_SCALE - 1),
-               1 << (SBC_PROTO_FIXED4_SCALE - 1),
-       };
-       __asm__ volatile (
-               "movq        (%0), %%mm0\n"
-               "movq       8(%0), %%mm1\n"
-               "pmaddwd     (%1), %%mm0\n"
-               "pmaddwd    8(%1), %%mm1\n"
-               "paddd       (%2), %%mm0\n"
-               "paddd       (%2), %%mm1\n"
-               "\n"
-               "movq      16(%0), %%mm2\n"
-               "movq      24(%0), %%mm3\n"
-               "pmaddwd   16(%1), %%mm2\n"
-               "pmaddwd   24(%1), %%mm3\n"
-               "paddd      %%mm2, %%mm0\n"
-               "paddd      %%mm3, %%mm1\n"
-               "\n"
-               "movq      32(%0), %%mm2\n"
-               "movq      40(%0), %%mm3\n"
-               "pmaddwd   32(%1), %%mm2\n"
-               "pmaddwd   40(%1), %%mm3\n"
-               "paddd      %%mm2, %%mm0\n"
-               "paddd      %%mm3, %%mm1\n"
-               "\n"
-               "movq      48(%0), %%mm2\n"
-               "movq      56(%0), %%mm3\n"
-               "pmaddwd   48(%1), %%mm2\n"
-               "pmaddwd   56(%1), %%mm3\n"
-               "paddd      %%mm2, %%mm0\n"
-               "paddd      %%mm3, %%mm1\n"
-               "\n"
-               "movq      64(%0), %%mm2\n"
-               "movq      72(%0), %%mm3\n"
-               "pmaddwd   64(%1), %%mm2\n"
-               "pmaddwd   72(%1), %%mm3\n"
-               "paddd      %%mm2, %%mm0\n"
-               "paddd      %%mm3, %%mm1\n"
-               "\n"
-               "psrad         %4, %%mm0\n"
-               "psrad         %4, %%mm1\n"
-               "packssdw   %%mm0, %%mm0\n"
-               "packssdw   %%mm1, %%mm1\n"
-               "\n"
-               "movq       %%mm0, %%mm2\n"
-               "pmaddwd   80(%1), %%mm0\n"
-               "pmaddwd   88(%1), %%mm2\n"
-               "\n"
-               "movq       %%mm1, %%mm3\n"
-               "pmaddwd   96(%1), %%mm1\n"
-               "pmaddwd  104(%1), %%mm3\n"
-               "paddd      %%mm1, %%mm0\n"
-               "paddd      %%mm3, %%mm2\n"
-               "\n"
-               "movq       %%mm0, (%3)\n"
-               "movq       %%mm2, 8(%3)\n"
-               :
-               : "r" (in), "r" (consts), "r" (&round_c), "r" (out),
-                       "i" (SBC_PROTO_FIXED4_SCALE)
-               : "cc", "memory");
-}
-
-static inline void sbc_analyze_eight_mmx(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       static const SBC_ALIGNED int32_t round_c[2] = {
-               1 << (SBC_PROTO_FIXED8_SCALE - 1),
-               1 << (SBC_PROTO_FIXED8_SCALE - 1),
-       };
-       __asm__ volatile (
-               "movq        (%0), %%mm0\n"
-               "movq       8(%0), %%mm1\n"
-               "movq      16(%0), %%mm2\n"
-               "movq      24(%0), %%mm3\n"
-               "pmaddwd     (%1), %%mm0\n"
-               "pmaddwd    8(%1), %%mm1\n"
-               "pmaddwd   16(%1), %%mm2\n"
-               "pmaddwd   24(%1), %%mm3\n"
-               "paddd       (%2), %%mm0\n"
-               "paddd       (%2), %%mm1\n"
-               "paddd       (%2), %%mm2\n"
-               "paddd       (%2), %%mm3\n"
-               "\n"
-               "movq      32(%0), %%mm4\n"
-               "movq      40(%0), %%mm5\n"
-               "movq      48(%0), %%mm6\n"
-               "movq      56(%0), %%mm7\n"
-               "pmaddwd   32(%1), %%mm4\n"
-               "pmaddwd   40(%1), %%mm5\n"
-               "pmaddwd   48(%1), %%mm6\n"
-               "pmaddwd   56(%1), %%mm7\n"
-               "paddd      %%mm4, %%mm0\n"
-               "paddd      %%mm5, %%mm1\n"
-               "paddd      %%mm6, %%mm2\n"
-               "paddd      %%mm7, %%mm3\n"
-               "\n"
-               "movq      64(%0), %%mm4\n"
-               "movq      72(%0), %%mm5\n"
-               "movq      80(%0), %%mm6\n"
-               "movq      88(%0), %%mm7\n"
-               "pmaddwd   64(%1), %%mm4\n"
-               "pmaddwd   72(%1), %%mm5\n"
-               "pmaddwd   80(%1), %%mm6\n"
-               "pmaddwd   88(%1), %%mm7\n"
-               "paddd      %%mm4, %%mm0\n"
-               "paddd      %%mm5, %%mm1\n"
-               "paddd      %%mm6, %%mm2\n"
-               "paddd      %%mm7, %%mm3\n"
-               "\n"
-               "movq      96(%0), %%mm4\n"
-               "movq     104(%0), %%mm5\n"
-               "movq     112(%0), %%mm6\n"
-               "movq     120(%0), %%mm7\n"
-               "pmaddwd   96(%1), %%mm4\n"
-               "pmaddwd  104(%1), %%mm5\n"
-               "pmaddwd  112(%1), %%mm6\n"
-               "pmaddwd  120(%1), %%mm7\n"
-               "paddd      %%mm4, %%mm0\n"
-               "paddd      %%mm5, %%mm1\n"
-               "paddd      %%mm6, %%mm2\n"
-               "paddd      %%mm7, %%mm3\n"
-               "\n"
-               "movq     128(%0), %%mm4\n"
-               "movq     136(%0), %%mm5\n"
-               "movq     144(%0), %%mm6\n"
-               "movq     152(%0), %%mm7\n"
-               "pmaddwd  128(%1), %%mm4\n"
-               "pmaddwd  136(%1), %%mm5\n"
-               "pmaddwd  144(%1), %%mm6\n"
-               "pmaddwd  152(%1), %%mm7\n"
-               "paddd      %%mm4, %%mm0\n"
-               "paddd      %%mm5, %%mm1\n"
-               "paddd      %%mm6, %%mm2\n"
-               "paddd      %%mm7, %%mm3\n"
-               "\n"
-               "psrad         %4, %%mm0\n"
-               "psrad         %4, %%mm1\n"
-               "psrad         %4, %%mm2\n"
-               "psrad         %4, %%mm3\n"
-               "\n"
-               "packssdw   %%mm0, %%mm0\n"
-               "packssdw   %%mm1, %%mm1\n"
-               "packssdw   %%mm2, %%mm2\n"
-               "packssdw   %%mm3, %%mm3\n"
-               "\n"
-               "movq       %%mm0, %%mm4\n"
-               "movq       %%mm0, %%mm5\n"
-               "pmaddwd  160(%1), %%mm4\n"
-               "pmaddwd  168(%1), %%mm5\n"
-               "\n"
-               "movq       %%mm1, %%mm6\n"
-               "movq       %%mm1, %%mm7\n"
-               "pmaddwd  192(%1), %%mm6\n"
-               "pmaddwd  200(%1), %%mm7\n"
-               "paddd      %%mm6, %%mm4\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm2, %%mm6\n"
-               "movq       %%mm2, %%mm7\n"
-               "pmaddwd  224(%1), %%mm6\n"
-               "pmaddwd  232(%1), %%mm7\n"
-               "paddd      %%mm6, %%mm4\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm3, %%mm6\n"
-               "movq       %%mm3, %%mm7\n"
-               "pmaddwd  256(%1), %%mm6\n"
-               "pmaddwd  264(%1), %%mm7\n"
-               "paddd      %%mm6, %%mm4\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm4, (%3)\n"
-               "movq       %%mm5, 8(%3)\n"
-               "\n"
-               "movq       %%mm0, %%mm5\n"
-               "pmaddwd  176(%1), %%mm0\n"
-               "pmaddwd  184(%1), %%mm5\n"
-               "\n"
-               "movq       %%mm1, %%mm7\n"
-               "pmaddwd  208(%1), %%mm1\n"
-               "pmaddwd  216(%1), %%mm7\n"
-               "paddd      %%mm1, %%mm0\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm2, %%mm7\n"
-               "pmaddwd  240(%1), %%mm2\n"
-               "pmaddwd  248(%1), %%mm7\n"
-               "paddd      %%mm2, %%mm0\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm3, %%mm7\n"
-               "pmaddwd  272(%1), %%mm3\n"
-               "pmaddwd  280(%1), %%mm7\n"
-               "paddd      %%mm3, %%mm0\n"
-               "paddd      %%mm7, %%mm5\n"
-               "\n"
-               "movq       %%mm0, 16(%3)\n"
-               "movq       %%mm5, 24(%3)\n"
-               :
-               : "r" (in), "r" (consts), "r" (&round_c), "r" (out),
-                       "i" (SBC_PROTO_FIXED8_SCALE)
-               : "cc", "memory");
-}
-
-static inline void sbc_analyze_4b_4s_mmx(int16_t *x, int32_t *out,
-                                               int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_four_mmx(x + 12, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_mmx(x + 8, out, analysis_consts_fixed4_simd_even);
-       out += out_stride;
-       sbc_analyze_four_mmx(x + 4, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       sbc_analyze_four_mmx(x + 0, out, analysis_consts_fixed4_simd_even);
-
-       __asm__ volatile ("emms\n");
-}
-
-static inline void sbc_analyze_4b_8s_mmx(int16_t *x, int32_t *out,
-                                               int out_stride)
-{
-       /* Analyze blocks */
-       sbc_analyze_eight_mmx(x + 24, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_mmx(x + 16, out, analysis_consts_fixed8_simd_even);
-       out += out_stride;
-       sbc_analyze_eight_mmx(x + 8, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       sbc_analyze_eight_mmx(x + 0, out, analysis_consts_fixed8_simd_even);
-
-       __asm__ volatile ("emms\n");
-}
-
-static void sbc_calc_scalefactors_mmx(
-       int32_t sb_sample_f[16][2][8],
-       uint32_t scale_factor[2][8],
-       int blocks, int channels, int subbands)
-{
-       static const SBC_ALIGNED int32_t consts[2] = {
-               1 << SCALE_OUT_BITS,
-               1 << SCALE_OUT_BITS,
-       };
-       int ch, sb;
-       intptr_t blk;
-       for (ch = 0; ch < channels; ch++) {
-               for (sb = 0; sb < subbands; sb += 2) {
-                       blk = (blocks - 1) * (((char *) &sb_sample_f[1][0][0] -
-                               (char *) &sb_sample_f[0][0][0]));
-                       __asm__ volatile (
-                               "movq         (%4), %%mm0\n"
-                       "1:\n"
-                               "movq     (%1, %0), %%mm1\n"
-                               "pxor        %%mm2, %%mm2\n"
-                               "pcmpgtd     %%mm2, %%mm1\n"
-                               "paddd    (%1, %0), %%mm1\n"
-                               "pcmpgtd     %%mm1, %%mm2\n"
-                               "pxor        %%mm2, %%mm1\n"
-
-                               "por         %%mm1, %%mm0\n"
-
-                               "sub            %2, %0\n"
-                               "jns            1b\n"
-
-                               "movd        %%mm0, %k0\n"
-                               "psrlq         $32, %%mm0\n"
-                               "bsrl          %k0, %k0\n"
-                               "subl           %5, %k0\n"
-                               "movl          %k0, (%3)\n"
-
-                               "movd        %%mm0, %k0\n"
-                               "bsrl          %k0, %k0\n"
-                               "subl           %5, %k0\n"
-                               "movl          %k0, 4(%3)\n"
-                       : "+r" (blk)
-                       : "r" (&sb_sample_f[0][ch][sb]),
-                               "i" ((char *) &sb_sample_f[1][0][0] -
-                                       (char *) &sb_sample_f[0][0][0]),
-                               "r" (&scale_factor[ch][sb]),
-                               "r" (&consts),
-                               "i" (SCALE_OUT_BITS)
-                       : "cc", "memory");
-               }
-       }
-       __asm__ volatile ("emms\n");
-}
-
-static int check_mmx_support(void)
-{
-#ifdef __amd64__
-       return 1; /* We assume that all 64-bit processors have MMX support */
-#else
-       int cpuid_feature_information;
-       __asm__ volatile (
-               /* According to Intel manual, CPUID instruction is supported
-                * if the value of ID bit (bit 21) in EFLAGS can be modified */
-               "pushf\n"
-               "movl     (%%esp),   %0\n"
-               "xorl     $0x200000, (%%esp)\n" /* try to modify ID bit */
-               "popf\n"
-               "pushf\n"
-               "xorl     (%%esp),   %0\n"      /* check if ID bit changed */
-               "jz       1f\n"
-               "push     %%eax\n"
-               "push     %%ebx\n"
-               "push     %%ecx\n"
-               "mov      $1,        %%eax\n"
-               "cpuid\n"
-               "pop      %%ecx\n"
-               "pop      %%ebx\n"
-               "pop      %%eax\n"
-               "1:\n"
-               "popf\n"
-               : "=d" (cpuid_feature_information)
-               :
-               : "cc");
-    return cpuid_feature_information & (1 << 23);
-#endif
-}
-
-void sbc_init_primitives_mmx(struct sbc_encoder_state *state)
-{
-       if (check_mmx_support()) {
-               state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_mmx;
-               state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_mmx;
-               state->sbc_calc_scalefactors = sbc_calc_scalefactors_mmx;
-               state->implementation_info = "MMX";
-       }
-}
-
-#endif
diff --git a/sbc/sbc_primitives_neon.c b/sbc/sbc_primitives_neon.c
deleted file mode 100644 (file)
index 5d4d0e3..0000000
+++ /dev/null
@@ -1,893 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <stdint.h>
-#include <limits.h>
-#include "sbc.h"
-#include "sbc_math.h"
-#include "sbc_tables.h"
-
-#include "sbc_primitives_neon.h"
-
-/*
- * ARM NEON optimizations
- */
-
-#ifdef SBC_BUILD_WITH_NEON_SUPPORT
-
-static inline void _sbc_analyze_four_neon(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       /* TODO: merge even and odd cases (or even merge all four calls to this
-        * function) in order to have only aligned reads from 'in' array
-        * and reduce number of load instructions */
-       __asm__ volatile (
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmull.s16  q0, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmull.s16  q1, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-
-               "vmlal.s16  q0, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmlal.s16  q1, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q0, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmlal.s16  q1, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-
-               "vmlal.s16  q0, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmlal.s16  q1, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q0, d4, d8\n"
-               "vmlal.s16  q1, d5, d9\n"
-
-               "vpadd.s32  d0, d0, d1\n"
-               "vpadd.s32  d1, d2, d3\n"
-
-               "vrshrn.s32 d0, q0, %3\n"
-
-               "vld1.16    {d2, d3, d4, d5}, [%1, :128]!\n"
-
-               "vdup.i32   d1, d0[1]\n"  /* TODO: can be eliminated */
-               "vdup.i32   d0, d0[0]\n"  /* TODO: can be eliminated */
-
-               "vmull.s16  q3, d2, d0\n"
-               "vmull.s16  q4, d3, d0\n"
-               "vmlal.s16  q3, d4, d1\n"
-               "vmlal.s16  q4, d5, d1\n"
-
-               "vpadd.s32  d0, d6, d7\n" /* TODO: can be eliminated */
-               "vpadd.s32  d1, d8, d9\n" /* TODO: can be eliminated */
-
-               "vst1.32    {d0, d1}, [%2, :128]\n"
-               : "+r" (in), "+r" (consts)
-               : "r" (out),
-                       "i" (SBC_PROTO_FIXED4_SCALE)
-               : "memory",
-                       "d0", "d1", "d2", "d3", "d4", "d5",
-                       "d6", "d7", "d8", "d9", "d10", "d11");
-}
-
-static inline void _sbc_analyze_eight_neon(const int16_t *in, int32_t *out,
-                                                       const FIXED_T *consts)
-{
-       /* TODO: merge even and odd cases (or even merge all four calls to this
-        * function) in order to have only aligned reads from 'in' array
-        * and reduce number of load instructions */
-       __asm__ volatile (
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmull.s16  q6, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmull.s16  q7, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-               "vmull.s16  q8, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmull.s16  q9, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q6, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmlal.s16  q7, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-               "vmlal.s16  q8, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmlal.s16  q9, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q6, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmlal.s16  q7, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-               "vmlal.s16  q8, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmlal.s16  q9, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q6, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmlal.s16  q7, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-               "vmlal.s16  q8, d6, d10\n"
-               "vld1.16    {d4, d5}, [%0, :64]!\n"
-               "vmlal.s16  q9, d7, d11\n"
-               "vld1.16    {d8, d9}, [%1, :128]!\n"
-
-               "vmlal.s16  q6, d4, d8\n"
-               "vld1.16    {d6,  d7}, [%0, :64]!\n"
-               "vmlal.s16  q7, d5, d9\n"
-               "vld1.16    {d10, d11}, [%1, :128]!\n"
-
-               "vmlal.s16  q8, d6, d10\n"
-               "vmlal.s16  q9, d7, d11\n"
-
-               "vpadd.s32  d0, d12, d13\n"
-               "vpadd.s32  d1, d14, d15\n"
-               "vpadd.s32  d2, d16, d17\n"
-               "vpadd.s32  d3, d18, d19\n"
-
-               "vrshr.s32 q0, q0, %3\n"
-               "vrshr.s32 q1, q1, %3\n"
-               "vmovn.s32 d0, q0\n"
-               "vmovn.s32 d1, q1\n"
-
-               "vdup.i32   d3, d1[1]\n"  /* TODO: can be eliminated */
-               "vdup.i32   d2, d1[0]\n"  /* TODO: can be eliminated */
-               "vdup.i32   d1, d0[1]\n"  /* TODO: can be eliminated */
-               "vdup.i32   d0, d0[0]\n"  /* TODO: can be eliminated */
-
-               "vld1.16    {d4, d5}, [%1, :128]!\n"
-               "vmull.s16  q6, d4, d0\n"
-               "vld1.16    {d6, d7}, [%1, :128]!\n"
-               "vmull.s16  q7, d5, d0\n"
-               "vmull.s16  q8, d6, d0\n"
-               "vmull.s16  q9, d7, d0\n"
-
-               "vld1.16    {d4, d5}, [%1, :128]!\n"
-               "vmlal.s16  q6, d4, d1\n"
-               "vld1.16    {d6, d7}, [%1, :128]!\n"
-               "vmlal.s16  q7, d5, d1\n"
-               "vmlal.s16  q8, d6, d1\n"
-               "vmlal.s16  q9, d7, d1\n"
-
-               "vld1.16    {d4, d5}, [%1, :128]!\n"
-               "vmlal.s16  q6, d4, d2\n"
-               "vld1.16    {d6, d7}, [%1, :128]!\n"
-               "vmlal.s16  q7, d5, d2\n"
-               "vmlal.s16  q8, d6, d2\n"
-               "vmlal.s16  q9, d7, d2\n"
-
-               "vld1.16    {d4, d5}, [%1, :128]!\n"
-               "vmlal.s16  q6, d4, d3\n"
-               "vld1.16    {d6, d7}, [%1, :128]!\n"
-               "vmlal.s16  q7, d5, d3\n"
-               "vmlal.s16  q8, d6, d3\n"
-               "vmlal.s16  q9, d7, d3\n"
-
-               "vpadd.s32  d0, d12, d13\n" /* TODO: can be eliminated */
-               "vpadd.s32  d1, d14, d15\n" /* TODO: can be eliminated */
-               "vpadd.s32  d2, d16, d17\n" /* TODO: can be eliminated */
-               "vpadd.s32  d3, d18, d19\n" /* TODO: can be eliminated */
-
-               "vst1.32    {d0, d1, d2, d3}, [%2, :128]\n"
-               : "+r" (in), "+r" (consts)
-               : "r" (out),
-                       "i" (SBC_PROTO_FIXED8_SCALE)
-               : "memory",
-                       "d0", "d1", "d2", "d3", "d4", "d5",
-                       "d6", "d7", "d8", "d9", "d10", "d11",
-                       "d12", "d13", "d14", "d15", "d16", "d17",
-                       "d18", "d19");
-}
-
-static inline void sbc_analyze_4b_4s_neon(int16_t *x,
-                                               int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       _sbc_analyze_four_neon(x + 12, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       _sbc_analyze_four_neon(x + 8, out, analysis_consts_fixed4_simd_even);
-       out += out_stride;
-       _sbc_analyze_four_neon(x + 4, out, analysis_consts_fixed4_simd_odd);
-       out += out_stride;
-       _sbc_analyze_four_neon(x + 0, out, analysis_consts_fixed4_simd_even);
-}
-
-static inline void sbc_analyze_4b_8s_neon(int16_t *x,
-                                               int32_t *out, int out_stride)
-{
-       /* Analyze blocks */
-       _sbc_analyze_eight_neon(x + 24, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       _sbc_analyze_eight_neon(x + 16, out, analysis_consts_fixed8_simd_even);
-       out += out_stride;
-       _sbc_analyze_eight_neon(x + 8, out, analysis_consts_fixed8_simd_odd);
-       out += out_stride;
-       _sbc_analyze_eight_neon(x + 0, out, analysis_consts_fixed8_simd_even);
-}
-
-static void sbc_calc_scalefactors_neon(
-       int32_t sb_sample_f[16][2][8],
-       uint32_t scale_factor[2][8],
-       int blocks, int channels, int subbands)
-{
-       int ch, sb;
-       for (ch = 0; ch < channels; ch++) {
-               for (sb = 0; sb < subbands; sb += 4) {
-                       int blk = blocks;
-                       int32_t *in = &sb_sample_f[0][ch][sb];
-                       __asm__ volatile (
-                               "vmov.s32  q0, #0\n"
-                               "vmov.s32  q1, %[c1]\n"
-                               "vmov.s32  q14, #1\n"
-                               "vmov.s32  q15, %[c2]\n"
-                               "vadd.s32  q1, q1, q14\n"
-                       "1:\n"
-                               "vld1.32   {d16, d17}, [%[in], :128], %[inc]\n"
-                               "vabs.s32  q8,  q8\n"
-                               "vld1.32   {d18, d19}, [%[in], :128], %[inc]\n"
-                               "vabs.s32  q9,  q9\n"
-                               "vld1.32   {d20, d21}, [%[in], :128], %[inc]\n"
-                               "vabs.s32  q10, q10\n"
-                               "vld1.32   {d22, d23}, [%[in], :128], %[inc]\n"
-                               "vabs.s32  q11, q11\n"
-                               "vmax.s32  q0,  q0,  q8\n"
-                               "vmax.s32  q1,  q1,  q9\n"
-                               "vmax.s32  q0,  q0,  q10\n"
-                               "vmax.s32  q1,  q1,  q11\n"
-                               "subs      %[blk], %[blk], #4\n"
-                               "bgt       1b\n"
-                               "vmax.s32  q0,  q0,  q1\n"
-                               "vsub.s32  q0,  q0,  q14\n"
-                               "vclz.s32  q0,  q0\n"
-                               "vsub.s32  q0,  q15, q0\n"
-                               "vst1.32   {d0, d1}, [%[out], :128]\n"
-                       :
-                         [blk]    "+r" (blk),
-                         [in]     "+r" (in)
-                       :
-                         [inc]     "r" ((char *) &sb_sample_f[1][0][0] -
-                                        (char *) &sb_sample_f[0][0][0]),
-                         [out]     "r" (&scale_factor[ch][sb]),
-                         [c1]      "i" (1 << SCALE_OUT_BITS),
-                         [c2]      "i" (31 - SCALE_OUT_BITS)
-                       : "d0", "d1", "d2", "d3", "d16", "d17", "d18", "d19",
-                         "d20", "d21", "d22", "d23", "d24", "d25", "d26",
-                         "d27", "d28", "d29", "d30", "d31", "cc", "memory");
-               }
-       }
-}
-
-int sbc_calc_scalefactors_j_neon(
-       int32_t sb_sample_f[16][2][8],
-       uint32_t scale_factor[2][8],
-       int blocks, int subbands)
-{
-       static SBC_ALIGNED int32_t joint_bits_mask[8] = {
-               8,   4,  2,  1, 128, 64, 32, 16
-       };
-       int joint, i;
-       int32_t  *in0, *in1;
-       int32_t  *in = &sb_sample_f[0][0][0];
-       uint32_t *out0, *out1;
-       uint32_t *out = &scale_factor[0][0];
-       int32_t  *consts = joint_bits_mask;
-
-       i = subbands;
-
-       __asm__ volatile (
-               /*
-                * constants: q13 = (31 - SCALE_OUT_BITS), q14 = 1
-                * input:     q0  = ((1 << SCALE_OUT_BITS) + 1)
-                *            %[in0] - samples for channel 0
-                *            %[in1] - samples for shannel 1
-                * output:    q0, q1 - scale factors without joint stereo
-                *            q2, q3 - scale factors with joint stereo
-                *            q15    - joint stereo selection mask
-                */
-               ".macro calc_scalefactors\n"
-                       "vmov.s32  q1, q0\n"
-                       "vmov.s32  q2, q0\n"
-                       "vmov.s32  q3, q0\n"
-                       "mov       %[i], %[blocks]\n"
-               "1:\n"
-                       "vld1.32   {d18, d19}, [%[in1], :128], %[inc]\n"
-                       "vbic.s32  q11, q9,  q14\n"
-                       "vld1.32   {d16, d17}, [%[in0], :128], %[inc]\n"
-                       "vhadd.s32 q10, q8,  q11\n"
-                       "vhsub.s32 q11, q8,  q11\n"
-                       "vabs.s32  q8,  q8\n"
-                       "vabs.s32  q9,  q9\n"
-                       "vabs.s32  q10, q10\n"
-                       "vabs.s32  q11, q11\n"
-                       "vmax.s32  q0,  q0,  q8\n"
-                       "vmax.s32  q1,  q1,  q9\n"
-                       "vmax.s32  q2,  q2,  q10\n"
-                       "vmax.s32  q3,  q3,  q11\n"
-                       "subs      %[i], %[i], #1\n"
-                       "bgt       1b\n"
-                       "vsub.s32  q0,  q0,  q14\n"
-                       "vsub.s32  q1,  q1,  q14\n"
-                       "vsub.s32  q2,  q2,  q14\n"
-                       "vsub.s32  q3,  q3,  q14\n"
-                       "vclz.s32  q0,  q0\n"
-                       "vclz.s32  q1,  q1\n"
-                       "vclz.s32  q2,  q2\n"
-                       "vclz.s32  q3,  q3\n"
-                       "vsub.s32  q0,  q13, q0\n"
-                       "vsub.s32  q1,  q13, q1\n"
-                       "vsub.s32  q2,  q13, q2\n"
-                       "vsub.s32  q3,  q13, q3\n"
-               ".endm\n"
-               /*
-                * constants: q14 = 1
-                * input: q15    - joint stereo selection mask
-                *        %[in0] - value set by calc_scalefactors macro
-                *        %[in1] - value set by calc_scalefactors macro
-                */
-               ".macro update_joint_stereo_samples\n"
-                       "sub       %[out1], %[in1], %[inc]\n"
-                       "sub       %[out0], %[in0], %[inc]\n"
-                       "sub       %[in1], %[in1], %[inc], asl #1\n"
-                       "sub       %[in0], %[in0], %[inc], asl #1\n"
-                       "vld1.32   {d18, d19}, [%[in1], :128]\n"
-                       "vbic.s32  q11, q9,  q14\n"
-                       "vld1.32   {d16, d17}, [%[in0], :128]\n"
-                       "vld1.32   {d2, d3}, [%[out1], :128]\n"
-                       "vbic.s32  q3,  q1,  q14\n"
-                       "vld1.32   {d0, d1}, [%[out0], :128]\n"
-                       "vhsub.s32 q10, q8,  q11\n"
-                       "vhadd.s32 q11, q8,  q11\n"
-                       "vhsub.s32 q2,  q0,  q3\n"
-                       "vhadd.s32 q3,  q0,  q3\n"
-                       "vbif.s32  q10, q9,  q15\n"
-                       "vbif.s32  d22, d16, d30\n"
-                       "sub       %[inc], %[zero], %[inc], asl #1\n"
-                       "sub       %[i], %[blocks], #2\n"
-               "2:\n"
-                       "vbif.s32  d23, d17, d31\n"
-                       "vst1.32   {d20, d21}, [%[in1], :128], %[inc]\n"
-                       "vbif.s32  d4,  d2,  d30\n"
-                       "vld1.32   {d18, d19}, [%[in1], :128]\n"
-                       "vbif.s32  d5,  d3,  d31\n"
-                       "vst1.32   {d22, d23}, [%[in0], :128], %[inc]\n"
-                       "vbif.s32  d6,  d0,  d30\n"
-                       "vld1.32   {d16, d17}, [%[in0], :128]\n"
-                       "vbif.s32  d7,  d1,  d31\n"
-                       "vst1.32   {d4, d5}, [%[out1], :128], %[inc]\n"
-                       "vbic.s32  q11, q9,  q14\n"
-                       "vld1.32   {d2, d3}, [%[out1], :128]\n"
-                       "vst1.32   {d6, d7}, [%[out0], :128], %[inc]\n"
-                       "vbic.s32  q3,  q1,  q14\n"
-                       "vld1.32   {d0, d1}, [%[out0], :128]\n"
-                       "vhsub.s32 q10, q8,  q11\n"
-                       "vhadd.s32 q11, q8,  q11\n"
-                       "vhsub.s32 q2,  q0,  q3\n"
-                       "vhadd.s32 q3,  q0,  q3\n"
-                       "vbif.s32  q10, q9,  q15\n"
-                       "vbif.s32  d22, d16, d30\n"
-                       "subs      %[i], %[i], #2\n"
-                       "bgt       2b\n"
-                       "sub       %[inc], %[zero], %[inc], asr #1\n"
-                       "vbif.s32  d23, d17, d31\n"
-                       "vst1.32   {d20, d21}, [%[in1], :128]\n"
-                       "vbif.s32  q2,  q1,  q15\n"
-                       "vst1.32   {d22, d23}, [%[in0], :128]\n"
-                       "vbif.s32  q3,  q0,  q15\n"
-                       "vst1.32   {d4, d5}, [%[out1], :128]\n"
-                       "vst1.32   {d6, d7}, [%[out0], :128]\n"
-               ".endm\n"
-
-               "vmov.s32  q14, #1\n"
-               "vmov.s32  q13, %[c2]\n"
-
-               "cmp   %[i], #4\n"
-               "bne   8f\n"
-
-       "4:\n" /* 4 subbands */
-               "add   %[in0], %[in], #0\n"
-               "add   %[in1], %[in], #32\n"
-               "add   %[out0], %[out], #0\n"
-               "add   %[out1], %[out], #32\n"
-               "vmov.s32  q0, %[c1]\n"
-               "vadd.s32  q0, q0, q14\n"
-
-               "calc_scalefactors\n"
-
-               /* check whether to use joint stereo for subbands 0, 1, 2 */
-               "vadd.s32  q15, q0,  q1\n"
-               "vadd.s32  q9,  q2,  q3\n"
-               "vmov.s32  d31[1], %[zero]\n" /* last subband -> no joint */
-               "vld1.32   {d16, d17}, [%[consts], :128]!\n"
-               "vcgt.s32  q15, q15, q9\n"
-
-               /* calculate and save to memory 'joint' variable */
-               /* update and save scale factors to memory */
-               "  vand.s32  q8, q8, q15\n"
-               "vbit.s32  q0,  q2,  q15\n"
-               "  vpadd.s32 d16, d16, d17\n"
-               "vbit.s32  q1,  q3,  q15\n"
-               "  vpadd.s32 d16, d16, d16\n"
-               "vst1.32   {d0, d1}, [%[out0], :128]\n"
-               "vst1.32   {d2, d3}, [%[out1], :128]\n"
-               "  vst1.32   {d16[0]}, [%[joint]]\n"
-
-               "update_joint_stereo_samples\n"
-               "b     9f\n"
-
-       "8:\n" /* 8 subbands */
-               "add   %[in0], %[in], #16\n\n"
-               "add   %[in1], %[in], #48\n"
-               "add   %[out0], %[out], #16\n\n"
-               "add   %[out1], %[out], #48\n"
-               "vmov.s32  q0, %[c1]\n"
-               "vadd.s32  q0, q0, q14\n"
-
-               "calc_scalefactors\n"
-
-               /* check whether to use joint stereo for subbands 4, 5, 6 */
-               "vadd.s32  q15, q0,  q1\n"
-               "vadd.s32  q9,  q2,  q3\n"
-               "vmov.s32  d31[1], %[zero]\n"  /* last subband -> no joint */
-               "vld1.32   {d16, d17}, [%[consts], :128]!\n"
-               "vcgt.s32  q15, q15, q9\n"
-
-               /* calculate part of 'joint' variable and save it to d24 */
-               /* update and save scale factors to memory */
-               "  vand.s32  q8, q8, q15\n"
-               "vbit.s32  q0,  q2,  q15\n"
-               "  vpadd.s32 d16, d16, d17\n"
-               "vbit.s32  q1,  q3,  q15\n"
-               "vst1.32   {d0, d1}, [%[out0], :128]\n"
-               "vst1.32   {d2, d3}, [%[out1], :128]\n"
-               "  vpadd.s32 d24, d16, d16\n"
-
-               "update_joint_stereo_samples\n"
-
-               "add   %[in0], %[in], #0\n"
-               "add   %[in1], %[in], #32\n"
-               "add   %[out0], %[out], #0\n\n"
-               "add   %[out1], %[out], #32\n"
-               "vmov.s32  q0, %[c1]\n"
-               "vadd.s32  q0, q0, q14\n"
-
-               "calc_scalefactors\n"
-
-               /* check whether to use joint stereo for subbands 0, 1, 2, 3 */
-               "vadd.s32  q15, q0,  q1\n"
-               "vadd.s32  q9,  q2,  q3\n"
-               "vld1.32   {d16, d17}, [%[consts], :128]!\n"
-               "vcgt.s32  q15, q15, q9\n"
-
-               /* combine last part of 'joint' with d24 and save to memory */
-               /* update and save scale factors to memory */
-               "  vand.s32  q8, q8, q15\n"
-               "vbit.s32  q0,  q2,  q15\n"
-               "  vpadd.s32 d16, d16, d17\n"
-               "vbit.s32  q1,  q3,  q15\n"
-               "  vpadd.s32 d16, d16, d16\n"
-               "vst1.32   {d0, d1}, [%[out0], :128]\n"
-               "  vadd.s32  d16, d16, d24\n"
-               "vst1.32   {d2, d3}, [%[out1], :128]\n"
-               "  vst1.32   {d16[0]}, [%[joint]]\n"
-
-               "update_joint_stereo_samples\n"
-       "9:\n"
-               ".purgem calc_scalefactors\n"
-               ".purgem update_joint_stereo_samples\n"
-               :
-                 [i]      "+&r" (i),
-                 [in]     "+&r" (in),
-                 [in0]    "=&r" (in0),
-                 [in1]    "=&r" (in1),
-                 [out]    "+&r" (out),
-                 [out0]   "=&r" (out0),
-                 [out1]   "=&r" (out1),
-                 [consts] "+&r" (consts)
-               :
-                 [inc]      "r" ((char *) &sb_sample_f[1][0][0] -
-                                (char *) &sb_sample_f[0][0][0]),
-                 [blocks]   "r" (blocks),
-                 [joint]    "r" (&joint),
-                 [c1]       "i" (1 << SCALE_OUT_BITS),
-                 [c2]       "i" (31 - SCALE_OUT_BITS),
-                 [zero]     "r" (0)
-               : "d0", "d1", "d2", "d3", "d4", "d5", "d6", "d7",
-                 "d16", "d17", "d18", "d19", "d20", "d21", "d22",
-                 "d23", "d24", "d25", "d26", "d27", "d28", "d29",
-                 "d30", "d31", "cc", "memory");
-
-       return joint;
-}
-
-#define PERM_BE(a, b, c, d) {             \
-               (a * 2) + 1, (a * 2) + 0, \
-               (b * 2) + 1, (b * 2) + 0, \
-               (c * 2) + 1, (c * 2) + 0, \
-               (d * 2) + 1, (d * 2) + 0  \
-       }
-#define PERM_LE(a, b, c, d) {             \
-               (a * 2) + 0, (a * 2) + 1, \
-               (b * 2) + 0, (b * 2) + 1, \
-               (c * 2) + 0, (c * 2) + 1, \
-               (d * 2) + 0, (d * 2) + 1  \
-       }
-
-static SBC_ALWAYS_INLINE int sbc_enc_process_input_4s_neon_internal(
-       int position,
-       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-       int nsamples, int nchannels, int big_endian)
-{
-       static SBC_ALIGNED uint8_t perm_be[2][8] = {
-               PERM_BE(7, 3, 6, 4),
-               PERM_BE(0, 2, 1, 5)
-       };
-       static SBC_ALIGNED uint8_t perm_le[2][8] = {
-               PERM_LE(7, 3, 6, 4),
-               PERM_LE(0, 2, 1, 5)
-       };
-       /* handle X buffer wraparound */
-       if (position < nsamples) {
-               int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 40];
-               int16_t *src = &X[0][position];
-               __asm__ volatile (
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0}, [%[src], :64]!\n"
-                       "vst1.16 {d0}, [%[dst], :64]!\n"
-                       :
-                         [dst] "+r" (dst),
-                         [src] "+r" (src)
-                       : : "memory", "d0", "d1", "d2", "d3");
-               if (nchannels > 1) {
-                       dst = &X[1][SBC_X_BUFFER_SIZE - 40];
-                       src = &X[1][position];
-                       __asm__ volatile (
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0}, [%[src], :64]!\n"
-                               "vst1.16 {d0}, [%[dst], :64]!\n"
-                               :
-                                 [dst] "+r" (dst),
-                                 [src] "+r" (src)
-                               : : "memory", "d0", "d1", "d2", "d3");
-               }
-               position = SBC_X_BUFFER_SIZE - 40;
-       }
-
-       if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
-               /* poor 'pcm' alignment */
-               int16_t *x = &X[0][position];
-               int16_t *y = &X[1][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #16\n"
-                       "sub     %[y], %[y], #16\n"
-                       "sub     %[position], %[position], #8\n"
-                       "vld1.8  {d4, d5}, [%[pcm]]!\n"
-                       "vuzp.16 d4,  d5\n"
-                       "vld1.8  {d20, d21}, [%[pcm]]!\n"
-                       "vuzp.16 d20, d21\n"
-                       "vswp    d5,  d20\n"
-                       "vtbl.8  d16, {d4, d5}, d0\n"
-                       "vtbl.8  d17, {d4, d5}, d1\n"
-                       "vtbl.8  d18, {d20, d21}, d0\n"
-                       "vtbl.8  d19, {d20, d21}, d1\n"
-                       "vst1.16 {d16, d17}, [%[x], :128]\n"
-                       "vst1.16 {d18, d19}, [%[y], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #8\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [y]        "+r" (y),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19",
-                         "d20", "d21", "d22", "d23");
-       } else if (nchannels > 1) {
-               /* proper 'pcm' alignment */
-               int16_t *x = &X[0][position];
-               int16_t *y = &X[1][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #16\n"
-                       "sub     %[y], %[y], #16\n"
-                       "sub     %[position], %[position], #8\n"
-                       "vld2.16 {d4, d5}, [%[pcm]]!\n"
-                       "vld2.16 {d20, d21}, [%[pcm]]!\n"
-                       "vswp    d5, d20\n"
-                       "vtbl.8  d16, {d4, d5}, d0\n"
-                       "vtbl.8  d17, {d4, d5}, d1\n"
-                       "vtbl.8  d18, {d20, d21}, d0\n"
-                       "vtbl.8  d19, {d20, d21}, d1\n"
-                       "vst1.16 {d16, d17}, [%[x], :128]\n"
-                       "vst1.16 {d18, d19}, [%[y], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #8\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [y]        "+r" (y),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19",
-                         "d20", "d21", "d22", "d23");
-       } else {
-               int16_t *x = &X[0][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #16\n"
-                       "sub     %[position], %[position], #8\n"
-                       "vld1.8  {d4, d5}, [%[pcm]]!\n"
-                       "vtbl.8  d16, {d4, d5}, d0\n"
-                       "vtbl.8  d17, {d4, d5}, d1\n"
-                       "vst1.16 {d16, d17}, [%[x], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #8\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19");
-       }
-       return position;
-}
-
-static SBC_ALWAYS_INLINE int sbc_enc_process_input_8s_neon_internal(
-       int position,
-       const uint8_t *pcm, int16_t X[2][SBC_X_BUFFER_SIZE],
-       int nsamples, int nchannels, int big_endian)
-{
-       static SBC_ALIGNED uint8_t perm_be[4][8] = {
-               PERM_BE(15, 7, 14, 8),
-               PERM_BE(13, 9, 12, 10),
-               PERM_BE(11, 3, 6,  0),
-               PERM_BE(5,  1, 4,  2)
-       };
-       static SBC_ALIGNED uint8_t perm_le[4][8] = {
-               PERM_LE(15, 7, 14, 8),
-               PERM_LE(13, 9, 12, 10),
-               PERM_LE(11, 3, 6,  0),
-               PERM_LE(5,  1, 4,  2)
-       };
-       /* handle X buffer wraparound */
-       if (position < nsamples) {
-               int16_t *dst = &X[0][SBC_X_BUFFER_SIZE - 72];
-               int16_t *src = &X[0][position];
-               __asm__ volatile (
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                       "vld1.16 {d0, d1}, [%[src], :128]!\n"
-                       "vst1.16 {d0, d1}, [%[dst], :128]!\n"
-                       :
-                         [dst] "+r" (dst),
-                         [src] "+r" (src)
-                       : : "memory", "d0", "d1", "d2", "d3");
-               if (nchannels > 1) {
-                       dst = &X[1][SBC_X_BUFFER_SIZE - 72];
-                       src = &X[1][position];
-                       __asm__ volatile (
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0, d1, d2, d3}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1, d2, d3}, [%[dst], :128]!\n"
-                               "vld1.16 {d0, d1}, [%[src], :128]!\n"
-                               "vst1.16 {d0, d1}, [%[dst], :128]!\n"
-                               :
-                                 [dst] "+r" (dst),
-                                 [src] "+r" (src)
-                               : : "memory", "d0", "d1", "d2", "d3");
-               }
-               position = SBC_X_BUFFER_SIZE - 72;
-       }
-
-       if ((nchannels > 1) && ((uintptr_t)pcm & 1)) {
-               /* poor 'pcm' alignment */
-               int16_t *x = &X[0][position];
-               int16_t *y = &X[1][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #32\n"
-                       "sub     %[y], %[y], #32\n"
-                       "sub     %[position], %[position], #16\n"
-                       "vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
-                       "vuzp.16 q2,  q3\n"
-                       "vld1.8  {d20, d21, d22, d23}, [%[pcm]]!\n"
-                       "vuzp.16 q10, q11\n"
-                       "vswp    q3,  q10\n"
-                       "vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
-                       "vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
-                       "vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
-                       "vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
-                       "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
-                       "vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
-                       "vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
-                       "vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
-                       "vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
-                       "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #16\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [y]        "+r" (y),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19",
-                         "d20", "d21", "d22", "d23");
-       } else if (nchannels > 1) {
-               /* proper 'pcm' alignment */
-               int16_t *x = &X[0][position];
-               int16_t *y = &X[1][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #32\n"
-                       "sub     %[y], %[y], #32\n"
-                       "sub     %[position], %[position], #16\n"
-                       "vld2.16  {d4, d5, d6, d7}, [%[pcm]]!\n"
-                       "vld2.16  {d20, d21, d22, d23}, [%[pcm]]!\n"
-                       "vswp    q3, q10\n"
-                       "vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
-                       "vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
-                       "vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
-                       "vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
-                       "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
-                       "vtbl.8  d16, {d20, d21, d22, d23}, d0\n"
-                       "vtbl.8  d17, {d20, d21, d22, d23}, d1\n"
-                       "vtbl.8  d18, {d20, d21, d22, d23}, d2\n"
-                       "vtbl.8  d19, {d20, d21, d22, d23}, d3\n"
-                       "vst1.16 {d16, d17, d18, d19}, [%[y], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #16\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [y]        "+r" (y),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19",
-                         "d20", "d21", "d22", "d23");
-       } else {
-               int16_t *x = &X[0][position];
-               __asm__ volatile (
-                       "vld1.8  {d0, d1, d2, d3}, [%[perm], :128]\n"
-               "1:\n"
-                       "sub     %[x], %[x], #32\n"
-                       "sub     %[position], %[position], #16\n"
-                       "vld1.8  {d4, d5, d6, d7}, [%[pcm]]!\n"
-                       "vtbl.8  d16, {d4, d5, d6, d7}, d0\n"
-                       "vtbl.8  d17, {d4, d5, d6, d7}, d1\n"
-                       "vtbl.8  d18, {d4, d5, d6, d7}, d2\n"
-                       "vtbl.8  d19, {d4, d5, d6, d7}, d3\n"
-                       "vst1.16 {d16, d17, d18, d19}, [%[x], :128]\n"
-                       "subs    %[nsamples], %[nsamples], #16\n"
-                       "bgt     1b\n"
-                       :
-                         [x]        "+r" (x),
-                         [pcm]      "+r" (pcm),
-                         [nsamples] "+r" (nsamples),
-                         [position] "+r" (position)
-                       :
-                         [perm]      "r" (big_endian ? perm_be : perm_le)
-                       : "cc", "memory", "d0", "d1", "d2", "d3", "d4",
-                         "d5", "d6", "d7", "d16", "d17", "d18", "d19");
-       }
-       return position;
-}
-
-#undef PERM_BE
-#undef PERM_LE
-
-static int sbc_enc_process_input_4s_be_neon(int position, const uint8_t *pcm,
-                                       int16_t X[2][SBC_X_BUFFER_SIZE],
-                                       int nsamples, int nchannels)
-{
-       return sbc_enc_process_input_4s_neon_internal(
-               position, pcm, X, nsamples, nchannels, 1);
-}
-
-static int sbc_enc_process_input_4s_le_neon(int position, const uint8_t *pcm,
-                                       int16_t X[2][SBC_X_BUFFER_SIZE],
-                                       int nsamples, int nchannels)
-{
-       return sbc_enc_process_input_4s_neon_internal(
-               position, pcm, X, nsamples, nchannels, 0);
-}
-
-static int sbc_enc_process_input_8s_be_neon(int position, const uint8_t *pcm,
-                                       int16_t X[2][SBC_X_BUFFER_SIZE],
-                                       int nsamples, int nchannels)
-{
-       return sbc_enc_process_input_8s_neon_internal(
-               position, pcm, X, nsamples, nchannels, 1);
-}
-
-static int sbc_enc_process_input_8s_le_neon(int position, const uint8_t *pcm,
-                                       int16_t X[2][SBC_X_BUFFER_SIZE],
-                                       int nsamples, int nchannels)
-{
-       return sbc_enc_process_input_8s_neon_internal(
-               position, pcm, X, nsamples, nchannels, 0);
-}
-
-void sbc_init_primitives_neon(struct sbc_encoder_state *state)
-{
-       state->sbc_analyze_4b_4s = sbc_analyze_4b_4s_neon;
-       state->sbc_analyze_4b_8s = sbc_analyze_4b_8s_neon;
-       state->sbc_calc_scalefactors = sbc_calc_scalefactors_neon;
-       state->sbc_calc_scalefactors_j = sbc_calc_scalefactors_j_neon;
-       state->sbc_enc_process_input_4s_le = sbc_enc_process_input_4s_le_neon;
-       state->sbc_enc_process_input_4s_be = sbc_enc_process_input_4s_be_neon;
-       state->sbc_enc_process_input_8s_le = sbc_enc_process_input_8s_le_neon;
-       state->sbc_enc_process_input_8s_be = sbc_enc_process_input_8s_be_neon;
-       state->implementation_info = "NEON";
-}
-
-#endif
diff --git a/sbc/sbc_tables.h b/sbc/sbc_tables.h
deleted file mode 100644 (file)
index 25e24e6..0000000
+++ /dev/null
@@ -1,662 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-/* A2DP specification: Appendix B, page 69 */
-static const int sbc_offset4[4][4] = {
-       { -1, 0, 0, 0 },
-       { -2, 0, 0, 1 },
-       { -2, 0, 0, 1 },
-       { -2, 0, 0, 1 }
-};
-
-/* A2DP specification: Appendix B, page 69 */
-static const int sbc_offset8[4][8] = {
-       { -2, 0, 0, 0, 0, 0, 0, 1 },
-       { -3, 0, 0, 0, 0, 0, 1, 2 },
-       { -4, 0, 0, 0, 0, 0, 1, 2 },
-       { -4, 0, 0, 0, 0, 0, 1, 2 }
-};
-
-/* extra bits of precision for the synthesis filter input data */
-#define SBCDEC_FIXED_EXTRA_BITS 2
-
-#define SS4(val) ASR(val, SCALE_SPROTO4_TBL)
-#define SS8(val) ASR(val, SCALE_SPROTO8_TBL)
-#define SN4(val) ASR(val, SCALE_NPROTO4_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
-#define SN8(val) ASR(val, SCALE_NPROTO8_TBL + 1 + SBCDEC_FIXED_EXTRA_BITS)
-
-static const int32_t sbc_proto_4_40m0[] = {
-       SS4(0x00000000), SS4(0xffa6982f), SS4(0xfba93848), SS4(0x0456c7b8),
-       SS4(0x005967d1), SS4(0xfffb9ac7), SS4(0xff589157), SS4(0xf9c2a8d8),
-       SS4(0x027c1434), SS4(0x0019118b), SS4(0xfff3c74c), SS4(0xff137330),
-       SS4(0xf81b8d70), SS4(0x00ec1b8b), SS4(0xfff0b71a), SS4(0xffe99b00),
-       SS4(0xfef84470), SS4(0xf6fb4370), SS4(0xffcdc351), SS4(0xffe01dc7)
-};
-
-static const int32_t sbc_proto_4_40m1[] = {
-       SS4(0xffe090ce), SS4(0xff2c0475), SS4(0xf694f800), SS4(0xff2c0475),
-       SS4(0xffe090ce), SS4(0xffe01dc7), SS4(0xffcdc351), SS4(0xf6fb4370),
-       SS4(0xfef84470), SS4(0xffe99b00), SS4(0xfff0b71a), SS4(0x00ec1b8b),
-       SS4(0xf81b8d70), SS4(0xff137330), SS4(0xfff3c74c), SS4(0x0019118b),
-       SS4(0x027c1434), SS4(0xf9c2a8d8), SS4(0xff589157), SS4(0xfffb9ac7)
-};
-
-static const int32_t sbc_proto_8_80m0[] = {
-       SS8(0x00000000), SS8(0xfe8d1970), SS8(0xee979f00), SS8(0x11686100),
-       SS8(0x0172e690), SS8(0xfff5bd1a), SS8(0xfdf1c8d4), SS8(0xeac182c0),
-       SS8(0x0d9daee0), SS8(0x00e530da), SS8(0xffe9811d), SS8(0xfd52986c),
-       SS8(0xe7054ca0), SS8(0x0a00d410), SS8(0x006c1de4), SS8(0xffdba705),
-       SS8(0xfcbc98e8), SS8(0xe3889d20), SS8(0x06af2308), SS8(0x000bb7db),
-       SS8(0xffca00ed), SS8(0xfc3fbb68), SS8(0xe071bc00), SS8(0x03bf7948),
-       SS8(0xffc4e05c), SS8(0xffb54b3b), SS8(0xfbedadc0), SS8(0xdde26200),
-       SS8(0x0142291c), SS8(0xff960e94), SS8(0xff9f3e17), SS8(0xfbd8f358),
-       SS8(0xdbf79400), SS8(0xff405e01), SS8(0xff7d4914), SS8(0xff8b1a31),
-       SS8(0xfc1417b8), SS8(0xdac7bb40), SS8(0xfdbb828c), SS8(0xff762170)
-};
-
-static const int32_t sbc_proto_8_80m1[] = {
-       SS8(0xff7c272c), SS8(0xfcb02620), SS8(0xda612700), SS8(0xfcb02620),
-       SS8(0xff7c272c), SS8(0xff762170), SS8(0xfdbb828c), SS8(0xdac7bb40),
-       SS8(0xfc1417b8), SS8(0xff8b1a31), SS8(0xff7d4914), SS8(0xff405e01),
-       SS8(0xdbf79400), SS8(0xfbd8f358), SS8(0xff9f3e17), SS8(0xff960e94),
-       SS8(0x0142291c), SS8(0xdde26200), SS8(0xfbedadc0), SS8(0xffb54b3b),
-       SS8(0xffc4e05c), SS8(0x03bf7948), SS8(0xe071bc00), SS8(0xfc3fbb68),
-       SS8(0xffca00ed), SS8(0x000bb7db), SS8(0x06af2308), SS8(0xe3889d20),
-       SS8(0xfcbc98e8), SS8(0xffdba705), SS8(0x006c1de4), SS8(0x0a00d410),
-       SS8(0xe7054ca0), SS8(0xfd52986c), SS8(0xffe9811d), SS8(0x00e530da),
-       SS8(0x0d9daee0), SS8(0xeac182c0), SS8(0xfdf1c8d4), SS8(0xfff5bd1a)
-};
-
-static const int32_t synmatrix4[8][4] = {
-       { SN4(0x05a82798), SN4(0xfa57d868), SN4(0xfa57d868), SN4(0x05a82798) },
-       { SN4(0x030fbc54), SN4(0xf89be510), SN4(0x07641af0), SN4(0xfcf043ac) },
-       { SN4(0x00000000), SN4(0x00000000), SN4(0x00000000), SN4(0x00000000) },
-       { SN4(0xfcf043ac), SN4(0x07641af0), SN4(0xf89be510), SN4(0x030fbc54) },
-       { SN4(0xfa57d868), SN4(0x05a82798), SN4(0x05a82798), SN4(0xfa57d868) },
-       { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) },
-       { SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000), SN4(0xf8000000) },
-       { SN4(0xf89be510), SN4(0xfcf043ac), SN4(0x030fbc54), SN4(0x07641af0) }
-};
-
-static const int32_t synmatrix8[16][8] = {
-       { SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798),
-         SN8(0x05a82798), SN8(0xfa57d868), SN8(0xfa57d868), SN8(0x05a82798) },
-       { SN8(0x0471ced0), SN8(0xf8275a10), SN8(0x018f8b84), SN8(0x06a6d988),
-         SN8(0xf9592678), SN8(0xfe70747c), SN8(0x07d8a5f0), SN8(0xfb8e3130) },
-       { SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac),
-         SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54) },
-       { SN8(0x018f8b84), SN8(0xfb8e3130), SN8(0x06a6d988), SN8(0xf8275a10),
-         SN8(0x07d8a5f0), SN8(0xf9592678), SN8(0x0471ced0), SN8(0xfe70747c) },
-       { SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000),
-         SN8(0x00000000), SN8(0x00000000), SN8(0x00000000), SN8(0x00000000) },
-       { SN8(0xfe70747c), SN8(0x0471ced0), SN8(0xf9592678), SN8(0x07d8a5f0),
-         SN8(0xf8275a10), SN8(0x06a6d988), SN8(0xfb8e3130), SN8(0x018f8b84) },
-       { SN8(0xfcf043ac), SN8(0x07641af0), SN8(0xf89be510), SN8(0x030fbc54),
-         SN8(0x030fbc54), SN8(0xf89be510), SN8(0x07641af0), SN8(0xfcf043ac) },
-       { SN8(0xfb8e3130), SN8(0x07d8a5f0), SN8(0xfe70747c), SN8(0xf9592678),
-         SN8(0x06a6d988), SN8(0x018f8b84), SN8(0xf8275a10), SN8(0x0471ced0) },
-       { SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868),
-         SN8(0xfa57d868), SN8(0x05a82798), SN8(0x05a82798), SN8(0xfa57d868) },
-       { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
-         SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) },
-       { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
-         SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
-       { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
-         SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
-       { SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000),
-         SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000), SN8(0xf8000000) },
-       { SN8(0xf8275a10), SN8(0xf9592678), SN8(0xfb8e3130), SN8(0xfe70747c),
-         SN8(0x018f8b84), SN8(0x0471ced0), SN8(0x06a6d988), SN8(0x07d8a5f0) },
-       { SN8(0xf89be510), SN8(0xfcf043ac), SN8(0x030fbc54), SN8(0x07641af0),
-         SN8(0x07641af0), SN8(0x030fbc54), SN8(0xfcf043ac), SN8(0xf89be510) },
-       { SN8(0xf9592678), SN8(0x018f8b84), SN8(0x07d8a5f0), SN8(0x0471ced0),
-         SN8(0xfb8e3130), SN8(0xf8275a10), SN8(0xfe70747c), SN8(0x06a6d988) }
-};
-
-/* Uncomment the following line to enable high precision build of SBC encoder */
-
-/* #define SBC_HIGH_PRECISION */
-
-#ifdef SBC_HIGH_PRECISION
-#define FIXED_A int64_t /* data type for fixed point accumulator */
-#define FIXED_T int32_t /* data type for fixed point constants */
-#define SBC_FIXED_EXTRA_BITS 16
-#else
-#define FIXED_A int32_t /* data type for fixed point accumulator */
-#define FIXED_T int16_t /* data type for fixed point constants */
-#define SBC_FIXED_EXTRA_BITS 0
-#endif
-
-/* A2DP specification: Section 12.8 Tables
- *
- * Original values are premultiplied by 2 for better precision (that is the
- * maximum which is possible without overflows)
- *
- * Note: in each block of 8 numbers sign was changed for elements 2 and 7
- * in order to compensate the same change applied to cos_table_fixed_4
- */
-#define SBC_PROTO_FIXED4_SCALE \
-       ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
-#define F_PROTO4(x) (FIXED_A) ((x * 2) * \
-       ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
-#define F(x) F_PROTO4(x)
-static const FIXED_T _sbc_proto_fixed4[40] = {
-       F(0.00000000E+00),  F(5.36548976E-04),
-       -F(1.49188357E-03),  F(2.73370904E-03),
-       F(3.83720193E-03),  F(3.89205149E-03),
-       F(1.86581691E-03),  F(3.06012286E-03),
-
-       F(1.09137620E-02),  F(2.04385087E-02),
-       -F(2.88757392E-02),  F(3.21939290E-02),
-       F(2.58767811E-02),  F(6.13245186E-03),
-       -F(2.88217274E-02),  F(7.76463494E-02),
-
-       F(1.35593274E-01),  F(1.94987841E-01),
-       -F(2.46636662E-01),  F(2.81828203E-01),
-       F(2.94315332E-01),  F(2.81828203E-01),
-       F(2.46636662E-01), -F(1.94987841E-01),
-
-       -F(1.35593274E-01), -F(7.76463494E-02),
-       F(2.88217274E-02),  F(6.13245186E-03),
-       F(2.58767811E-02),  F(3.21939290E-02),
-       F(2.88757392E-02), -F(2.04385087E-02),
-
-       -F(1.09137620E-02), -F(3.06012286E-03),
-       -F(1.86581691E-03),  F(3.89205149E-03),
-       F(3.83720193E-03),  F(2.73370904E-03),
-       F(1.49188357E-03), -F(5.36548976E-04),
-};
-#undef F
-
-/*
- * To produce this cosine matrix in Octave:
- *
- * b = zeros(4, 8);
- * for i = 0:3
- * for j = 0:7 b(i+1, j+1) = cos((i + 0.5) * (j - 2) * (pi/4))
- * endfor
- * endfor;
- * printf("%.10f, ", b');
- *
- * Note: in each block of 8 numbers sign was changed for elements 2 and 7
- *
- * Change of sign for element 2 allows to replace constant 1.0 (not
- * representable in Q15 format) with -1.0 (fine with Q15).
- * Changed sign for element 7 allows to have more similar constants
- * and simplify subband filter function code.
- */
-#define SBC_COS_TABLE_FIXED4_SCALE \
-       ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
-#define F_COS4(x) (FIXED_A) ((x) * \
-       ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
-#define F(x) F_COS4(x)
-static const FIXED_T cos_table_fixed_4[32] = {
-       F(0.7071067812),  F(0.9238795325), -F(1.0000000000),  F(0.9238795325),
-       F(0.7071067812),  F(0.3826834324),  F(0.0000000000),  F(0.3826834324),
-
-       -F(0.7071067812),  F(0.3826834324), -F(1.0000000000),  F(0.3826834324),
-       -F(0.7071067812), -F(0.9238795325), -F(0.0000000000), -F(0.9238795325),
-
-       -F(0.7071067812), -F(0.3826834324), -F(1.0000000000), -F(0.3826834324),
-       -F(0.7071067812),  F(0.9238795325),  F(0.0000000000),  F(0.9238795325),
-
-       F(0.7071067812), -F(0.9238795325), -F(1.0000000000), -F(0.9238795325),
-       F(0.7071067812), -F(0.3826834324), -F(0.0000000000), -F(0.3826834324),
-};
-#undef F
-
-/* A2DP specification: Section 12.8 Tables
- *
- * Original values are premultiplied by 4 for better precision (that is the
- * maximum which is possible without overflows)
- *
- * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
- * in order to compensate the same change applied to cos_table_fixed_8
- */
-#define SBC_PROTO_FIXED8_SCALE \
-       ((sizeof(FIXED_T) * CHAR_BIT - 1) - SBC_FIXED_EXTRA_BITS + 1)
-#define F_PROTO8(x) (FIXED_A) ((x * 2) * \
-       ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
-#define F(x) F_PROTO8(x)
-static const FIXED_T _sbc_proto_fixed8[80] = {
-       F(0.00000000E+00),  F(1.56575398E-04),
-       F(3.43256425E-04),  F(5.54620202E-04),
-       -F(8.23919506E-04),  F(1.13992507E-03),
-       F(1.47640169E-03),  F(1.78371725E-03),
-       F(2.01182542E-03),  F(2.10371989E-03),
-       F(1.99454554E-03),  F(1.61656283E-03),
-       F(9.02154502E-04),  F(1.78805361E-04),
-       F(1.64973098E-03),  F(3.49717454E-03),
-
-       F(5.65949473E-03),  F(8.02941163E-03),
-       F(1.04584443E-02),  F(1.27472335E-02),
-       -F(1.46525263E-02),  F(1.59045603E-02),
-       F(1.62208471E-02),  F(1.53184106E-02),
-       F(1.29371806E-02),  F(8.85757540E-03),
-       F(2.92408442E-03), -F(4.91578024E-03),
-       -F(1.46404076E-02),  F(2.61098752E-02),
-       F(3.90751381E-02),  F(5.31873032E-02),
-
-       F(6.79989431E-02),  F(8.29847578E-02),
-       F(9.75753918E-02),  F(1.11196689E-01),
-       -F(1.23264548E-01),  F(1.33264415E-01),
-       F(1.40753505E-01),  F(1.45389847E-01),
-       F(1.46955068E-01),  F(1.45389847E-01),
-       F(1.40753505E-01),  F(1.33264415E-01),
-       F(1.23264548E-01), -F(1.11196689E-01),
-       -F(9.75753918E-02), -F(8.29847578E-02),
-
-       -F(6.79989431E-02), -F(5.31873032E-02),
-       -F(3.90751381E-02), -F(2.61098752E-02),
-       F(1.46404076E-02), -F(4.91578024E-03),
-       F(2.92408442E-03),  F(8.85757540E-03),
-       F(1.29371806E-02),  F(1.53184106E-02),
-       F(1.62208471E-02),  F(1.59045603E-02),
-       F(1.46525263E-02), -F(1.27472335E-02),
-       -F(1.04584443E-02), -F(8.02941163E-03),
-
-       -F(5.65949473E-03), -F(3.49717454E-03),
-       -F(1.64973098E-03), -F(1.78805361E-04),
-       -F(9.02154502E-04),  F(1.61656283E-03),
-       F(1.99454554E-03),  F(2.10371989E-03),
-       F(2.01182542E-03),  F(1.78371725E-03),
-       F(1.47640169E-03),  F(1.13992507E-03),
-       F(8.23919506E-04), -F(5.54620202E-04),
-       -F(3.43256425E-04), -F(1.56575398E-04),
-};
-#undef F
-
-/*
- * To produce this cosine matrix in Octave:
- *
- * b = zeros(8, 16);
- * for i = 0:7
- * for j = 0:15 b(i+1, j+1) = cos((i + 0.5) * (j - 4) * (pi/8))
- * endfor endfor;
- * printf("%.10f, ", b');
- *
- * Note: in each block of 16 numbers sign was changed for elements 4, 13, 14, 15
- *
- * Change of sign for element 4 allows to replace constant 1.0 (not
- * representable in Q15 format) with -1.0 (fine with Q15).
- * Changed signs for elements 13, 14, 15 allow to have more similar constants
- * and simplify subband filter function code.
- */
-#define SBC_COS_TABLE_FIXED8_SCALE \
-       ((sizeof(FIXED_T) * CHAR_BIT - 1) + SBC_FIXED_EXTRA_BITS)
-#define F_COS8(x) (FIXED_A) ((x) * \
-       ((FIXED_A) 1 << (sizeof(FIXED_T) * CHAR_BIT - 1)) + 0.5)
-#define F(x) F_COS8(x)
-static const FIXED_T cos_table_fixed_8[128] = {
-       F(0.7071067812),  F(0.8314696123),  F(0.9238795325),  F(0.9807852804),
-       -F(1.0000000000),  F(0.9807852804),  F(0.9238795325),  F(0.8314696123),
-       F(0.7071067812),  F(0.5555702330),  F(0.3826834324),  F(0.1950903220),
-       F(0.0000000000),  F(0.1950903220),  F(0.3826834324),  F(0.5555702330),
-
-       -F(0.7071067812), -F(0.1950903220),  F(0.3826834324),  F(0.8314696123),
-       -F(1.0000000000),  F(0.8314696123),  F(0.3826834324), -F(0.1950903220),
-       -F(0.7071067812), -F(0.9807852804), -F(0.9238795325), -F(0.5555702330),
-       -F(0.0000000000), -F(0.5555702330), -F(0.9238795325), -F(0.9807852804),
-
-       -F(0.7071067812), -F(0.9807852804), -F(0.3826834324),  F(0.5555702330),
-       -F(1.0000000000),  F(0.5555702330), -F(0.3826834324), -F(0.9807852804),
-       -F(0.7071067812),  F(0.1950903220),  F(0.9238795325),  F(0.8314696123),
-       F(0.0000000000),  F(0.8314696123),  F(0.9238795325),  F(0.1950903220),
-
-       F(0.7071067812), -F(0.5555702330), -F(0.9238795325),  F(0.1950903220),
-       -F(1.0000000000),  F(0.1950903220), -F(0.9238795325), -F(0.5555702330),
-       F(0.7071067812),  F(0.8314696123), -F(0.3826834324), -F(0.9807852804),
-       -F(0.0000000000), -F(0.9807852804), -F(0.3826834324),  F(0.8314696123),
-
-       F(0.7071067812),  F(0.5555702330), -F(0.9238795325), -F(0.1950903220),
-       -F(1.0000000000), -F(0.1950903220), -F(0.9238795325),  F(0.5555702330),
-       F(0.7071067812), -F(0.8314696123), -F(0.3826834324),  F(0.9807852804),
-       F(0.0000000000),  F(0.9807852804), -F(0.3826834324), -F(0.8314696123),
-
-       -F(0.7071067812),  F(0.9807852804), -F(0.3826834324), -F(0.5555702330),
-       -F(1.0000000000), -F(0.5555702330), -F(0.3826834324),  F(0.9807852804),
-       -F(0.7071067812), -F(0.1950903220),  F(0.9238795325), -F(0.8314696123),
-       -F(0.0000000000), -F(0.8314696123),  F(0.9238795325), -F(0.1950903220),
-
-       -F(0.7071067812),  F(0.1950903220),  F(0.3826834324), -F(0.8314696123),
-       -F(1.0000000000), -F(0.8314696123),  F(0.3826834324),  F(0.1950903220),
-       -F(0.7071067812),  F(0.9807852804), -F(0.9238795325),  F(0.5555702330),
-       -F(0.0000000000),  F(0.5555702330), -F(0.9238795325),  F(0.9807852804),
-
-       F(0.7071067812), -F(0.8314696123),  F(0.9238795325), -F(0.9807852804),
-       -F(1.0000000000), -F(0.9807852804),  F(0.9238795325), -F(0.8314696123),
-       F(0.7071067812), -F(0.5555702330),  F(0.3826834324), -F(0.1950903220),
-       -F(0.0000000000), -F(0.1950903220),  F(0.3826834324), -F(0.5555702330),
-};
-#undef F
-
-/*
- * Enforce 16 byte alignment for the data, which is supposed to be used
- * with SIMD optimized code.
- */
-
-#define SBC_ALIGN_BITS 4
-#define SBC_ALIGN_MASK ((1 << (SBC_ALIGN_BITS)) - 1)
-
-#ifdef __GNUC__
-#define SBC_ALIGNED __attribute__((aligned(1 << (SBC_ALIGN_BITS))))
-#else
-#define SBC_ALIGNED
-#endif
-
-/*
- * Constant tables for the use in SIMD optimized analysis filters
- * Each table consists of two parts:
- * 1. reordered "proto" table
- * 2. reordered "cos" table
- *
- * Due to non-symmetrical reordering, separate tables for "even"
- * and "odd" cases are needed
- */
-
-static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_even[40 + 16] = {
-#define C0 1.0932568993
-#define C1 1.3056875580
-#define C2 1.3056875580
-#define C3 1.6772280856
-
-#define F(x) F_PROTO4(x)
-        F(0.00000000E+00 * C0),  F(3.83720193E-03 * C0),
-        F(5.36548976E-04 * C1),  F(2.73370904E-03 * C1),
-        F(3.06012286E-03 * C2),  F(3.89205149E-03 * C2),
-        F(0.00000000E+00 * C3), -F(1.49188357E-03 * C3),
-        F(1.09137620E-02 * C0),  F(2.58767811E-02 * C0),
-        F(2.04385087E-02 * C1),  F(3.21939290E-02 * C1),
-        F(7.76463494E-02 * C2),  F(6.13245186E-03 * C2),
-        F(0.00000000E+00 * C3), -F(2.88757392E-02 * C3),
-        F(1.35593274E-01 * C0),  F(2.94315332E-01 * C0),
-        F(1.94987841E-01 * C1),  F(2.81828203E-01 * C1),
-       -F(1.94987841E-01 * C2),  F(2.81828203E-01 * C2),
-        F(0.00000000E+00 * C3), -F(2.46636662E-01 * C3),
-       -F(1.35593274E-01 * C0),  F(2.58767811E-02 * C0),
-       -F(7.76463494E-02 * C1),  F(6.13245186E-03 * C1),
-       -F(2.04385087E-02 * C2),  F(3.21939290E-02 * C2),
-        F(0.00000000E+00 * C3),  F(2.88217274E-02 * C3),
-       -F(1.09137620E-02 * C0),  F(3.83720193E-03 * C0),
-       -F(3.06012286E-03 * C1),  F(3.89205149E-03 * C1),
-       -F(5.36548976E-04 * C2),  F(2.73370904E-03 * C2),
-        F(0.00000000E+00 * C3), -F(1.86581691E-03 * C3),
-#undef F
-#define F(x) F_COS4(x)
-        F(0.7071067812 / C0),  F(0.9238795325 / C1),
-       -F(0.7071067812 / C0),  F(0.3826834324 / C1),
-       -F(0.7071067812 / C0), -F(0.3826834324 / C1),
-        F(0.7071067812 / C0), -F(0.9238795325 / C1),
-        F(0.3826834324 / C2), -F(1.0000000000 / C3),
-       -F(0.9238795325 / C2), -F(1.0000000000 / C3),
-        F(0.9238795325 / C2), -F(1.0000000000 / C3),
-       -F(0.3826834324 / C2), -F(1.0000000000 / C3),
-#undef F
-
-#undef C0
-#undef C1
-#undef C2
-#undef C3
-};
-
-static const FIXED_T SBC_ALIGNED analysis_consts_fixed4_simd_odd[40 + 16] = {
-#define C0 1.3056875580
-#define C1 1.6772280856
-#define C2 1.0932568993
-#define C3 1.3056875580
-
-#define F(x) F_PROTO4(x)
-        F(2.73370904E-03 * C0),  F(5.36548976E-04 * C0),
-       -F(1.49188357E-03 * C1),  F(0.00000000E+00 * C1),
-        F(3.83720193E-03 * C2),  F(1.09137620E-02 * C2),
-        F(3.89205149E-03 * C3),  F(3.06012286E-03 * C3),
-        F(3.21939290E-02 * C0),  F(2.04385087E-02 * C0),
-       -F(2.88757392E-02 * C1),  F(0.00000000E+00 * C1),
-        F(2.58767811E-02 * C2),  F(1.35593274E-01 * C2),
-        F(6.13245186E-03 * C3),  F(7.76463494E-02 * C3),
-        F(2.81828203E-01 * C0),  F(1.94987841E-01 * C0),
-       -F(2.46636662E-01 * C1),  F(0.00000000E+00 * C1),
-        F(2.94315332E-01 * C2), -F(1.35593274E-01 * C2),
-        F(2.81828203E-01 * C3), -F(1.94987841E-01 * C3),
-        F(6.13245186E-03 * C0), -F(7.76463494E-02 * C0),
-        F(2.88217274E-02 * C1),  F(0.00000000E+00 * C1),
-        F(2.58767811E-02 * C2), -F(1.09137620E-02 * C2),
-        F(3.21939290E-02 * C3), -F(2.04385087E-02 * C3),
-        F(3.89205149E-03 * C0), -F(3.06012286E-03 * C0),
-       -F(1.86581691E-03 * C1),  F(0.00000000E+00 * C1),
-        F(3.83720193E-03 * C2),  F(0.00000000E+00 * C2),
-        F(2.73370904E-03 * C3), -F(5.36548976E-04 * C3),
-#undef F
-#define F(x) F_COS4(x)
-        F(0.9238795325 / C0), -F(1.0000000000 / C1),
-        F(0.3826834324 / C0), -F(1.0000000000 / C1),
-       -F(0.3826834324 / C0), -F(1.0000000000 / C1),
-       -F(0.9238795325 / C0), -F(1.0000000000 / C1),
-        F(0.7071067812 / C2),  F(0.3826834324 / C3),
-       -F(0.7071067812 / C2), -F(0.9238795325 / C3),
-       -F(0.7071067812 / C2),  F(0.9238795325 / C3),
-        F(0.7071067812 / C2), -F(0.3826834324 / C3),
-#undef F
-
-#undef C0
-#undef C1
-#undef C2
-#undef C3
-};
-
-static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_even[80 + 64] = {
-#define C0 2.7906148894
-#define C1 2.4270044280
-#define C2 2.8015616024
-#define C3 3.1710363741
-#define C4 2.5377944043
-#define C5 2.4270044280
-#define C6 2.8015616024
-#define C7 3.1710363741
-
-#define F(x) F_PROTO8(x)
-        F(0.00000000E+00 * C0),  F(2.01182542E-03 * C0),
-        F(1.56575398E-04 * C1),  F(1.78371725E-03 * C1),
-        F(3.43256425E-04 * C2),  F(1.47640169E-03 * C2),
-        F(5.54620202E-04 * C3),  F(1.13992507E-03 * C3),
-       -F(8.23919506E-04 * C4),  F(0.00000000E+00 * C4),
-        F(2.10371989E-03 * C5),  F(3.49717454E-03 * C5),
-        F(1.99454554E-03 * C6),  F(1.64973098E-03 * C6),
-        F(1.61656283E-03 * C7),  F(1.78805361E-04 * C7),
-        F(5.65949473E-03 * C0),  F(1.29371806E-02 * C0),
-        F(8.02941163E-03 * C1),  F(1.53184106E-02 * C1),
-        F(1.04584443E-02 * C2),  F(1.62208471E-02 * C2),
-        F(1.27472335E-02 * C3),  F(1.59045603E-02 * C3),
-       -F(1.46525263E-02 * C4),  F(0.00000000E+00 * C4),
-        F(8.85757540E-03 * C5),  F(5.31873032E-02 * C5),
-        F(2.92408442E-03 * C6),  F(3.90751381E-02 * C6),
-       -F(4.91578024E-03 * C7),  F(2.61098752E-02 * C7),
-        F(6.79989431E-02 * C0),  F(1.46955068E-01 * C0),
-        F(8.29847578E-02 * C1),  F(1.45389847E-01 * C1),
-        F(9.75753918E-02 * C2),  F(1.40753505E-01 * C2),
-        F(1.11196689E-01 * C3),  F(1.33264415E-01 * C3),
-       -F(1.23264548E-01 * C4),  F(0.00000000E+00 * C4),
-        F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
-        F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
-        F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
-       -F(6.79989431E-02 * C0),  F(1.29371806E-02 * C0),
-       -F(5.31873032E-02 * C1),  F(8.85757540E-03 * C1),
-       -F(3.90751381E-02 * C2),  F(2.92408442E-03 * C2),
-       -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
-        F(1.46404076E-02 * C4),  F(0.00000000E+00 * C4),
-        F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
-        F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
-        F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
-       -F(5.65949473E-03 * C0),  F(2.01182542E-03 * C0),
-       -F(3.49717454E-03 * C1),  F(2.10371989E-03 * C1),
-       -F(1.64973098E-03 * C2),  F(1.99454554E-03 * C2),
-       -F(1.78805361E-04 * C3),  F(1.61656283E-03 * C3),
-       -F(9.02154502E-04 * C4),  F(0.00000000E+00 * C4),
-        F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
-        F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
-        F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
-#undef F
-#define F(x) F_COS8(x)
-        F(0.7071067812 / C0),  F(0.8314696123 / C1),
-       -F(0.7071067812 / C0), -F(0.1950903220 / C1),
-       -F(0.7071067812 / C0), -F(0.9807852804 / C1),
-        F(0.7071067812 / C0), -F(0.5555702330 / C1),
-        F(0.7071067812 / C0),  F(0.5555702330 / C1),
-       -F(0.7071067812 / C0),  F(0.9807852804 / C1),
-       -F(0.7071067812 / C0),  F(0.1950903220 / C1),
-        F(0.7071067812 / C0), -F(0.8314696123 / C1),
-        F(0.9238795325 / C2),  F(0.9807852804 / C3),
-        F(0.3826834324 / C2),  F(0.8314696123 / C3),
-       -F(0.3826834324 / C2),  F(0.5555702330 / C3),
-       -F(0.9238795325 / C2),  F(0.1950903220 / C3),
-       -F(0.9238795325 / C2), -F(0.1950903220 / C3),
-       -F(0.3826834324 / C2), -F(0.5555702330 / C3),
-        F(0.3826834324 / C2), -F(0.8314696123 / C3),
-        F(0.9238795325 / C2), -F(0.9807852804 / C3),
-       -F(1.0000000000 / C4),  F(0.5555702330 / C5),
-       -F(1.0000000000 / C4), -F(0.9807852804 / C5),
-       -F(1.0000000000 / C4),  F(0.1950903220 / C5),
-       -F(1.0000000000 / C4),  F(0.8314696123 / C5),
-       -F(1.0000000000 / C4), -F(0.8314696123 / C5),
-       -F(1.0000000000 / C4), -F(0.1950903220 / C5),
-       -F(1.0000000000 / C4),  F(0.9807852804 / C5),
-       -F(1.0000000000 / C4), -F(0.5555702330 / C5),
-        F(0.3826834324 / C6),  F(0.1950903220 / C7),
-       -F(0.9238795325 / C6), -F(0.5555702330 / C7),
-        F(0.9238795325 / C6),  F(0.8314696123 / C7),
-       -F(0.3826834324 / C6), -F(0.9807852804 / C7),
-       -F(0.3826834324 / C6),  F(0.9807852804 / C7),
-        F(0.9238795325 / C6), -F(0.8314696123 / C7),
-       -F(0.9238795325 / C6),  F(0.5555702330 / C7),
-        F(0.3826834324 / C6), -F(0.1950903220 / C7),
-#undef F
-
-#undef C0
-#undef C1
-#undef C2
-#undef C3
-#undef C4
-#undef C5
-#undef C6
-#undef C7
-};
-
-static const FIXED_T SBC_ALIGNED analysis_consts_fixed8_simd_odd[80 + 64] = {
-#define C0 2.5377944043
-#define C1 2.4270044280
-#define C2 2.8015616024
-#define C3 3.1710363741
-#define C4 2.7906148894
-#define C5 2.4270044280
-#define C6 2.8015616024
-#define C7 3.1710363741
-
-#define F(x) F_PROTO8(x)
-        F(0.00000000E+00 * C0), -F(8.23919506E-04 * C0),
-        F(1.56575398E-04 * C1),  F(1.78371725E-03 * C1),
-        F(3.43256425E-04 * C2),  F(1.47640169E-03 * C2),
-        F(5.54620202E-04 * C3),  F(1.13992507E-03 * C3),
-        F(2.01182542E-03 * C4),  F(5.65949473E-03 * C4),
-        F(2.10371989E-03 * C5),  F(3.49717454E-03 * C5),
-        F(1.99454554E-03 * C6),  F(1.64973098E-03 * C6),
-        F(1.61656283E-03 * C7),  F(1.78805361E-04 * C7),
-        F(0.00000000E+00 * C0), -F(1.46525263E-02 * C0),
-        F(8.02941163E-03 * C1),  F(1.53184106E-02 * C1),
-        F(1.04584443E-02 * C2),  F(1.62208471E-02 * C2),
-        F(1.27472335E-02 * C3),  F(1.59045603E-02 * C3),
-        F(1.29371806E-02 * C4),  F(6.79989431E-02 * C4),
-        F(8.85757540E-03 * C5),  F(5.31873032E-02 * C5),
-        F(2.92408442E-03 * C6),  F(3.90751381E-02 * C6),
-       -F(4.91578024E-03 * C7),  F(2.61098752E-02 * C7),
-        F(0.00000000E+00 * C0), -F(1.23264548E-01 * C0),
-        F(8.29847578E-02 * C1),  F(1.45389847E-01 * C1),
-        F(9.75753918E-02 * C2),  F(1.40753505E-01 * C2),
-        F(1.11196689E-01 * C3),  F(1.33264415E-01 * C3),
-        F(1.46955068E-01 * C4), -F(6.79989431E-02 * C4),
-        F(1.45389847E-01 * C5), -F(8.29847578E-02 * C5),
-        F(1.40753505E-01 * C6), -F(9.75753918E-02 * C6),
-        F(1.33264415E-01 * C7), -F(1.11196689E-01 * C7),
-        F(0.00000000E+00 * C0),  F(1.46404076E-02 * C0),
-       -F(5.31873032E-02 * C1),  F(8.85757540E-03 * C1),
-       -F(3.90751381E-02 * C2),  F(2.92408442E-03 * C2),
-       -F(2.61098752E-02 * C3), -F(4.91578024E-03 * C3),
-        F(1.29371806E-02 * C4), -F(5.65949473E-03 * C4),
-        F(1.53184106E-02 * C5), -F(8.02941163E-03 * C5),
-        F(1.62208471E-02 * C6), -F(1.04584443E-02 * C6),
-        F(1.59045603E-02 * C7), -F(1.27472335E-02 * C7),
-        F(0.00000000E+00 * C0), -F(9.02154502E-04 * C0),
-       -F(3.49717454E-03 * C1),  F(2.10371989E-03 * C1),
-       -F(1.64973098E-03 * C2),  F(1.99454554E-03 * C2),
-       -F(1.78805361E-04 * C3),  F(1.61656283E-03 * C3),
-        F(2.01182542E-03 * C4),  F(0.00000000E+00 * C4),
-        F(1.78371725E-03 * C5), -F(1.56575398E-04 * C5),
-        F(1.47640169E-03 * C6), -F(3.43256425E-04 * C6),
-        F(1.13992507E-03 * C7), -F(5.54620202E-04 * C7),
-#undef F
-#define F(x) F_COS8(x)
-       -F(1.0000000000 / C0),  F(0.8314696123 / C1),
-       -F(1.0000000000 / C0), -F(0.1950903220 / C1),
-       -F(1.0000000000 / C0), -F(0.9807852804 / C1),
-       -F(1.0000000000 / C0), -F(0.5555702330 / C1),
-       -F(1.0000000000 / C0),  F(0.5555702330 / C1),
-       -F(1.0000000000 / C0),  F(0.9807852804 / C1),
-       -F(1.0000000000 / C0),  F(0.1950903220 / C1),
-       -F(1.0000000000 / C0), -F(0.8314696123 / C1),
-        F(0.9238795325 / C2),  F(0.9807852804 / C3),
-        F(0.3826834324 / C2),  F(0.8314696123 / C3),
-       -F(0.3826834324 / C2),  F(0.5555702330 / C3),
-       -F(0.9238795325 / C2),  F(0.1950903220 / C3),
-       -F(0.9238795325 / C2), -F(0.1950903220 / C3),
-       -F(0.3826834324 / C2), -F(0.5555702330 / C3),
-        F(0.3826834324 / C2), -F(0.8314696123 / C3),
-        F(0.9238795325 / C2), -F(0.9807852804 / C3),
-        F(0.7071067812 / C4),  F(0.5555702330 / C5),
-       -F(0.7071067812 / C4), -F(0.9807852804 / C5),
-       -F(0.7071067812 / C4),  F(0.1950903220 / C5),
-        F(0.7071067812 / C4),  F(0.8314696123 / C5),
-        F(0.7071067812 / C4), -F(0.8314696123 / C5),
-       -F(0.7071067812 / C4), -F(0.1950903220 / C5),
-       -F(0.7071067812 / C4),  F(0.9807852804 / C5),
-        F(0.7071067812 / C4), -F(0.5555702330 / C5),
-        F(0.3826834324 / C6),  F(0.1950903220 / C7),
-       -F(0.9238795325 / C6), -F(0.5555702330 / C7),
-        F(0.9238795325 / C6),  F(0.8314696123 / C7),
-       -F(0.3826834324 / C6), -F(0.9807852804 / C7),
-       -F(0.3826834324 / C6),  F(0.9807852804 / C7),
-        F(0.9238795325 / C6), -F(0.8314696123 / C7),
-       -F(0.9238795325 / C6),  F(0.5555702330 / C7),
-        F(0.3826834324 / C6), -F(0.1950903220 / C7),
-#undef F
-
-#undef C0
-#undef C1
-#undef C2
-#undef C3
-#undef C4
-#undef C5
-#undef C6
-#undef C7
-};
diff --git a/sbc/sbcdec.c b/sbc/sbcdec.c
deleted file mode 100644 (file)
index 7008e88..0000000
+++ /dev/null
@@ -1,293 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) decoder
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  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 <getopt.h>
-#include <sys/stat.h>
-#include <sys/ioctl.h>
-#include <sys/soundcard.h>
-
-#include "sbc.h"
-#include "formats.h"
-
-#define BUF_SIZE 8192
-
-static int verbose = 0;
-
-static void decode(char *filename, char *output, int tofile)
-{
-       unsigned char buf[BUF_SIZE], *stream;
-       struct stat st;
-       sbc_t sbc;
-       int fd, ad, pos, streamlen, framelen, count;
-       size_t len;
-       int format = AFMT_S16_BE, frequency, channels;
-       ssize_t written;
-
-       if (stat(filename, &st) < 0) {
-               fprintf(stderr, "Can't get size of file %s: %s\n",
-                                               filename, strerror(errno));
-               return;
-       }
-
-       stream = malloc(st.st_size);
-
-       if (!stream) {
-               fprintf(stderr, "Can't allocate memory for %s: %s\n",
-                                               filename, strerror(errno));
-               return;
-       }
-
-       fd = open(filename, O_RDONLY);
-       if (fd < 0) {
-               fprintf(stderr, "Can't open file %s: %s\n",
-                                               filename, strerror(errno));
-               goto free;
-       }
-
-       if (read(fd, stream, st.st_size) != st.st_size) {
-               fprintf(stderr, "Can't read content of %s: %s\n",
-                                               filename, strerror(errno));
-               close(fd);
-               goto free;
-       }
-
-       close(fd);
-
-       pos = 0;
-       streamlen = st.st_size;
-
-       if (tofile)
-               ad = open(output, O_WRONLY | O_CREAT | O_TRUNC, 0644);
-       else
-               ad = open(output, O_WRONLY, 0);
-
-       if (ad < 0) {
-               fprintf(stderr, "Can't open output %s: %s\n",
-                                               output, strerror(errno));
-               goto free;
-       }
-
-       sbc_init(&sbc, 0L);
-       sbc.endian = SBC_BE;
-
-       framelen = sbc_decode(&sbc, stream, streamlen, buf, sizeof(buf), &len);
-       channels = sbc.mode == SBC_MODE_MONO ? 1 : 2;
-       switch (sbc.frequency) {
-       case SBC_FREQ_16000:
-               frequency = 16000;
-               break;
-
-       case SBC_FREQ_32000:
-               frequency = 32000;
-               break;
-
-       case SBC_FREQ_44100:
-               frequency = 44100;
-               break;
-
-       case SBC_FREQ_48000:
-               frequency = 48000;
-               break;
-       default:
-               frequency = 0;
-       }
-
-       if (verbose) {
-               fprintf(stderr,"decoding %s with rate %d, %d subbands, "
-                       "%d bits, allocation method %s and mode %s\n",
-                       filename, frequency, sbc.subbands * 4 + 4, sbc.bitpool,
-                       sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS",
-                       sbc.mode == SBC_MODE_MONO ? "MONO" :
-                                       sbc.mode == SBC_MODE_STEREO ?
-                                               "STEREO" : "JOINTSTEREO");
-       }
-
-       if (tofile) {
-               struct au_header au_hdr;
-
-               au_hdr.magic       = AU_MAGIC;
-               au_hdr.hdr_size    = BE_INT(24);
-               au_hdr.data_size   = BE_INT(0);
-               au_hdr.encoding    = BE_INT(AU_FMT_LIN16);
-               au_hdr.sample_rate = BE_INT(frequency);
-               au_hdr.channels    = BE_INT(channels);
-
-               written = write(ad, &au_hdr, sizeof(au_hdr));
-               if (written < (ssize_t) sizeof(au_hdr)) {
-                       fprintf(stderr, "Failed to write header\n");
-                       goto close;
-               }
-       } else {
-               if (ioctl(ad, SNDCTL_DSP_SETFMT, &format) < 0) {
-                       fprintf(stderr, "Can't set audio format on %s: %s\n",
-                                               output, strerror(errno));
-                       goto close;
-               }
-
-               if (ioctl(ad, SNDCTL_DSP_CHANNELS, &channels) < 0) {
-                       fprintf(stderr, "Can't set number of channels on %s: %s\n",
-                                               output, strerror(errno));
-                       goto close;
-               }
-
-               if (ioctl(ad, SNDCTL_DSP_SPEED, &frequency) < 0) {
-                       fprintf(stderr, "Can't set audio rate on %s: %s\n",
-                                               output, strerror(errno));
-                       goto close;
-               }
-       }
-
-       count = len;
-
-       while (framelen > 0) {
-               /* we have completed an sbc_decode at this point sbc.len is the
-                * length of the frame we just decoded count is the number of
-                * decoded bytes yet to be written */
-
-               if (count + len >= BUF_SIZE) {
-                       /* buffer is too full to stuff decoded audio in so it
-                        * must be written to the device */
-                       written = write(ad, buf, count);
-                       if (written > 0)
-                               count -= written;
-               }
-
-               /* sanity check */
-               if (count + len >= BUF_SIZE) {
-                       fprintf(stderr,
-                               "buffer size of %d is too small for decoded"
-                               " data (%lu)\n", BUF_SIZE, (unsigned long) (len + count));
-                       exit(1);
-               }
-
-               /* push the pointer in the file forward to the next bit to be
-                * decoded tell the decoder to decode up to the remaining
-                * length of the file (!) */
-               pos += framelen;
-               framelen = sbc_decode(&sbc, stream + pos, streamlen - pos,
-                                       buf + count, sizeof(buf) - count, &len);
-
-               /* increase the count */
-               count += len;
-       }
-
-       if (count > 0) {
-               written = write(ad, buf, count);
-               if (written > 0)
-                       count -= written;
-       }
-
-close:
-       sbc_finish(&sbc);
-
-       close(ad);
-
-free:
-       free(stream);
-}
-
-static void usage(void)
-{
-       printf("SBC decoder utility ver %s\n", VERSION);
-       printf("Copyright (c) 2004-2010  Marcel Holtmann\n\n");
-
-       printf("Usage:\n"
-               "\tsbcdec [options] file(s)\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-h, --help           Display help\n"
-               "\t-v, --verbose        Verbose mode\n"
-               "\t-d, --device <dsp>   Sound device\n"
-               "\t-f, --file <file>    Decode to a file\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "device",     1, 0, 'd' },
-       { "verbose",    0, 0, 'v' },
-       { "file",       1, 0, 'f' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       char *output = NULL;
-       int i, opt, tofile = 0;
-
-       while ((opt = getopt_long(argc, argv, "+hvd:f:",
-                                               main_options, NULL)) != -1) {
-               switch(opt) {
-               case 'h':
-                       usage();
-                       exit(0);
-
-               case 'v':
-                       verbose = 1;
-                       break;
-
-               case 'd':
-                       free(output);
-                       output = strdup(optarg);
-                       tofile = 0;
-                       break;
-
-               case 'f' :
-                       free(output);
-                       output = strdup(optarg);
-                       tofile = 1;
-                       break;
-
-               default:
-                       exit(1);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       for (i = 0; i < argc; i++)
-               decode(argv[i], output ? output : "/dev/dsp", tofile);
-
-       free(output);
-
-       return 0;
-}
diff --git a/sbc/sbcenc.c b/sbc/sbcenc.c
deleted file mode 100644 (file)
index 3d3a7dc..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) encoder
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  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 <stdint.h>
-#include <string.h>
-#include <getopt.h>
-#include <sys/stat.h>
-
-#include "sbc.h"
-#include "formats.h"
-
-static int verbose = 0;
-
-#define BUF_SIZE 32768
-static unsigned char input[BUF_SIZE], output[BUF_SIZE + BUF_SIZE / 4];
-
-static void encode(char *filename, int subbands, int bitpool, int joint,
-                                       int dualchannel, int snr, int blocks)
-{
-       struct au_header au_hdr;
-       sbc_t sbc;
-       int fd, size, srate, codesize, nframes;
-       ssize_t encoded;
-       ssize_t len;
-
-       if (sizeof(au_hdr) != 24) {
-               /* Sanity check just in case */
-               fprintf(stderr, "FIXME: sizeof(au_hdr) != 24\n");
-               return;
-       }
-
-       if (strcmp(filename, "-")) {
-               fd = open(filename, O_RDONLY);
-               if (fd < 0) {
-                       fprintf(stderr, "Can't open file %s: %s\n",
-                                               filename, strerror(errno));
-                       return;
-               }
-       } else
-               fd = fileno(stdin);
-
-       len = read(fd, &au_hdr, sizeof(au_hdr));
-       if (len < (ssize_t) sizeof(au_hdr)) {
-               if (fd > fileno(stderr))
-                       fprintf(stderr, "Can't read header from file %s: %s\n",
-                                               filename, strerror(errno));
-               else
-                       perror("Can't read audio header");
-               goto done;
-       }
-
-       if (au_hdr.magic != AU_MAGIC ||
-                       BE_INT(au_hdr.hdr_size) > 128 ||
-                       BE_INT(au_hdr.hdr_size) < sizeof(au_hdr) ||
-                       BE_INT(au_hdr.encoding) != AU_FMT_LIN16) {
-               fprintf(stderr, "Not in Sun/NeXT audio S16_BE format\n");
-               goto done;
-       }
-
-       sbc_init(&sbc, 0L);
-
-       switch (BE_INT(au_hdr.sample_rate)) {
-       case 16000:
-               sbc.frequency = SBC_FREQ_16000;
-               break;
-       case 32000:
-               sbc.frequency = SBC_FREQ_32000;
-               break;
-       case 44100:
-               sbc.frequency = SBC_FREQ_44100;
-               break;
-       case 48000:
-               sbc.frequency = SBC_FREQ_48000;
-               break;
-       }
-
-       srate = BE_INT(au_hdr.sample_rate);
-
-       sbc.subbands = subbands == 4 ? SBC_SB_4 : SBC_SB_8;
-
-       if (BE_INT(au_hdr.channels) == 1) {
-               sbc.mode = SBC_MODE_MONO;
-               if (joint || dualchannel) {
-                       fprintf(stderr, "Audio is mono but joint or "
-                               "dualchannel mode has been specified\n");
-                       goto done;
-               }
-       } else if (joint && !dualchannel)
-               sbc.mode = SBC_MODE_JOINT_STEREO;
-       else if (!joint && dualchannel)
-               sbc.mode = SBC_MODE_DUAL_CHANNEL;
-       else if (!joint && !dualchannel)
-               sbc.mode = SBC_MODE_STEREO;
-       else {
-               fprintf(stderr, "Both joint and dualchannel mode have been "
-                                                               "specified\n");
-               goto done;
-       }
-
-       sbc.endian = SBC_BE;
-       /* Skip extra bytes of the header if any */
-       if (read(fd, input, BE_INT(au_hdr.hdr_size) - len) < 0)
-               goto done;
-
-       sbc.bitpool = bitpool;
-       sbc.allocation = snr ? SBC_AM_SNR : SBC_AM_LOUDNESS;
-       sbc.blocks = blocks == 4 ? SBC_BLK_4 :
-                       blocks == 8 ? SBC_BLK_8 :
-                               blocks == 12 ? SBC_BLK_12 : SBC_BLK_16;
-
-       if (verbose) {
-               fprintf(stderr, "encoding %s with rate %d, %d blocks, "
-                       "%d subbands, %d bits, allocation method %s, "
-                                                       "and mode %s\n",
-                       filename, srate, blocks, subbands, bitpool,
-                       sbc.allocation == SBC_AM_SNR ? "SNR" : "LOUDNESS",
-                       sbc.mode == SBC_MODE_MONO ? "MONO" :
-                                       sbc.mode == SBC_MODE_STEREO ?
-                                               "STEREO" : "JOINTSTEREO");
-       }
-
-       codesize = sbc_get_codesize(&sbc);
-       nframes = sizeof(input) / codesize;
-       while (1) {
-               unsigned char *inp, *outp;
-               /* read data for up to 'nframes' frames of input data */
-               size = read(fd, input, codesize * nframes);
-               if (size < 0) {
-                       /* Something really bad happened */
-                       perror("Can't read audio data");
-                       break;
-               }
-               if (size < codesize) {
-                       /* Not enough data for encoding even a single frame */
-                       break;
-               }
-               /* encode all the data from the input buffer in a loop */
-               inp = input;
-               outp = output;
-               while (size >= codesize) {
-                       len = sbc_encode(&sbc, inp, codesize,
-                               outp, sizeof(output) - (outp - output),
-                               &encoded);
-                       if (len != codesize || encoded <= 0) {
-                               fprintf(stderr,
-                                       "sbc_encode fail, len=%zd, encoded=%lu\n",
-                                       len, (unsigned long) encoded);
-                               break;
-                       }
-                       size -= len;
-                       inp += len;
-                       outp += encoded;
-               }
-               len = write(fileno(stdout), output, outp - output);
-               if (len != outp - output) {
-                       perror("Can't write SBC output");
-                       break;
-               }
-               if (size != 0) {
-                       /*
-                        * sbc_encode failure has been detected earlier or end
-                        * of file reached (have trailing partial data which is
-                        * insufficient to encode SBC frame)
-                        */
-                       break;
-               }
-       }
-
-       sbc_finish(&sbc);
-
-done:
-       if (fd > fileno(stderr))
-               close(fd);
-}
-
-static void usage(void)
-{
-       printf("SBC encoder utility ver %s\n", VERSION);
-       printf("Copyright (c) 2004-2010  Marcel Holtmann\n\n");
-
-       printf("Usage:\n"
-               "\tsbcenc [options] file(s)\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-h, --help           Display help\n"
-               "\t-v, --verbose        Verbose mode\n"
-               "\t-s, --subbands       Number of subbands to use (4 or 8)\n"
-               "\t-b, --bitpool        Bitpool value (default is 32)\n"
-               "\t-j, --joint          Joint stereo\n"
-               "\t-d, --dualchannel    Dual channel\n"
-               "\t-S, --snr            Use SNR mode (default is loudness)\n"
-               "\t-B, --blocks         Number of blocks (4, 8, 12 or 16)\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "verbose",    0, 0, 'v' },
-       { "subbands",   1, 0, 's' },
-       { "bitpool",    1, 0, 'b' },
-       { "joint",      0, 0, 'j' },
-       { "dualchannel",0, 0, 'd' },
-       { "snr",        0, 0, 'S' },
-       { "blocks",     1, 0, 'B' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       int i, opt, subbands = 8, bitpool = 32, joint = 0, dualchannel = 0;
-       int snr = 0, blocks = 16;
-
-       while ((opt = getopt_long(argc, argv, "+hvs:b:jdSB:",
-                                               main_options, NULL)) != -1) {
-               switch(opt) {
-               case 'h':
-                       usage();
-                       exit(0);
-
-               case 'v':
-                       verbose = 1;
-                       break;
-
-               case 's':
-                       subbands = atoi(optarg);
-                       if (subbands != 8 && subbands != 4) {
-                               fprintf(stderr, "Invalid subbands\n");
-                               exit(1);
-                       }
-                       break;
-
-               case 'b':
-                       bitpool = atoi(optarg);
-                       break;
-
-               case 'j':
-                       joint = 1;
-                       break;
-
-               case 'd':
-                       dualchannel = 1;
-                       break;
-
-               case 'S':
-                       snr = 1;
-                       break;
-
-               case 'B':
-                       blocks = atoi(optarg);
-                       if (blocks != 16 && blocks != 12 &&
-                                               blocks != 8 && blocks != 4) {
-                               fprintf(stderr, "Invalid blocks\n");
-                               exit(1);
-                       }
-                       break;
-
-               default:
-                       usage();
-                       exit(1);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       for (i = 0; i < argc; i++)
-               encode(argv[i], subbands, bitpool, joint, dualchannel,
-                                                               snr, blocks);
-
-       return 0;
-}
diff --git a/sbc/sbcinfo.c b/sbc/sbcinfo.c
deleted file mode 100644 (file)
index 8cfb54a..0000000
+++ /dev/null
@@ -1,321 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  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 <stdint.h>
-#include <string.h>
-#include <libgen.h>
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-struct sbc_frame_hdr {
-       uint8_t syncword:8;             /* Sync word */
-       uint8_t subbands:1;             /* Subbands */
-       uint8_t allocation_method:1;    /* Allocation method */
-       uint8_t channel_mode:2;         /* Channel mode */
-       uint8_t blocks:2;               /* Blocks */
-       uint8_t sampling_frequency:2;   /* Sampling frequency */
-       uint8_t bitpool:8;              /* Bitpool */
-       uint8_t crc_check:8;            /* CRC check */
-} __attribute__ ((packed));
-#elif __BYTE_ORDER == __BIG_ENDIAN
-struct sbc_frame_hdr {
-       uint8_t syncword:8;             /* Sync word */
-       uint8_t sampling_frequency:2;   /* Sampling frequency */
-       uint8_t blocks:2;               /* Blocks */
-       uint8_t channel_mode:2;         /* Channel mode */
-       uint8_t allocation_method:1;    /* Allocation method */
-       uint8_t subbands:1;             /* Subbands */
-       uint8_t bitpool:8;              /* Bitpool */
-       uint8_t crc_check:8;            /* CRC check */
-} __attribute__ ((packed));
-#else
-#error "Unknown byte order"
-#endif
-
-static int calc_frame_len(struct sbc_frame_hdr *hdr)
-{
-       int tmp, nrof_subbands, nrof_blocks;
-
-       nrof_subbands = (hdr->subbands + 1) * 4;
-       nrof_blocks = (hdr->blocks + 1) * 4;
-
-       switch (hdr->channel_mode) {
-       case 0x00:
-               nrof_subbands /= 2;
-               tmp = nrof_blocks * hdr->bitpool;
-               break;
-       case 0x01:
-               tmp = nrof_blocks * hdr->bitpool * 2;
-               break;
-       case 0x02:
-               tmp = nrof_blocks * hdr->bitpool;
-               break;
-       case 0x03:
-               tmp = nrof_blocks * hdr->bitpool + nrof_subbands;
-               break;
-       default:
-               return 0;
-       }
-
-       return (nrof_subbands + ((tmp + 7) / 8));
-}
-
-static double calc_bit_rate(struct sbc_frame_hdr *hdr)
-{
-       int nrof_subbands, nrof_blocks;
-       double f;
-
-       nrof_subbands = (hdr->subbands + 1) * 4;
-       nrof_blocks = (hdr->blocks + 1) * 4;
-
-       switch (hdr->sampling_frequency) {
-       case 0:
-               f = 16;
-               break;
-       case 1:
-               f = 32;
-               break;
-       case 2:
-               f = 44.1;
-               break;
-       case 3:
-               f = 48;
-               break;
-       default:
-               return 0;
-       }
-
-       return ((8 * (calc_frame_len(hdr) + 4) * f) /
-                       (nrof_subbands * nrof_blocks));
-}
-
-static char *freq2str(uint8_t freq)
-{
-       switch (freq) {
-       case 0:
-               return "16 kHz";
-       case 1:
-               return "32 kHz";
-       case 2:
-               return "44.1 kHz";
-       case 3:
-               return "48 kHz";
-       default:
-               return "Unknown";
-       }
-}
-
-static char *mode2str(uint8_t mode)
-{
-       switch (mode) {
-       case 0:
-               return "Mono";
-       case 1:
-               return "Dual Channel";
-       case 2:
-               return "Stereo";
-       case 3:
-               return "Joint Stereo";
-       default:
-               return "Unknown";
-       }
-}
-
-static ssize_t __read(int fd, void *buf, size_t count)
-{
-       ssize_t len, pos = 0;
-
-       while (count > 0) {
-               len = read(fd, buf + pos, count);
-               if (len <= 0)
-                       return len;
-
-               count -= len;
-               pos   += len;
-       }
-
-       return pos;
-}
-
-#define SIZE 32
-
-static int analyze_file(char *filename)
-{
-       struct sbc_frame_hdr hdr;
-       unsigned char buf[64];
-       double rate;
-       int bitpool[SIZE], frame_len[SIZE];
-       int subbands, blocks, freq, method;
-       int n, p1, p2, fd, size, num;
-       ssize_t len;
-       unsigned int count;
-
-       if (strcmp(filename, "-")) {
-               printf("Filename\t\t%s\n", basename(filename));
-
-               fd = open(filename, O_RDONLY);
-               if (fd < 0) {
-                       perror("Can't open file");
-                       return -1;
-               }
-       } else
-               fd = fileno(stdin);
-
-       len = __read(fd, &hdr, sizeof(hdr));
-       if (len != sizeof(hdr) || hdr.syncword != 0x9c) {
-               fprintf(stderr, "Not a SBC audio file\n");
-               return -1;
-       }
-
-       subbands = (hdr.subbands + 1) * 4;
-       blocks = (hdr.blocks + 1) * 4;
-       freq = hdr.sampling_frequency;
-       method = hdr.allocation_method;
-
-       count = calc_frame_len(&hdr);
-
-       bitpool[0] = hdr.bitpool;
-       frame_len[0] = count + 4;
-
-       for (n = 1; n < SIZE; n++) {
-               bitpool[n] = 0;
-               frame_len[n] = 0;
-       }
-
-       if (lseek(fd, 0, SEEK_SET) < 0) {
-               num = 1;
-               rate = calc_bit_rate(&hdr);
-               while (count) {
-                       size = count > sizeof(buf) ? sizeof(buf) : count;
-                       len = __read(fd, buf, size);
-                       if (len < 0)
-                               break;
-                       count -= len;
-               }
-       } else {
-               num = 0;
-               rate = 0;
-       }
-
-       while (1) {
-               len = __read(fd, &hdr, sizeof(hdr));
-               if (len < 0) {
-                       fprintf(stderr, "Unable to read frame header"
-                                       " (error %d)\n", errno);
-                       break;
-               }
-
-               if (len == 0)
-                       break;
-
-               if ((size_t) len < sizeof(hdr) || hdr.syncword != 0x9c) {
-                       fprintf(stderr, "Corrupted SBC stream "
-                                       "(len %zd syncword 0x%02x)\n",
-                                       len, hdr.syncword);
-                       break;
-               }
-
-               count = calc_frame_len(&hdr);
-               len = count + 4;
-
-               p1 = -1;
-               p2 = -1;
-               for (n = 0; n < SIZE; n++) {
-                       if (p1 < 0 && (bitpool[n] == 0 || bitpool[n] == hdr.bitpool))
-                               p1 = n;
-                       if (p2 < 0 && (frame_len[n] == 0 || frame_len[n] == len))
-                               p2 = n;
-               }
-               if (p1 >= 0)
-                       bitpool[p1] = hdr.bitpool;
-               if (p2 >= 0)
-                       frame_len[p2] = len;
-
-               while (count) {
-                       size = count > sizeof(buf) ? sizeof(buf) : count;
-
-                       len = __read(fd, buf, size);
-                       if (len != size) {
-                               fprintf(stderr, "Unable to read frame data "
-                                               "(error %d)\n", errno);
-                               break;
-                       }
-
-                       count -= len;
-               }
-
-               rate += calc_bit_rate(&hdr);
-               num++;
-       }
-
-       printf("Subbands\t\t%d\n", subbands);
-       printf("Block length\t\t%d\n", blocks);
-       printf("Sampling frequency\t%s\n", freq2str(freq));
-       printf("Channel mode\t\t%s\n", mode2str(hdr.channel_mode));
-       printf("Allocation method\t%s\n", method ? "SNR" : "Loudness");
-       printf("Bitpool\t\t\t%d", bitpool[0]);
-       for (n = 1; n < SIZE; n++)
-               if (bitpool[n] > 0)
-                       printf(", %d", bitpool[n]);
-       printf("\n");
-       printf("Number of frames\t%d\n", num);
-       printf("Frame length\t\t%d", frame_len[0]);
-       for (n = 1; n < SIZE; n++)
-               if (frame_len[n] > 0)
-                       printf(", %d", frame_len[n]);
-       printf(" Bytes\n");
-       if (num > 0)
-               printf("Bit rate\t\t%.3f kbps\n", rate / num);
-
-       if (fd > fileno(stderr))
-               close(fd);
-
-       printf("\n");
-
-       return 0;
-}
-
-int main(int argc, char *argv[])
-{
-       int i;
-
-       if (argc < 2) {
-               fprintf(stderr, "Usage: sbcinfo <file>\n");
-               exit(1);
-       }
-
-       for (i = 0; i < argc - 1; i++)
-               if (analyze_file(argv[i + 1]) < 0)
-                       exit(1);
-
-       return 0;
-}
diff --git a/sbc/sbctester.c b/sbc/sbctester.c
deleted file mode 100644 (file)
index c08c22a..0000000
+++ /dev/null
@@ -1,358 +0,0 @@
-/*
- *
- *  Bluetooth low-complexity, subband codec (SBC) library
- *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2007-2008  Frederic Dalleau <fdalleau@free.fr>
- *
- *
- *  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 <sndfile.h>
-#include <math.h>
-#include <string.h>
-
-#define MAXCHANNELS 2
-#define DEFACCURACY 7
-
-static double sampletobits(short sample16, int verbose)
-{
-       double bits = 0;
-       unsigned short bit;
-       int i;
-
-       if (verbose)
-               printf("===> sampletobits(%hd, %04hX)\n", sample16, sample16);
-
-       /* Bit 0 is MSB */
-       if (sample16 < 0)
-               bits = -1;
-
-       if (verbose)
-               printf("%d", (sample16 < 0) ? 1 : 0);
-
-       /* Bit 15 is LSB */
-       for (i = 1; i < 16; i++) {
-               bit = (unsigned short) sample16;
-               bit >>= 15 - i;
-               bit %= 2;
-
-               if (verbose)
-                       printf("%d", bit);
-
-               if (bit)
-                       bits += (1.0 / pow(2.0, i));
-       }
-
-       if (verbose)
-               printf("\n");
-
-       return bits;
-}
-
-static int calculate_rms_level(SNDFILE * sndref, SF_INFO * infosref,
-                               SNDFILE * sndtst, SF_INFO * infostst,
-                                               int accuracy, char *csvname)
-{
-       short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
-       double refbits, tstbits;
-       double rms_accu[MAXCHANNELS];
-       double rms_level[MAXCHANNELS];
-       double rms_limit = 1.0 / (pow(2.0, accuracy - 1) * pow(12.0, 0.5));
-       FILE *csv = NULL;
-       int i, j, r1, r2, verdict;
-
-       if (csvname)
-               csv = fopen(csvname, "wt");
-
-       if (csv) {
-               fprintf(csv, "num;");
-               for (j = 0; j < infostst->channels; j++)
-                       fprintf(csv, "ref channel %d;tst channel %d;", j, j);
-               fprintf(csv, "\r\n");
-       }
-
-       sf_seek(sndref, 0, SEEK_SET);
-       sf_seek(sndtst, 0, SEEK_SET);
-
-       memset(rms_accu, 0, sizeof(rms_accu));
-       memset(rms_level, 0, sizeof(rms_level));
-
-       for (i = 0; i < infostst->frames; i++) {
-               if (csv)
-                       fprintf(csv, "%d;", i);
-
-               r1 = sf_read_short(sndref, refsample, infostst->channels);
-               if (r1 != infostst->channels) {
-                       printf("Failed to read reference data: %s "
-                                       "(r1=%d, channels=%d)",
-                                       sf_strerror(sndref), r1,
-                                       infostst->channels);
-                       if (csv)
-                               fclose(csv);
-                       return -1;
-               }
-
-               r2 = sf_read_short(sndtst, tstsample, infostst->channels);
-               if (r2 != infostst->channels) {
-                       printf("Failed to read test data: %s "
-                                       "(r2=%d, channels=%d)\n",
-                                       sf_strerror(sndtst), r2,
-                                       infostst->channels);
-                       if (csv)
-                               fclose(csv);
-                       return -1;
-               }
-
-               for (j = 0; j < infostst->channels; j++) {
-                       if (csv)
-                               fprintf(csv, "%d;%d;", refsample[j],
-                                               tstsample[j]);
-
-                       refbits = sampletobits(refsample[j], 0);
-                       tstbits = sampletobits(tstsample[j], 0);
-
-                       rms_accu[j] += pow(tstbits - refbits, 2.0);
-               }
-
-               if (csv)
-                       fprintf(csv, "\r\n");
-       }
-
-       printf("Limit: %f\n", rms_limit);
-
-       for (j = 0; j < infostst->channels; j++) {
-               printf("Channel %d\n", j);
-               printf("Accumulated %f\n", rms_accu[j]);
-               rms_accu[j] /= (double) infostst->frames;
-               printf("Accumulated / %f = %f\n", (double) infostst->frames,
-                               rms_accu[j]);
-               rms_level[j] = sqrt(rms_accu[j]);
-               printf("Level = %f (%f x %f = %f)\n",
-                               rms_level[j], rms_level[j], rms_level[j],
-                                               rms_level[j] * rms_level[j]);
-       }
-
-       verdict = 1;
-
-       for (j = 0; j < infostst->channels; j++) {
-               printf("Channel %d: %f\n", j, rms_level[j]);
-
-               if (rms_level[j] > rms_limit)
-                       verdict = 0;
-       }
-
-       printf("%s return %d\n", __FUNCTION__, verdict);
-
-       return verdict;
-}
-
-static int check_absolute_diff(SNDFILE * sndref, SF_INFO * infosref,
-                               SNDFILE * sndtst, SF_INFO * infostst,
-                               int accuracy)
-{
-       short refsample[MAXCHANNELS], tstsample[MAXCHANNELS];
-       short refmax[MAXCHANNELS], tstmax[MAXCHANNELS];
-       double refbits, tstbits;
-       double rms_absolute = 1.0 / (pow(2, accuracy - 2));
-       double calc_max[MAXCHANNELS];
-       int calc_count = 0;
-       short r1, r2;
-       double cur_diff;
-       int i, j, verdict;
-
-       memset(&refmax, 0, sizeof(refmax));
-       memset(&tstmax, 0, sizeof(tstmax));
-       memset(&calc_max, 0, sizeof(calc_max));
-       memset(&refsample, 0, sizeof(refsample));
-       memset(&tstsample, 0, sizeof(tstsample));
-
-       sf_seek(sndref, 0, SEEK_SET);
-       sf_seek(sndtst, 0, SEEK_SET);
-
-       verdict = 1;
-
-       printf("Absolute max: %f\n", rms_absolute);
-       for (i = 0; i < infostst->frames; i++) {
-               r1 = sf_read_short(sndref, refsample, infostst->channels);
-
-               if (r1 != infostst->channels) {
-                       printf("Failed to read reference data: %s "
-                                       "(r1=%d, channels=%d)",
-                                       sf_strerror(sndref), r1,
-                                       infostst->channels);
-                       return -1;
-               }
-
-               r2 = sf_read_short(sndtst, tstsample, infostst->channels);
-               if (r2 != infostst->channels) {
-                       printf("Failed to read test data: %s "
-                                       "(r2=%d, channels=%d)\n",
-                                       sf_strerror(sndtst), r2,
-                                       infostst->channels);
-                       return -1;
-               }
-
-               for (j = 0; j < infostst->channels; j++) {
-                       refbits = sampletobits(refsample[j], 0);
-                       tstbits = sampletobits(tstsample[j], 0);
-
-                       cur_diff = fabs(tstbits - refbits);
-
-                       if (cur_diff > rms_absolute) {
-                               calc_count++;
-                               /* printf("Channel %d exceeded : fabs(%f - %f) = %f > %f\n", j, tstbits, refbits, cur_diff, rms_absolute); */
-                               verdict = 0;
-                       }
-
-                       if (cur_diff > calc_max[j]) {
-                               calc_max[j] = cur_diff;
-                               refmax[j] = refsample[j];
-                               tstmax[j] = tstsample[j];
-                       }
-               }
-       }
-
-       for (j = 0; j < infostst->channels; j++) {
-               printf("Calculated max: %f (%hd-%hd=%hd)\n",
-                       calc_max[j], tstmax[j], refmax[j],
-                       tstmax[j] - refmax[j]);
-       }
-
-       printf("%s return %d\n", __FUNCTION__, verdict);
-
-       return verdict;
-}
-
-static void usage(void)
-{
-       printf("SBC conformance test ver %s\n", VERSION);
-       printf("Copyright (c) 2007-2010  Marcel Holtmann\n");
-       printf("Copyright (c) 2007-2008  Frederic Dalleau\n\n");
-
-       printf("Usage:\n"
-               "\tsbctester reference.wav checkfile.wav\n"
-               "\tsbctester integer\n"
-               "\n");
-
-       printf("To test the encoder:\n");
-       printf("\tUse a reference codec to encode original.wav to reference.sbc\n");
-       printf("\tUse sbcenc to encode original.wav to checkfile.sbc\n");
-       printf("\tDecode both file using the reference decoder\n");
-       printf("\tRun sbctester with these two wav files to get the result\n\n");
-
-       printf("\tA file called out.csv is generated to use the data in a\n");
-       printf("\tspreadsheet application or database.\n\n");
-}
-
-int main(int argc, char *argv[])
-{
-       SNDFILE *sndref = NULL;
-       SNDFILE *sndtst = NULL;
-       SF_INFO infosref;
-       SF_INFO infostst;
-       char *ref;
-       char *tst;
-       int pass_rms, pass_absolute, pass, accuracy;
-
-       if (argc == 2) {
-               double db;
-
-               printf("Test sampletobits\n");
-               db = sampletobits((short) atoi(argv[1]), 1);
-               printf("db = %f\n", db);
-               exit(0);
-       }
-
-       if (argc < 3) {
-               usage();
-               exit(1);
-       }
-
-       ref = argv[1];
-       tst = argv[2];
-
-       printf("opening reference %s\n", ref);
-
-       sndref = sf_open(ref, SFM_READ, &infosref);
-       if (!sndref) {
-               printf("Failed to open reference file\n");
-               exit(1);
-       }
-
-       printf("opening testfile %s\n", tst);
-       sndtst = sf_open(tst, SFM_READ, &infostst);
-       if (!sndtst) {
-               printf("Failed to open test file\n");
-               sf_close(sndref);
-               exit(1);
-       }
-
-       printf("reference:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
-               (int) infosref.frames, (int) infosref.samplerate,
-               (int) infosref.channels);
-       printf("testfile:\n\t%d frames,\n\t%d hz,\n\t%d channels\n",
-               (int) infostst.frames, (int) infostst.samplerate,
-               (int) infostst.channels);
-
-       /* check number of channels */
-       if (infosref.channels > 2 || infostst.channels > 2) {
-               printf("Too many channels\n");
-               goto error;
-       }
-
-       /* compare number of samples */
-       if (infosref.samplerate != infostst.samplerate ||
-                               infosref.channels != infostst.channels) {
-               printf("Cannot compare files with different charasteristics\n");
-               goto error;
-       }
-
-       accuracy = DEFACCURACY;
-       printf("Accuracy: %d\n", accuracy);
-
-       /* Condition 1 rms level */
-       pass_rms = calculate_rms_level(sndref, &infosref, sndtst, &infostst,
-                                       accuracy, "out.csv");
-       if (pass_rms < 0)
-               goto error;
-
-       /* Condition 2 absolute difference */
-       pass_absolute = check_absolute_diff(sndref, &infosref, sndtst,
-                                               &infostst, accuracy);
-       if (pass_absolute < 0)
-               goto error;
-
-       /* Verdict */
-       pass = pass_rms && pass_absolute;
-       printf("Verdict: %s\n", pass ? "pass" : "fail");
-
-       return 0;
-
-error:
-       sf_close(sndref);
-       sf_close(sndtst);
-
-       exit(1);
-}
diff --git a/scripts/bluetooth-serial.rules b/scripts/bluetooth-serial.rules
deleted file mode 100644 (file)
index 072335f..0000000
+++ /dev/null
@@ -1,35 +0,0 @@
-# Brain Boxes BL-620 Bluetooth Adapter
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Brain Boxes", ATTRS{prod_id2}=="Bluetooth PC Card", ENV{HCIOPTS}="bboxes", RUN+="bluetooth_serial"
-
-# Xircom CreditCard Bluetooth Adapter
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Xircom", ATTRS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial"
-
-# Xircom RealPort2 Bluetooth Adapter
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Xircom", ATTRS{prod_id3}=="CBT", ENV{HCIOPTS}="xircom", RUN+="bluetooth_serial"
-
-# IBM Bluetooth PC Card II
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="IBM", ATTRS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial"
-
-# TDK Bluetooth PC Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="TDK", ATTRS{prod_id2}=="Bluetooth PC Card II", ENV{HCIOPTS}="tdk", RUN+="bluetooth_serial"
-
-# AmbiCom BT2000C Bluetooth PC/CF Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="AmbiCom BT2000C", ATTRS{prod_id2}=="Bluetooth PC/CF Card", ENV{HCIOPTS}="bt2000c", RUN+="bluetooth_serial"
-
-# COM One Platinium Bluetooth PC Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="COM1 SA", ATTRS{prod_id2}=="MC310 CARD", ENV{HCIOPTS}="comone", RUN+="bluetooth_serial"
-
-# Sphinx PICO Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="SPHINX", ATTRS{prod_id2}=="BT-CARD", ENV{HCIOPTS}="picocard", RUN+="bluetooth_serial"
-
-# H-Soft blue+Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="H-Soft", ATTRS{prod_id2}=="Blue+CARD", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial"
-
-# Compaq iPAQ Bluetooth Sleeve, Belkin F8T020, any other muppet who used an OXCF950 and didn't bother to program it appropriately.
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="CF CARD", ATTRS{prod_id2}=="GENERIC", ENV{HCIOPTS}="$sysfs{manf_id},$sysfs{card_id}", RUN+="bluetooth_serial"
-
-# Zoom Bluetooth Card and Sitecom CN-504 Card
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="PCMCIA", ATTRS{prod_id2}=="Bluetooth Card", ENV{HCIOPTS}="zoom", RUN+="bluetooth_serial"
-
-# CC&C BT0100M
-SUBSYSTEM=="tty", SUBSYSTEMS=="pcmcia", ATTRS{prod_id1}=="Bluetooth BT0100M", ENV{HCIOPTS}="bcsp 115200", RUN+="bluetooth_serial"
diff --git a/scripts/bluetooth_serial b/scripts/bluetooth_serial
deleted file mode 100644 (file)
index e5be6c2..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-#!/bin/sh
-#
-# bluetooth_serial
-#
-# Bluetooth serial PCMCIA card initialization
-#
-
-start_serial()
-{
-       if [ ! -x /bin/setserial -o ! -x /usr/sbin/hciattach ]; then
-               logger "$0: setserial or hciattach not executable, cannot start $DEVNAME"
-               return 1
-       fi
-
-       if [ "$BAUDBASE" != "" ]; then
-               /bin/setserial $DEVNAME baud_base $BAUDBASE
-       fi
-
-       /usr/sbin/hciattach $DEVNAME $HCIOPTS 2>&1 | logger -t hciattach
-}
-
-stop_serial()
-{
-       [ -x /bin/fuser ] || return 1 
-
-       /bin/fuser -k -HUP $DEVNAME > /dev/null
-}
-
-case "$ACTION" in
-   add)
-       start_serial
-       ;;
-   remove)
-       stop_serial
-       ;;
-   *)
-       logger "Unknown action received $0: $ACTION"
-       ;;
-esac
diff --git a/serial/manager.c b/serial/manager.c
deleted file mode 100644 (file)
index 438ba6c..0000000
+++ /dev/null
@@ -1,174 +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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/uuid.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/dbus-common.h"
-#include "adapter.h"
-#include "device.h"
-
-#include "log.h"
-
-#include "error.h"
-#include "port.h"
-#include "proxy.h"
-#include "storage.h"
-#include "manager.h"
-#include "sdpd.h"
-#include "glib-helper.h"
-
-static DBusConnection *connection = NULL;
-
-static int serial_probe(struct btd_device *device, const char *uuid)
-{
-       struct btd_adapter *adapter = device_get_adapter(device);
-       const gchar *path = device_get_path(device);
-       sdp_list_t *protos;
-       int ch;
-       bdaddr_t src, dst;
-       const sdp_record_t *rec;
-
-       DBG("path %s: %s", path, uuid);
-
-       rec = btd_device_get_record(device, uuid);
-       if (!rec)
-               return -EINVAL;
-
-       if (sdp_get_access_protos(rec, &protos) < 0)
-               return -EINVAL;
-
-       ch = sdp_get_proto_port(protos, RFCOMM_UUID);
-       sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-       sdp_list_free(protos, NULL);
-
-       if (ch < 1 || ch > 30) {
-               error("Channel out of range: %d", ch);
-               return -EINVAL;
-       }
-
-       adapter_get_address(adapter, &src);
-       device_get_address(device, &dst, NULL);
-
-       return port_register(connection, path, &src, &dst, uuid, ch);
-}
-
-static void serial_remove(struct btd_device *device)
-{
-       const gchar *path = device_get_path(device);
-
-       DBG("path %s", path);
-
-       port_unregister(path);
-}
-
-
-static int port_probe(struct btd_device *device, GSList *uuids)
-{
-       while (uuids) {
-               serial_probe(device, uuids->data);
-               uuids = uuids->next;
-       }
-
-       return 0;
-}
-
-static void port_remove(struct btd_device *device)
-{
-       return serial_remove(device);
-}
-
-static struct btd_device_driver serial_port_driver = {
-       .name   = "serial-port",
-       .uuids  = BTD_UUIDS(RFCOMM_UUID_STR),
-       .probe  = port_probe,
-       .remove = port_remove,
-};
-
-static int proxy_probe(struct btd_adapter *adapter)
-{
-       const char *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       return proxy_register(connection, adapter);
-}
-
-static void proxy_remove(struct btd_adapter *adapter)
-{
-       const char *path = adapter_get_path(adapter);
-
-       DBG("path %s", path);
-
-       proxy_unregister(adapter);
-}
-
-static struct btd_adapter_driver serial_proxy_driver = {
-       .name   = "serial-proxy",
-       .probe  = proxy_probe,
-       .remove = proxy_remove,
-};
-
-int serial_manager_init(DBusConnection *conn)
-{
-       connection = dbus_connection_ref(conn);
-
-       btd_register_adapter_driver(&serial_proxy_driver);
-       btd_register_device_driver(&serial_port_driver);
-
-       return 0;
-}
-
-void serial_manager_exit(void)
-{
-       btd_unregister_device_driver(&serial_port_driver);
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-}
diff --git a/serial/port.c b/serial/port.c
deleted file mode 100644 (file)
index f90bb6a..0000000
+++ /dev/null
@@ -1,646 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <errno.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/dbus-common.h"
-
-#include "log.h"
-#include "glib-helper.h"
-#include "sdp-client.h"
-#include "btio.h"
-
-#include "error.h"
-#include "manager.h"
-#include "adapter.h"
-#include "device.h"
-#include "storage.h"
-#include "port.h"
-
-#define SERIAL_PORT_INTERFACE  "org.bluez.Serial"
-
-#define MAX_OPEN_TRIES         5
-#define OPEN_WAIT              300     /* ms. udev node creation retry wait */
-
-struct serial_device {
-       DBusConnection  *conn;          /* for name listener handling */
-       bdaddr_t        src;            /* Source (local) address */
-       bdaddr_t        dst;            /* Destination address */
-       char            *path;          /* Device path */
-       GSList          *ports;         /* Available ports */
-};
-
-struct serial_port {
-       DBusMessage     *msg;           /* for name listener handling */
-       int16_t         id;             /* RFCOMM device id */
-       uint8_t         channel;        /* RFCOMM channel */
-       char            *uuid;          /* service identification */
-       char            *dev;           /* RFCOMM device name */
-       int             fd;             /* Opened file descriptor */
-       GIOChannel      *io;            /* BtIO channel */
-       guint           listener_id;
-       struct serial_device *device;
-};
-
-static GSList *devices = NULL;
-
-static struct serial_device *find_device(GSList *devices, const char *path)
-{
-       GSList *l;
-
-       for (l = devices; l != NULL; l = l->next) {
-               struct serial_device *device = l->data;
-
-               if (!strcmp(device->path, path))
-                       return device;
-       }
-
-       return NULL;
-}
-
-static struct serial_port *find_port(GSList *ports, const char *pattern)
-{
-       GSList *l;
-       int channel;
-       char *endptr = NULL;
-
-       channel = strtol(pattern, &endptr, 10);
-
-       for (l = ports; l != NULL; l = l->next) {
-               struct serial_port *port = l->data;
-               char *uuid_str;
-               int ret;
-
-               if (port->uuid && !strcasecmp(port->uuid, pattern))
-                       return port;
-
-               if (endptr && *endptr == '\0' && port->channel == channel)
-                       return port;
-
-               if (port->dev && !strcmp(port->dev, pattern))
-                       return port;
-
-               if (!port->uuid)
-                       continue;
-
-               uuid_str = bt_name2string(pattern);
-               if (!uuid_str)
-                       continue;
-
-               ret = strcasecmp(port->uuid, uuid_str);
-               g_free(uuid_str);
-               if (ret == 0)
-                       return port;
-       }
-
-       return NULL;
-}
-
-static int port_release(struct serial_port *port)
-{
-       struct rfcomm_dev_req req;
-       int rfcomm_ctl;
-       int err = 0;
-
-       if (port->id < 0) {
-               if (port->io) {
-                       g_io_channel_shutdown(port->io, TRUE, NULL);
-                       g_io_channel_unref(port->io);
-                       port->io = NULL;
-               } else
-                       bt_cancel_discovery(&port->device->src,
-                                               &port->device->dst);
-
-               return 0;
-       }
-
-       DBG("Serial port %s released", port->dev);
-
-       rfcomm_ctl = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_RFCOMM);
-       if (rfcomm_ctl < 0)
-               return -errno;
-
-       if (port->fd >= 0) {
-               close(port->fd);
-               port->fd = -1;
-       }
-
-       memset(&req, 0, sizeof(req));
-       req.dev_id = port->id;
-
-       /*
-        * We are hitting a kernel bug inside RFCOMM code when
-        * RFCOMM_HANGUP_NOW bit is set on request's flags passed to
-        * ioctl(RFCOMMRELEASEDEV)!
-        */
-       req.flags = (1 << RFCOMM_HANGUP_NOW);
-
-       if (ioctl(rfcomm_ctl, RFCOMMRELEASEDEV, &req) < 0) {
-               err = -errno;
-               error("Can't release device %s: %s (%d)",
-                               port->dev, strerror(-err), -err);
-       }
-
-       g_free(port->dev);
-       port->dev = NULL;
-       port->id = -1;
-       close(rfcomm_ctl);
-       return err;
-}
-
-static void serial_port_free(void *data)
-{
-       struct serial_port *port = data;
-       struct serial_device *device = port->device;
-
-       if (device && port->listener_id > 0)
-               g_dbus_remove_watch(device->conn, port->listener_id);
-
-       port_release(port);
-
-       g_free(port->uuid);
-       g_free(port);
-}
-
-static void serial_device_free(void *data)
-{
-       struct serial_device *device = data;
-
-       g_free(device->path);
-       if (device->conn)
-               dbus_connection_unref(device->conn);
-       g_free(device);
-}
-
-static void port_owner_exited(DBusConnection *conn, void *user_data)
-{
-       struct serial_port *port = user_data;
-
-       port_release(port);
-
-       port->listener_id = 0;
-}
-
-static void path_unregister(void *data)
-{
-       struct serial_device *device = data;
-
-       DBG("Unregistered interface %s on path %s", SERIAL_PORT_INTERFACE,
-               device->path);
-
-       devices = g_slist_remove(devices, device);
-       serial_device_free(device);
-}
-
-void port_release_all(void)
-{
-       g_slist_free_full(devices, serial_device_free);
-}
-
-static void open_notify(int fd, int err, struct serial_port *port)
-{
-       struct serial_device *device = port->device;
-       DBusMessage *reply;
-
-       if (err < 0) {
-               /* Max tries exceeded */
-               port_release(port);
-               reply = btd_error_failed(port->msg, strerror(-err));
-       } else {
-               port->fd = fd;
-               reply = g_dbus_create_reply(port->msg,
-                               DBUS_TYPE_STRING, &port->dev,
-                               DBUS_TYPE_INVALID);
-       }
-
-       /* Reply to the requestor */
-       g_dbus_send_message(device->conn, reply);
-}
-
-static gboolean open_continue(gpointer user_data)
-{
-       struct serial_port *port = user_data;
-       int fd;
-       static int ntries = MAX_OPEN_TRIES;
-
-       if (!port->listener_id)
-               return FALSE; /* Owner exited */
-
-       fd = open(port->dev, O_RDONLY | O_NOCTTY);
-       if (fd < 0) {
-               int err = -errno;
-               error("Could not open %s: %s (%d)",
-                               port->dev, strerror(-err), -err);
-               if (!--ntries) {
-                       /* Reporting error */
-                       open_notify(fd, err, port);
-                       ntries = MAX_OPEN_TRIES;
-                       return FALSE;
-               }
-               return TRUE;
-       }
-
-       /* Connection succeeded */
-       open_notify(fd, 0, port);
-       return FALSE;
-}
-
-static int port_open(struct serial_port *port)
-{
-       int fd;
-
-       fd = open(port->dev, O_RDONLY | O_NOCTTY);
-       if (fd < 0) {
-               g_timeout_add(OPEN_WAIT, open_continue, port);
-               return -EINPROGRESS;
-       }
-
-       return fd;
-}
-
-static void rfcomm_connect_cb(GIOChannel *chan, GError *conn_err,
-                                                       gpointer user_data)
-{
-       struct serial_port *port = user_data;
-       struct serial_device *device = port->device;
-       struct rfcomm_dev_req req;
-       int sk, fd;
-       DBusMessage *reply;
-
-       /* Owner exited? */
-       if (!port->listener_id)
-               return;
-
-       if (conn_err) {
-               error("%s", conn_err->message);
-               reply = btd_error_failed(port->msg, conn_err->message);
-               goto fail;
-       }
-
-       sk = g_io_channel_unix_get_fd(chan);
-
-       if (dbus_message_has_member(port->msg, "ConnectFD")) {
-               reply = g_dbus_create_reply(port->msg, DBUS_TYPE_UNIX_FD, &sk,
-                                                       DBUS_TYPE_INVALID);
-               g_dbus_send_message(device->conn, reply);
-
-               close(sk);
-
-               g_dbus_remove_watch(device->conn, port->listener_id);
-               port->listener_id = 0;
-
-               return;
-       }
-
-       memset(&req, 0, sizeof(req));
-       req.dev_id = -1;
-       req.flags = (1 << RFCOMM_REUSE_DLC);
-       bacpy(&req.src, &device->src);
-       bacpy(&req.dst, &device->dst);
-       req.channel = port->channel;
-
-       g_io_channel_unref(port->io);
-       port->io = NULL;
-
-       port->id = ioctl(sk, RFCOMMCREATEDEV, &req);
-       if (port->id < 0) {
-               int err = -errno;
-               error("ioctl(RFCOMMCREATEDEV): %s (%d)", strerror(-err), -err);
-               reply = btd_error_failed(port->msg, strerror(-err));
-               g_io_channel_shutdown(chan, TRUE, NULL);
-               goto fail;
-       }
-
-       port->dev = g_strdup_printf("/dev/rfcomm%d", port->id);
-
-       DBG("Serial port %s created", port->dev);
-
-       g_io_channel_shutdown(chan, TRUE, NULL);
-
-       /* Addressing connect port */
-       fd = port_open(port);
-       if (fd < 0)
-               /* Open in progress: Wait the callback */
-               return;
-
-       open_notify(fd, 0, port);
-       return;
-
-fail:
-       g_dbus_send_message(device->conn, reply);
-       g_dbus_remove_watch(device->conn, port->listener_id);
-       port->listener_id = 0;
-}
-
-static void get_record_cb(sdp_list_t *recs, int err, gpointer user_data)
-{
-       struct serial_port *port = user_data;
-       struct serial_device *device = port->device;
-       sdp_record_t *record = NULL;
-       sdp_list_t *protos;
-       DBusMessage *reply;
-       GError *gerr = NULL;
-
-       if (!port->listener_id)
-               return;
-
-       if (err < 0) {
-               error("Unable to get service record: %s (%d)", strerror(-err),
-                       -err);
-               reply = btd_error_failed(port->msg, strerror(-err));
-               goto failed;
-       }
-
-       if (!recs || !recs->data) {
-               error("No record found");
-               reply = btd_error_failed(port->msg, "No record found");
-               goto failed;
-       }
-
-       record = recs->data;
-
-       if (sdp_get_access_protos(record, &protos) < 0) {
-               error("Unable to get access protos from port record");
-               reply = btd_error_failed(port->msg, "Invalid channel");
-               goto failed;
-       }
-
-       port->channel = sdp_get_proto_port(protos, RFCOMM_UUID);
-
-       sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free, NULL);
-       sdp_list_free(protos, NULL);
-
-       port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
-                               NULL, &gerr,
-                               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);
-               reply = btd_error_failed(port->msg, gerr->message);
-               g_error_free(gerr);
-               goto failed;
-       }
-
-       return;
-
-failed:
-       g_dbus_remove_watch(device->conn, port->listener_id);
-       port->listener_id = 0;
-       g_dbus_send_message(device->conn, reply);
-}
-
-static int connect_port(struct serial_port *port)
-{
-       struct serial_device *device = port->device;
-       uuid_t uuid;
-       int err;
-
-       if (!port->uuid)
-               goto connect;
-
-       err = bt_string2uuid(&uuid, port->uuid);
-       if (err < 0)
-               return err;
-
-       sdp_uuid128_to_uuid(&uuid);
-
-       return bt_search_service(&device->src, &device->dst, &uuid,
-                               get_record_cb, port, NULL);
-
-connect:
-       port->io = bt_io_connect(BT_IO_RFCOMM, rfcomm_connect_cb, port,
-                               NULL, NULL,
-                               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;
-
-       return 0;
-}
-
-static struct serial_port *create_port(struct serial_device *device,
-                                       const char *uuid, uint8_t channel)
-{
-       struct serial_port *port;
-
-       port = g_new0(struct serial_port, 1);
-       port->uuid = g_strdup(uuid);
-       port->channel = channel;
-       port->device = device;
-       port->id = -1;
-       port->fd = -1;
-
-       device->ports = g_slist_append(device->ports, port);
-
-       return port;
-}
-
-static DBusMessage *port_connect(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
-{
-       struct serial_device *device = user_data;
-       struct serial_port *port;
-       const char *pattern;
-       int err;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       port = find_port(device->ports, pattern);
-       if (!port) {
-               char *endptr = NULL;
-               int channel;
-
-               channel = strtol(pattern, &endptr, 10);
-               if ((endptr && *endptr != '\0') || channel < 1 || channel > 30)
-                       return btd_error_does_not_exist(msg);
-
-               port = create_port(device, NULL, channel);
-       }
-
-       if (port->listener_id)
-               return btd_error_failed(msg, "Port already in use");
-
-       port->listener_id = g_dbus_add_disconnect_watch(conn,
-                                               dbus_message_get_sender(msg),
-                                               port_owner_exited, port,
-                                               NULL);
-
-       port->msg = dbus_message_ref(msg);
-
-       err = connect_port(port);
-       if (err < 0) {
-               error("%s", strerror(-err));
-               g_dbus_remove_watch(conn, port->listener_id);
-               port->listener_id = 0;
-
-               return btd_error_failed(msg, strerror(-err));
-       }
-
-       return NULL;
-}
-
-static DBusMessage *port_disconnect(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
-{
-       struct serial_device *device = user_data;
-       struct serial_port *port;
-       const char *dev, *owner, *caller;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &dev,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return NULL;
-
-       port = find_port(device->ports, dev);
-       if (!port)
-               return btd_error_does_not_exist(msg);
-
-       if (!port->listener_id)
-               return btd_error_not_connected(msg);
-
-       owner = dbus_message_get_sender(port->msg);
-       caller = dbus_message_get_sender(msg);
-       if (!g_str_equal(owner, caller))
-               return btd_error_not_authorized(msg);
-
-       port_release(port);
-
-       g_dbus_remove_watch(conn, port->listener_id);
-       port->listener_id = 0;
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-}
-
-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) },
-       { }
-};
-
-static struct serial_device *create_serial_device(DBusConnection *conn,
-                                       const char *path, bdaddr_t *src,
-                                       bdaddr_t *dst)
-{
-       struct serial_device *device;
-
-       device = g_new0(struct serial_device, 1);
-       device->conn = dbus_connection_ref(conn);
-       bacpy(&device->dst, dst);
-       bacpy(&device->src, src);
-       device->path = g_strdup(path);
-
-       if (!g_dbus_register_interface(conn, path,
-                               SERIAL_PORT_INTERFACE,
-                               port_methods, NULL, NULL,
-                               device, path_unregister)) {
-               error("D-Bus failed to register %s interface",
-                               SERIAL_PORT_INTERFACE);
-               serial_device_free(device);
-               return NULL;
-       }
-
-       DBG("Registered interface %s on path %s",
-               SERIAL_PORT_INTERFACE, path);
-
-       return device;
-}
-
-int port_register(DBusConnection *conn, const char *path, bdaddr_t *src,
-                       bdaddr_t *dst, const char *uuid, uint8_t channel)
-{
-       struct serial_device *device;
-       struct serial_port *port;
-
-       device = find_device(devices, path);
-       if (!device) {
-               device = create_serial_device(conn, path, src, dst);
-               if (!device)
-                       return -1;
-               devices = g_slist_append(devices, device);
-       }
-
-       if (find_port(device->ports, uuid))
-               return 0;
-
-       port = g_new0(struct serial_port, 1);
-       port->uuid = g_strdup(uuid);
-       port->channel = channel;
-       port->device = device;
-       port->id = -1;
-       port->fd = -1;
-
-       device->ports = g_slist_append(device->ports, port);
-
-       return 0;
-}
-
-int port_unregister(const char *path)
-{
-       struct serial_device *device;
-
-       device = find_device(devices, path);
-       if (!device)
-               return -ENOENT;
-
-       g_slist_free_full(device->ports, serial_port_free);
-
-       g_dbus_unregister_interface(device->conn, path, SERIAL_PORT_INTERFACE);
-
-       return 0;
-}
diff --git a/serial/proxy.c b/serial/proxy.c
deleted file mode 100644 (file)
index dd38317..0000000
+++ /dev/null
@@ -1,1269 +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 <ctype.h>
-#include <dirent.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <termios.h>
-#include <unistd.h>
-#include <arpa/inet.h>
-#include <sys/param.h>
-#include <sys/ioctl.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/un.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-#include <bluetooth/rfcomm.h>
-
-#include <glib.h>
-#include <gdbus.h>
-
-#include "../src/dbus-common.h"
-#include "../src/adapter.h"
-
-#include "log.h"
-
-#include "error.h"
-#include "sdpd.h"
-#include "glib-helper.h"
-#include "btio.h"
-#include "proxy.h"
-
-#define SERIAL_PROXY_INTERFACE "org.bluez.SerialProxy"
-#define SERIAL_MANAGER_INTERFACE "org.bluez.SerialProxyManager"
-#define BUF_SIZE               1024
-
-typedef enum {
-       TTY_PROXY,
-       UNIX_SOCKET_PROXY,
-       TCP_SOCKET_PROXY,
-       UNKNOWN_PROXY_TYPE = 0xFF
-} proxy_type_t;
-
-struct serial_adapter {
-       struct btd_adapter      *btd_adapter;   /* Adapter pointer */
-       DBusConnection          *conn;          /* Adapter connection */
-       GSList                  *proxies;       /* Proxies list */
-};
-
-struct serial_proxy {
-       bdaddr_t        src;            /* Local address */
-       bdaddr_t        dst;            /* Remote address */
-       char            *path;          /* Proxy path */
-       char            *uuid128;       /* UUID 128 */
-       char            *address;       /* TTY or Unix socket name */
-       char            *owner;         /* Application bus name */
-       guint           watch;          /* Application watch */
-       short int       port;           /* TCP port */
-       proxy_type_t    type;           /* TTY or Unix socket */
-       struct termios  sys_ti;         /* Default TTY setting */
-       struct termios  proxy_ti;       /* Proxy TTY settings */
-       uint8_t         channel;        /* RFCOMM channel */
-       uint32_t        record_id;      /* Service record id */
-       GIOChannel      *io;            /* Server listen */
-       GIOChannel      *rfcomm;        /* Remote RFCOMM channel*/
-       GIOChannel      *local;         /* Local channel: TTY or Unix socket */
-       struct serial_adapter *adapter; /* Adapter pointer */
-};
-
-static GSList *adapters = NULL;
-static int sk_counter = 0;
-
-static void disable_proxy(struct serial_proxy *prx)
-{
-       if (prx->rfcomm) {
-               g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-               g_io_channel_unref(prx->rfcomm);
-               prx->rfcomm = NULL;
-       }
-
-       if (prx->local) {
-               g_io_channel_shutdown(prx->local, TRUE, NULL);
-               g_io_channel_unref(prx->local);
-               prx->local = NULL;
-       }
-
-       remove_record_from_server(prx->record_id);
-       prx->record_id = 0;
-
-       g_io_channel_unref(prx->io);
-       prx->io = NULL;
-}
-
-static void proxy_free(struct serial_proxy *prx)
-{
-       g_free(prx->owner);
-       g_free(prx->path);
-       g_free(prx->address);
-       g_free(prx->uuid128);
-       g_free(prx);
-}
-
-static sdp_record_t *proxy_record_new(const char *uuid128, uint8_t channel)
-{
-       sdp_list_t *apseq, *aproto, *profiles, *proto[2], *root, *svclass_id;
-       uuid_t uuid, root_uuid, l2cap, rfcomm;
-       sdp_profile_desc_t profile;
-       sdp_record_t *record;
-       sdp_data_t *ch;
-
-       record = sdp_record_alloc();
-       if (!record)
-               return NULL;
-
-       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
-       root = sdp_list_append(NULL, &root_uuid);
-       sdp_set_browse_groups(record, root);
-       sdp_list_free(root, NULL);
-
-       bt_string2uuid(&uuid, uuid128);
-       sdp_uuid128_to_uuid(&uuid);
-       svclass_id = sdp_list_append(NULL, &uuid);
-       sdp_set_service_classes(record, svclass_id);
-       sdp_list_free(svclass_id, NULL);
-
-       sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
-       profile.version = 0x0100;
-       profiles = sdp_list_append(NULL, &profile);
-       sdp_set_profile_descs(record, profiles);
-       sdp_list_free(profiles, NULL);
-
-       sdp_uuid16_create(&l2cap, L2CAP_UUID);
-       proto[0] = sdp_list_append(NULL, &l2cap);
-       apseq = sdp_list_append(NULL, proto[0]);
-
-       sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
-       proto[1] = sdp_list_append(NULL, &rfcomm);
-       ch = sdp_data_alloc(SDP_UINT8, &channel);
-       proto[1] = sdp_list_append(proto[1], ch);
-       apseq = sdp_list_append(apseq, proto[1]);
-
-       aproto = sdp_list_append(NULL, apseq);
-       sdp_set_access_protos(record, aproto);
-
-       sdp_add_lang_attr(record);
-
-       sdp_set_info_attr(record, "Serial Proxy", NULL, "Serial Proxy");
-
-       sdp_data_free(ch);
-       sdp_list_free(proto[0], NULL);
-       sdp_list_free(proto[1], NULL);
-       sdp_list_free(apseq, NULL);
-       sdp_list_free(aproto, NULL);
-
-       return record;
-}
-
-static int channel_write(GIOChannel *chan, char *buf, size_t size)
-{
-       size_t wbytes;
-       ssize_t written;
-       int fd;
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       wbytes = 0;
-       while (wbytes < size) {
-               written = write(fd, buf + wbytes, size - wbytes);
-               if (written < 0)
-                       return -errno;
-
-               wbytes += written;
-       }
-
-       return 0;
-}
-
-static gboolean forward_data(GIOChannel *chan, GIOCondition cond, gpointer data)
-{
-       char buf[BUF_SIZE];
-       struct serial_proxy *prx = data;
-       GIOChannel *dest;
-       ssize_t rbytes;
-       int fd, err;
-
-       if (cond & G_IO_NVAL)
-               return FALSE;
-
-       dest = (chan == prx->rfcomm) ? prx->local : prx->rfcomm;
-
-       fd = g_io_channel_unix_get_fd(chan);
-
-       if (cond & (G_IO_HUP | G_IO_ERR)) {
-               /* Try forward remaining data */
-               do {
-                       rbytes = read(fd, buf, sizeof(buf));
-                       if (rbytes <= 0)
-                               break;
-
-                       err = channel_write(dest, buf, rbytes);
-               } while (err == 0);
-
-               g_io_channel_shutdown(prx->local, TRUE, NULL);
-               g_io_channel_unref(prx->local);
-               prx->local = NULL;
-
-               g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-               g_io_channel_unref(prx->rfcomm);
-               prx->rfcomm = NULL;
-
-               return FALSE;
-       }
-
-       rbytes = read(fd, buf, sizeof(buf));
-       if (rbytes < 0)
-               return FALSE;
-
-       err = channel_write(dest, buf, rbytes);
-       if (err != 0)
-               return FALSE;
-
-       return TRUE;
-}
-
-static inline int unix_socket_connect(const char *address)
-{
-       struct sockaddr_un addr;
-       int err, sk;
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sun_family = PF_UNIX;
-
-       if (strncmp("x00", address, 3) == 0) {
-               /*
-                * Abstract namespace: first byte NULL, x00
-                * must be removed from the original address.
-                */
-               strncpy(addr.sun_path + 1, address + 3,
-                                               sizeof(addr.sun_path) - 2);
-       } else {
-               /* Filesystem address */
-               strncpy(addr.sun_path, address, sizeof(addr.sun_path) - 1);
-       }
-
-       /* Unix socket */
-       sk = socket(AF_UNIX, SOCK_STREAM, 0);
-       if (sk < 0) {
-               err = -errno;
-               error("Unix socket(%s) create failed: %s(%d)",
-                               address, strerror(-err), -err);
-               return err;
-       }
-
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               error("Unix socket(%s) connect failed: %s(%d)",
-                               address, strerror(-err), -err);
-               close(sk);
-               return err;
-       }
-
-       return sk;
-}
-
-static int tcp_socket_connect(const char *address)
-{
-       struct sockaddr_in addr;
-       int err, sk, port;
-
-       memset(&addr, 0, sizeof(addr));
-
-       if (strncmp(address, "localhost", 9) != 0) {
-               error("Address should have the form localhost:port.");
-               return -1;
-       }
-       port = atoi(strchr(address, ':') + 1);
-       if (port <= 0) {
-               error("Invalid port '%d'.", port);
-               return -1;
-       }
-       addr.sin_family = AF_INET;
-       addr.sin_addr.s_addr = inet_addr("127.0.0.1");
-       addr.sin_port = htons(port);
-
-       sk = socket(PF_INET, SOCK_STREAM, 0);
-       if (sk < 0) {
-               err = -errno;
-               error("TCP socket(%s) create failed %s(%d)", address,
-                                                       strerror(-err), -err);
-               return err;
-       }
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               err = -errno;
-               error("TCP socket(%s) connect failed: %s(%d)",
-                                               address, strerror(-err), -err);
-               close(sk);
-               return err;
-       }
-       return sk;
-}
-
-static inline int tty_open(const char *tty, struct termios *ti)
-{
-       int err, sk;
-
-       sk = open(tty, O_RDWR | O_NOCTTY);
-       if (sk < 0) {
-               err = -errno;
-               error("Can't open TTY %s: %s(%d)", tty, strerror(-err), -err);
-               return err;
-       }
-
-       if (ti && tcsetattr(sk, TCSANOW, ti) < 0) {
-               err = -errno;
-               error("Can't change serial settings: %s(%d)",
-                               strerror(-err), -err);
-               close(sk);
-               return err;
-       }
-
-       return sk;
-}
-
-static void connect_event_cb(GIOChannel *chan, GError *conn_err, gpointer data)
-{
-       struct serial_proxy *prx = data;
-       int sk;
-
-       if (conn_err) {
-               error("%s", conn_err->message);
-               goto drop;
-       }
-
-       /* Connect local */
-       switch (prx->type) {
-       case UNIX_SOCKET_PROXY:
-               sk = unix_socket_connect(prx->address);
-               break;
-       case TTY_PROXY:
-               sk = tty_open(prx->address, &prx->proxy_ti);
-               break;
-       case TCP_SOCKET_PROXY:
-               sk = tcp_socket_connect(prx->address);
-               break;
-       default:
-               sk = -1;
-       }
-
-       if (sk < 0)
-               goto drop;
-
-       prx->local = g_io_channel_unix_new(sk);
-
-       g_io_add_watch(prx->rfcomm,
-                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                       forward_data, prx);
-
-       g_io_add_watch(prx->local,
-                       G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
-                       forward_data, prx);
-
-       return;
-
-drop:
-       g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-       g_io_channel_unref(prx->rfcomm);
-       prx->rfcomm = NULL;
-}
-
-static void auth_cb(DBusError *derr, void *user_data)
-{
-       struct serial_proxy *prx = user_data;
-       GError *err = NULL;
-
-       if (derr) {
-               error("Access denied: %s", derr->message);
-               goto reject;
-       }
-
-       if (!bt_io_accept(prx->rfcomm, connect_event_cb, prx, NULL,
-                                                       &err)) {
-               error("bt_io_accept: %s", err->message);
-               g_error_free(err);
-               goto reject;
-       }
-
-       return;
-
-reject:
-       g_io_channel_shutdown(prx->rfcomm, TRUE, NULL);
-       g_io_channel_unref(prx->rfcomm);
-       prx->rfcomm = NULL;
-}
-
-static void confirm_event_cb(GIOChannel *chan, gpointer user_data)
-{
-       struct serial_proxy *prx = user_data;
-       int perr;
-       char address[18];
-       GError *err = NULL;
-
-       bt_io_get(chan, BT_IO_RFCOMM, &err,
-                       BT_IO_OPT_DEST_BDADDR, &prx->dst,
-                       BT_IO_OPT_DEST, address,
-                       BT_IO_OPT_INVALID);
-       if (err) {
-               error("%s", err->message);
-               g_error_free(err);
-               goto drop;
-       }
-
-       if (prx->rfcomm) {
-               error("Refusing connect from %s: Proxy already in use",
-                               address);
-               goto drop;
-       }
-
-       DBG("Serial Proxy: incoming connect from %s", address);
-
-       prx->rfcomm = g_io_channel_ref(chan);
-
-       perr = btd_request_authorization(&prx->src, &prx->dst,
-                                       prx->uuid128, auth_cb, prx);
-       if (perr < 0) {
-               error("Refusing connect from %s: %s (%d)", address,
-                               strerror(-perr), -perr);
-               g_io_channel_unref(prx->rfcomm);
-               prx->rfcomm = NULL;
-               goto drop;
-       }
-
-       return;
-
-drop:
-       g_io_channel_shutdown(chan, TRUE, NULL);
-}
-
-static int enable_proxy(struct serial_proxy *prx)
-{
-       sdp_record_t *record;
-       GError *gerr = NULL;
-       int err;
-
-       if (prx->io)
-               return -EALREADY;
-
-       /* Listen */
-       prx->io = bt_io_listen(BT_IO_RFCOMM, NULL, confirm_event_cb, prx,
-                               NULL, &gerr,
-                               BT_IO_OPT_SOURCE_BDADDR, &prx->src,
-                               BT_IO_OPT_INVALID);
-       if (!prx->io)
-               goto failed;
-
-       bt_io_get(prx->io, BT_IO_RFCOMM, &gerr,
-                       BT_IO_OPT_CHANNEL, &prx->channel,
-                       BT_IO_OPT_INVALID);
-       if (gerr) {
-               g_io_channel_unref(prx->io);
-               prx->io = NULL;
-               goto failed;
-       }
-
-       DBG("Allocated channel %d", prx->channel);
-
-       g_io_channel_set_close_on_unref(prx->io, TRUE);
-
-       record = proxy_record_new(prx->uuid128, prx->channel);
-       if (!record) {
-               g_io_channel_unref(prx->io);
-               return -ENOMEM;
-       }
-
-       err = add_record_to_server(&prx->src, record);
-       if (err < 0) {
-               sdp_record_free(record);
-               g_io_channel_unref(prx->io);
-               return err;
-       }
-
-       prx->record_id = record->handle;
-
-       return 0;
-
-failed:
-       error("%s", gerr->message);
-       g_error_free(gerr);
-       return -EIO;
-
-}
-static DBusMessage *proxy_enable(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_proxy *prx = data;
-       int err;
-
-       err = enable_proxy(prx);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_disable(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_proxy *prx = data;
-
-       if (!prx->io)
-               return btd_error_failed(msg, "Not enabled");
-
-       /* Remove the watches and unregister the record */
-       disable_proxy(prx);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *proxy_get_info(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_proxy *prx = data;
-       DBusMessage *reply;
-       DBusMessageIter iter, dict;
-       dbus_bool_t boolean;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       dict_append_entry(&dict, "uuid", DBUS_TYPE_STRING, &prx->uuid128);
-
-       dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &prx->address);
-
-       if (prx->channel)
-               dict_append_entry(&dict, "channel",
-                                       DBUS_TYPE_BYTE, &prx->channel);
-
-       boolean = (prx->io ? TRUE : FALSE);
-       dict_append_entry(&dict, "enabled", DBUS_TYPE_BOOLEAN, &boolean);
-
-       boolean = (prx->rfcomm ? TRUE : FALSE);
-       dict_append_entry(&dict, "connected", DBUS_TYPE_BOOLEAN, &boolean);
-
-       /* If connected: append the remote address */
-       if (boolean) {
-               char bda[18];
-               const char *pstr = bda;
-
-               ba2str(&prx->dst, bda);
-               dict_append_entry(&dict, "address", DBUS_TYPE_STRING, &pstr);
-       }
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static struct {
-       const char      *str;
-       speed_t         speed;
-} supported_speed[]  = {
-       {"50",          B50     },
-       {"300",         B300    },
-       {"600",         B600    },
-       {"1200",        B1200   },
-       {"1800",        B1800   },
-       {"2400",        B2400   },
-       {"4800",        B4800   },
-       {"9600",        B9600   },
-       {"19200",       B19200  },
-       {"38400",       B38400  },
-       {"57600",       B57600  },
-       {"115200",      B115200 },
-       { NULL,         B0      }
-};
-
-static speed_t str2speed(const char *str, speed_t *speed)
-{
-       int i;
-
-       for (i = 0; supported_speed[i].str; i++) {
-               if (strcmp(supported_speed[i].str, str) != 0)
-                       continue;
-
-               if (speed)
-                       *speed = supported_speed[i].speed;
-
-               return supported_speed[i].speed;
-       }
-
-       return B0;
-}
-
-static int set_parity(const char *str, tcflag_t *ctrl)
-{
-       if (strcasecmp("even", str) == 0) {
-               *ctrl |= PARENB;
-               *ctrl &= ~PARODD;
-       } else if (strcasecmp("odd", str) == 0) {
-               *ctrl |= PARENB;
-               *ctrl |= PARODD;
-       } else if (strcasecmp("mark", str) == 0)
-               *ctrl |= PARENB;
-       else if ((strcasecmp("none", str) == 0) ||
-                       (strcasecmp("space", str) == 0))
-               *ctrl &= ~PARENB;
-       else
-               return -1;
-
-       return 0;
-}
-
-static int set_databits(uint8_t databits, tcflag_t *ctrl)
-{
-       if (databits < 5 || databits > 8)
-               return -EINVAL;
-
-       *ctrl &= ~CSIZE;
-       switch (databits) {
-       case 5:
-               *ctrl |= CS5;
-               break;
-       case 6:
-               *ctrl |= CS6;
-               break;
-       case 7:
-               *ctrl |= CS7;
-               break;
-       case 8:
-               *ctrl |= CS8;
-               break;
-       }
-
-       return 0;
-}
-
-static int set_stopbits(uint8_t stopbits, tcflag_t *ctrl)
-{
-       /* 1.5 will not be allowed */
-       switch (stopbits) {
-       case 1:
-               *ctrl &= ~CSTOPB;
-               return 0;
-       case 2:
-               *ctrl |= CSTOPB;
-               return 0;
-       }
-
-       return -EINVAL;
-}
-
-static DBusMessage *proxy_set_serial_params(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct serial_proxy *prx = data;
-       const char *ratestr, *paritystr;
-       uint8_t databits, stopbits;
-       tcflag_t ctrl;          /* Control mode flags */
-       speed_t speed = B0;     /* In/Out speed */
-
-       /* Don't allow change TTY settings if it is open */
-       if (prx->local)
-               return btd_error_not_authorized(msg);
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &ratestr,
-                               DBUS_TYPE_BYTE, &databits,
-                               DBUS_TYPE_BYTE, &stopbits,
-                               DBUS_TYPE_STRING, &paritystr,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       if (str2speed(ratestr, &speed)  == B0)
-               return btd_error_invalid_args(msg);
-
-       ctrl = prx->proxy_ti.c_cflag;
-       if (set_databits(databits, &ctrl) < 0)
-               return btd_error_invalid_args(msg);
-
-       if (set_stopbits(stopbits, &ctrl) < 0)
-               return btd_error_invalid_args(msg);
-
-       if (set_parity(paritystr, &ctrl) < 0)
-               return btd_error_invalid_args(msg);
-
-       prx->proxy_ti.c_cflag = ctrl;
-       prx->proxy_ti.c_cflag |= (CLOCAL | CREAD);
-       cfsetispeed(&prx->proxy_ti, speed);
-       cfsetospeed(&prx->proxy_ti, speed);
-
-       return dbus_message_new_method_return(msg);
-}
-
-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) },
-       { },
-};
-
-static void proxy_path_unregister(gpointer data)
-{
-       struct serial_proxy *prx = data;
-       int sk;
-
-       DBG("Unregistered proxy: %s", prx->address);
-
-       if (prx->type != TTY_PROXY)
-               goto done;
-
-       /* Restore the initial TTY configuration */
-       sk = open(prx->address, O_RDWR | O_NOCTTY);
-       if (sk >= 0) {
-               tcsetattr(sk, TCSAFLUSH, &prx->sys_ti);
-               close(sk);
-       }
-done:
-
-       proxy_free(prx);
-}
-
-static int register_proxy_object(struct serial_proxy *prx)
-{
-       struct serial_adapter *adapter = prx->adapter;
-       char path[MAX_PATH_LENGTH + 1];
-
-       snprintf(path, MAX_PATH_LENGTH, "%s/proxy%d",
-                       adapter_get_path(adapter->btd_adapter), sk_counter++);
-
-       if (!g_dbus_register_interface(adapter->conn, path,
-                                       SERIAL_PROXY_INTERFACE,
-                                       proxy_methods, NULL, NULL,
-                                       prx, proxy_path_unregister)) {
-               error("D-Bus failed to register %s path", path);
-               return -1;
-       }
-
-       prx->path = g_strdup(path);
-       adapter->proxies = g_slist_append(adapter->proxies, prx);
-
-       DBG("Registered proxy: %s", path);
-
-       return 0;
-}
-
-static int proxy_tty_register(struct serial_adapter *adapter,
-                               const char *uuid128, const char *address,
-                               struct termios *ti,
-                               struct serial_proxy **proxy)
-{
-       struct termios sys_ti;
-       struct serial_proxy *prx;
-       int sk, ret;
-
-       sk = open(address, O_RDONLY | O_NOCTTY);
-       if (sk < 0) {
-               error("Can't open TTY: %s(%d)", strerror(errno), errno);
-               return -EINVAL;
-       }
-
-       prx = g_new0(struct serial_proxy, 1);
-       prx->address = g_strdup(address);
-       prx->uuid128 = g_strdup(uuid128);
-       prx->type = TTY_PROXY;
-       adapter_get_address(adapter->btd_adapter, &prx->src);
-       prx->adapter = adapter;
-
-       /* Current TTY settings */
-       memset(&sys_ti, 0, sizeof(sys_ti));
-       tcgetattr(sk, &sys_ti);
-       memcpy(&prx->sys_ti, &sys_ti, sizeof(sys_ti));
-       close(sk);
-
-       if (!ti) {
-               /* Use current settings */
-               memcpy(&prx->proxy_ti, &sys_ti, sizeof(sys_ti));
-       } else {
-               /* New TTY settings: user provided */
-               memcpy(&prx->proxy_ti, ti, sizeof(*ti));
-       }
-
-       ret = register_proxy_object(prx);
-       if (ret < 0) {
-               proxy_free(prx);
-               return ret;
-       }
-
-       *proxy = prx;
-
-       return ret;
-}
-
-static int proxy_socket_register(struct serial_adapter *adapter,
-                               const char *uuid128, const char *address,
-                               struct serial_proxy **proxy)
-{
-       struct serial_proxy *prx;
-       int ret;
-
-       prx = g_new0(struct serial_proxy, 1);
-       prx->address = g_strdup(address);
-       prx->uuid128 = g_strdup(uuid128);
-       prx->type = UNIX_SOCKET_PROXY;
-       adapter_get_address(adapter->btd_adapter, &prx->src);
-       prx->adapter = adapter;
-
-       ret = register_proxy_object(prx);
-       if (ret < 0) {
-               proxy_free(prx);
-               return ret;
-       }
-
-       *proxy = prx;
-
-       return ret;
-}
-
-static int proxy_tcp_register(struct serial_adapter *adapter,
-                               const char *uuid128, const char *address,
-                               struct serial_proxy **proxy)
-{
-       struct serial_proxy *prx;
-       int ret;
-
-       prx = g_new0(struct serial_proxy, 1);
-       prx->address = g_strdup(address);
-       prx->uuid128 = g_strdup(uuid128);
-       prx->type = TCP_SOCKET_PROXY;
-       adapter_get_address(adapter->btd_adapter, &prx->src);
-       prx->adapter = adapter;
-
-       ret = register_proxy_object(prx);
-       if (ret < 0) {
-               proxy_free(prx);
-               return ret;
-       }
-
-       *proxy = prx;
-
-       return ret;
-}
-
-static proxy_type_t addr2type(const char *address)
-{
-       struct stat st;
-
-       if (stat(address, &st) < 0) {
-               /*
-                * Unix socket: if the sun_path starts with null byte
-                * it refers to abstract namespace. 'x00' will be used
-                * to represent the null byte.
-                */
-               if (strncmp("localhost:", address, 10) == 0)
-                       return TCP_SOCKET_PROXY;
-               if (strncmp("x00", address, 3) != 0)
-                       return UNKNOWN_PROXY_TYPE;
-               else
-                       return UNIX_SOCKET_PROXY;
-       } else {
-               /* Filesystem: char device or unix socket */
-               if (S_ISCHR(st.st_mode) && strncmp("/dev/", address, 4) == 0)
-                       return TTY_PROXY;
-               else if (S_ISSOCK(st.st_mode))
-                       return UNIX_SOCKET_PROXY;
-               else
-                       return UNKNOWN_PROXY_TYPE;
-       }
-}
-
-static int proxy_addrcmp(gconstpointer proxy, gconstpointer addr)
-{
-       const struct serial_proxy *prx = proxy;
-       const char *address = addr;
-
-       return strcmp(prx->address, address);
-}
-
-static int proxy_pathcmp(gconstpointer proxy, gconstpointer p)
-{
-       const struct serial_proxy *prx = proxy;
-       const char *path = p;
-
-       return strcmp(prx->path, path);
-}
-
-static int register_proxy(struct serial_adapter *adapter,
-                               const char *uuid_str, const char *address,
-                               struct serial_proxy **proxy)
-{
-       proxy_type_t type;
-       int err;
-
-       type = addr2type(address);
-       if (type == UNKNOWN_PROXY_TYPE)
-               return -EINVAL;
-
-       /* Only one proxy per address(TTY or unix socket) is allowed */
-       if (g_slist_find_custom(adapter->proxies, address, proxy_addrcmp))
-               return -EALREADY;
-
-       switch (type) {
-       case UNIX_SOCKET_PROXY:
-               err = proxy_socket_register(adapter, uuid_str, address, proxy);
-               break;
-       case TTY_PROXY:
-               err = proxy_tty_register(adapter, uuid_str, address, NULL,
-                                       proxy);
-               break;
-       case TCP_SOCKET_PROXY:
-               err = proxy_tcp_register(adapter, uuid_str, address, proxy);
-               break;
-       default:
-               err = -EINVAL;
-       }
-
-       if (err < 0)
-               return err;
-
-       g_dbus_emit_signal(adapter->conn,
-                               adapter_get_path(adapter->btd_adapter),
-                               SERIAL_MANAGER_INTERFACE, "ProxyCreated",
-                               DBUS_TYPE_STRING, &(*proxy)->path,
-                               DBUS_TYPE_INVALID);
-
-       return 0;
-}
-
-static void unregister_proxy(struct serial_proxy *proxy)
-{
-       struct serial_adapter *adapter = proxy->adapter;
-       char *path = g_strdup(proxy->path);
-
-       if (proxy->watch > 0)
-               g_dbus_remove_watch(adapter->conn, proxy->watch);
-
-       g_dbus_emit_signal(adapter->conn,
-                       adapter_get_path(adapter->btd_adapter),
-                       SERIAL_MANAGER_INTERFACE, "ProxyRemoved",
-                       DBUS_TYPE_STRING, &path,
-                       DBUS_TYPE_INVALID);
-
-       adapter->proxies = g_slist_remove(adapter->proxies, proxy);
-
-       g_dbus_unregister_interface(adapter->conn, path,
-                                       SERIAL_PROXY_INTERFACE);
-
-       g_free(path);
-}
-
-static void watch_proxy(DBusConnection *connection, void *user_data)
-{
-       struct serial_proxy *proxy = user_data;
-
-       proxy->watch = 0;
-       unregister_proxy(proxy);
-}
-
-static DBusMessage *create_proxy(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_adapter *adapter = data;
-       struct serial_proxy *proxy;
-       const char *pattern, *address;
-       char *uuid_str;
-       int err;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &pattern,
-                               DBUS_TYPE_STRING, &address,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       uuid_str = bt_name2string(pattern);
-       if (!uuid_str)
-               return btd_error_invalid_args(msg);
-
-       err = register_proxy(adapter, uuid_str, address, &proxy);
-       g_free(uuid_str);
-
-       if (err == -EINVAL)
-               return btd_error_invalid_args(msg);
-       else if (err == -EALREADY)
-               return btd_error_already_exists(msg);
-       else if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       proxy->owner = g_strdup(dbus_message_get_sender(msg));
-       proxy->watch = g_dbus_add_disconnect_watch(conn, proxy->owner,
-                                               watch_proxy,
-                                               proxy, NULL);
-
-       return g_dbus_create_reply(msg, DBUS_TYPE_STRING, &proxy->path,
-                                       DBUS_TYPE_INVALID);
-}
-
-static DBusMessage *list_proxies(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_adapter *adapter = data;
-       const GSList *l;
-       DBusMessage *reply;
-       DBusMessageIter iter, iter_array;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_TYPE_STRING_AS_STRING, &iter_array);
-
-       for (l = adapter->proxies; l; l = l->next) {
-               struct serial_proxy *prx = l->data;
-
-               dbus_message_iter_append_basic(&iter_array,
-                               DBUS_TYPE_STRING, &prx->path);
-       }
-
-       dbus_message_iter_close_container(&iter, &iter_array);
-
-       return reply;
-}
-
-static DBusMessage *remove_proxy(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
-{
-       struct serial_adapter *adapter = data;
-       struct serial_proxy *prx;
-       const char *path, *sender;
-       GSList *l;
-
-       if (!dbus_message_get_args(msg, NULL,
-                               DBUS_TYPE_STRING, &path,
-                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       l = g_slist_find_custom(adapter->proxies, path, proxy_pathcmp);
-       if (!l)
-               return btd_error_does_not_exist(msg);
-
-       prx = l->data;
-
-       sender = dbus_message_get_sender(msg);
-       if (g_strcmp0(prx->owner, sender) != 0)
-               return btd_error_not_authorized(msg);
-
-       unregister_proxy(prx);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static void manager_path_unregister(void *data)
-{
-       struct serial_adapter *adapter = data;
-       GSList *l;
-
-       /* Remove proxy objects */
-       for (l = adapter->proxies; l; l = l->next) {
-               struct serial_proxy *prx = l->data;
-               char *path = g_strdup(prx->path);
-
-               g_dbus_unregister_interface(adapter->conn, path,
-                                       SERIAL_PROXY_INTERFACE);
-               g_free(path);
-       }
-
-       if (adapter->conn)
-               dbus_connection_unref(adapter->conn);
-
-       adapters = g_slist_remove(adapters, adapter);
-       g_slist_free(adapter->proxies);
-       btd_adapter_unref(adapter->btd_adapter);
-       g_free(adapter);
-}
-
-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 const GDBusSignalTable manager_signals[] = {
-       { GDBUS_SIGNAL("ProxyCreated", GDBUS_ARGS({ "path", "s" })) },
-       { GDBUS_SIGNAL("ProxyRemoved", GDBUS_ARGS({ "path", "s" })) },
-       { }
-};
-
-static struct serial_adapter *find_adapter(GSList *list,
-                                       struct btd_adapter *btd_adapter)
-{
-       for (; list; list = list->next) {
-               struct serial_adapter *adapter = list->data;
-
-               if (adapter->btd_adapter == btd_adapter)
-                       return adapter;
-       }
-
-       return NULL;
-}
-
-static void serial_proxy_init(struct serial_adapter *adapter)
-{
-       GKeyFile *config;
-       GError *gerr = NULL;
-       const char *file = CONFIGDIR "/serial.conf";
-       char **group_list;
-       int i;
-
-       config = g_key_file_new();
-
-       if (!g_key_file_load_from_file(config, file, 0, &gerr)) {
-               error("Parsing %s failed: %s", file, gerr->message);
-               g_error_free(gerr);
-               g_key_file_free(config);
-               return;
-       }
-
-       group_list = g_key_file_get_groups(config, NULL);
-
-       for (i = 0; group_list[i] != NULL; i++) {
-               char *group_str = group_list[i], *uuid_str, *address;
-               int err;
-               struct serial_proxy *prx;
-
-               /* string length of "Proxy" is 5 */
-               if (strlen(group_str) < 5 || strncmp(group_str, "Proxy", 5))
-                       continue;
-
-               uuid_str = g_key_file_get_string(config, group_str, "UUID",
-                                                                       &gerr);
-               if (gerr) {
-                       DBG("%s: %s", file, gerr->message);
-                       g_error_free(gerr);
-                       g_key_file_free(config);
-                       g_strfreev(group_list);
-                       return;
-               }
-
-               address = g_key_file_get_string(config, group_str, "Address",
-                                                                       &gerr);
-               if (gerr) {
-                       DBG("%s: %s", file, gerr->message);
-                       g_error_free(gerr);
-                       g_key_file_free(config);
-                       g_free(uuid_str);
-                       g_strfreev(group_list);
-                       return;
-               }
-
-               err = register_proxy(adapter, uuid_str, address, &prx);
-               if (err == -EINVAL)
-                       error("Invalid address.");
-               else if (err == -EALREADY)
-                       DBG("Proxy already exists.");
-               else if (err < 0)
-                       error("Proxy creation failed (%s)", strerror(-err));
-               else {
-                       err = enable_proxy(prx);
-                       if (err < 0)
-                               error("Proxy enable failed (%s)",
-                                               strerror(-err));
-               }
-
-               g_free(uuid_str);
-               g_free(address);
-       }
-
-       g_strfreev(group_list);
-       g_key_file_free(config);
-}
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter)
-{
-       struct serial_adapter *adapter;
-       const char *path;
-
-       adapter = find_adapter(adapters, btd_adapter);
-       if (adapter)
-               return -EINVAL;
-
-       adapter = g_new0(struct serial_adapter, 1);
-       adapter->conn = dbus_connection_ref(conn);
-       adapter->btd_adapter = btd_adapter_ref(btd_adapter);
-
-       path = adapter_get_path(btd_adapter);
-
-       if (!g_dbus_register_interface(conn, path,
-                                       SERIAL_MANAGER_INTERFACE,
-                                       manager_methods, manager_signals, NULL,
-                                       adapter, manager_path_unregister)) {
-               error("Failed to register %s interface to %s",
-                               SERIAL_MANAGER_INTERFACE, path);
-               return -1;
-       }
-
-       adapters = g_slist_append(adapters, adapter);
-
-       DBG("Registered interface %s on path %s",
-               SERIAL_MANAGER_INTERFACE, path);
-
-       serial_proxy_init(adapter);
-
-       return 0;
-}
-
-void proxy_unregister(struct btd_adapter *btd_adapter)
-{
-       struct serial_adapter *adapter;
-
-       adapter = find_adapter(adapters, btd_adapter);
-       if (!adapter)
-               return;
-
-       g_dbus_unregister_interface(adapter->conn,
-                       adapter_get_path(btd_adapter),
-                       SERIAL_MANAGER_INTERFACE);
-}
diff --git a/serial/proxy.h b/serial/proxy.h
deleted file mode 100644 (file)
index 7871665..0000000
+++ /dev/null
@@ -1,25 +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
- *
- */
-
-int proxy_register(DBusConnection *conn, struct btd_adapter *btd_adapter);
-void proxy_unregister(struct btd_adapter *btd_adapter);
diff --git a/serial/serial.conf b/serial/serial.conf
deleted file mode 100644 (file)
index 43ee6af..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-# Configuration file for serial
-
-# There could be multiple proxy sections, the format is [Proxy <user chosen name>]
-#[Proxy DUN]
-
-# UUID for DUN proxy service
-#UUID=00001103-0000-1000-8000-00805F9B34FB
-
-# Address for device node
-#Address=/dev/ttyx
index f922876..40a9c4e 100644 (file)
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <sys/ioctl.h>
+#include <sys/file.h>
+#include <sys/stat.h>
+#include <dirent.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
+#include <bluetooth/hci.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 #include "textfile.h"
 
+#include "lib/uuid.h"
+#include "lib/mgmt.h"
+#include "src/shared/mgmt.h"
+
 #include "hcid.h"
 #include "sdpd.h"
 #include "adapter.h"
-#include "manager.h"
 #include "device.h"
+#include "profile.h"
 #include "dbus-common.h"
 #include "error.h"
 #include "glib-helper.h"
 #include "agent.h"
 #include "storage.h"
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
 #include "attrib-server.h"
 #include "eir.h"
 
+#define ADAPTER_INTERFACE      "org.bluez.Adapter1"
+
 /* Flags Descriptions */
 #define EIR_LIM_DISC                0x01 /* LE Limited Discoverable Mode */
 #define EIR_GEN_DISC                0x02 /* LE General Discoverable Mode */
 #define EIR_SIM_HOST                0x10 /* Simultaneous LE and BR/EDR to Same
                                            Device Capable (Host) */
 
-#define IO_CAPABILITY_DISPLAYONLY      0x00
-#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 MODE_OFF               0x00
+#define MODE_CONNECTABLE       0x01
+#define MODE_DISCOVERABLE      0x02
+#define MODE_UNKNOWN           0xff
 
-#define check_address(address) bachk(address)
+#define CONN_SCAN_TIMEOUT (3)
+#define IDLE_DISCOV_TIMEOUT (5)
+#define TEMP_DEV_TIMEOUT (3 * 60)
+#define BONDING_TIMEOUT (2 * 60)
 
-#define OFF_TIMER 3
+static DBusConnection *dbus_conn = NULL;
 
-static DBusConnection *connection = NULL;
-static GSList *adapter_drivers = NULL;
+static GList *adapter_list = NULL;
+static unsigned int adapter_remaining = 0;
+static bool powering_down = false;
+
+static GSList *adapters = NULL;
 
-static GSList *ops_candidates = NULL;
+static struct mgmt *mgmt_master = NULL;
 
-const struct btd_adapter_ops *adapter_ops = NULL;
+#define MGMT_VERSION(v, r) ((v << 16) + (r))
+static uint8_t mgmt_version = 0;
+static uint8_t mgmt_revision = 0;
 
-struct session_req {
-       struct btd_adapter      *adapter;
-       DBusConnection          *conn;          /* Connection reference */
-       DBusMessage             *msg;           /* Unreplied message ref */
-       char                    *owner;         /* Bus name of the owner */
-       guint                   id;             /* Listener id */
-       uint8_t                 mode;           /* Requested mode */
-       int                     refcount;       /* Session refcount */
-       gboolean                got_reply;      /* Agent reply received */
+static GSList *adapter_drivers = NULL;
+
+struct watch_client {
+       struct btd_adapter *adapter;
+       char *owner;
+       guint watch;
 };
 
 struct service_auth {
+       guint id;
        service_auth_cb cb;
        void *user_data;
+       const char *uuid;
        struct btd_device *device;
        struct btd_adapter *adapter;
+       struct agent *agent;            /* NULL for queued auths */
+};
+
+struct btd_adapter_pin_cb_iter {
+       GSList *it;                     /* current callback function */
+       unsigned int attempt;           /* numer of times it() was called */
+       /* When the iterator reaches the end, it is NULL and attempt is 0 */
 };
 
 struct btd_adapter {
+       int ref_count;
+
        uint16_t dev_id;
-       gboolean up;
+       struct mgmt *mgmt;
+
+       bdaddr_t bdaddr;                /* controller Bluetooth address */
+       uint32_t dev_class;             /* controller class of device */
+       char *name;                     /* controller device name */
+       char *short_name;               /* controller short name */
+       uint32_t supported_settings;    /* controller supported settings */
+       uint32_t current_settings;      /* current controller settings */
+
        char *path;                     /* adapter object path */
-       bdaddr_t bdaddr;                /* adapter Bluetooth Address */
-       uint32_t dev_class;             /* Class of Device */
-       char *name;                     /* adapter name */
-       gboolean allow_name_changes;    /* whether the adapter name can be changed */
-       guint stop_discov_id;           /* stop inquiry/scanning id */
-       uint32_t discov_timeout;        /* discoverable time(sec) */
-       guint pairable_timeout_id;      /* pairable timeout id */
+       uint8_t major_class;            /* configured major class */
+       uint8_t minor_class;            /* configured minor class */
+       char *system_name;              /* configured system name */
+       char *modalias;                 /* device id (modalias) */
+       bool stored_discoverable;       /* stored discoverable mode */
+       uint32_t discoverable_timeout;  /* discoverable time(sec) */
        uint32_t pairable_timeout;      /* pairable time(sec) */
-       uint8_t scan_mode;              /* scan mode: SCAN_DISABLED, SCAN_PAGE,
-                                        * SCAN_INQUIRY */
-       uint8_t mode;                   /* off, connectable, discoverable,
-                                        * limited */
-       uint8_t global_mode;            /* last valid global mode */
-       struct session_req *pending_mode;
-       int state;                      /* standard inq, periodic inq, name
-                                        * resolving, suspended discovery */
-       GSList *found_devices;
-       GSList *oor_devices;            /* out of range device list */
-       struct agent *agent;            /* For the new API */
-       guint auth_idle_id;             /* Ongoing authorization */
+
+       char *current_alias;            /* current adapter name alias */
+       char *stored_alias;             /* stored adapter name alias */
+
+       bool discovering;               /* discovering property state */
+       uint8_t discovery_type;         /* current active discovery type */
+       uint8_t discovery_enable;       /* discovery enabled/disabled */
+       bool discovery_suspended;       /* discovery has been suspended */
+       GSList *discovery_list;         /* list of discovery clients */
+       GSList *discovery_found;        /* list of found devices */
+       guint discovery_idle_timeout;   /* timeout between discovery runs */
+       guint passive_scan_timeout;     /* timeout between passive scans */
+       guint temp_devices_timeout;     /* timeout for temporary devices */
+
+       guint pairable_timeout_id;      /* pairable timeout id */
+       guint auth_idle_id;             /* Pending authorization dequeue */
+       GQueue *auths;                  /* Ongoing and pending auths */
+       bool pincode_requested;         /* PIN requested during last bonding */
        GSList *connections;            /* Connected devices */
        GSList *devices;                /* Devices structure pointers */
-       GSList *mode_sessions;          /* Request Mode sessions */
-       GSList *disc_sessions;          /* Discovery sessions */
-       guint discov_id;                /* Discovery timer */
-       gboolean discovering;           /* Discovery active */
-       gboolean discov_suspended;      /* Discovery suspended */
-       guint auto_timeout_id;          /* Automatic connections timeout */
+       GSList *connect_list;           /* Devices to connect when found */
+       struct btd_device *connect_le;  /* LE device waiting to be connected */
        sdp_list_t *services;           /* Services associated to adapter */
 
-       gboolean pairable;              /* pairable state */
        gboolean initialized;
 
-       gboolean off_requested;         /* DEVDOWN ioctl was called */
+       GSList *pin_callbacks;
+
+       GSList *drivers;
+       GSList *profiles;
 
-       gint ref;
+       struct oob_handler *oob_handler;
 
-       guint off_timer;
+       unsigned int load_ltks_id;
+       guint load_ltks_timeout;
 
-       GSList *powered_callbacks;
-       GSList *pin_callbacks;
+       unsigned int confirm_name_id;
+       guint confirm_name_timeout;
 
-       GSList *loaded_drivers;
+       unsigned int pair_device_id;
+       guint pair_device_timeout;
+
+       bool is_default;                /* true if adapter is default one */
 };
 
-static void dev_info_free(void *data)
+static struct btd_adapter *btd_adapter_lookup(uint16_t index)
 {
-       struct remote_dev_info *dev = data;
+       GList *list;
 
-       g_free(dev->name);
-       g_free(dev->alias);
-       g_slist_free_full(dev->services, g_free);
-       g_strfreev(dev->uuids);
-       g_free(dev);
-}
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
 
-int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
-                                                       uint8_t minor)
-{
-       return adapter_ops->set_dev_class(adapter->dev_id, major, minor);
+               if (adapter->dev_id == index)
+                       return adapter;
+       }
+
+       return NULL;
 }
 
-static const char *mode2str(uint8_t mode)
+struct btd_adapter *btd_adapter_get_default(void)
 {
-       switch(mode) {
-       case MODE_OFF:
-               return "off";
-       case MODE_CONNECTABLE:
-               return "connectable";
-       case MODE_DISCOVERABLE:
-               return "discoverable";
-       default:
-               return "unknown";
+       GList *list;
+
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
+
+               if (adapter->is_default)
+                       return adapter;
        }
+
+       return NULL;
 }
 
-static uint8_t get_mode(const bdaddr_t *bdaddr, const char *mode)
+bool btd_adapter_is_default(struct btd_adapter *adapter)
 {
-       if (strcasecmp("off", mode) == 0)
-               return MODE_OFF;
-       else if (strcasecmp("connectable", mode) == 0)
-               return MODE_CONNECTABLE;
-       else if (strcasecmp("discoverable", mode) == 0)
-               return MODE_DISCOVERABLE;
-       else if (strcasecmp("on", mode) == 0) {
-               char onmode[14], srcaddr[18];
-
-               ba2str(bdaddr, srcaddr);
-               if (read_on_mode(srcaddr, onmode, sizeof(onmode)) < 0)
-                       return MODE_CONNECTABLE;
+       if (!adapter)
+               return false;
 
-               return get_mode(bdaddr, onmode);
-       } else
-               return MODE_UNKNOWN;
+       return adapter->is_default;
 }
 
-static struct session_req *session_ref(struct session_req *req)
+uint16_t btd_adapter_get_index(struct btd_adapter *adapter)
 {
-       req->refcount++;
-
-       DBG("%p: ref=%d", req, req->refcount);
+       if (!adapter)
+               return MGMT_INDEX_NONE;
 
-       return req;
+       return adapter->dev_id;
 }
 
-static struct session_req *create_session(struct btd_adapter *adapter,
-                                       DBusConnection *conn, DBusMessage *msg,
-                                       uint8_t mode, GDBusWatchFunction cb)
+static gboolean process_auth_queue(gpointer user_data);
+
+static void dev_class_changed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       const char *sender = dbus_message_get_sender(msg);
-       struct session_req *req;
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cod *rp = param;
+       uint8_t appearance[3];
+       uint32_t dev_class;
 
-       req = g_new0(struct session_req, 1);
-       req->adapter = adapter;
-       req->conn = dbus_connection_ref(conn);
-       req->msg = dbus_message_ref(msg);
-       req->mode = mode;
+       if (length < sizeof(*rp)) {
+               error("Wrong size of class of device changed parameters");
+               return;
+       }
 
-       if (cb == NULL)
-               return session_ref(req);
+       dev_class = rp->val[0] | (rp->val[1] << 8) | (rp->val[2] << 16);
 
-       req->owner = g_strdup(sender);
-       req->id = g_dbus_add_disconnect_watch(conn, sender, cb, req, NULL);
+       if (dev_class == adapter->dev_class)
+               return;
 
-       info("%s session %p with %s activated",
-               req->mode ? "Mode" : "Discovery", req, sender);
+       DBG("Class: 0x%06x", dev_class);
 
-       return session_ref(req);
-}
+       adapter->dev_class = dev_class;
 
-static int adapter_set_mode(struct btd_adapter *adapter, uint8_t mode)
-{
-       int err;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Class");
 
-       if (mode == MODE_CONNECTABLE)
-               err = adapter_ops->set_discoverable(adapter->dev_id, FALSE, 0);
-       else
-               err = adapter_ops->set_discoverable(adapter->dev_id, TRUE,
-                                               adapter->discov_timeout);
+       appearance[0] = rp->val[0];
+       appearance[1] = rp->val[1] & 0x1f;      /* removes service class */
+       appearance[2] = rp->val[2];
 
-       return err;
+       attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, appearance, 2);
 }
 
-static struct session_req *find_session_by_msg(GSList *list, const DBusMessage *msg)
+static void set_dev_class_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       for (; list; list = list->next) {
-               struct session_req *req = list->data;
+       struct btd_adapter *adapter = user_data;
 
-               if (req->msg == msg)
-                       return req;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set device class: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       return NULL;
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
 }
 
-static int set_mode(struct btd_adapter *adapter, uint8_t new_mode,
-                       DBusMessage *msg)
+static void set_dev_class(struct btd_adapter *adapter)
 {
-       int err;
-       const char *modestr;
+       struct mgmt_cp_set_dev_class cp;
 
-       if (adapter->pending_mode != NULL)
-               return -EALREADY;
+       /*
+        * If the controller does not support BR/EDR operation,
+        * there is no point in trying to set a major and minor
+        * class value.
+        *
+        * This is an optimization for Low Energy only controllers.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
+               return;
 
-       if (!adapter->up && new_mode != MODE_OFF) {
-               err = adapter_ops->set_powered(adapter->dev_id, TRUE);
-               if (err < 0)
-                       return err;
+       memset(&cp, 0, sizeof(cp));
 
-               goto done;
-       }
+       /*
+        * Silly workaround for a really stupid kernel bug :(
+        *
+        * All current kernel versions assign the major and minor numbers
+        * straight to dev_class[0] and dev_class[1] without considering
+        * the proper bit shifting.
+        *
+        * To make this work, shift the value in userspace for now until
+        * we get a fixed kernel version.
+        */
+       cp.major = adapter->major_class & 0x1f;
+       cp.minor = adapter->minor_class << 2;
 
-       if (adapter->up && new_mode == MODE_OFF) {
-               err = adapter_ops->set_powered(adapter->dev_id, FALSE);
-               if (err < 0)
-                       return err;
+       DBG("sending set device class command for index %u", adapter->dev_id);
 
-               adapter->off_requested = TRUE;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEV_CLASS,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_dev_class_complete, adapter, NULL) > 0)
+               return;
 
-               goto done;
-       }
+       error("Failed to set class of device for index %u", adapter->dev_id);
+}
 
-       if (new_mode == adapter->mode)
-               return 0;
+void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
+                                                       uint8_t minor)
+{
+       if (adapter->major_class == major && adapter->minor_class == minor)
+               return;
 
-       err = adapter_set_mode(adapter, new_mode);
+       DBG("class: major %u minor %u", major, minor);
 
-       if (err < 0)
-               return err;
+       adapter->major_class = major;
+       adapter->minor_class = minor;
 
-done:
-       modestr = mode2str(new_mode);
-       write_device_mode(&adapter->bdaddr, modestr);
-
-       DBG("%s", modestr);
-
-       if (msg != NULL) {
-               struct session_req *req;
-
-               req = find_session_by_msg(adapter->mode_sessions, msg);
-               if (req) {
-                       adapter->pending_mode = req;
-                       session_ref(req);
-               } else
-                       /* Wait for mode change to reply */
-                       adapter->pending_mode = create_session(adapter,
-                                       connection, msg, new_mode, NULL);
-       } else
-               /* Nothing to reply just write the new mode */
-               adapter->mode = new_mode;
+       set_dev_class(adapter);
+}
 
-       return 0;
+static uint8_t get_mode(const char *mode)
+{
+       if (strcasecmp("off", mode) == 0)
+               return MODE_OFF;
+       else if (strcasecmp("connectable", mode) == 0)
+               return MODE_CONNECTABLE;
+       else if (strcasecmp("discoverable", mode) == 0)
+               return MODE_DISCOVERABLE;
+       else
+               return MODE_UNKNOWN;
 }
 
-static DBusMessage *set_discoverable(DBusConnection *conn, DBusMessage *msg,
-                               gboolean discoverable, void *data)
+static void store_adapter_info(struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = data;
-       uint8_t mode;
-       int err;
+       GKeyFile *key_file;
+       char filename[PATH_MAX + 1];
+       char address[18];
+       char *str;
+       gsize length = 0;
+       gboolean discoverable;
 
-       mode = discoverable ? MODE_DISCOVERABLE : MODE_CONNECTABLE;
+       key_file = g_key_file_new();
 
-       if (mode == adapter->mode) {
-               adapter->global_mode = mode;
-               return dbus_message_new_method_return(msg);
-       }
+       if (adapter->pairable_timeout != main_opts.pairto)
+               g_key_file_set_integer(key_file, "General", "PairableTimeout",
+                                       adapter->pairable_timeout);
 
-       err = set_mode(adapter, mode, msg);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       if ((adapter->current_settings & MGMT_SETTING_DISCOVERABLE) &&
+                                               !adapter->discoverable_timeout)
+               discoverable = TRUE;
+       else
+               discoverable = FALSE;
 
-       return NULL;
-}
+       g_key_file_set_boolean(key_file, "General", "Discoverable",
+                                                       discoverable);
 
-static DBusMessage *set_powered(DBusConnection *conn, DBusMessage *msg,
-                               gboolean powered, void *data)
-{
-       struct btd_adapter *adapter = data;
-       uint8_t mode;
-       int err;
+       if (adapter->discoverable_timeout != main_opts.discovto)
+               g_key_file_set_integer(key_file, "General",
+                                       "DiscoverableTimeout",
+                                       adapter->discoverable_timeout);
 
-       if (powered) {
-               mode = get_mode(&adapter->bdaddr, "on");
-               return set_discoverable(conn, msg, mode == MODE_DISCOVERABLE,
-                                                                       data);
-       }
+       if (adapter->stored_alias)
+               g_key_file_set_string(key_file, "General", "Alias",
+                                                       adapter->stored_alias);
 
-       mode = MODE_OFF;
+       ba2str(&adapter->bdaddr, address);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings", address);
+       filename[PATH_MAX] = '\0';
 
-       if (mode == adapter->mode) {
-               adapter->global_mode = mode;
-               return dbus_message_new_method_return(msg);
-       }
+       create_file(filename, S_IRUSR | S_IWUSR);
 
-       err = set_mode(adapter, mode, msg);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
 
-       return NULL;
+       g_key_file_free(key_file);
 }
 
-static DBusMessage *set_pairable(DBusConnection *conn, DBusMessage *msg,
-                               gboolean pairable, void *data)
+static void trigger_pairable_timeout(struct btd_adapter *adapter);
+static void adapter_start(struct btd_adapter *adapter);
+static void adapter_stop(struct btd_adapter *adapter);
+
+static void settings_changed(struct btd_adapter *adapter, uint32_t settings)
 {
-       struct btd_adapter *adapter = data;
-       int err;
+       uint32_t changed_mask;
 
-       if (adapter->scan_mode == SCAN_DISABLED)
-               return btd_error_not_ready(msg);
+       changed_mask = adapter->current_settings ^ settings;
 
-       if (pairable == adapter->pairable)
-               goto done;
+       adapter->current_settings = settings;
 
-       if (!(adapter->scan_mode & SCAN_INQUIRY))
-               goto store;
+       DBG("Changed settings: 0x%08x", changed_mask);
 
-       err = set_mode(adapter, MODE_DISCOVERABLE, NULL);
-       if (err < 0 && msg)
-               return btd_error_failed(msg, strerror(-err));
+       if (changed_mask & MGMT_SETTING_POWERED) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Powered");
 
-store:
-       adapter_ops->set_pairable(adapter->dev_id, pairable);
+               if (adapter->current_settings & MGMT_SETTING_POWERED) {
+                       adapter_start(adapter);
+               } else {
+                       adapter_stop(adapter);
 
-done:
-       return msg ? dbus_message_new_method_return(msg) : NULL;
-}
+                       if (powering_down) {
+                               adapter_remaining--;
 
-static gboolean pairable_timeout_handler(void *data)
-{
-       set_pairable(NULL, NULL, FALSE, data);
+                               if (!adapter_remaining)
+                                       btd_exit();
+                       }
+               }
+       }
 
-       return FALSE;
-}
+       if (changed_mask & MGMT_SETTING_CONNECTABLE)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Connectable");
 
-static void adapter_set_pairable_timeout(struct btd_adapter *adapter,
-                                       guint interval)
-{
-       if (adapter->pairable_timeout_id) {
-               g_source_remove(adapter->pairable_timeout_id);
-               adapter->pairable_timeout_id = 0;
+       if (changed_mask & MGMT_SETTING_DISCOVERABLE) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discoverable");
+
+               store_adapter_info(adapter);
        }
 
-       if (interval == 0)
-               return;
+       if (changed_mask & MGMT_SETTING_PAIRABLE) {
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Pairable");
 
-       adapter->pairable_timeout_id = g_timeout_add_seconds(interval,
-                                               pairable_timeout_handler,
-                                               adapter);
+               trigger_pairable_timeout(adapter);
+       }
 }
 
-void btd_adapter_pairable_changed(struct btd_adapter *adapter,
-                                                       gboolean pairable)
+static void new_settings_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       adapter->pairable = pairable;
+       struct btd_adapter *adapter = user_data;
+       uint32_t settings;
+
+       if (length < sizeof(settings)) {
+               error("Wrong size of new settings parameters");
+               return;
+       }
 
-       write_device_pairable(&adapter->bdaddr, pairable);
+       settings = bt_get_le32(param);
 
-       emit_property_changed(connection, adapter->path,
-                               ADAPTER_INTERFACE, "Pairable",
-                               DBUS_TYPE_BOOLEAN, &pairable);
+       if (settings == adapter->current_settings)
+               return;
+
+       DBG("Settings: 0x%08x", settings);
 
-       if (pairable && adapter->pairable_timeout)
-               adapter_set_pairable_timeout(adapter,
-                                               adapter->pairable_timeout);
+       settings_changed(adapter, settings);
 }
 
-static struct session_req *find_session(GSList *list, const char *sender)
+static void set_mode_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       for (; list; list = list->next) {
-               struct session_req *req = list->data;
+       struct btd_adapter *adapter = user_data;
 
-               if (g_str_equal(req->owner, sender))
-                       return req;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set mode: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
        }
 
-       return NULL;
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       new_settings_callback(adapter->dev_id, length, param, adapter);
 }
 
-static uint8_t get_needed_mode(struct btd_adapter *adapter, uint8_t mode)
+static bool set_mode(struct btd_adapter *adapter, uint16_t opcode,
+                                                       uint8_t mode)
 {
-       GSList *l;
+       struct mgmt_mode cp;
 
-       if (adapter->global_mode > mode)
-               mode = adapter->global_mode;
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
 
-       for (l = adapter->mode_sessions; l; l = l->next) {
-               struct session_req *req = l->data;
+       DBG("sending set mode command for index %u", adapter->dev_id);
 
-               if (req->mode > mode)
-                       mode = req->mode;
-       }
+       if (mgmt_send(adapter->mgmt, opcode,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_mode_complete, adapter, NULL) > 0)
+               return true;
+
+       error("Failed to set mode for index %u", adapter->dev_id);
 
-       return mode;
+       return false;
 }
 
-static GSList *remove_bredr(GSList *all)
+static bool set_discoverable(struct btd_adapter *adapter, uint8_t mode,
+                                                       uint16_t timeout)
 {
-       GSList *l, *le;
+       struct mgmt_cp_set_discoverable cp;
 
-       for (l = all, le = NULL; l; l = l->next) {
-               struct remote_dev_info *dev = l->data;
-               if (dev->bdaddr_type == BDADDR_BREDR) {
-                       dev_info_free(dev);
-                       continue;
-               }
+       memset(&cp, 0, sizeof(cp));
+       cp.val = mode;
+       cp.timeout = htobs(timeout);
 
-               le = g_slist_append(le, dev);
-       }
+       DBG("sending set mode command for index %u", adapter->dev_id);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DISCOVERABLE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_mode_complete, adapter, NULL) > 0)
+               return true;
 
-       g_slist_free(all);
+       error("Failed to set mode for index %u", adapter->dev_id);
 
-       return le;
+       return false;
 }
 
-/* Called when a session gets removed or the adapter is stopped */
-static void stop_discovery(struct btd_adapter *adapter)
+static gboolean pairable_timeout_handler(gpointer user_data)
 {
-       adapter->found_devices = remove_bredr(adapter->found_devices);
+       struct btd_adapter *adapter = user_data;
 
-       if (adapter->oor_devices) {
-               g_slist_free(adapter->oor_devices);
-               adapter->oor_devices = NULL;
-       }
+       adapter->pairable_timeout_id = 0;
 
-       /* Reset if suspended, otherwise remove timer (software scheduler)
-        * or request inquiry to stop */
-       if (adapter->discov_suspended) {
-               adapter->discov_suspended = FALSE;
-               return;
+       set_mode(adapter, MGMT_OP_SET_PAIRABLE, 0x00);
+
+       return FALSE;
+}
+
+static void trigger_pairable_timeout(struct btd_adapter *adapter)
+{
+       if (adapter->pairable_timeout_id > 0) {
+               g_source_remove(adapter->pairable_timeout_id);
+               adapter->pairable_timeout_id = 0;
        }
 
-       if (adapter->discov_id > 0) {
-               g_source_remove(adapter->discov_id);
-               adapter->discov_id = 0;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "PairableTimeout");
+
+       if (!(adapter->current_settings & MGMT_SETTING_PAIRABLE))
                return;
-       }
 
-       if (adapter->up)
-               adapter_ops->stop_discovery(adapter->dev_id);
+       if (adapter->pairable_timeout > 0)
+               g_timeout_add_seconds(adapter->pairable_timeout,
+                                       pairable_timeout_handler, adapter);
 }
 
-static void session_remove(struct session_req *req)
+static void local_name_changed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = req->adapter;
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_set_local_name *rp = param;
 
-       /* Ignore set_mode session */
-       if (req->owner == NULL)
+       if (length < sizeof(*rp)) {
+               error("Wrong size of local name changed parameters");
                return;
+       }
 
-       DBG("%s session %p with %s deactivated",
-               req->mode ? "Mode" : "Discovery", req, req->owner);
-
-       if (req->mode) {
-               uint8_t mode;
-
-               adapter->mode_sessions = g_slist_remove(adapter->mode_sessions,
-                                                       req);
+       if (!g_strcmp0(adapter->short_name, (const char *) rp->short_name) &&
+                       !g_strcmp0(adapter->name, (const char *) rp->name))
+               return;
 
-               mode = get_needed_mode(adapter, adapter->global_mode);
+       DBG("Name: %s", rp->name);
+       DBG("Short name: %s", rp->short_name);
 
-               if (mode == adapter->mode)
-                       return;
+       g_free(adapter->name);
+       adapter->name = g_strdup((const char *) rp->name);
 
-               DBG("Switching to '%s' mode", mode2str(mode));
+       g_free(adapter->short_name);
+       adapter->short_name = g_strdup((const char *) rp->short_name);
 
-               set_mode(adapter, mode, NULL);
+       /*
+        * Changing the name (even manually via HCI) will update the
+        * current alias property.
+        *
+        * In case the name is empty, use the short name.
+        *
+        * There is a difference between the stored alias (which is
+        * configured by the user) and the current alias. The current
+        * alias is temporary for the lifetime of the daemon.
+        */
+       if (adapter->name && adapter->name[0] != '\0') {
+               g_free(adapter->current_alias);
+               adapter->current_alias = g_strdup(adapter->name);
        } else {
-               adapter->disc_sessions = g_slist_remove(adapter->disc_sessions,
-                                                       req);
-
-               if (adapter->disc_sessions)
-                       return;
-
-               DBG("Stopping discovery");
-
-               stop_discovery(adapter);
-       }
-}
-
-static void session_free(void *data)
-{
-       struct session_req *req = data;
-
-       if (req->id)
-               g_dbus_remove_watch(req->conn, req->id);
-
-       if (req->msg) {
-               dbus_message_unref(req->msg);
-               if (!req->got_reply && req->mode && req->adapter->agent)
-                       agent_cancel(req->adapter->agent);
+               g_free(adapter->current_alias);
+               adapter->current_alias = g_strdup(adapter->short_name);
        }
 
-       if (req->conn)
-               dbus_connection_unref(req->conn);
-       g_free(req->owner);
-       g_free(req);
-}
+       DBG("Current alias: %s", adapter->current_alias);
 
-static void session_owner_exit(DBusConnection *conn, void *user_data)
-{
-       struct session_req *req = user_data;
+       if (!adapter->current_alias)
+               return;
 
-       req->id = 0;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Alias");
 
-       session_remove(req);
-       session_free(req);
+       attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
+                               (const uint8_t *) adapter->current_alias,
+                                       strlen(adapter->current_alias));
 }
 
-static void session_unref(struct session_req *req)
+static void set_local_name_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       req->refcount--;
-
-       DBG("%p: ref=%d", req, req->refcount);
+       struct btd_adapter *adapter = user_data;
 
-       if (req->refcount)
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to set local name: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
                return;
+       }
 
-       session_remove(req);
-       session_free(req);
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       local_name_changed_callback(adapter->dev_id, length, param, adapter);
 }
 
-static void confirm_mode_cb(struct agent *agent, DBusError *derr, void *data)
+static int set_name(struct btd_adapter *adapter, const char *name)
 {
-       struct session_req *req = data;
-       int err;
-       DBusMessage *reply;
+       struct mgmt_cp_set_local_name cp;
+       char maxname[MAX_NAME_LENGTH + 1];
 
-       req->got_reply = TRUE;
+       memset(maxname, 0, sizeof(maxname));
+       strncpy(maxname, name, MAX_NAME_LENGTH);
 
-       if (derr && dbus_error_is_set(derr)) {
-               reply = dbus_message_new_error(req->msg, derr->name,
-                                               derr->message);
-               g_dbus_send_message(req->conn, reply);
-               session_unref(req);
-               return;
+       if (!g_utf8_validate(maxname, -1, NULL)) {
+               error("Name change failed: supplied name isn't valid UTF-8");
+               return -EINVAL;
        }
 
-       err = set_mode(req->adapter, req->mode, req->msg);
-       if (err < 0)
-               reply = btd_error_failed(req->msg, strerror(-err));
-       else if (!req->adapter->pending_mode)
-               reply = dbus_message_new_method_return(req->msg);
-       else
-               reply = NULL;
+       memset(&cp, 0, sizeof(cp));
+       strncpy((char *) cp.name, maxname, sizeof(cp.name) - 1);
 
-       if (reply) {
-               /*
-                * Send reply immediately only if there was an error changing
-                * mode, or change is not needed. Otherwise, reply is sent in
-                * set_mode_complete.
-                */
-               g_dbus_send_message(req->conn, reply);
+       DBG("sending set local name command for index %u", adapter->dev_id);
 
-               dbus_message_unref(req->msg);
-               req->msg = NULL;
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_LOCAL_NAME,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               set_local_name_complete, adapter, NULL) > 0)
+               return 0;
+
+       error("Failed to set local name for index %u", adapter->dev_id);
 
-       if (!find_session(req->adapter->mode_sessions, req->owner))
-               session_unref(req);
+       return -EIO;
 }
 
-static DBusMessage *set_discoverable_timeout(DBusConnection *conn,
-                                                       DBusMessage *msg,
-                                                       uint32_t timeout,
-                                                       void *data)
+int adapter_set_name(struct btd_adapter *adapter, const char *name)
 {
-       struct btd_adapter *adapter = data;
-       const char *path;
+       if (g_strcmp0(adapter->system_name, name) == 0)
+               return 0;
 
-       if (adapter->discov_timeout == timeout && timeout == 0)
-               return dbus_message_new_method_return(msg);
+       DBG("name: %s", name);
 
-       if (adapter->scan_mode & SCAN_INQUIRY)
-               adapter_ops->set_discoverable(adapter->dev_id, TRUE, timeout);
+       g_free(adapter->system_name);
+       adapter->system_name = g_strdup(name);
 
-       adapter->discov_timeout = timeout;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Name");
 
-       write_discoverable_timeout(&adapter->bdaddr, timeout);
+       /* alias is preferred over system name */
+       if (adapter->stored_alias)
+               return 0;
 
-       path = dbus_message_get_path(msg);
+       DBG("alias: %s", name);
 
-       emit_property_changed(conn, path,
-                               ADAPTER_INTERFACE, "DiscoverableTimeout",
-                               DBUS_TYPE_UINT32, &timeout);
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Alias");
 
-       return dbus_message_new_method_return(msg);
+       return set_name(adapter, name);
 }
 
-static DBusMessage *set_pairable_timeout(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               uint32_t timeout,
-                                               void *data)
+struct btd_device *adapter_find_device(struct btd_adapter *adapter,
+                                                       const bdaddr_t *dst)
 {
-       struct btd_adapter *adapter = data;
-       const char *path;
-
-       if (adapter->pairable_timeout == timeout && timeout == 0)
-               return dbus_message_new_method_return(msg);
+       struct btd_device *device;
+       char addr[18];
+       GSList *list;
 
-       if (adapter->pairable)
-               adapter_set_pairable_timeout(adapter, timeout);
+       if (!adapter)
+               return NULL;
 
-       adapter->pairable_timeout = timeout;
+       ba2str(dst, addr);
 
-       write_pairable_timeout(&adapter->bdaddr, timeout);
+       list = g_slist_find_custom(adapter->devices, addr, device_address_cmp);
+       if (!list)
+               return NULL;
 
-       path = dbus_message_get_path(msg);
+       device = list->data;
 
-       emit_property_changed(conn, path,
-                               ADAPTER_INTERFACE, "PairableTimeout",
-                               DBUS_TYPE_UINT32, &timeout);
+       return device;
+}
 
-       return dbus_message_new_method_return(msg);
+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));
 }
 
-void btd_adapter_class_changed(struct btd_adapter *adapter, uint32_t new_class)
+static bool is_supported_uuid(const uuid_t *uuid)
 {
-       uint8_t class[3];
+       uuid_t tmp;
 
-       class[2] = (new_class >> 16) & 0xff;
-       class[1] = (new_class >> 8) & 0xff;
-       class[0] = new_class & 0xff;
+       /* mgmt versions from 1.3 onwards support all types of UUIDs */
+       if (MGMT_VERSION(mgmt_version, mgmt_revision) >= MGMT_VERSION(1, 3))
+               return true;
 
-       write_local_class(&adapter->bdaddr, class);
+       uuid_to_uuid128(&tmp, uuid);
 
-       adapter->dev_class = new_class;
+       if (!sdp_uuid128_to_uuid(&tmp))
+               return false;
 
-       if (main_opts.gatt_enabled) {
-               /* Removes service class */
-               class[1] = class[1] & 0x1f;
-               attrib_gap_set(adapter, GATT_CHARAC_APPEARANCE, class, 2);
-       }
+       if (tmp.type != SDP_UUID16)
+               return false;
 
-       emit_property_changed(connection, adapter->path,
-                               ADAPTER_INTERFACE, "Class",
-                               DBUS_TYPE_UINT32, &new_class);
+       return true;
 }
 
-void adapter_name_changed(struct btd_adapter *adapter, const char *name)
+static void add_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       if (g_strcmp0(adapter->name, name) == 0)
-               return;
+       struct btd_adapter *adapter = user_data;
 
-       g_free(adapter->name);
-       adapter->name = g_strdup(name);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to add UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       if (connection)
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Name",
-                                       DBUS_TYPE_STRING, &name);
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
 
-       if (main_opts.gatt_enabled)
-               attrib_gap_set(adapter, GATT_CHARAC_DEVICE_NAME,
-                               (const uint8_t *) name, strlen(name));
+       if (adapter->initialized)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
 }
 
-int adapter_set_name(struct btd_adapter *adapter, const char *name)
+static int add_uuid(struct btd_adapter *adapter, uuid_t *uuid, uint8_t svc_hint)
 {
-       char maxname[MAX_NAME_LENGTH + 1];
+       struct mgmt_cp_add_uuid cp;
+       uuid_t uuid128;
+       uint128_t uint128;
 
-       if (g_strcmp0(adapter->name, name) == 0)
+       if (!is_supported_uuid(uuid)) {
+               warn("Ignoring unsupported UUID for addition");
                return 0;
-
-       memset(maxname, 0, sizeof(maxname));
-       strncpy(maxname, name, MAX_NAME_LENGTH);
-       if (!g_utf8_validate(maxname, -1, NULL)) {
-               error("Name change failed: supplied name isn't valid UTF-8");
-               return -EINVAL;
-       }
-
-       if (adapter->up) {
-               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);
+       uuid_to_uuid128(&uuid128, uuid);
 
-       return 0;
-}
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+       cp.svc_hint = svc_hint;
 
-static DBusMessage *set_name(DBusConnection *conn, DBusMessage *msg,
-                                       const char *name, void *data)
-{
-       struct btd_adapter *adapter = data;
-       int ret;
+       DBG("sending add uuid command for index %u", adapter->dev_id);
 
-       if (adapter->allow_name_changes == FALSE)
-               return btd_error_failed(msg, strerror(EPERM));
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               add_uuid_complete, adapter, NULL) > 0)
+               return 0;
 
-       ret = adapter_set_name(adapter, name);
-       if (ret == -EINVAL)
-               return btd_error_invalid_args(msg);
-       else if (ret < 0)
-               return btd_error_failed(msg, strerror(-ret));
+       error("Failed to add UUID for index %u", adapter->dev_id);
 
-       return dbus_message_new_method_return(msg);
+       return -EIO;
 }
 
-struct btd_device *adapter_find_device(struct btd_adapter *adapter,
-                                                       const char *dest)
+static void remove_uuid_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_device *device;
-       GSList *l;
-
-       if (!adapter)
-               return NULL;
+       struct btd_adapter *adapter = user_data;
 
-       l = g_slist_find_custom(adapter->devices, dest,
-                                       (GCompareFunc) device_address_cmp);
-       if (!l)
-               return NULL;
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to remove UUID: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       device = l->data;
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
 
-       return device;
+       if (adapter->initialized)
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "UUIDs");
 }
 
-static void adapter_update_devices(struct btd_adapter *adapter)
+static int remove_uuid(struct btd_adapter *adapter, uuid_t *uuid)
 {
-       char **devices;
-       int i;
-       GSList *l;
+       struct mgmt_cp_remove_uuid cp;
+       uuid_t uuid128;
+       uint128_t uint128;
 
-       /* Devices */
-       devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
-       for (i = 0, l = adapter->devices; l; l = l->next, i++) {
-               struct btd_device *dev = l->data;
-               devices[i] = (char *) device_get_path(dev);
+       if (!is_supported_uuid(uuid)) {
+               warn("Ignoring unsupported UUID for removal");
+               return 0;
        }
 
-       emit_array_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Devices",
-                                       DBUS_TYPE_OBJECT_PATH, &devices, i);
-       g_free(devices);
+       uuid_to_uuid128(&uuid128, uuid);
+
+       ntoh128((uint128_t *) uuid128.value.uuid128.data, &uint128);
+       htob128(&uint128, (uint128_t *) cp.uuid);
+
+       DBG("sending remove uuid command for index %u", adapter->dev_id);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               remove_uuid_complete, adapter, NULL) > 0)
+               return 0;
+
+       error("Failed to remove UUID for index %u", adapter->dev_id);
+
+       return -EIO;
 }
 
-static void adapter_emit_uuids_updated(struct btd_adapter *adapter)
+static void clear_uuids_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       char **uuids;
-       int i;
-       sdp_list_t *list;
+       struct btd_adapter *adapter = user_data;
 
-       if (!adapter->initialized)
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to clear UUIDs: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
                return;
+       }
 
-       uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       dev_class_changed_callback(adapter->dev_id, length, param, adapter);
+}
 
-       for (i = 0, list = adapter->services; list; list = list->next) {
-               char *uuid;
-               sdp_record_t *rec = list->data;
+static int clear_uuids(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_remove_uuid cp;
 
-               uuid = bt_uuid2string(&rec->svclass);
-               if (uuid)
-                       uuids[i++] = uuid;
-       }
+       memset(&cp, 0, sizeof(cp));
 
-       emit_array_property_changed(connection, adapter->path,
-                       ADAPTER_INTERFACE, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+       DBG("sending clear uuids command for index %u", adapter->dev_id);
 
-       g_strfreev(uuids);
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_UUID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               clear_uuids_complete, adapter, NULL) > 0)
+               return 0;
+
+       error("Failed to clear UUIDs for index %u", adapter->dev_id);
+
+       return -EIO;
 }
 
 static uint8_t get_uuid_mask(uuid_t *uuid)
@@ -890,11 +934,26 @@ static int uuid_cmp(const void *a, const void *b)
        return sdp_uuid_cmp(&rec->svclass, uuid);
 }
 
-void adapter_service_insert(struct btd_adapter *adapter, void *r)
+static void adapter_service_insert(struct btd_adapter *adapter, sdp_record_t *rec)
 {
-       sdp_record_t *rec = r;
+       sdp_list_t *browse_list = NULL;
+       uuid_t browse_uuid;
        gboolean new_uuid;
 
+       DBG("%s", adapter->path);
+
+       /* skip record without a browse group */
+       if (sdp_get_browse_groups(rec, &browse_list) < 0) {
+               DBG("skipping record without browse group");
+               return;
+       }
+
+       sdp_uuid16_create(&browse_uuid, PUBLIC_BROWSE_GROUP);
+
+       /* skip record without public browse group */
+       if (!sdp_list_find(browse_list, &browse_uuid, sdp_uuid_cmp))
+               goto done;
+
        if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
                new_uuid = TRUE;
        else
@@ -905,35 +964,52 @@ void adapter_service_insert(struct btd_adapter *adapter, void *r)
 
        if (new_uuid) {
                uint8_t svc_hint = get_uuid_mask(&rec->svclass);
-               adapter_ops->add_uuid(adapter->dev_id, &rec->svclass, svc_hint);
+               add_uuid(adapter, &rec->svclass, svc_hint);
        }
 
-       adapter_emit_uuids_updated(adapter);
+done:
+       sdp_list_free(browse_list, free);
+}
+
+int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec)
+{
+       int ret;
+
+       DBG("%s", adapter->path);
+
+       ret = add_record_to_server(&adapter->bdaddr, rec);
+       if (ret < 0)
+               return ret;
+
+       adapter_service_insert(adapter, rec);
+
+       return 0;
 }
 
-void adapter_service_remove(struct btd_adapter *adapter, void *r)
+void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle)
 {
-       sdp_record_t *rec = r;
+       sdp_record_t *rec = sdp_record_find(handle);
+
+       DBG("%s", adapter->path);
+
+       if (!rec)
+               return;
 
        adapter->services = sdp_list_remove(adapter->services, rec);
 
        if (sdp_list_find(adapter->services, &rec->svclass, uuid_cmp) == NULL)
-               adapter_ops->remove_uuid(adapter->dev_id, &rec->svclass);
+               remove_uuid(adapter, &rec->svclass);
 
-       adapter_emit_uuids_updated(adapter);
+       remove_record_from_server(rec->handle);
 }
 
-static struct btd_device *adapter_create_device(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const char *address,
+static struct btd_device *adapter_create_device(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
                                                uint8_t bdaddr_type)
 {
        struct btd_device *device;
-       const char *path;
 
-       DBG("%s", address);
-
-       device = device_create(conn, adapter, address, bdaddr_type);
+       device = device_create(adapter, bdaddr, bdaddr_type);
        if (!device)
                return NULL;
 
@@ -941,2640 +1017,5303 @@ static struct btd_device *adapter_create_device(DBusConnection *conn,
 
        adapter->devices = g_slist_append(adapter->devices, device);
 
-       path = device_get_path(device);
-       g_dbus_emit_signal(conn, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceCreated",
-                       DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_INVALID);
+       return device;
+}
+
+static void service_auth_cancel(struct service_auth *auth)
+{
+       DBusError derr;
 
-       adapter_update_devices(adapter);
+       dbus_error_init(&derr);
+       dbus_set_error_const(&derr, ERROR_INTERFACE ".Canceled", NULL);
 
-       return device;
+       auth->cb(&derr, auth->user_data);
+
+       dbus_error_free(&derr);
+
+       if (auth->agent != NULL)
+               agent_cancel(auth->agent);
+
+       g_free(auth);
 }
 
-void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
-                                               struct btd_device *device,
-                                               gboolean remove_storage)
+static void adapter_remove_device(struct btd_adapter *adapter,
+                                               struct btd_device *dev)
 {
-       const gchar *dev_path = device_get_path(device);
-       struct agent *agent;
+       GList *l;
 
-       adapter->devices = g_slist_remove(adapter->devices, device);
-       adapter->connections = g_slist_remove(adapter->connections, device);
+       adapter->connect_list = g_slist_remove(adapter->connect_list, dev);
+
+       adapter->devices = g_slist_remove(adapter->devices, dev);
 
-       adapter_update_devices(adapter);
+       adapter->discovery_found = g_slist_remove(adapter->discovery_found,
+                                                                       dev);
 
-       g_dbus_emit_signal(conn, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceRemoved",
-                       DBUS_TYPE_OBJECT_PATH, &dev_path,
-                       DBUS_TYPE_INVALID);
+       adapter->connections = g_slist_remove(adapter->connections, dev);
+
+       if (adapter->connect_le == dev)
+               adapter->connect_le = NULL;
+
+       l = adapter->auths->head;
+       while (l != NULL) {
+               struct service_auth *auth = l->data;
+               GList *next = g_list_next(l);
+
+               if (auth->device != dev) {
+                       l = next;
+                       continue;
+               }
 
-       agent = device_get_agent(device);
+               g_queue_delete_link(adapter->auths, l);
+               l = next;
 
-       if (agent && device_is_authorizing(device))
-               agent_cancel(agent);
+               service_auth_cancel(auth);
+       }
 
-       device_remove(device, remove_storage);
+       device_remove(dev, TRUE);
 }
 
-struct btd_device *adapter_get_device(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const gchar *address)
+struct btd_device *adapter_get_device(struct btd_adapter *adapter,
+                                       const bdaddr_t *addr,
+                                       uint8_t addr_type)
 {
        struct btd_device *device;
 
-       DBG("%s", address);
-
        if (!adapter)
                return NULL;
 
-       device = adapter_find_device(adapter, address);
+       device = adapter_find_device(adapter, addr);
        if (device)
                return device;
 
-       return adapter_create_device(conn, adapter, address,
-                                               BDADDR_BREDR);
+       return adapter_create_device(adapter, addr, addr_type);
+}
+
+sdp_list_t *btd_adapter_get_services(struct btd_adapter *adapter)
+{
+       return adapter->services;
 }
 
-static gboolean discovery_cb(gpointer user_data)
+static void passive_scanning_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
-       int err;
+       const struct mgmt_cp_start_discovery *rp = param;
 
-       adapter->discov_id = 0;
+       DBG("status 0x%02x", status);
 
-       err = adapter_ops->start_discovery(adapter->dev_id);
-       if (err < 0)
-               error("start_discovery: %s (%d)", strerror(-err), -err);
+       if (length < sizeof(*rp)) {
+               error("Wrong size of start scanning return parameters");
+               return;
+       }
 
-       return FALSE;
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = rp->type;
+               adapter->discovery_enable = 0x01;
+       }
 }
 
-static DBusMessage *adapter_start_discovery(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+static gboolean passive_scanning_timeout(gpointer user_data)
 {
-       struct session_req *req;
-       struct btd_adapter *adapter = data;
-       const char *sender = dbus_message_get_sender(msg);
-       int err;
-
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
-
-       req = find_session(adapter->disc_sessions, sender);
-       if (req) {
-               session_ref(req);
-               return dbus_message_new_method_return(msg);
-       }
+       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_start_discovery cp;
 
-       if (adapter->disc_sessions)
-               goto done;
+       adapter->passive_scan_timeout = 0;
 
-       g_slist_free_full(adapter->found_devices, dev_info_free);
-       adapter->found_devices = NULL;
+       cp.type = (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
 
-       g_slist_free(adapter->oor_devices);
-       adapter->oor_devices = NULL;
+       mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               passive_scanning_complete, adapter, NULL);
 
-       if (adapter->discov_suspended)
-               goto done;
+       return FALSE;
+}
 
-       err = adapter_ops->start_discovery(adapter->dev_id);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+static void trigger_passive_scanning(struct btd_adapter *adapter)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_LE))
+               return;
 
-done:
-       req = create_session(adapter, conn, msg, 0,
-                               session_owner_exit);
+       DBG("");
 
-       adapter->disc_sessions = g_slist_append(adapter->disc_sessions, req);
+       if (adapter->passive_scan_timeout > 0) {
+               g_source_remove(adapter->passive_scan_timeout);
+               adapter->passive_scan_timeout = 0;
+       }
 
-       return dbus_message_new_method_return(msg);
-}
+       /*
+        * If any client is running a discovery right now, then do not
+        * even try to start passive scanning.
+        *
+        * The discovery procedure is using interleaved scanning and
+        * thus will discover Low Energy devices as well.
+        */
+       if (adapter->discovery_list)
+               return;
 
-static DBusMessage *adapter_stop_discovery(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
+       if (adapter->discovery_enable == 0x01)
+               return;
 
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       /*
+        * In case the discovery is suspended (for example for an ongoing
+        * pairing attempt), then also do not start passive scanning.
+        */
+       if (adapter->discovery_suspended)
+               return;
 
-       req = find_session(adapter->disc_sessions, sender);
-       if (!req)
-               return btd_error_failed(msg, "Invalid discovery session");
+       /*
+        * If the list of connectable Low Energy devices is empty,
+        * then do not start passive scanning.
+        */
+       if (!adapter->connect_list)
+               return;
 
-       session_unref(req);
-       info("Stopping discovery");
-       return dbus_message_new_method_return(msg);
+       adapter->passive_scan_timeout = g_timeout_add_seconds(CONN_SCAN_TIMEOUT,
+                                       passive_scanning_timeout, adapter);
 }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void stop_passive_scanning_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       const char *property;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       char srcaddr[18];
-       gboolean value;
-       char **devices, **uuids;
-       int i;
-       GSList *l;
-       sdp_list_t *list;
-
-       ba2str(&adapter->bdaddr, srcaddr);
-
-       if (check_address(srcaddr) < 0)
-               return btd_error_invalid_args(msg);
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *dev;
+       int err;
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       DBG("status 0x%02x (%s)", status, mgmt_errstr(status));
 
-       dbus_message_iter_init_append(reply, &iter);
+       dev = adapter->connect_le;
+       adapter->connect_le = NULL;
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Stopping passive scanning failed: %s",
+                                                       mgmt_errstr(status));
+               return;
+       }
 
-       /* Address */
-       property = srcaddr;
-       dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &property);
+       adapter->discovery_type = 0x00;
+       adapter->discovery_enable = 0x00;
 
-       /* Name */
-       property = adapter->name ? : "";
+       if (!dev) {
+               DBG("Device removed while stopping passive scanning");
+               trigger_passive_scanning(adapter);
+               return;
+       }
 
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &property);
+       err = device_connect_le(dev);
+       if (err < 0) {
+               error("LE auto connection failed: %s (%d)",
+                                               strerror(-err), -err);
+               trigger_passive_scanning(adapter);
+       }
+}
 
-       /* Class */
-       dict_append_entry(&dict, "Class",
-                               DBUS_TYPE_UINT32, &adapter->dev_class);
+static void stop_passive_scanning(struct btd_adapter *adapter)
+{
+       struct mgmt_cp_stop_discovery cp;
 
-       /* Powered */
-       value = (adapter->up && !adapter->off_requested) ? TRUE : FALSE;
-       dict_append_entry(&dict, "Powered", DBUS_TYPE_BOOLEAN, &value);
+       DBG("");
 
-       /* Discoverable */
-       value = adapter->scan_mode & SCAN_INQUIRY ? TRUE : FALSE;
-       dict_append_entry(&dict, "Discoverable", DBUS_TYPE_BOOLEAN, &value);
+       /* If there are any normal discovery clients passive scanning
+        * wont be running */
+       if (adapter->discovery_list)
+               return;
 
-       /* Pairable */
-       dict_append_entry(&dict, "Pairable", DBUS_TYPE_BOOLEAN,
-                               &adapter->pairable);
+       if (adapter->discovery_enable == 0x00)
+               return;
 
-       /* DiscoverableTimeout */
-       dict_append_entry(&dict, "DiscoverableTimeout",
-                               DBUS_TYPE_UINT32, &adapter->discov_timeout);
+       cp.type = adapter->discovery_type;
 
-       /* PairableTimeout */
-       dict_append_entry(&dict, "PairableTimeout",
-                               DBUS_TYPE_UINT32, &adapter->pairable_timeout);
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                       adapter->dev_id, sizeof(cp), &cp,
+                       stop_passive_scanning_complete, adapter, NULL);
+}
 
+static void cancel_passive_scanning(struct btd_adapter *adapter)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_LE))
+               return;
 
-       /* Discovering */
-       dict_append_entry(&dict, "Discovering", DBUS_TYPE_BOOLEAN,
-                                                       &adapter->discovering);
+       DBG("");
 
-       /* Devices */
-       devices = g_new0(char *, g_slist_length(adapter->devices) + 1);
-       for (i = 0, l = adapter->devices; l; l = l->next, i++) {
-               struct btd_device *dev = l->data;
-               devices[i] = (char *) device_get_path(dev);
+       if (adapter->passive_scan_timeout > 0) {
+               g_source_remove(adapter->passive_scan_timeout);
+               adapter->passive_scan_timeout = 0;
        }
-       dict_append_array(&dict, "Devices", DBUS_TYPE_OBJECT_PATH,
-                                                               &devices, i);
-       g_free(devices);
+}
 
-       /* UUIDs */
-       uuids = g_new0(char *, sdp_list_len(adapter->services) + 1);
+static void trigger_start_discovery(struct btd_adapter *adapter, guint delay);
 
-       for (i = 0, list = adapter->services; list; list = list->next) {
-               sdp_record_t *rec = list->data;
-               char *uuid;
+static void start_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_cp_start_discovery *rp = param;
 
-               uuid = bt_uuid2string(&rec->svclass);
-               if (uuid)
-                       uuids[i++] = uuid;
+       DBG("status 0x%02x", status);
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of start discovery return parameters");
+               return;
        }
 
-       dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &uuids, i);
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = rp->type;
+               adapter->discovery_enable = 0x01;
 
-       g_strfreev(uuids);
+               if (adapter->discovering)
+                       return;
 
-       dbus_message_iter_close_container(&iter, &dict);
+               adapter->discovering = true;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+               return;
+       }
 
-       return reply;
+       /*
+        * In case the restart of the discovery failed, then just trigger
+        * it for the next idle timeout again.
+        */
+       trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT * 2);
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static gboolean start_discovery_timeout(gpointer user_data)
 {
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
+       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_start_discovery cp;
+       uint8_t new_type;
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-       dbus_message_iter_recurse(&iter, &sub);
+       DBG("");
 
-       if (g_str_equal("Name", property)) {
-               const char *name;
+       adapter->discovery_idle_timeout = 0;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
-                       return btd_error_invalid_args(msg);
-               dbus_message_iter_get_basic(&sub, &name);
+       if (adapter->current_settings & MGMT_SETTING_BREDR)
+               new_type = (1 << BDADDR_BREDR);
+       else
+               new_type = 0;
 
-               return set_name(conn, msg, name, data);
-       } else if (g_str_equal("Powered", property)) {
-               gboolean powered;
+       if (adapter->current_settings & MGMT_SETTING_LE)
+               new_type |= (1 << BDADDR_LE_PUBLIC) | (1 << BDADDR_LE_RANDOM);
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       if (adapter->discovery_enable == 0x01) {
+               /*
+                * If there is an already running discovery and it has the
+                * same type, then just keep it.
+                */
+               if (adapter->discovery_type == new_type) {
+                       if (adapter->discovering)
+                               return FALSE;
+
+                       adapter->discovering = true;
+                       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+                       return FALSE;
+               }
 
-               dbus_message_iter_get_basic(&sub, &powered);
+               /*
+                * Otherwise the current discovery must be stopped. So
+                * queue up a stop discovery command.
+                *
+                * This can happen if a passive scanning for Low Energy
+                * devices is ongoing.
+                */
+               cp.type = adapter->discovery_type;
 
-               return set_powered(conn, msg, powered, data);
-       } else if (g_str_equal("Discoverable", property)) {
-               gboolean discoverable;
+               mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       }
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       cp.type = new_type;
 
-               dbus_message_iter_get_basic(&sub, &discoverable);
+       mgmt_send(adapter->mgmt, MGMT_OP_START_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               start_discovery_complete, adapter, NULL);
 
-               return set_discoverable(conn, msg, discoverable, data);
-       } else if (g_str_equal("DiscoverableTimeout", property)) {
-               uint32_t timeout;
+       return FALSE;
+}
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)
-                       return btd_error_invalid_args(msg);
+static void trigger_start_discovery(struct btd_adapter *adapter, guint delay)
+{
 
-               dbus_message_iter_get_basic(&sub, &timeout);
+       DBG("");
 
-               return set_discoverable_timeout(conn, msg, timeout, data);
-       } else if (g_str_equal("Pairable", property)) {
-               gboolean pairable;
+       cancel_passive_scanning(adapter);
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
 
-               dbus_message_iter_get_basic(&sub, &pairable);
+       /*
+        * If the controller got powered down in between, then ensure
+        * that we do not keep trying to restart discovery.
+        *
+        * This is safe-guard and should actually never trigger.
+        */
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return;
 
-               return set_pairable(conn, msg, pairable, data);
-       } else if (g_str_equal("PairableTimeout", property)) {
-               uint32_t timeout;
+       adapter->discovery_idle_timeout = g_timeout_add_seconds(delay,
+                                       start_discovery_timeout, adapter);
+}
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT32)
-                       return btd_error_invalid_args(msg);
+static void suspend_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-               dbus_message_iter_get_basic(&sub, &timeout);
+       DBG("status 0x%02x", status);
 
-               return set_pairable_timeout(conn, msg, timeout, data);
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = 0x00;
+               adapter->discovery_enable = 0x00;
+               return;
        }
-
-       return btd_error_invalid_args(msg);
 }
 
-static DBusMessage *request_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void suspend_discovery(struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
-       uint8_t new_mode;
-       int err;
+       struct mgmt_cp_stop_discovery cp;
 
-       if (!adapter->agent)
-               return btd_error_agent_not_available(msg);
+       DBG("");
 
-       if (!adapter->mode_sessions)
-               adapter->global_mode = adapter->mode;
+       adapter->discovery_suspended = true;
 
-       new_mode = get_mode(&adapter->bdaddr, "on");
+       /*
+        * If there are no clients discovering right now, then there is
+        * also nothing to suspend.
+        */
+       if (!adapter->discovery_list)
+               return;
 
-       req = find_session(adapter->mode_sessions, sender);
-       if (req) {
-               session_ref(req);
-               return dbus_message_new_method_return(msg);
-       } else {
-               req = create_session(adapter, conn, msg, new_mode,
-                                       session_owner_exit);
-               adapter->mode_sessions = g_slist_append(adapter->mode_sessions,
-                                                       req);
+       /*
+        * In case of being inside the idle phase, make sure to remove
+        * the timeout to not trigger a restart.
+        *
+        * The restart will be triggered when the discovery is resumed.
+        */
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
        }
 
-       /* No need to change mode */
-       if (adapter->mode >= new_mode)
-               return dbus_message_new_method_return(msg);
+       if (adapter->discovery_enable == 0x00)
+               return;
 
-       err = agent_confirm_mode_change(adapter->agent, mode2str(new_mode),
-                                       confirm_mode_cb, req, NULL);
-       if (err < 0) {
-               session_unref(req);
-               return btd_error_failed(msg, strerror(-err));
-       }
+       cp.type = adapter->discovery_type;
 
-       return NULL;
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               suspend_discovery_complete, adapter, NULL);
 }
 
-static DBusMessage *release_session(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void resume_discovery(struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = data;
-       struct session_req *req;
-       const char *sender = dbus_message_get_sender(msg);
+       DBG("");
 
-       req = find_session(adapter->mode_sessions, sender);
-       if (!req)
-               return btd_error_failed(msg, "Invalid Session");
+       adapter->discovery_suspended = false;
 
-       session_unref(req);
+       /*
+        * If there are no clients discovering right now, then there is
+        * also nothing to resume.
+        */
+       if (!adapter->discovery_list)
+               return;
 
-       return dbus_message_new_method_return(msg);
+       /*
+        * Treat a suspended discovery session the same as extra long
+        * idle time for a normal discovery. So just trigger the default
+        * restart procedure.
+        */
+       trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
 }
 
-static DBusMessage *list_devices(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+static void discovering_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       DBusMessage *reply;
-       GSList *l;
-       DBusMessageIter iter;
-       DBusMessageIter array_iter;
-       const gchar *dev_path;
+       const struct mgmt_ev_discovering *ev = param;
+       struct btd_adapter *adapter = user_data;
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       if (length < sizeof(*ev)) {
+               error("Too small discovering event");
+               return;
+       }
 
-       dbus_message_iter_init_append(reply, &iter);
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
+       DBG("hci%u type %u discovering %u", adapter->dev_id,
+                                       ev->type, ev->discovering);
 
-       for (l = adapter->devices; l; l = l->next) {
-               struct btd_device *device = l->data;
+       if (adapter->discovery_enable == ev->discovering)
+               return;
 
-               dev_path = device_get_path(device);
+       adapter->discovery_type = ev->type;
+       adapter->discovery_enable = ev->discovering;
 
-               dbus_message_iter_append_basic(&array_iter,
-                               DBUS_TYPE_OBJECT_PATH, &dev_path);
+       /*
+        * Check for existing discoveries triggered by client applications
+        * and ignore all others.
+        *
+        * If there are no clients, then it is good idea to trigger a
+        * passive scanning attempt.
+        */
+       if (!adapter->discovery_list) {
+               trigger_passive_scanning(adapter);
+               return;
        }
 
-       dbus_message_iter_close_container(&iter, &array_iter);
+       if (adapter->discovery_suspended)
+               return;
+
+       switch (adapter->discovery_enable) {
+       case 0x00:
+               trigger_start_discovery(adapter, IDLE_DISCOV_TIMEOUT);
+               break;
 
-       return reply;
+       case 0x01:
+               if (adapter->discovery_idle_timeout > 0) {
+                       g_source_remove(adapter->discovery_idle_timeout);
+                       adapter->discovery_idle_timeout = 0;
+               }
+               break;
+       }
 }
 
-static DBusMessage *cancel_device_creation(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
+static void stop_discovery_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       const gchar *address, *sender = dbus_message_get_sender(msg);
-       struct btd_device *device;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       struct btd_adapter *adapter = user_data;
 
-       device = adapter_find_device(adapter, address);
-       if (!device || !device_is_creating(device, NULL))
-               return btd_error_does_not_exist(msg);
+       DBG("status 0x%02x", status);
 
-       if (!device_is_creating(device, sender))
-               return btd_error_not_authorized(msg);
+       if (status == MGMT_STATUS_SUCCESS) {
+               adapter->discovery_type = 0x00;
+               adapter->discovery_enable = 0x00;
 
-       device_set_temporary(device, TRUE);
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
 
-       if (device_is_connected(device)) {
-               device_request_disconnect(device, msg);
-               return NULL;
+               trigger_passive_scanning(adapter);
        }
-
-       adapter_remove_device(conn, adapter, device, TRUE);
-
-       return dbus_message_new_method_return(msg);
 }
 
-static struct btd_device *create_device_internal(DBusConnection *conn,
-                                               struct btd_adapter *adapter,
-                                               const char *address, int *err)
+static int compare_sender(gconstpointer a, gconstpointer b)
 {
-       struct remote_dev_info *dev;
-       struct btd_device *device;
-       bdaddr_t addr;
-       uint8_t bdaddr_type;
+       const struct watch_client *client = a;
+       const char *sender = b;
 
-       str2ba(address, &addr);
+       return g_strcmp0(client->owner, sender);
+}
 
-       dev = adapter_search_found_devices(adapter, &addr);
-       if (dev)
-               bdaddr_type = dev->bdaddr_type;
-       else
-               bdaddr_type = BDADDR_BREDR;
+static void invalidate_rssi(gpointer a)
+{
+       struct btd_device *dev = a;
 
-       device = adapter_create_device(conn, adapter, address, bdaddr_type);
-       if (!device && err)
-               *err = -ENOMEM;
+       device_set_rssi(dev, 0);
+}
 
-       return device;
+static void discovery_cleanup(struct btd_adapter *adapter)
+{
+       g_slist_free_full(adapter->discovery_found, invalidate_rssi);
+       adapter->discovery_found = NULL;
 }
 
-static DBusMessage *create_device(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static gboolean remove_temp_devices(gpointer user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address;
-       DBusMessage *reply;
-       int err;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
-
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
-
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       struct btd_adapter *adapter = user_data;
+       GSList *l, *next;
 
-       if (adapter_find_device(adapter, address))
-               return btd_error_already_exists(msg);
+       DBG("%s", adapter->path);
 
-       DBG("%s", address);
+       adapter->temp_devices_timeout = 0;
 
-       device = create_device_internal(conn, adapter, address, &err);
-       if (!device)
-               goto failed;
+       for (l = adapter->devices; l != NULL; l = next) {
+               struct btd_device *dev = l->data;
 
-       if (device_is_bredr(device))
-               err = device_browse_sdp(device, conn, msg, NULL, FALSE);
-       else
-               err = device_browse_primary(device, conn, msg, FALSE);
+               next = g_slist_next(l);
 
-       if (err < 0) {
-               adapter_remove_device(conn, adapter, device, TRUE);
-               return btd_error_failed(msg, strerror(-err));
+               if (device_is_temporary(dev))
+                       adapter_remove_device(adapter, dev);
        }
 
-       return NULL;
-
-failed:
-       if (err == -ENOTCONN) {
-               /* Device is not connectable */
-               const char *path = device_get_path(device);
-
-               reply = dbus_message_new_method_return(msg);
-
-               dbus_message_append_args(reply,
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-       } else
-               reply = btd_error_failed(msg, strerror(-err));
-
-       return reply;
-}
-
-static uint8_t parse_io_capability(const char *capability)
-{
-       if (g_str_equal(capability, ""))
-               return IO_CAPABILITY_DISPLAYYESNO;
-       if (g_str_equal(capability, "DisplayOnly"))
-               return IO_CAPABILITY_DISPLAYONLY;
-       if (g_str_equal(capability, "DisplayYesNo"))
-               return IO_CAPABILITY_DISPLAYYESNO;
-       if (g_str_equal(capability, "KeyboardOnly"))
-               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;
+       return FALSE;
 }
 
-static DBusMessage *create_paired_device(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
+static void discovery_destroy(void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const gchar *address, *agent_path, *capability, *sender;
-       uint8_t cap;
-       int err;
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capability,
-                                       DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       DBG("owner %s", client->owner);
 
-       if (check_address(address) < 0)
-               return btd_error_invalid_args(msg);
+       adapter->discovery_list = g_slist_remove(adapter->discovery_list,
+                                                               client);
 
-       if (!adapter->up)
-               return btd_error_not_ready(msg);
+       g_free(client->owner);
+       g_free(client);
 
-       sender = dbus_message_get_sender(msg);
-       if (adapter->agent &&
-                       agent_matches(adapter->agent, sender, agent_path)) {
-               error("Refusing adapter agent usage as device specific one");
-               return btd_error_invalid_args(msg);
-       }
+       /*
+        * If there are other client discoveries in progress, then leave
+        * it active. If not, then make sure to stop the restart timeout.
+        */
+       if (adapter->discovery_list)
+               return;
 
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
+       adapter->discovery_type = 0x00;
 
-       device = adapter_find_device(adapter, address);
-       if (!device) {
-               device = create_device_internal(conn, adapter, address, &err);
-               if (!device)
-                       return btd_error_failed(msg, strerror(-err));
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
        }
 
-       return device_create_bonding(device, conn, msg, agent_path, cap);
-}
+       if (adapter->temp_devices_timeout > 0) {
+               g_source_remove(adapter->temp_devices_timeout);
+               adapter->temp_devices_timeout = 0;
+       }
 
-static gint device_path_cmp(struct btd_device *device, const gchar *path)
-{
-       const gchar *dev_path = device_get_path(device);
+       discovery_cleanup(adapter);
 
-       return strcasecmp(dev_path, path);
+       adapter->temp_devices_timeout = g_timeout_add_seconds(TEMP_DEV_TIMEOUT,
+                                               remove_temp_devices, adapter);
 }
 
-static DBusMessage *remove_device(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+static void discovery_disconnect(DBusConnection *conn, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       const char *path;
-       GSList *l;
-
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       struct watch_client *client = user_data;
+       struct btd_adapter *adapter = client->adapter;
+       struct mgmt_cp_stop_discovery cp;
 
-       l = g_slist_find_custom(adapter->devices,
-                       path, (GCompareFunc) device_path_cmp);
-       if (!l)
-               return btd_error_does_not_exist(msg);
+       DBG("owner %s", client->owner);
 
-       device = l->data;
+       adapter->discovery_list = g_slist_remove(adapter->discovery_list,
+                                                               client);
 
-       if (device_is_temporary(device) || device_is_busy(device))
-               return g_dbus_create_error(msg,
-                               ERROR_INTERFACE ".DoesNotExist",
-                               "Device creation in progress");
+       /*
+        * There is no need for extra cleanup of the client since that
+        * will be done by the destroy callback.
+        *
+        * However in case this is the last client, the discovery in
+        * the kernel needs to be disabled.
+        */
+       if (adapter->discovery_list)
+               return;
 
-       device_set_temporary(device, TRUE);
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       if (adapter->discovery_enable == 0x00) {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
 
-       if (!device_is_connected(device)) {
-               adapter_remove_device(conn, adapter, device, TRUE);
-               return dbus_message_new_method_return(msg);
+               trigger_passive_scanning(adapter);
+               return;
        }
 
-       device_request_disconnect(device, msg);
-       return NULL;
+       cp.type = adapter->discovery_type;
+
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_discovery_complete, adapter, NULL);
 }
 
-static DBusMessage *find_device(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+static DBusMessage *start_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
 {
-       struct btd_adapter *adapter = data;
-       struct btd_device *device;
-       DBusMessage *reply;
-       const gchar *address;
-       GSList *l;
-       const gchar *dev_path;
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct watch_client *client;
+       GSList *list;
 
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &address,
-                                               DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
+       DBG("sender %s", sender);
 
-       l = g_slist_find_custom(adapter->devices,
-                       address, (GCompareFunc) device_address_cmp);
-       if (!l)
-               return btd_error_does_not_exist(msg);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
+
+       /*
+        * Every client can only start one discovery, if the client
+        * already started a discovery then return an error.
+        */
+       list = g_slist_find_custom(adapter->discovery_list, sender,
+                                               compare_sender);
+       if (list)
+               return btd_error_busy(msg);
 
-       device = l->data;
+       client = g_new0(struct watch_client, 1);
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       client->adapter = adapter;
+       client->owner = g_strdup(sender);
+       client->watch = g_dbus_add_disconnect_watch(dbus_conn, sender,
+                                               discovery_disconnect, client,
+                                               discovery_destroy);
 
-       dev_path = device_get_path(device);
+       adapter->discovery_list = g_slist_prepend(adapter->discovery_list,
+                                                               client);
 
-       dbus_message_append_args(reply,
-                               DBUS_TYPE_OBJECT_PATH, &dev_path,
-                               DBUS_TYPE_INVALID);
+       /*
+        * Just trigger the discovery here. In case an already running
+        * discovery in idle phase exists, it will be restarted right
+        * away.
+        */
+       trigger_start_discovery(adapter, 0);
 
-       return reply;
+       return dbus_message_new_method_return(msg);
 }
 
-static void agent_removed(struct agent *agent, struct btd_adapter *adapter)
+static DBusMessage *stop_discovery(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
 {
-       adapter_ops->set_io_capability(adapter->dev_id,
-                                       IO_CAPABILITY_NOINPUTNOOUTPUT);
+       struct btd_adapter *adapter = user_data;
+       const char *sender = dbus_message_get_sender(msg);
+       struct mgmt_cp_stop_discovery cp;
+       struct watch_client *client;
+       GSList *list;
 
-       adapter->agent = NULL;
-}
+       DBG("sender %s", sender);
 
-static DBusMessage *register_agent(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *path, *name, *capability;
-       struct btd_adapter *adapter = data;
-       uint8_t cap;
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
 
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_STRING, &capability, DBUS_TYPE_INVALID))
-               return NULL;
+       list = g_slist_find_custom(adapter->discovery_list, sender,
+                                               compare_sender);
+       if (!list)
+               return btd_error_failed(msg, "No discovery started");
 
-       if (adapter->agent)
-               return btd_error_already_exists(msg);
+       client = list->data;
 
-       cap = parse_io_capability(capability);
-       if (cap == IO_CAPABILITY_INVALID)
-               return btd_error_invalid_args(msg);
+       cp.type = adapter->discovery_type;
+
+       /*
+        * The destroy function will cleanup the client information and
+        * also remove it from the list of discovery clients.
+        */
+       g_dbus_remove_watch(dbus_conn, client->watch);
+
+       /*
+        * As long as other discovery clients are still active, just
+        * return success.
+        */
+       if (adapter->discovery_list)
+               return dbus_message_new_method_return(msg);
 
-       name = dbus_message_get_sender(msg);
+       /*
+        * In the idle phase of a discovery, there is no need to stop it
+        * and so it is enough to send out the signal and just return.
+        */
+       if (adapter->discovery_enable == 0x00) {
+               adapter->discovering = false;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
 
-       adapter->agent = agent_create(adapter, name, path, cap,
-                               (agent_remove_cb) agent_removed, adapter);
+               trigger_passive_scanning(adapter);
 
-       DBG("Agent registered for hci%d at %s:%s", adapter->dev_id, name,
-                       path);
+               return dbus_message_new_method_return(msg);
+       }
 
-       adapter_ops->set_io_capability(adapter->dev_id, cap);
+       mgmt_send(adapter->mgmt, MGMT_OP_STOP_DISCOVERY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               stop_discovery_complete, adapter, NULL);
 
        return dbus_message_new_method_return(msg);
 }
 
-static DBusMessage *unregister_agent(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
+static gboolean property_get_address(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       const char *path, *name;
-       struct btd_adapter *adapter = data;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID))
-               return NULL;
-
-       name = dbus_message_get_sender(msg);
+       struct btd_adapter *adapter = user_data;
+       char addr[18];
+       const char *str = addr;
 
-       if (!adapter->agent || !agent_matches(adapter->agent, name, path))
-               return btd_error_does_not_exist(msg);
+       ba2str(&adapter->bdaddr, addr);
 
-       agent_free(adapter->agent);
-       adapter->agent = NULL;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
 
-       return dbus_message_new_method_return(msg);
+       return TRUE;
 }
 
-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 gboolean property_get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->system_name ? : "";
 
-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" })) },
-       { }
-};
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
+
+       return TRUE;
+}
 
-static void create_stored_device_from_profiles(char *key, char *value,
-                                               void *user_data)
+static gboolean property_get_alias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
-       GSList *list, *uuids = bt_string2list(value);
-       struct btd_device *device;
+       const char *str;
 
-       if (g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp))
-               return;
+       if (adapter->current_alias)
+               str = adapter->current_alias;
+       else if (adapter->stored_alias)
+               str = adapter->stored_alias;
+       else
+               str = adapter->system_name ? : "";
 
-       device = device_create(connection, adapter, key, BDADDR_BREDR);
-       if (!device)
-               return;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
 
-       device_set_temporary(device, FALSE);
-       adapter->devices = g_slist_append(adapter->devices, device);
+       return TRUE;
+}
 
-       list = device_services_from_record(device, uuids);
-       if (list)
-               device_register_services(connection, device, list, ATT_PSM);
+static void property_set_alias(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const char *name;
+       int ret;
 
-       device_probe_drivers(device, uuids);
+       dbus_message_iter_get_basic(iter, &name);
 
-       g_slist_free_full(uuids, g_free);
-}
+       if (g_str_equal(name, "")  == TRUE) {
+               if (adapter->stored_alias == NULL) {
+                       /* no alias set, nothing to restore */
+                       g_dbus_pending_property_success(id);
+                       return;
+               }
 
-struct adapter_keys {
-       struct btd_adapter *adapter;
-       GSList *keys;
-};
+               /* restore to system name */
+               ret = set_name(adapter, adapter->system_name);
+       } else {
+               if (g_strcmp0(adapter->stored_alias, name) == 0) {
+                       /* alias already set, nothing to do */
+                       g_dbus_pending_property_success(id);
+                       return;
+               }
 
-static int str2buf(const char *str, uint8_t *buf, size_t blen)
-{
-       int i, dlen;
+               /* set to alias */
+               ret = set_name(adapter, name);
+       }
 
-       if (str == NULL)
-               return -EINVAL;
+       if (ret >= 0) {
+               g_free(adapter->stored_alias);
 
-       memset(buf, 0, blen);
+               if (g_str_equal(name, "")  == TRUE)
+                       adapter->stored_alias = NULL;
+               else
+                       adapter->stored_alias = g_strdup(name);
 
-       dlen = MIN((strlen(str) / 2), blen);
+               store_adapter_info(adapter);
 
-       for (i = 0; i < dlen; i++)
-               sscanf(str + (i * 2), "%02hhX", &buf[i]);
+               g_dbus_pending_property_success(id);
+               return;
+       }
 
-       return 0;
+       if (ret == -EINVAL)
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+       else
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                       strerror(-ret));
 }
 
-static struct link_key_info *get_key_info(const char *addr, const char *value)
+static gboolean property_get_class(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       struct link_key_info *info;
-       char tmp[3];
-       long int l;
-
-       if (strlen(value) < 36) {
-               error("Unexpectedly short (%zu) link key line", strlen(value));
-               return NULL;
-       }
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t val = adapter->dev_class;
 
-       info = g_new0(struct link_key_info, 1);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &val);
 
-       str2ba(addr, &info->bdaddr);
+       return TRUE;
+}
 
-       str2buf(value, info->key, sizeof(info->key));
+static gboolean property_get_mode(struct btd_adapter *adapter,
+                               uint32_t setting, DBusMessageIter *iter)
+{
+       dbus_bool_t enable;
 
-       memcpy(tmp, value + 33, 2);
-       info->type = (uint8_t) strtol(tmp, NULL, 10);
+       enable = (adapter->current_settings & setting) ? TRUE : FALSE;
 
-       memcpy(tmp, value + 35, 2);
-       l = strtol(tmp, NULL, 10);
-       if (l < 0)
-               l = 0;
-       info->pin_len = l;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &enable);
 
-       return info;
+       return TRUE;
 }
 
-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;
-       }
+struct property_set_data {
+       struct btd_adapter *adapter;
+       GDBusPendingPropertySet id;
+};
 
-       ltk = g_new0(struct smp_ltk_info, 1);
+static void property_set_mode_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct property_set_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
 
-       str2ba(addr, &ltk->bdaddr);
+       DBG("%s (0x%02x)", mgmt_errstr(status), status);
 
-       ltk->bdaddr_type = bdaddr_type;
+       if (status != MGMT_STATUS_SUCCESS) {
+               const char *dbus_err;
 
-       str2buf(value, ltk->val, sizeof(ltk->val));
+               error("Failed to set mode: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
 
-       ptr = (char *) value + 2 * sizeof(ltk->val) + 1;
+               if (status == MGMT_STATUS_RFKILLED)
+                       dbus_err = ERROR_INTERFACE ".Blocked";
+               else
+                       dbus_err = ERROR_INTERFACE ".Failed";
 
-       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;
+               g_dbus_pending_property_error(data->id, dbus_err,
+                                                       mgmt_errstr(status));
+               return;
        }
-       ptr += i;
 
-       str2buf(ptr, ltk->rand, sizeof(ltk->rand));
+       g_dbus_pending_property_success(data->id);
 
-       return ltk;
+       /*
+        * The parameters are idential and also the task that is
+        * required in both cases. So it is safe to just call the
+        * event handling functions here.
+        */
+       new_settings_callback(adapter->dev_id, length, param, adapter);
 }
 
-static void create_stored_device_from_linkkeys(char *key, char *value,
-                                                       void *user_data)
+static void property_set_mode(struct btd_adapter *adapter, uint32_t setting,
+                                               DBusMessageIter *value,
+                                               GDBusPendingPropertySet id)
 {
-       struct adapter_keys *keys = user_data;
-       struct btd_adapter *adapter = keys->adapter;
-       struct btd_device *device;
-       struct link_key_info *info;
+       struct property_set_data *data;
+       struct mgmt_cp_set_discoverable cp;
+       void *param;
+       dbus_bool_t enable, current_enable;
+       uint16_t opcode, len;
+       uint8_t mode;
 
-       info = get_key_info(key, value);
-       if (info)
-               keys->keys = g_slist_append(keys->keys, info);
+       dbus_message_iter_get_basic(value, &enable);
 
-       if (g_slist_find_custom(adapter->devices, key,
-                                       (GCompareFunc) device_address_cmp))
-               return;
+       if (adapter->current_settings & setting)
+               current_enable = TRUE;
+       else
+               current_enable = FALSE;
 
-       device = device_create(connection, adapter, key, BDADDR_BREDR);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
+       if (enable == current_enable) {
+               g_dbus_pending_property_success(id);
+               return;
        }
-}
 
-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;
+       mode = (enable == TRUE) ? 0x01 : 0x00;
 
-       if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
-               return;
+       switch (setting) {
+       case MGMT_SETTING_POWERED:
+               opcode = MGMT_OP_SET_POWERED;
+               param = &mode;
+               len = sizeof(mode);
+               break;
+       case MGMT_SETTING_DISCOVERABLE:
+               memset(&cp, 0, sizeof(cp));
+               cp.val = mode;
+               if (cp.val)
+                       cp.timeout = htobs(adapter->discoverable_timeout);
+
+               opcode = MGMT_OP_SET_DISCOVERABLE;
+               param = &cp;
+               len = sizeof(cp);
+               break;
+       case MGMT_SETTING_PAIRABLE:
+               opcode = MGMT_OP_SET_PAIRABLE;
+               param = &mode;
+               len = sizeof(mode);
+               break;
+       default:
+               goto failed;
+       }
 
-       info = get_ltk_info(address, bdaddr_type, value);
-       if (info == NULL)
-               return;
+       DBG("sending %s command for index %u", mgmt_opstr(opcode),
+                                                       adapter->dev_id);
+
+       data = g_try_new0(struct property_set_data, 1);
+       if (!data)
+               goto failed;
 
-       keys->keys = g_slist_append(keys->keys, info);
+       data->adapter = adapter;
+       data->id = id;
 
-       if (g_slist_find_custom(adapter->devices, address,
-                                       (GCompareFunc) device_address_cmp))
+       if (mgmt_send(adapter->mgmt, opcode, adapter->dev_id, len, param,
+                               property_set_mode_complete, data, g_free) > 0)
                return;
 
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
+       g_free(data);
 
-       if (g_strcmp0(srcaddr, address) == 0)
-               return;
+failed:
+       error("Failed to set mode for index %u", adapter->dev_id);
 
-       device = device_create(connection, adapter, address, bdaddr_type);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
+       g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed", NULL);
 }
 
-static void create_stored_device_from_blocked(char *key, char *value,
-                                                       void *user_data)
+static gboolean property_get_powered(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-
-       if (g_slist_find_custom(adapter->devices,
-                               key, (GCompareFunc) device_address_cmp))
-               return;
 
-       device = device_create(connection, adapter, key, BDADDR_BREDR);
-       if (device) {
-               device_set_temporary(device, FALSE);
-               adapter->devices = g_slist_append(adapter->devices, device);
-       }
+       return property_get_mode(adapter, MGMT_SETTING_POWERED, iter);
 }
 
-static GSList *string_to_primary_list(char *str)
+static void property_set_powered(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
 {
-       GSList *l = NULL;
-       char **services;
-       int i;
+       struct btd_adapter *adapter = user_data;
 
-       if (str == NULL)
-               return NULL;
+       if (powering_down) {
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                       "Powering down");
+               return;
+       }
 
-       services = g_strsplit(str, " ", 0);
-       if (services == NULL)
-               return NULL;
+       property_set_mode(adapter, MGMT_SETTING_POWERED, iter, id);
+}
 
-       for (i = 0; services[i]; i++) {
-               struct gatt_primary *prim;
-               int ret;
+static gboolean property_get_discoverable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-               prim = g_new0(struct gatt_primary, 1);
+       return property_get_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter);
+}
 
-               ret = sscanf(services[i], "%04hX#%04hX#%s", &prim->range.start,
-                                                       &prim->range.end, prim->uuid);
+static void property_set_discoverable(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-               if (ret < 3) {
-                       g_free(prim);
-                       continue;
-               }
+       property_set_mode(adapter, MGMT_SETTING_DISCOVERABLE, iter, id);
+}
 
-               l = g_slist_append(l, prim);
-       }
+static gboolean property_get_discoverable_timeout(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value = adapter->discoverable_timeout;
 
-       g_strfreev(services);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &value);
 
-       return l;
+       return TRUE;
 }
 
-static void create_stored_device_from_primaries(char *key, char *value,
-                                                       void *user_data)
+static void property_set_discoverable_timeout(
+                               const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
 {
        struct btd_adapter *adapter = user_data;
-       struct btd_device *device;
-       GSList *services, *uuids, *l;
-       char address[18];
-       uint8_t bdaddr_type;
+       dbus_uint32_t value;
 
-       if (sscanf(key, "%17s#%hhu", address, &bdaddr_type) < 2)
-               return;
+       dbus_message_iter_get_basic(iter, &value);
 
-       if (g_slist_find_custom(adapter->devices,
-                       address, (GCompareFunc) device_address_cmp))
-               return;
+       adapter->discoverable_timeout = value;
 
-       device = device_create(connection, adapter, address, bdaddr_type);
-       if (!device)
-               return;
+       g_dbus_pending_property_success(id);
 
-       device_set_temporary(device, FALSE);
-       adapter->devices = g_slist_append(adapter->devices, device);
+       store_adapter_info(adapter);
 
-       services = string_to_primary_list(value);
-       if (services == NULL)
-               return;
-
-       for (l = services, uuids = NULL; l; l = l->next) {
-               struct gatt_primary *prim = l->data;
-               uuids = g_slist_append(uuids, prim->uuid);
-       }
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                               ADAPTER_INTERFACE, "DiscoverableTimeout");
 
-       device_register_services(connection, device, services, -1);
+       if (adapter->current_settings & MGMT_SETTING_DISCOVERABLE)
+               set_discoverable(adapter, 0x01, adapter->discoverable_timeout);
+}
 
-       device_probe_drivers(device, uuids);
+static gboolean property_get_pairable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-       g_slist_free(uuids);
+       return property_get_mode(adapter, MGMT_SETTING_PAIRABLE, iter);
 }
 
-static void smp_key_free(void *data)
+static void property_set_pairable(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
 {
-       struct smp_ltk_info *info = data;
+       struct btd_adapter *adapter = user_data;
 
-       g_free(info);
+       property_set_mode(adapter, MGMT_SETTING_PAIRABLE, iter, id);
 }
 
-static void load_devices(struct btd_adapter *adapter)
+static gboolean property_get_pairable_timeout(
+                                       const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       char filename[PATH_MAX + 1];
-       char srcaddr[18];
-       struct adapter_keys keys = { adapter, NULL };
-       int err;
-
-       ba2str(&adapter->bdaddr, srcaddr);
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value = adapter->pairable_timeout;
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "profiles");
-       textfile_foreach(filename, create_stored_device_from_profiles,
-                                                               adapter);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &value);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "primaries");
-       textfile_foreach(filename, create_stored_device_from_primaries,
-                                                               adapter);
+       return TRUE;
+}
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "linkkeys");
-       textfile_foreach(filename, create_stored_device_from_linkkeys, &keys);
+static void property_set_pairable_timeout(const GDBusPropertyTable *property,
+                               DBusMessageIter *iter,
+                               GDBusPendingPropertySet id, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       dbus_uint32_t value;
 
-       err = adapter_ops->load_keys(adapter->dev_id, keys.keys,
-                                                       main_opts.debug_keys);
-       if (err < 0)
-               error("Unable to load keys to adapter_ops: %s (%d)",
-                                                       strerror(-err), -err);
+       dbus_message_iter_get_basic(iter, &value);
 
-       g_slist_free_full(keys.keys, g_free);
-       keys.keys = NULL;
+       adapter->pairable_timeout = value;
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "longtermkeys");
-       textfile_foreach(filename, create_stored_device_from_ltks, &keys);
+       g_dbus_pending_property_success(id);
 
-       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;
+       store_adapter_info(adapter);
 
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "blocked");
-       textfile_foreach(filename, create_stored_device_from_blocked, adapter);
+       trigger_pairable_timeout(adapter);
 }
 
-int btd_adapter_block_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint8_t bdaddr_type)
+static gboolean property_get_discovering(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       return adapter_ops->block_device(adapter->dev_id, bdaddr, bdaddr_type);
-}
+       struct btd_adapter *adapter = user_data;
+       dbus_bool_t discovering = adapter->discovering;
 
-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,
-                                                               bdaddr_type);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &discovering);
+
+       return TRUE;
 }
 
-static void clear_blocked(struct btd_adapter *adapter)
+static gboolean property_get_uuids(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       int err;
+       struct btd_adapter *adapter = user_data;
+       DBusMessageIter entry;
+       sdp_list_t *l;
 
-       err = adapter_ops->unblock_device(adapter->dev_id, BDADDR_ANY, 0);
-       if (err < 0)
-               error("Clearing blocked list failed: %s (%d)",
-                                               strerror(-err), -err);
-}
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_STRING_AS_STRING, &entry);
 
-static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
-{
-       struct btd_adapter_driver *driver = user_data;
-       int err;
+       for (l = adapter->services; l != NULL; l = l->next) {
+               sdp_record_t *rec = l->data;
+               char *uuid;
 
-       if (driver->probe == NULL)
-               return;
+               uuid = bt_uuid2string(&rec->svclass);
+               if (uuid == NULL)
+                       continue;
 
-       err = driver->probe(adapter);
-       if (err < 0) {
-               error("%s: %s (%d)", driver->name, strerror(-err), -err);
-               return;
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+                                                               &uuid);
+               g_free(uuid);
        }
 
-       adapter->loaded_drivers = g_slist_prepend(adapter->loaded_drivers,
-                                                                       driver);
+       dbus_message_iter_close_container(iter, &entry);
+
+       return TRUE;
 }
 
-static void load_drivers(struct btd_adapter *adapter)
+static gboolean property_exists_modalias(const GDBusPropertyTable *property,
+                                                       void *user_data)
 {
-       GSList *l;
+       struct btd_adapter *adapter = user_data;
 
-       for (l = adapter_drivers; l; l = l->next)
-               probe_driver(adapter, l->data);
+       return adapter->modalias ? TRUE : FALSE;
 }
 
-static void load_connections(struct btd_adapter *adapter)
+static gboolean property_get_modalias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *user_data)
 {
-       GSList *l, *conns;
-       int err;
-
-       err = adapter_ops->get_conn_list(adapter->dev_id, &conns);
-       if (err < 0) {
-               error("Unable to fetch existing connections: %s (%d)",
-                                                       strerror(-err), -err);
-               return;
-       }
+       struct btd_adapter *adapter = user_data;
+       const char *str = adapter->modalias ? : "";
 
-       for (l = conns; l != NULL; l = g_slist_next(l)) {
-               bdaddr_t *bdaddr = l->data;
-               struct btd_device *device;
-               char address[18];
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &str);
 
-               ba2str(bdaddr, address);
-               DBG("Adding existing connection to %s", address);
+       return TRUE;
+}
 
-               device = adapter_get_device(connection, adapter, address);
-               if (device)
-                       adapter_add_connection(adapter, device);
-       }
+static int device_path_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct btd_device *device = a;
+       const char *path = b;
+       const char *dev_path = device_get_path(device);
 
-       g_slist_free_full(conns, g_free);
+       return strcasecmp(dev_path, path);
 }
 
-static int get_discoverable_timeout(const char *src)
+static DBusMessage *remove_device(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
 {
-       int timeout;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       const char *path;
+       GSList *list;
 
-       if (read_discoverable_timeout(src, &timeout) == 0)
-               return timeout;
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
 
-       return main_opts.discovto;
-}
+       list = g_slist_find_custom(adapter->devices, path, device_path_cmp);
+       if (!list)
+               return btd_error_does_not_exist(msg);
 
-static int get_pairable_timeout(const char *src)
-{
-       int timeout;
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return btd_error_not_ready(msg);
 
-       if (read_pairable_timeout(src, &timeout) == 0)
-               return timeout;
+       device = list->data;
 
-       return main_opts.pairto;
-}
+       device_set_temporary(device, TRUE);
 
-static void call_adapter_powered_callbacks(struct btd_adapter *adapter,
-                                               gboolean powered)
-{
-       GSList *l;
+       if (!device_is_connected(device)) {
+               adapter_remove_device(adapter, device);
+               return dbus_message_new_method_return(msg);
+       }
 
-       for (l = adapter->powered_callbacks; l; l = l->next) {
-               btd_adapter_powered_cb cb = l->data;
+       device_request_disconnect(device, msg);
 
-               cb(adapter, powered);
-       }
+       return NULL;
 }
 
-static void emit_device_disappeared(gpointer data, gpointer user_data)
-{
-       struct remote_dev_info *dev = data;
-       struct btd_adapter *adapter = user_data;
-       char address[18];
-       const char *paddr = address;
-
-       ba2str(&dev->bdaddr, address);
+static const GDBusMethodTable adapter_methods[] = {
+       { GDBUS_METHOD("StartDiscovery", NULL, NULL, start_discovery) },
+       { GDBUS_METHOD("StopDiscovery", NULL, NULL, stop_discovery) },
+       { GDBUS_ASYNC_METHOD("RemoveDevice",
+                       GDBUS_ARGS({ "device", "o" }), NULL, remove_device) },
+       { }
+};
 
-       g_dbus_emit_signal(connection, adapter->path,
-                       ADAPTER_INTERFACE, "DeviceDisappeared",
-                       DBUS_TYPE_STRING, &paddr,
-                       DBUS_TYPE_INVALID);
+static const GDBusPropertyTable adapter_properties[] = {
+       { "Address", "s", property_get_address },
+       { "Name", "s", property_get_name },
+       { "Alias", "s", property_get_alias, property_set_alias },
+       { "Class", "u", property_get_class },
+       { "Powered", "b", property_get_powered, property_set_powered },
+       { "Discoverable", "b", property_get_discoverable,
+                                       property_set_discoverable },
+       { "DiscoverableTimeout", "u", property_get_discoverable_timeout,
+                                       property_set_discoverable_timeout },
+       { "Pairable", "b", property_get_pairable, property_set_pairable },
+       { "PairableTimeout", "u", property_get_pairable_timeout,
+                                       property_set_pairable_timeout },
+       { "Discovering", "b", property_get_discovering },
+       { "UUIDs", "as", property_get_uuids },
+       { "Modalias", "s", property_get_modalias, NULL,
+                                       property_exists_modalias },
+       { }
+};
 
-       adapter->found_devices = g_slist_remove(adapter->found_devices, dev);
-}
+struct adapter_keys {
+       struct btd_adapter *adapter;
+       GSList *keys;
+};
 
-void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
-                                               uint8_t *on_mode,
-                                               uint16_t *discoverable_timeout,
-                                               gboolean *pairable)
+static int str2buf(const char *str, uint8_t *buf, size_t blen)
 {
-       char str[14], address[18];
+       int i, dlen;
 
-       ba2str(&adapter->bdaddr, address);
+       if (str == NULL)
+               return -EINVAL;
 
-       if (mode) {
-               if (main_opts.remember_powered == FALSE)
-                       *mode = main_opts.mode;
-               else if (read_device_mode(address, str, sizeof(str)) == 0)
-                       *mode = get_mode(&adapter->bdaddr, str);
-               else
-                       *mode = main_opts.mode;
-       }
+       memset(buf, 0, blen);
 
-       if (on_mode)
-               *on_mode = get_mode(&adapter->bdaddr, "on");
+       dlen = MIN((strlen(str) / 2), blen);
 
-       if (discoverable_timeout)
-               *discoverable_timeout = get_discoverable_timeout(address);
+       for (i = 0; i < dlen; i++)
+               sscanf(str + (i * 2), "%02hhX", &buf[i]);
 
-       if (pairable)
-               *pairable = adapter->pairable;
+       return 0;
 }
 
-void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
-                                                               uint8_t *minor)
+static struct link_key_info *get_key_info(GKeyFile *key_file, const char *peer)
 {
-       uint8_t cls[3];
+       struct link_key_info *info = NULL;
+       char *str;
 
-       if (read_local_class(&adapter->bdaddr, cls) < 0) {
-               uint32_t class = htobl(main_opts.class);
-               memcpy(cls, &class, 3);
-       }
+       str = g_key_file_get_string(key_file, "LinkKey", "Key", NULL);
+       if (!str || strlen(str) != 34)
+               goto failed;
 
-       *major = cls[1];
-       *minor = cls[0];
-}
+       info = g_new0(struct link_key_info, 1);
 
-const char *btd_adapter_get_name(struct btd_adapter *adapter)
-{
-       return adapter->name;
+       str2ba(peer, &info->bdaddr);
+       str2buf(&str[2], info->key, sizeof(info->key));
+
+       info->type = g_key_file_get_integer(key_file, "LinkKey", "Type", NULL);
+       info->pin_len = g_key_file_get_integer(key_file, "LinkKey", "PINLength",
+                                               NULL);
+
+failed:
+       g_free(str);
+
+       return info;
 }
 
-void btd_adapter_start(struct btd_adapter *adapter)
+static struct smp_ltk_info *get_ltk_info(GKeyFile *key_file, const char *peer)
 {
-       char address[18];
-       gboolean powered;
+       struct smp_ltk_info *ltk = NULL;
+       char *key;
+       char *rand = NULL;
+       char *type = NULL;
+       uint8_t bdaddr_type;
 
-       ba2str(&adapter->bdaddr, address);
+       key = g_key_file_get_string(key_file, "LongTermKey", "Key", NULL);
+       if (!key || strlen(key) != 34)
+               goto failed;
+
+       rand = g_key_file_get_string(key_file, "LongTermKey", "Rand", NULL);
+       if (!rand || strlen(rand) != 18)
+               goto failed;
 
-       adapter->dev_class = 0;
-       adapter->off_requested = FALSE;
-       adapter->up = TRUE;
-       adapter->discov_timeout = get_discoverable_timeout(address);
-       adapter->pairable_timeout = get_pairable_timeout(address);
-       adapter->off_timer = 0;
+       type = g_key_file_get_string(key_file, "General", "AddressType", NULL);
+       if (!type)
+               goto failed;
 
-       if (adapter->scan_mode & SCAN_INQUIRY)
-               adapter->mode = MODE_DISCOVERABLE;
+       if (g_str_equal(type, "public"))
+               bdaddr_type = BDADDR_LE_PUBLIC;
+       else if (g_str_equal(type, "static"))
+               bdaddr_type = BDADDR_LE_RANDOM;
        else
-               adapter->mode = MODE_CONNECTABLE;
+               goto failed;
 
-       powered = TRUE;
-       emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Powered",
-                                       DBUS_TYPE_BOOLEAN, &powered);
+       ltk = g_new0(struct smp_ltk_info, 1);
 
-       call_adapter_powered_callbacks(adapter, TRUE);
+       str2ba(peer, &ltk->bdaddr);
+       ltk->bdaddr_type = bdaddr_type;
+       str2buf(&key[2], ltk->val, sizeof(ltk->val));
+       str2buf(&rand[2], ltk->rand, sizeof(ltk->rand));
+
+       ltk->authenticated = g_key_file_get_integer(key_file, "LongTermKey",
+                                                       "Authenticated", NULL);
+       ltk->master = g_key_file_get_integer(key_file, "LongTermKey", "Master",
+                                               NULL);
+       ltk->enc_size = g_key_file_get_integer(key_file, "LongTermKey",
+                                               "EncSize", NULL);
+       ltk->ediv = g_key_file_get_integer(key_file, "LongTermKey", "EDiv",
+                                               NULL);
 
-       adapter_ops->disable_cod_cache(adapter->dev_id);
+failed:
+       g_free(key);
+       g_free(rand);
+       g_free(type);
 
-       info("Adapter %s has been enabled", adapter->path);
+       return ltk;
 }
 
-static void reply_pending_requests(struct btd_adapter *adapter)
+static void load_link_keys_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       GSList *l;
+       struct btd_adapter *adapter = user_data;
 
-       if (!adapter)
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to load link keys for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
                return;
-
-       /* pending bonding */
-       for (l = adapter->devices; l; l = l->next) {
-               struct btd_device *device = l->data;
-
-               if (device_is_bonding(device, NULL))
-                       device_cancel_bonding(device,
-                                               HCI_OE_USER_ENDED_CONNECTION);
        }
+
+       DBG("link keys loaded for hci%u", adapter->dev_id);
 }
 
-static void remove_driver(gpointer data, gpointer user_data)
+static void load_link_keys(struct btd_adapter *adapter, GSList *keys,
+                                                       bool debug_keys)
 {
-       struct btd_adapter_driver *driver = data;
-       struct btd_adapter *adapter = user_data;
+       struct mgmt_cp_load_link_keys *cp;
+       struct mgmt_link_key_info *key;
+       size_t key_count, cp_size;
+       unsigned int id;
+       GSList *l;
 
-       if (driver->remove)
-               driver->remove(adapter);
-}
+       /*
+        * If the controller does not support BR/EDR operation,
+        * there is no point in trying to load the link keys into
+        * the kernel.
+        *
+        * This is an optimization for Low Energy only controllers.
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_BREDR))
+               return;
 
-static void unload_drivers(struct btd_adapter *adapter)
-{
-       g_slist_foreach(adapter->loaded_drivers, remove_driver, adapter);
-       g_slist_free(adapter->loaded_drivers);
-       adapter->loaded_drivers = NULL;
-}
+       key_count = g_slist_length(keys);
 
-static void set_mode_complete(struct btd_adapter *adapter)
-{
-       struct session_req *pending;
-       const char *modestr;
-       int err;
+       DBG("hci%u keys %zu debug_keys %d", adapter->dev_id, key_count,
+                                                               debug_keys);
 
-       DBG("");
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
 
-       if (adapter->mode == MODE_OFF) {
-               g_slist_free_full(adapter->mode_sessions, session_free);
-               adapter->mode_sessions = NULL;
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("No memory for link keys for hci%u", adapter->dev_id);
+               return;
        }
 
-       if (adapter->pending_mode == NULL)
-               return;
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way it is ensured
+        * that no old keys from a previous daemon are present.
+        *
+        * In addition it is also the only way to toggle the different
+        * behavior for debug keys.
+        */
+       cp->debug_keys = debug_keys;
+       cp->key_count = htobs(key_count);
 
-       pending = adapter->pending_mode;
-       adapter->pending_mode = NULL;
+       for (l = keys, key = cp->keys; l != NULL; l = g_slist_next(l), key++) {
+               struct link_key_info *info = l->data;
 
-       err = (pending->mode != adapter->mode) ? -EINVAL : 0;
+               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;
+       }
 
-       if (pending->msg != NULL) {
-               DBusMessage *msg = pending->msg;
-               DBusMessage *reply;
+       id = mgmt_send(adapter->mgmt, MGMT_OP_LOAD_LINK_KEYS,
+                               adapter->dev_id, cp_size, cp,
+                               load_link_keys_complete, adapter, NULL);
 
-               if (err < 0)
-                       reply = btd_error_failed(msg, strerror(-err));
-               else {
-                       if (strcmp(dbus_message_get_member(msg),
-                                               "SetProperty") == 0)
-                               adapter->global_mode = adapter->mode;
-                       reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
-               }
+       g_free(cp);
 
-               g_dbus_send_message(connection, reply);
-       }
+       if (id == 0)
+               error("Failed to load link keys for hci%u", adapter->dev_id);
+}
+
+static gboolean load_ltks_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
 
-       modestr = mode2str(adapter->mode);
+       error("Loading LTKs timed out for hci%u", adapter->dev_id);
 
-       DBG("%s", modestr);
+       adapter->load_ltks_timeout = 0;
 
-       /* restore if the mode doesn't matches the pending */
-       if (err != 0) {
-               write_device_mode(&adapter->bdaddr, modestr);
-               error("unable to set mode: %s", mode2str(pending->mode));
-       }
+       mgmt_cancel(adapter->mgmt, adapter->load_ltks_id);
+       adapter->load_ltks_id = 0;
 
-       session_unref(pending);
+       return FALSE;
 }
 
-int btd_adapter_stop(struct btd_adapter *adapter)
+static void load_ltks_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       gboolean prop_false = FALSE;
+       struct btd_adapter *adapter = user_data;
 
-       /* check pending requests */
-       reply_pending_requests(adapter);
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to load LTKs for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+       }
 
-       adapter->up = FALSE;
+       adapter->load_ltks_id = 0;
 
-       stop_discovery(adapter);
+       g_source_remove(adapter->load_ltks_timeout);
+       adapter->load_ltks_timeout = 0;
 
-       if (adapter->disc_sessions) {
-               g_slist_free_full(adapter->disc_sessions, session_free);
-               adapter->disc_sessions = NULL;
-       }
+       DBG("LTKs loaded for hci%u", adapter->dev_id);
+}
 
-       while (adapter->connections) {
-               struct btd_device *device = adapter->connections->data;
-               adapter_remove_connection(adapter, device);
-       }
+static void load_ltks(struct btd_adapter *adapter, GSList *keys)
+{
+       struct mgmt_cp_load_long_term_keys *cp;
+       struct mgmt_ltk_info *key;
+       size_t key_count, cp_size;
+       GSList *l;
 
-       if (adapter->scan_mode == (SCAN_PAGE | SCAN_INQUIRY))
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Discoverable",
-                                       DBUS_TYPE_BOOLEAN, &prop_false);
+       /*
+        * If the controller does not support Low Energy operation,
+        * there is no point in trying to load the long term keys
+        * into the kernel.
+        *
+        * While there is no harm in loading keys into the kernel,
+        * this is an optimization to avoid a confusing warning
+        * message when the loading of the keys timed out due to
+        * a kernel bug (see comment below).
+        */
+       if (!(adapter->supported_settings & MGMT_SETTING_LE))
+               return;
 
-       if ((adapter->scan_mode & SCAN_PAGE) && adapter->pairable == TRUE)
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &prop_false);
+       key_count = g_slist_length(keys);
 
-       if (adapter->discovering)
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Discovering",
-                                       DBUS_TYPE_BOOLEAN, &prop_false);
+       DBG("hci%u keys %zu", adapter->dev_id, key_count);
 
-       emit_property_changed(connection, adapter->path, ADAPTER_INTERFACE,
-                               "Powered", DBUS_TYPE_BOOLEAN, &prop_false);
+       cp_size = sizeof(*cp) + (key_count * sizeof(*key));
 
-       adapter->discovering = FALSE;
-       adapter->scan_mode = SCAN_DISABLED;
-       adapter->mode = MODE_OFF;
-       adapter->off_requested = FALSE;
+       cp = g_try_malloc0(cp_size);
+       if (cp == NULL) {
+               error("No memory for LTKs for hci%u", adapter->dev_id);
+               return;
+       }
 
-       call_adapter_powered_callbacks(adapter, FALSE);
+       /*
+        * Even if the list of stored keys is empty, it is important to
+        * load an empty list into the kernel. That way it is ensured
+        * that no old keys from a previous daemon are present.
+        */
+       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;
+       }
 
-       info("Adapter %s has been disabled", adapter->path);
+       adapter->load_ltks_id = mgmt_send(adapter->mgmt,
+                                       MGMT_OP_LOAD_LONG_TERM_KEYS,
+                                       adapter->dev_id, cp_size, cp,
+                                       load_ltks_complete, adapter, NULL);
 
-       set_mode_complete(adapter);
+       g_free(cp);
 
-       return 0;
-}
+       if (adapter->load_ltks_id == 0) {
+               error("Failed to load LTKs for hci%u", adapter->dev_id);
+               return;
+       }
 
-static void off_timer_remove(struct btd_adapter *adapter)
-{
-       g_source_remove(adapter->off_timer);
-       adapter->off_timer = 0;
+       /*
+        * This timeout handling is needed since the kernel is stupid
+        * and forgets to send a command complete response. However in
+        * case of failures it does send a command status.
+        */
+       adapter->load_ltks_timeout = g_timeout_add_seconds(2,
+                                               load_ltks_timeout, adapter);
 }
 
-static void adapter_free(gpointer user_data)
+static void load_devices(struct btd_adapter *adapter)
 {
-       struct btd_adapter *adapter = user_data;
+       char filename[PATH_MAX + 1];
+       char srcaddr[18];
+       struct adapter_keys keys = { adapter, NULL };
+       struct adapter_keys ltks = { adapter, NULL };
+       DIR *dir;
+       struct dirent *entry;
 
-       agent_free(adapter->agent);
-       adapter->agent = NULL;
+       ba2str(&adapter->bdaddr, srcaddr);
 
-       DBG("%p", adapter);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s", srcaddr);
+       filename[PATH_MAX] = '\0';
 
-       if (adapter->auth_idle_id)
-               g_source_remove(adapter->auth_idle_id);
+       dir = opendir(filename);
+       if (!dir) {
+               error("Unable to open adapter storage directory: %s", filename);
+               return;
+       }
 
-       if (adapter->off_timer)
-               off_timer_remove(adapter);
+       while ((entry = readdir(dir)) != NULL) {
+               struct btd_device *device;
+               char filename[PATH_MAX + 1];
+               GKeyFile *key_file;
+               struct link_key_info *key_info;
+               struct smp_ltk_info *ltk_info;
+               GSList *list;
 
-       sdp_list_free(adapter->services, NULL);
+               if (entry->d_type != DT_DIR || bachk(entry->d_name) < 0)
+                       continue;
 
-       g_slist_free_full(adapter->found_devices, dev_info_free);
+               snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", srcaddr,
+                               entry->d_name);
 
-       g_slist_free(adapter->oor_devices);
+               key_file = g_key_file_new();
+               g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       g_free(adapter->path);
-       g_free(adapter->name);
-       g_free(adapter);
-}
+               key_info = get_key_info(key_file, entry->d_name);
+               if (key_info)
+                       keys.keys = g_slist_append(keys.keys, key_info);
 
-struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter)
-{
-       adapter->ref++;
+               ltk_info = get_ltk_info(key_file, entry->d_name);
+               if (ltk_info)
+                       ltks.keys = g_slist_append(ltks.keys, ltk_info);
 
-       DBG("%p: ref=%d", adapter, adapter->ref);
+               list = g_slist_find_custom(adapter->devices, entry->d_name,
+                                                       device_address_cmp);
+               if (list) {
+                       device = list->data;
+                       goto device_exist;
+               }
 
-       return adapter;
-}
+               device = device_create_from_storage(adapter, entry->d_name,
+                                                       key_file);
+               if (!device)
+                       goto free;
 
-void btd_adapter_unref(struct btd_adapter *adapter)
-{
-       gchar *path;
+               device_set_temporary(device, FALSE);
+               adapter->devices = g_slist_append(adapter->devices, device);
 
-       adapter->ref--;
+               /* TODO: register services from pre-loaded list of primaries */
 
-       DBG("%p: ref=%d", adapter, adapter->ref);
+               list = device_get_uuids(device);
+               if (list)
+                       device_probe_profiles(device, list);
 
-       if (adapter->ref > 0)
-               return;
+device_exist:
+               if (key_info || ltk_info) {
+                       device_set_paired(device, TRUE);
+                       device_set_bonded(device, TRUE);
+               }
+
+free:
+               g_key_file_free(key_file);
+       }
 
-       path = g_strdup(adapter->path);
+       closedir(dir);
 
-       g_dbus_unregister_interface(connection, path, ADAPTER_INTERFACE);
+       load_link_keys(adapter, keys.keys, main_opts.debug_keys);
+       g_slist_free_full(keys.keys, g_free);
 
-       g_free(path);
+       load_ltks(adapter, ltks.keys);
+       g_slist_free_full(ltks.keys, g_free);
 }
 
-gboolean adapter_init(struct btd_adapter *adapter, gboolean up)
+int btd_adapter_block_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
 {
-       adapter->up = up;
+       struct mgmt_cp_block_device cp;
+       char addr[18];
 
-       adapter->allow_name_changes = TRUE;
+       ba2str(bdaddr, addr);
+       DBG("hci%u %s", adapter->dev_id, addr);
 
-       adapter_ops->read_bdaddr(adapter->dev_id, &adapter->bdaddr);
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
 
-       if (bacmp(&adapter->bdaddr, BDADDR_ANY) == 0) {
-               error("No address available for hci%d", adapter->dev_id);
-               return FALSE;
-       }
+       if (mgmt_send(adapter->mgmt, MGMT_OP_BLOCK_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       sdp_init_services_list(&adapter->bdaddr);
+       return -EIO;
+}
 
-       if (main_opts.gatt_enabled)
-               btd_adapter_gatt_server_start(adapter);
+int btd_adapter_unblock_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct mgmt_cp_unblock_device cp;
+       char addr[18];
 
-       load_drivers(adapter);
-       clear_blocked(adapter);
-       load_devices(adapter);
+       ba2str(bdaddr, addr);
+       DBG("hci%u %s", adapter->dev_id, addr);
 
-       /* Set pairable mode */
-       if (read_device_pairable(&adapter->bdaddr, &adapter->pairable) < 0)
-               adapter->pairable = TRUE;
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
 
-       /* retrieve the active connections: address the scenario where
-        * the are active connections before the daemon've started */
-       load_connections(adapter);
-
-       adapter->initialized = TRUE;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_UNBLOCK_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
 
-       return TRUE;
+       return -EIO;
 }
 
-struct btd_adapter *adapter_create(DBusConnection *conn, int id)
+static int clear_blocked(struct btd_adapter *adapter)
 {
-       char path[MAX_PATH_LENGTH];
-       struct btd_adapter *adapter;
-       const char *base_path = manager_get_base_path();
-
-       if (!connection)
-               connection = conn;
-
-       adapter = g_try_new0(struct btd_adapter, 1);
-       if (!adapter) {
-               error("adapter_create: failed to alloc memory for hci%d", id);
-               return NULL;
-       }
+       return btd_adapter_unblock_address(adapter, BDADDR_ANY, 0);
+}
 
-       adapter->dev_id = id;
+static void probe_driver(struct btd_adapter *adapter, gpointer user_data)
+{
+       struct btd_adapter_driver *driver = user_data;
+       int err;
 
-       snprintf(path, sizeof(path), "%s/hci%d", base_path, id);
-       adapter->path = g_strdup(path);
+       if (driver->probe == NULL)
+               return;
 
-       if (!g_dbus_register_interface(conn, path, ADAPTER_INTERFACE,
-                                       adapter_methods, adapter_signals, NULL,
-                                       adapter, adapter_free)) {
-               error("Adapter interface init failed on path %s", path);
-               adapter_free(adapter);
-               return NULL;
+       err = driver->probe(adapter);
+       if (err < 0) {
+               error("%s: %s (%d)", driver->name, strerror(-err), -err);
+               return;
        }
 
-       return btd_adapter_ref(adapter);
+       adapter->drivers = g_slist_prepend(adapter->drivers, driver);
 }
 
-void adapter_remove(struct btd_adapter *adapter)
+static void load_drivers(struct btd_adapter *adapter)
 {
        GSList *l;
 
-       DBG("Removing adapter %s", adapter->path);
-
-       for (l = adapter->devices; l; l = l->next)
-               device_remove(l->data, FALSE);
-       g_slist_free(adapter->devices);
+       for (l = adapter_drivers; l; l = l->next)
+               probe_driver(adapter, l->data);
+}
 
-       unload_drivers(adapter);
-       if (main_opts.gatt_enabled)
-               btd_adapter_gatt_server_stop(adapter);
+static void probe_profile(struct btd_profile *profile, void *data)
+{
+       struct btd_adapter *adapter = data;
+       int err;
 
-       g_slist_free(adapter->pin_callbacks);
+       if (profile->adapter_probe == NULL)
+               return;
 
-       /* Return adapter to down state if it was not up on init */
-       adapter_ops->restore_powered(adapter->dev_id);
-}
+       err = profile->adapter_probe(profile, adapter);
+       if (err < 0) {
+               error("%s: %s (%d)", profile->name, strerror(-err), -err);
+               return;
+       }
 
-uint16_t adapter_get_dev_id(struct btd_adapter *adapter)
-{
-       return adapter->dev_id;
+       adapter->profiles = g_slist_prepend(adapter->profiles, profile);
 }
 
-const gchar *adapter_get_path(struct btd_adapter *adapter)
+void adapter_add_profile(struct btd_adapter *adapter, gpointer p)
 {
-       if (!adapter)
-               return NULL;
+       struct btd_profile *profile = p;
 
-       return adapter->path;
-}
+       if (!adapter->initialized)
+               return;
 
-void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       bacpy(bdaddr, &adapter->bdaddr);
-}
+       probe_profile(profile, adapter);
 
-void adapter_set_allow_name_changes(struct btd_adapter *adapter,
-                                               gboolean allow_name_changes)
-{
-       adapter->allow_name_changes = allow_name_changes;
+       g_slist_foreach(adapter->devices, device_probe_profile, profile);
 }
 
-void adapter_set_discovering(struct btd_adapter *adapter,
-                                               gboolean discovering)
+void adapter_remove_profile(struct btd_adapter *adapter, gpointer p)
 {
-       const char *path = adapter->path;
+       struct btd_profile *profile = p;
 
-       adapter->discovering = discovering;
+       if (!adapter->initialized)
+               return;
 
-       emit_property_changed(connection, path,
-                               ADAPTER_INTERFACE, "Discovering",
-                               DBUS_TYPE_BOOLEAN, &discovering);
+       if (profile->device_remove)
+               g_slist_foreach(adapter->devices, device_remove_profile, p);
 
-       if (discovering)
-               return;
+       adapter->profiles = g_slist_remove(adapter->profiles, profile);
 
-       g_slist_foreach(adapter->oor_devices, emit_device_disappeared, adapter);
-       g_slist_free_full(adapter->oor_devices, dev_info_free);
-       adapter->oor_devices = g_slist_copy(adapter->found_devices);
+       if (profile->adapter_remove)
+               profile->adapter_remove(profile, adapter);
+}
 
-       if (!adapter_has_discov_sessions(adapter) || adapter->discov_suspended)
+static void adapter_add_connection(struct btd_adapter *adapter,
+                                               struct btd_device *device)
+{
+       if (g_slist_find(adapter->connections, device)) {
+               error("Device is already marked as connected");
                return;
+       }
 
-       DBG("hci%u restarting discovery, disc_sessions %u", adapter->dev_id,
-                                       g_slist_length(adapter->disc_sessions));
+       device_add_connection(device);
 
-       adapter->discov_id = g_idle_add(discovery_cb, adapter);
+       adapter->connections = g_slist_append(adapter->connections, device);
 }
 
-static void suspend_discovery(struct btd_adapter *adapter)
+static void get_connections_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       if (adapter->disc_sessions == NULL || adapter->discov_suspended)
-               return;
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_get_connections *rp = param;
+       uint16_t i, conn_count;
 
-       DBG("Suspending discovery");
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to get connections: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
 
-       if (adapter->oor_devices) {
-               g_slist_free(adapter->oor_devices);
-               adapter->oor_devices = NULL;
+       if (length < sizeof(*rp)) {
+               error("Wrong size of get connections response");
+               return;
        }
 
-       adapter->discov_suspended = TRUE;
+       conn_count = btohs(rp->conn_count);
 
-       if (adapter->discov_id > 0) {
-               g_source_remove(adapter->discov_id);
-               adapter->discov_id = 0;
-       } else
-               adapter_ops->stop_discovery(adapter->dev_id);
-}
+       DBG("Connection count: %d", conn_count);
 
-static int found_device_cmp(gconstpointer a, gconstpointer b)
-{
-       const struct remote_dev_info *d = a;
-       const bdaddr_t *bdaddr = b;
+       if (conn_count * sizeof(struct mgmt_addr_info) +
+                                               sizeof(*rp) != length) {
+               error("Incorrect packet size for get connections response");
+               return;
+       }
 
-       if (bacmp(bdaddr, BDADDR_ANY) == 0)
-               return 0;
+       for (i = 0; i < conn_count; i++) {
+               const struct mgmt_addr_info *addr = &rp->addr[i];
+               struct btd_device *device;
+               char address[18];
+
+               ba2str(&addr->bdaddr, address);
+               DBG("Adding existing connection to %s", address);
 
-       return bacmp(&d->bdaddr, bdaddr);
+               device = adapter_get_device(adapter, &addr->bdaddr, addr->type);
+               if (device)
+                       adapter_add_connection(adapter, device);
+       }
 }
 
-struct remote_dev_info *adapter_search_found_devices(struct btd_adapter *adapter,
-                                                       bdaddr_t *bdaddr)
+static void load_connections(struct btd_adapter *adapter)
 {
-       GSList *l;
+       DBG("sending get connections command for index %u", adapter->dev_id);
 
-       l = g_slist_find_custom(adapter->found_devices, bdaddr,
-                                                       found_device_cmp);
-       if (l)
-               return l->data;
+       if (mgmt_send(adapter->mgmt, MGMT_OP_GET_CONNECTIONS,
+                               adapter->dev_id, 0, NULL,
+                               get_connections_complete, adapter, NULL) > 0)
+               return;
 
-       return NULL;
+       error("Failed to get connections for index %u", adapter->dev_id);
 }
 
-static int dev_rssi_cmp(struct remote_dev_info *d1, struct remote_dev_info *d2)
+bool btd_adapter_get_pairable(struct btd_adapter *adapter)
 {
-       int rssi1, rssi2;
+       if (adapter->current_settings & MGMT_SETTING_PAIRABLE)
+               return true;
 
-       rssi1 = d1->rssi < 0 ? -d1->rssi : d1->rssi;
-       rssi2 = d2->rssi < 0 ? -d2->rssi : d2->rssi;
-
-       return rssi1 - rssi2;
+       return false;
 }
 
-static void append_dict_valist(DBusMessageIter *iter,
-                                       const char *first_key,
-                                       va_list var_args)
+bool btd_adapter_get_powered(struct btd_adapter *adapter)
 {
-       DBusMessageIter dict;
-       const char *key;
-       int type;
-       int n_elements;
-       void *val;
-
-       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);
-
-       key = first_key;
-       while (key) {
-               type = va_arg(var_args, int);
-               val = va_arg(var_args, void *);
-               if (type == DBUS_TYPE_ARRAY) {
-                       n_elements = va_arg(var_args, int);
-                       if (n_elements > 0)
-                               dict_append_array(&dict, key, DBUS_TYPE_STRING,
-                                               val, n_elements);
-               } else
-                       dict_append_entry(&dict, key, type, val);
-               key = va_arg(var_args, char *);
-       }
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               return true;
 
-       dbus_message_iter_close_container(iter, &dict);
+       return false;
 }
 
-static void emit_device_found(const char *path, const char *address,
-                               const char *first_key, ...)
+bool btd_adapter_get_connectable(struct btd_adapter *adapter)
 {
-       DBusMessage *signal;
-       DBusMessageIter iter;
-       va_list var_args;
-
-       signal = dbus_message_new_signal(path, ADAPTER_INTERFACE,
-                                       "DeviceFound");
-       if (!signal) {
-               error("Unable to allocate new %s.DeviceFound signal",
-                               ADAPTER_INTERFACE);
-               return;
-       }
-       dbus_message_iter_init_append(signal, &iter);
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &address);
+       if (adapter->current_settings & MGMT_SETTING_CONNECTABLE)
+               return true;
 
-       va_start(var_args, first_key);
-       append_dict_valist(&iter, first_key, var_args);
-       va_end(var_args);
-
-       g_dbus_send_message(connection, signal);
+       return false;
 }
 
-static char **strlist2array(GSList *list)
+uint32_t btd_adapter_get_class(struct btd_adapter *adapter)
 {
-       unsigned int i, n;
-       char **array;
-
-       if (list == NULL)
-               return NULL;
+       return adapter->dev_class;
+}
 
-       n = g_slist_length(list);
-       array = g_new0(char *, n + 1);
+const char *btd_adapter_get_name(struct btd_adapter *adapter)
+{
+       if (adapter->stored_alias)
+               return adapter->stored_alias;
 
-       for (i = 0; list; list = list->next, i++)
-               array[i] = g_strdup((const gchar *) list->data);
+       if (adapter->system_name)
+               return adapter->system_name;
 
-       return array;
+       return NULL;
 }
 
-void adapter_emit_device_found(struct btd_adapter *adapter,
-                                               struct remote_dev_info *dev)
+int adapter_connect_list_add(struct btd_adapter *adapter,
+                                       struct btd_device *device)
 {
-       struct btd_device *device;
-       char peer_addr[18], local_addr[18];
-       const char *icon, *paddr = peer_addr;
-       dbus_bool_t paired = FALSE, trusted = FALSE;
-       dbus_int16_t rssi = dev->rssi;
-       char *alias;
-       size_t uuid_count;
-
-       ba2str(&dev->bdaddr, peer_addr);
-       ba2str(&adapter->bdaddr, local_addr);
+       /*
+        * If the adapter->connect_le device is getting added back to
+        * the connect list it probably means that the connect attempt
+        * failed and hence we should clear this pointer
+        */
+       if (device == adapter->connect_le)
+               adapter->connect_le = NULL;
 
-       device = adapter_find_device(adapter, paddr);
-       if (device) {
-               paired = device_is_paired(device);
-               trusted = device_is_trusted(device);
+       if (g_slist_find(adapter->connect_list, device)) {
+               DBG("ignoring already added device %s",
+                                               device_get_path(device));
+               return 0;
        }
 
-       /* The uuids string array is updated only if necessary */
-       uuid_count = g_slist_length(dev->services);
-       if (dev->services && dev->uuid_count != uuid_count) {
-               g_strfreev(dev->uuids);
-               dev->uuids = strlist2array(dev->services);
-               dev->uuid_count = uuid_count;
+       if (!(adapter->supported_settings & MGMT_SETTING_LE)) {
+               error("Can't add %s to non-LE capable adapter connect list",
+                                               device_get_path(device));
+               return -ENOTSUP;
        }
 
-       if (!dev->alias) {
-               if (!dev->name) {
-                       alias = g_strdup(peer_addr);
-                       g_strdelimit(alias, ":", '-');
-               } else
-                       alias = g_strdup(dev->name);
-       } else
-               alias = g_strdup(dev->alias);
+       adapter->connect_list = g_slist_append(adapter->connect_list, device);
+       DBG("%s added to %s's connect_list", device_get_path(device),
+                                                       adapter->system_name);
 
-       if (dev->bdaddr_type != BDADDR_BREDR) {
-               gboolean broadcaster;
-               uint16_t app;
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return 0;
 
-               if (dev->flags & (EIR_LIM_DISC | EIR_GEN_DISC))
-                       broadcaster = FALSE;
-               else
-                       broadcaster = TRUE;
+       trigger_passive_scanning(adapter);
 
-               dev->legacy = FALSE;
+       return 0;
+}
 
-               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,
-                               "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
-                               "Paired", DBUS_TYPE_BOOLEAN, &paired,
-                               "Broadcaster", DBUS_TYPE_BOOLEAN, &broadcaster,
-                               "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
-                               NULL);
-       } else {
-               icon = class_to_icon(dev->class);
+void adapter_connect_list_remove(struct btd_adapter *adapter,
+                                       struct btd_device *device)
+{
+       /*
+        * If the adapter->connect_le device is being removed from the
+        * connect list it means the connection was successful and hence
+        * the pointer should be cleared
+        */
+       if (device == adapter->connect_le)
+               adapter->connect_le = NULL;
+
+       if (!g_slist_find(adapter->connect_list, device)) {
+               DBG("device %s is not on the list, ignoring",
+                                               device_get_path(device));
+               return;
+       }
 
-               emit_device_found(adapter->path, paddr,
-                               "Address", DBUS_TYPE_STRING, &paddr,
-                               "Class", DBUS_TYPE_UINT32, &dev->class,
-                               "Icon", DBUS_TYPE_STRING, &icon,
-                               "RSSI", DBUS_TYPE_INT16, &rssi,
-                               "Name", DBUS_TYPE_STRING, &dev->name,
-                               "Alias", DBUS_TYPE_STRING, &alias,
-                               "LegacyPairing", DBUS_TYPE_BOOLEAN, &dev->legacy,
-                               "Paired", DBUS_TYPE_BOOLEAN, &paired,
-                               "Trusted", DBUS_TYPE_BOOLEAN, &trusted,
-                               "UUIDs", DBUS_TYPE_ARRAY, &dev->uuids, uuid_count,
-                               NULL);
+       adapter->connect_list = g_slist_remove(adapter->connect_list, device);
+       DBG("%s removed from %s's connect_list", device_get_path(device),
+                                                       adapter->system_name);
+
+       if (!adapter->connect_list) {
+               stop_passive_scanning(adapter);
+               return;
        }
 
-       g_free(alias);
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return;
+
+       trigger_passive_scanning(adapter);
 }
 
-static struct remote_dev_info *found_device_new(const bdaddr_t *bdaddr,
-                                       uint8_t bdaddr_type, const char *name,
-                                       const char *alias, uint32_t class,
-                                       gboolean legacy, int flags)
+static void adapter_start(struct btd_adapter *adapter)
 {
-       struct remote_dev_info *dev;
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Powered");
 
-       dev = g_new0(struct remote_dev_info, 1);
-       bacpy(&dev->bdaddr, bdaddr);
-       dev->bdaddr_type = bdaddr_type;
-       dev->name = g_strdup(name);
-       dev->alias = g_strdup(alias);
-       dev->class = class;
-       dev->legacy = legacy;
-       if (flags >= 0)
-               dev->flags = flags;
+       DBG("adapter %s has been enabled", adapter->path);
 
-       return dev;
+       trigger_passive_scanning(adapter);
 }
 
-static void remove_same_uuid(gpointer data, gpointer user_data)
+static void reply_pending_requests(struct btd_adapter *adapter)
 {
-       struct remote_dev_info *dev = user_data;
        GSList *l;
 
-       for (l = dev->services; l; l = l->next) {
-               char *current_uuid = l->data;
-               char *new_uuid = data;
+       if (!adapter)
+               return;
 
-               if (strcmp(current_uuid, new_uuid) == 0) {
-                       g_free(current_uuid);
-                       dev->services = g_slist_delete_link(dev->services, l);
-                       break;
-               }
+       /* pending bonding */
+       for (l = adapter->devices; l; l = l->next) {
+               struct btd_device *device = l->data;
+
+               if (device_is_bonding(device, NULL))
+                       device_bonding_failed(device,
+                                               HCI_OE_USER_ENDED_CONNECTION);
        }
 }
 
-static void dev_prepend_uuid(gpointer data, gpointer user_data)
+static void remove_driver(gpointer data, gpointer user_data)
 {
-       struct remote_dev_info *dev = user_data;
-       char *new_uuid = data;
+       struct btd_adapter_driver *driver = data;
+       struct btd_adapter *adapter = user_data;
 
-       dev->services = g_slist_prepend(dev->services, g_strdup(new_uuid));
+       if (driver->remove)
+               driver->remove(adapter);
 }
 
-static gboolean pairing_is_legacy(bdaddr_t *local, bdaddr_t *peer,
-                                       const uint8_t *eir, const char *name)
+static void remove_profile(gpointer data, gpointer user_data)
 {
-       unsigned char features[8];
-
-       if (eir)
-               return FALSE;
-
-       if (name == NULL)
-               return TRUE;
-
-       if (read_remote_features(local, peer, NULL, features) < 0)
-               return TRUE;
+       struct btd_profile *profile = data;
+       struct btd_adapter *adapter = user_data;
 
-       if (features[0] & 0x01)
-               return FALSE;
-       else
-               return TRUE;
+       if (profile->adapter_remove)
+               profile->adapter_remove(profile, adapter);
 }
 
-static char *read_stored_data(bdaddr_t *local, bdaddr_t *peer, const char *file)
+static void unload_drivers(struct btd_adapter *adapter)
 {
-       char local_addr[18], peer_addr[18], filename[PATH_MAX + 1];
+       g_slist_foreach(adapter->drivers, remove_driver, adapter);
+       g_slist_free(adapter->drivers);
+       adapter->drivers = NULL;
 
-       ba2str(local, local_addr);
-       ba2str(peer, peer_addr);
+       g_slist_foreach(adapter->profiles, remove_profile, adapter);
+       g_slist_free(adapter->profiles);
+       adapter->profiles = NULL;
+}
 
-       create_name(filename, PATH_MAX, STORAGEDIR, local_addr, file);
+static void free_service_auth(gpointer data, gpointer user_data)
+{
+       struct service_auth *auth = data;
 
-       return textfile_get(filename, peer_addr);
+       g_free(auth);
 }
 
-void adapter_update_found_devices(struct btd_adapter *adapter,
-                                       bdaddr_t *bdaddr, uint8_t bdaddr_type,
-                                       int8_t rssi, uint8_t confirm_name,
-                                       uint8_t *data, uint8_t data_len)
+static void adapter_free(gpointer user_data)
 {
-       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));
-       err = eir_parse(&eir_data, data, data_len);
-       if (err < 0) {
-               error("Error parsing EIR data: %s (%d)", strerror(-err), -err);
-               return;
-       }
+       struct btd_adapter *adapter = user_data;
 
-       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);
+       DBG("%p", adapter);
 
-       if (eir_data.appearance != 0)
-               write_remote_appearance(&adapter->bdaddr, bdaddr, bdaddr_type,
-                                                       eir_data.appearance);
+       if (adapter->load_ltks_timeout > 0)
+               g_source_remove(adapter->load_ltks_timeout);
 
-       if (eir_data.name != NULL && eir_data.name_complete)
-               write_device_name(&adapter->bdaddr, bdaddr, eir_data.name);
-
-       dev = adapter_search_found_devices(adapter, bdaddr);
-       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 (adapter->confirm_name_timeout > 0)
+               g_source_remove(adapter->confirm_name_timeout);
 
-               if (dev->rssi != rssi)
-                       goto done;
+       if (adapter->pair_device_timeout > 0)
+               g_source_remove(adapter->pair_device_timeout);
 
-               eir_data_free(&eir_data);
+       if (adapter->auth_idle_id)
+               g_source_remove(adapter->auth_idle_id);
 
-               return;
-       }
+       g_queue_foreach(adapter->auths, free_service_auth, NULL);
+       g_queue_free(adapter->auths);
 
-       /* New device in the discovery session */
+       /*
+        * Unregister all handlers for this specific index since
+        * the adapter bound to them is no longer valid.
+        *
+        * This also avoids having multiple instances of the same
+        * handler in case indexes got removed and re-added.
+        */
+       mgmt_unregister_index(adapter->mgmt, adapter->dev_id);
 
-       name = read_stored_data(&adapter->bdaddr, bdaddr, "names");
+       /*
+        * Cancel all pending commands for this specific index
+        * since the adapter bound to them is no longer valid.
+        */
+       mgmt_cancel_index(adapter->mgmt, adapter->dev_id);
 
-       if (bdaddr_type == BDADDR_BREDR) {
-               legacy = pairing_is_legacy(&adapter->bdaddr, bdaddr, data,
-                                                                       name);
+       mgmt_unref(adapter->mgmt);
 
-               if (!name && main_opts.name_resolv &&
-                               adapter_has_discov_sessions(adapter))
-                       name_known = FALSE;
-               else
-                       name_known = TRUE;
-       } else {
-               legacy = FALSE;
-               name_known = TRUE;
-       }
+       sdp_list_free(adapter->services, NULL);
 
-       if (confirm_name)
-               adapter_ops->confirm_name(adapter->dev_id, bdaddr, bdaddr_type,
-                                                               name_known);
+       g_slist_free(adapter->connections);
 
-       alias = read_stored_data(&adapter->bdaddr, bdaddr, "aliases");
+       g_free(adapter->path);
+       g_free(adapter->name);
+       g_free(adapter->short_name);
+       g_free(adapter->system_name);
+       g_free(adapter->stored_alias);
+       g_free(adapter->current_alias);
+       g_free(adapter->modalias);
+       g_free(adapter);
+}
 
-       dev = found_device_new(bdaddr, bdaddr_type, name, alias, dev_class,
-                                               legacy, eir_data.flags);
-       free(name);
-       free(alias);
+struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter)
+{
+       __sync_fetch_and_add(&adapter->ref_count, 1);
 
-       adapter->found_devices = g_slist_prepend(adapter->found_devices, dev);
+       return adapter;
+}
 
-done:
-       dev->rssi = rssi;
+void btd_adapter_unref(struct btd_adapter *adapter)
+{
+       if (__sync_sub_and_fetch(&adapter->ref_count, 1))
+               return;
 
-       adapter->found_devices = g_slist_sort(adapter->found_devices,
-                                               (GCompareFunc) dev_rssi_cmp);
+       if (!adapter->path) {
+               DBG("Freeing adapter %u", adapter->dev_id);
 
-       g_slist_foreach(eir_data.services, remove_same_uuid, dev);
-       g_slist_foreach(eir_data.services, dev_prepend_uuid, dev);
+               adapter_free(adapter);
+               return;
+       }
 
-       adapter_emit_device_found(adapter, dev);
+       DBG("Freeing adapter %s", adapter->path);
 
-       eir_data_free(&eir_data);
+       g_dbus_unregister_interface(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE);
 }
 
-void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode)
+static void convert_names_entry(char *key, char *value, void *user_data)
 {
-       const gchar *path = adapter_get_path(adapter);
-       gboolean discoverable, pairable;
+       char *address = user_data;
+       char *str = key;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
 
-       DBG("old 0x%02x new 0x%02x", adapter->scan_mode, scan_mode);
+       if (strchr(key, '#'))
+               str[17] = '\0';
 
-       if (adapter->scan_mode == scan_mode)
+       if (bachk(str) != 0)
                return;
 
-       switch (scan_mode) {
-       case SCAN_DISABLED:
-               adapter->mode = MODE_OFF;
-               discoverable = FALSE;
-               pairable = FALSE;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", address, str);
+       filename[PATH_MAX] = '\0';
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       g_key_file_set_string(key_file, "General", "Name", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, data, length, NULL);
+       g_free(data);
+
+       g_key_file_free(key_file);
+}
+
+struct device_converter {
+       char *address;
+       void (*cb)(GKeyFile *key_file, void *value);
+       gboolean force;
+};
+
+static void set_device_type(GKeyFile *key_file, char type)
+{
+       char *techno;
+       char *addr_type = NULL;
+       char *str;
+
+       switch (type) {
+       case BDADDR_BREDR:
+               techno = "BR/EDR";
                break;
-       case SCAN_PAGE:
-               adapter->mode = MODE_CONNECTABLE;
-               discoverable = FALSE;
-               pairable = adapter->pairable;
+       case BDADDR_LE_PUBLIC:
+               techno = "LE";
+               addr_type = "public";
                break;
-       case (SCAN_PAGE | SCAN_INQUIRY):
-               adapter->mode = MODE_DISCOVERABLE;
-               discoverable = TRUE;
-               pairable = adapter->pairable;
+       case BDADDR_LE_RANDOM:
+               techno = "LE";
+               addr_type = "static";
                break;
        default:
-               /* ignore, reserved */
                return;
        }
 
-       /* If page scanning gets toggled emit the Pairable property */
-       if ((adapter->scan_mode & SCAN_PAGE) != (scan_mode & SCAN_PAGE))
-               emit_property_changed(connection, adapter->path,
-                                       ADAPTER_INTERFACE, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &pairable);
+       str = g_key_file_get_string(key_file, "General",
+                                       "SupportedTechnologies", NULL);
+       if (!str)
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", techno);
+       else if (!strstr(str, techno))
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", "BR/EDR;LE");
 
-       emit_property_changed(connection, path,
-                               ADAPTER_INTERFACE, "Discoverable",
-                               DBUS_TYPE_BOOLEAN, &discoverable);
+       g_free(str);
 
-       adapter->scan_mode = scan_mode;
+       if (addr_type)
+               g_key_file_set_string(key_file, "General", "AddressType",
+                                       addr_type);
+}
 
-       set_mode_complete(adapter);
+static void convert_aliases_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Alias", value);
 }
 
-struct agent *adapter_get_agent(struct btd_adapter *adapter)
+static void convert_trusts_entry(GKeyFile *key_file, void *value)
 {
-       if (!adapter)
-               return NULL;
+       g_key_file_set_boolean(key_file, "General", "Trusted", TRUE);
+}
 
-       return adapter->agent;
+static void convert_classes_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Class", value);
 }
 
-void adapter_add_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device)
+static void convert_blocked_entry(GKeyFile *key_file, void *value)
 {
-       if (g_slist_find(adapter->connections, device)) {
-               error("Device is already marked as connected");
+       g_key_file_set_boolean(key_file, "General", "Blocked", TRUE);
+}
+
+static void convert_did_entry(GKeyFile *key_file, void *value)
+{
+       char *vendor_str, *product_str, *version_str;
+       uint16_t val;
+
+       vendor_str = strchr(value, ' ');
+       if (!vendor_str)
                return;
-       }
 
-       device_add_connection(device, connection);
+       *(vendor_str++) = 0;
 
-       adapter->connections = g_slist_append(adapter->connections, device);
-}
+       if (g_str_equal(value, "FFFF"))
+               return;
 
-void adapter_remove_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device)
-{
-       DBG("");
+       product_str = strchr(vendor_str, ' ');
+       if (!product_str)
+               return;
 
-       if (!g_slist_find(adapter->connections, device)) {
-               error("No matching connection for device");
+       *(product_str++) = 0;
+
+       version_str = strchr(product_str, ' ');
+       if (!version_str)
                return;
-       }
 
-       device_remove_connection(device, connection);
+       *(version_str++) = 0;
 
-       adapter->connections = g_slist_remove(adapter->connections, device);
+       val = (uint16_t) strtol(value, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Source", val);
 
-       if (device_is_authenticating(device))
-               device_cancel_authentication(device, TRUE);
+       val = (uint16_t) strtol(vendor_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Vendor", val);
 
-       if (device_is_temporary(device)) {
-               const char *path = device_get_path(device);
+       val = (uint16_t) strtol(product_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Product", val);
 
-               DBG("Removing temporary device %s", path);
-               adapter_remove_device(connection, adapter, device, TRUE);
-       }
+       val = (uint16_t) strtol(version_str, NULL, 16);
+       g_key_file_set_integer(key_file, "DeviceID", "Version", val);
 }
 
-gboolean adapter_has_discov_sessions(struct btd_adapter *adapter)
+static void convert_linkkey_entry(GKeyFile *key_file, void *value)
 {
-       if (!adapter || !adapter->disc_sessions)
-               return FALSE;
+       char *type_str, *length_str, *str;
+       int val;
 
-       return TRUE;
-}
+       type_str = strchr(value, ' ');
+       if (!type_str)
+               return;
 
-int btd_register_adapter_driver(struct btd_adapter_driver *driver)
-{
-       adapter_drivers = g_slist_append(adapter_drivers, driver);
+       *(type_str++) = 0;
 
-       if (driver->probe == NULL)
-               return 0;
+       length_str = strchr(type_str, ' ');
+       if (!length_str)
+               return;
 
-       manager_foreach_adapter(probe_driver, driver);
+       *(length_str++) = 0;
 
-       return 0;
-}
+       str = g_strconcat("0x", value, NULL);
+       g_key_file_set_string(key_file, "LinkKey", "Key", str);
+       g_free(str);
 
-static void unload_driver(struct btd_adapter *adapter, gpointer data)
-{
-       adapter->loaded_drivers = g_slist_remove(adapter->loaded_drivers, data);
+       val = strtol(type_str, NULL, 16);
+       g_key_file_set_integer(key_file, "LinkKey", "Type", val);
+
+       val = strtol(length_str, NULL, 16);
+       g_key_file_set_integer(key_file, "LinkKey", "PINLength", val);
 }
 
-void btd_unregister_adapter_driver(struct btd_adapter_driver *driver)
+static void convert_ltk_entry(GKeyFile *key_file, void *value)
 {
-       adapter_drivers = g_slist_remove(adapter_drivers, driver);
+       char *auth_str, *rand_str, *str;
+       int i, ret;
+       unsigned char auth, master, enc_size;
+       unsigned short ediv;
 
-       manager_foreach_adapter(unload_driver, driver);
-}
+       auth_str = strchr(value, ' ');
+       if (!auth_str)
+               return;
 
-static void agent_auth_cb(struct agent *agent, DBusError *derr,
-                                                       void *user_data)
-{
-       struct service_auth *auth = user_data;
+       *(auth_str++) = 0;
 
-       device_set_authorizing(auth->device, FALSE);
+       for (i = 0, rand_str = auth_str; i < 4; i++) {
+               rand_str = strchr(rand_str, ' ');
+               if (!rand_str || rand_str[1] == '\0')
+                       return;
 
-       auth->cb(derr, auth->user_data);
-}
+               rand_str++;
+       }
 
-static gboolean auth_idle_cb(gpointer user_data)
-{
-       struct service_auth *auth = user_data;
-       struct btd_adapter *adapter = auth->adapter;
+       ret = sscanf(auth_str, " %hhd %hhd %hhd %hd", &auth, &master,
+                                                       &enc_size, &ediv);
+       if (ret < 4)
+               return;
 
-       adapter->auth_idle_id = 0;
+       str = g_strconcat("0x", value, NULL);
+       g_key_file_set_string(key_file, "LongTermKey", "Key", str);
+       g_free(str);
 
-       auth->cb(NULL, auth->user_data);
+       g_key_file_set_integer(key_file, "LongTermKey", "Authenticated", auth);
+       g_key_file_set_integer(key_file, "LongTermKey", "Master", master);
+       g_key_file_set_integer(key_file, "LongTermKey", "EncSize", enc_size);
+       g_key_file_set_integer(key_file, "LongTermKey", "EDiv", ediv);
 
-       return FALSE;
+       str = g_strconcat("0x", rand_str, NULL);
+       g_key_file_set_string(key_file, "LongTermKey", "Rand", str);
+       g_free(str);
 }
 
-static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
-                                       const char *uuid, service_auth_cb cb,
-                                       void *user_data)
+static void convert_profiles_entry(GKeyFile *key_file, void *value)
 {
-       struct service_auth *auth;
-       struct btd_device *device;
-       struct agent *agent;
-       char address[18];
-       const gchar *dev_path;
-       int err;
+       g_strdelimit(value, " ", ';');
+       g_key_file_set_string(key_file, "General", "Services", value);
+}
 
-       ba2str(dst, address);
-       device = adapter_find_device(adapter, address);
-       if (!device)
-               return -EPERM;
+static void convert_appearances_entry(GKeyFile *key_file, void *value)
+{
+       g_key_file_set_string(key_file, "General", "Appearance", value);
+}
 
-       /* Device connected? */
-       if (!g_slist_find(adapter->connections, device))
-               error("Authorization request for non-connected device!?");
+static void convert_entry(char *key, char *value, void *user_data)
+{
+       struct device_converter *converter = user_data;
+       char type = BDADDR_BREDR;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
 
-       if (adapter->auth_idle_id)
-               return -EBUSY;
+       if (strchr(key, '#')) {
+               key[17] = '\0';
+               type = key[18] - '0';
+       }
 
-       auth = g_try_new0(struct service_auth, 1);
-       if (!auth)
-               return -ENOMEM;
+       if (bachk(key) != 0)
+               return;
 
-       auth->cb = cb;
-       auth->user_data = user_data;
-       auth->device = device;
-       auth->adapter = adapter;
+       if (converter->force == FALSE) {
+               struct stat st;
+               int err;
 
-       if (device_is_trusted(device) == TRUE) {
-               adapter->auth_idle_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-                                                       auth_idle_cb, auth,
-                                                       g_free);
-               return 0;
+               snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s",
+                               converter->address, key);
+               filename[PATH_MAX] = '\0';
+
+               err = stat(filename, &st);
+               if (err || !S_ISDIR(st.st_mode))
+                       return;
        }
 
-       agent = device_get_agent(device);
-       if (!agent) {
-               warn("Can't find device agent");
-               g_free(auth);
-               return -EPERM;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info",
+                       converter->address, key);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       set_device_type(key_file, type);
+
+       converter->cb(key_file, value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
        }
 
-       dev_path = device_get_path(device);
+       g_free(data);
 
-       err = agent_authorize(agent, dev_path, uuid, agent_auth_cb, auth, g_free);
-       if (err < 0)
-               g_free(auth);
-       else
-               device_set_authorizing(device, TRUE);
+       g_key_file_free(key_file);
+}
+
+static void convert_file(char *file, char *address,
+                               void (*cb)(GKeyFile *key_file, void *value),
+                               gboolean force)
+{
+       char filename[PATH_MAX + 1];
+       struct device_converter converter;
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", address, file);
+       filename[PATH_MAX] = '\0';
 
-       return err;
+       converter.address = address;
+       converter.cb = cb;
+       converter.force = force;
+
+       textfile_foreach(filename, convert_entry, &converter);
 }
 
-int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
-                                       const char *uuid, service_auth_cb cb,
-                                       void *user_data)
+static gboolean record_has_uuid(const sdp_record_t *rec,
+                               const char *profile_uuid)
 {
-       struct btd_adapter *adapter;
-       GSList *l;
+       sdp_list_t *pat;
 
-       if (bacmp(src, BDADDR_ANY) != 0) {
-               adapter = manager_find_adapter(src);
-               if (!adapter)
-                       return -EPERM;
+       for (pat = rec->pattern; pat != NULL; pat = pat->next) {
+               char *uuid;
+               int ret;
 
-               return adapter_authorize(adapter, dst, uuid, cb, user_data);
-       }
+               uuid = bt_uuid2string(pat->data);
+               if (!uuid)
+                       continue;
 
-       for (l = manager_get_adapters(); l != NULL; l = g_slist_next(l)) {
-               int err;
+               ret = strcasecmp(uuid, profile_uuid);
 
-               adapter = l->data;
+               g_free(uuid);
 
-               err = adapter_authorize(adapter, dst, uuid, cb, user_data);
-               if (err == 0)
-                       return 0;
+               if (ret == 0)
+                       return TRUE;
        }
 
-       return -EPERM;
+       return FALSE;
 }
 
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst)
+static void store_attribute_uuid(GKeyFile *key_file, uint16_t start,
+                                       uint16_t end, char *att_uuid,
+                                       uuid_t uuid)
 {
-       struct btd_adapter *adapter = manager_find_adapter(src);
-       struct btd_device *device;
-       struct agent *agent;
-       char address[18];
-       int err;
-
-       if (!adapter)
-               return -EPERM;
-
-       ba2str(dst, address);
-       device = adapter_find_device(adapter, address);
-       if (!device)
-               return -EPERM;
+       char handle[6], uuid_str[33];
+       int i;
 
-       if (adapter->auth_idle_id) {
-               g_source_remove(adapter->auth_idle_id);
-               adapter->auth_idle_id = 0;
-               return 0;
+       switch (uuid.type) {
+       case SDP_UUID16:
+               sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+               break;
+       case SDP_UUID32:
+               sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+               break;
+       case SDP_UUID128:
+               for (i = 0; i < 16; i++)
+                       sprintf(uuid_str + (i * 2), "%2.2X",
+                                       uuid.value.uuid128.data[i]);
+               break;
+       default:
+               uuid_str[0] = '\0';
        }
 
-       /*
-        * FIXME: Cancel fails if authorization is requested to adapter's
-        * agent and in the meanwhile CreatePairedDevice is called.
-        */
+       sprintf(handle, "%hu", start);
+       g_key_file_set_string(key_file, handle, "UUID", att_uuid);
+       g_key_file_set_string(key_file, handle, "Value", uuid_str);
+       g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);
+}
 
-       agent = device_get_agent(device);
-       if (!agent)
-               return -EPERM;
+static void store_sdp_record(char *local, char *peer, int handle, char *value)
+{
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char handle_str[11];
+       char *data;
+       gsize length = 0;
 
-       err = agent_cancel(agent);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
+       filename[PATH_MAX] = '\0';
 
-       if (err == 0)
-               device_set_authorizing(device, FALSE);
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       return err;
-}
+       sprintf(handle_str, "0x%8.8X", handle);
+       g_key_file_set_string(key_file, "ServiceRecords", handle_str, value);
 
-static gchar *adapter_any_path = NULL;
-static int adapter_any_refcount = 0;
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-const char *adapter_any_get_path(void)
-{
-       return adapter_any_path;
+       g_free(data);
+
+       g_key_file_free(key_file);
 }
 
-const char *btd_adapter_any_request_path(void)
+static void convert_sdp_entry(char *key, char *value, void *user_data)
 {
-       if (adapter_any_refcount++ > 0)
-               return adapter_any_path;
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       int handle, ret;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       struct stat st;
+       sdp_record_t *rec;
+       uuid_t uuid;
+       char *att_uuid, *prim_uuid;
+       uint16_t start = 0, end = 0, psm = 0;
+       int err;
+       char *data;
+       gsize length = 0;
 
-       adapter_any_path = g_strdup_printf("%s/any", manager_get_base_path());
+       ret = sscanf(key, "%17s#%hhu#%08X", dst_addr, &type, &handle);
+       if (ret < 3) {
+               ret = sscanf(key, "%17s#%08X", dst_addr, &handle);
+               if (ret < 2)
+                       return;
+       }
 
-       return adapter_any_path;
-}
+       if (bachk(dst_addr) != 0)
+               return;
 
-void btd_adapter_any_release_path(void)
-{
-       adapter_any_refcount--;
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       if (adapter_any_refcount > 0)
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
                return;
 
-       g_free(adapter_any_path);
-       adapter_any_path = NULL;
-}
+       /* store device records in cache */
+       store_sdp_record(src_addr, dst_addr, handle, value);
 
-gboolean adapter_powering_down(struct btd_adapter *adapter)
-{
-       return adapter->off_requested;
-}
+       /* Retrieve device record and check if there is an
+        * attribute entry in it */
+       sdp_uuid16_create(&uuid, ATT_UUID);
+       att_uuid = bt_uuid2string(&uuid);
 
-int btd_adapter_restore_powered(struct btd_adapter *adapter)
-{
-       char mode[14], address[18];
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
 
-       if (!adapter_ops)
-               return -EINVAL;
+       rec = record_from_string(value);
 
-       if (!main_opts.remember_powered)
-               return -EINVAL;
+       if (record_has_uuid(rec, att_uuid))
+               goto failed;
 
-       if (adapter->up)
-               return 0;
+       if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
+               goto failed;
 
-       ba2str(&adapter->bdaddr, address);
-       if (read_device_mode(address, mode, sizeof(mode)) == 0 &&
-                                               g_str_equal(mode, "off"))
-               return 0;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
+                                                               dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       return adapter_ops->set_powered(adapter->dev_id, TRUE);
-}
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-static gboolean switch_off_timeout(gpointer user_data)
-{
-       struct btd_adapter *adapter = user_data;
+       store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-       adapter_ops->set_powered(adapter->dev_id, FALSE);
-       adapter->off_timer = 0;
+       g_free(data);
+       g_key_file_free(key_file);
 
-       return FALSE;
+failed:
+       sdp_record_free(rec);
+       g_free(prim_uuid);
+       g_free(att_uuid);
 }
 
-int btd_adapter_switch_online(struct btd_adapter *adapter)
+static void convert_primaries_entry(char *key, char *value, void *user_data)
 {
-       if (!adapter_ops)
-               return -EINVAL;
+       char *address = user_data;
+       int device_type = -1;
+       uuid_t uuid;
+       char **services, **service, *prim_uuid;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       int ret;
+       uint16_t start, end;
+       char uuid_str[MAX_LEN_UUID_STR + 1];
+       char *data;
+       gsize length = 0;
+
+       if (strchr(key, '#')) {
+               key[17] = '\0';
+               device_type = key[18] - '0';
+       }
+
+       if (bachk(key) != 0)
+               return;
 
-       if (adapter->up)
-               return -EALREADY;
+       services = g_strsplit(value, " ", 0);
+       if (services == NULL)
+               return;
 
-       if (adapter->off_timer)
-               off_timer_remove(adapter);
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
 
-       return adapter_ops->set_powered(adapter->dev_id, TRUE);
-}
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", address,
+                                                                       key);
+       filename[PATH_MAX] = '\0';
 
-int btd_adapter_switch_offline(struct btd_adapter *adapter)
-{
-       if (!adapter_ops)
-               return -EINVAL;
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-       if (!adapter->up)
-               return -EALREADY;
+       for (service = services; *service; service++) {
+               ret = sscanf(*service, "%04hX#%04hX#%s", &start, &end,
+                                                               uuid_str);
+               if (ret < 3)
+                       continue;
 
-       if (adapter->off_timer)
-               return 0;
+               bt_string2uuid(&uuid, uuid_str);
+               sdp_uuid128_to_uuid(&uuid);
 
-       adapter->global_mode = MODE_OFF;
+               store_attribute_uuid(key_file, start, end, prim_uuid, uuid);
+       }
 
-       if (adapter->connections == NULL)
-               return adapter_ops->set_powered(adapter->dev_id, FALSE);
+       g_strfreev(services);
 
-       g_slist_foreach(adapter->connections,
-                               (GFunc) device_request_disconnect, NULL);
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length == 0)
+               goto end;
 
-       adapter->off_timer = g_timeout_add_seconds(OFF_TIMER,
-                                               switch_off_timeout, adapter);
+       create_file(filename, S_IRUSR | S_IWUSR);
+       g_file_set_contents(filename, data, length, NULL);
 
-       return 0;
-}
+       if (device_type < 0)
+               goto end;
 
-static gboolean disable_auto(gpointer user_data)
-{
-       struct btd_adapter *adapter = user_data;
-       GSList *l;
+       g_free(data);
+       g_key_file_free(key_file);
 
-       for (l = adapter->devices; l; l = l->next) {
-               struct btd_device *device = l->data;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", address, key);
+       filename[PATH_MAX] = '\0';
 
-               device_set_auto_connect(device, FALSE);
-       }
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       set_device_type(key_file, device_type);
 
-       adapter->auto_timeout_id = 0;
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-       return FALSE;
+end:
+       g_free(data);
+       g_free(prim_uuid);
+       g_key_file_free(key_file);
 }
 
-static void set_auto_connect(gpointer data, gpointer user_data)
+static void convert_ccc_entry(char *key, char *value, void *user_data)
 {
-       struct btd_device *device = data;
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       int handle, ret;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       struct stat st;
+       int err;
+       char group[6];
+       char *data;
+       gsize length = 0;
 
-       device_set_auto_connect(device, TRUE);
-}
+       ret = sscanf(key, "%17s#%hhu#%04X", dst_addr, &type, &handle);
+       if (ret < 3)
+               return;
 
-void btd_adapter_enable_auto_connect(struct btd_adapter *adapter)
-{
-       if (!adapter->up)
+       if (bachk(dst_addr) != 0)
                return;
 
-       DBG("Enabling automatic connections");
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       if (adapter->auto_timeout_id)
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
                return;
 
-       g_slist_foreach(adapter->devices, set_auto_connect, NULL);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/ccc", src_addr,
+                                                               dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       adapter->auto_timeout_id = g_timeout_add_seconds(main_opts.autoto,
-                                               disable_auto, adapter);
-}
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-void btd_adapter_register_pin_cb(struct btd_adapter *adapter,
-                                                       btd_adapter_pin_cb_t cb)
-{
-       adapter->pin_callbacks = g_slist_prepend(adapter->pin_callbacks, cb);
-}
+       sprintf(group, "%hu", handle);
+       g_key_file_set_string(key_file, group, "Value", value);
 
-void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
-                                                       btd_adapter_pin_cb_t cb)
-{
-       adapter->pin_callbacks = g_slist_remove(adapter->pin_callbacks, cb);
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
 }
 
-ssize_t btd_adapter_get_pin(struct btd_adapter *adapter, struct btd_device *dev,
-                                       char *pin_buf, gboolean *display)
+static void convert_gatt_entry(char *key, char *value, void *user_data)
 {
-       GSList *l;
-       btd_adapter_pin_cb_t cb;
-       bdaddr_t sba, dba;
-       ssize_t ret;
+       char *src_addr = user_data;
+       char dst_addr[18];
+       char type = BDADDR_BREDR;
+       int handle, ret;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       struct stat st;
+       int err;
+       char group[6];
+       char *data;
+       gsize length = 0;
 
-       for (l = adapter->pin_callbacks; l != NULL; l = g_slist_next(l)) {
-               cb = l->data;
-               ret = cb(adapter, dev, pin_buf, display);
-               if (ret > 0)
-                       return ret;
-       }
+       ret = sscanf(key, "%17s#%hhu#%04X", dst_addr, &type, &handle);
+       if (ret < 3)
+               return;
 
-       adapter_get_address(adapter, &sba);
-       device_get_address(dev, &dba, NULL);
+       if (bachk(dst_addr) != 0)
+               return;
 
-       return read_pin_code(&sba, &dba, pin_buf);
-}
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, dst_addr);
+       filename[PATH_MAX] = '\0';
 
-int btd_register_adapter_ops(struct btd_adapter_ops *ops, gboolean priority)
-{
-       if (ops->setup == NULL)
-               return -EINVAL;
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
 
-       if (priority)
-               ops_candidates = g_slist_prepend(ops_candidates, ops);
-       else
-               ops_candidates = g_slist_append(ops_candidates, ops);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/gatt", src_addr,
+                                                               dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       return 0;
-}
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-void btd_adapter_cleanup_ops(struct btd_adapter_ops *ops)
-{
-       ops_candidates = g_slist_remove(ops_candidates, ops);
-       ops->cleanup();
+       sprintf(group, "%hu", handle);
+       g_key_file_set_string(key_file, group, "Value", value);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-       if (adapter_ops == ops)
-               adapter_ops = NULL;
+       g_free(data);
+       g_key_file_free(key_file);
 }
 
-int adapter_ops_setup(void)
+static void convert_proximity_entry(char *key, char *value, void *user_data)
 {
-       GSList *l;
-       int ret;
+       char *src_addr = user_data;
+       char *alert;
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       struct stat st;
+       int err;
+       char *data;
+       gsize length = 0;
 
-       if (!ops_candidates)
-               return -EINVAL;
+       if (!strchr(key, '#'))
+               return;
 
-       for (l = ops_candidates; l != NULL; l = g_slist_next(l)) {
-               struct btd_adapter_ops *ops = l->data;
+       key[17] = '\0';
+       alert = &key[18];
 
-               ret = ops->setup();
-               if (ret < 0)
-                       continue;
+       if (bachk(key) != 0)
+               return;
 
-               adapter_ops = ops;
-               break;
-       }
+       /* Check if the device directory has been created as records should
+        * only be converted for known devices */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", src_addr, key);
+       filename[PATH_MAX] = '\0';
 
-       return ret;
-}
+       err = stat(filename, &st);
+       if (err || !S_ISDIR(st.st_mode))
+               return;
 
-void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb)
-{
-       adapter->powered_callbacks =
-                       g_slist_append(adapter->powered_callbacks, cb);
-}
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/proximity", src_addr,
+                                                                       key);
+       filename[PATH_MAX] = '\0';
 
-void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb)
-{
-       adapter->powered_callbacks =
-                       g_slist_remove(adapter->powered_callbacks, cb);
-}
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
 
-int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
-                                                       gboolean enable)
-{
-       if (!adapter_ops)
-               return -EINVAL;
+       g_key_file_set_string(key_file, alert, "Level", value);
 
-       if (!adapter->up)
-               return -EINVAL;
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
 
-       return adapter_ops->set_fast_connectable(adapter->dev_id, enable);
+       g_free(data);
+       g_key_file_free(key_file);
 }
 
-int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               int which, int timeout, uint32_t *clock,
-                               uint16_t *accuracy)
+static void convert_device_storage(struct btd_adapter *adapter)
 {
-       if (!adapter_ops)
-               return -EINVAL;
+       char filename[PATH_MAX + 1];
+       char address[18];
 
-       if (!adapter->up)
-               return -EINVAL;
+       ba2str(&adapter->bdaddr, address);
 
-       return adapter_ops->read_clock(adapter->dev_id, bdaddr, which,
-                                               timeout, clock, accuracy);
-}
+       /* Convert device's name cache */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/names", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_names_entry, address);
 
-int btd_adapter_disconnect_device(struct btd_adapter *adapter,
-                                       bdaddr_t *bdaddr, uint8_t bdaddr_type)
+       /* Convert aliases */
+       convert_file("aliases", address, convert_aliases_entry, TRUE);
 
-{
-       return adapter_ops->disconnect(adapter->dev_id, bdaddr, bdaddr_type);
-}
+       /* Convert trusts */
+       convert_file("trusts", address, convert_trusts_entry, TRUE);
 
-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,
-                                                               bdaddr_type);
-}
+       /* Convert blocked */
+       convert_file("blocked", address, convert_blocked_entry, TRUE);
 
-int btd_adapter_pincode_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       const char *pin, size_t pin_len)
-{
-       return adapter_ops->pincode_reply(adapter->dev_id, bdaddr, pin,
-                                                               pin_len);
-}
+       /* Convert profiles */
+       convert_file("profiles", address, convert_profiles_entry, TRUE);
 
-int btd_adapter_confirm_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       uint8_t bdaddr_type, gboolean success)
-{
-       return adapter_ops->confirm_reply(adapter->dev_id, bdaddr, bdaddr_type,
-                                                               success);
-}
+       /* Convert primaries */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/primaries", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_primaries_entry, address);
 
-int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       uint8_t bdaddr_type, uint32_t passkey)
-{
-       return adapter_ops->passkey_reply(adapter->dev_id, bdaddr, bdaddr_type,
-                                                               passkey);
-}
+       /* Convert linkkeys */
+       convert_file("linkkeys", address, convert_linkkey_entry, TRUE);
 
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       bt_hci_result_t cb, gpointer user_data)
-{
-       return adapter_ops->encrypt_link(adapter->dev_id, bdaddr, cb, user_data);
-}
+       /* Convert longtermkeys */
+       convert_file("longtermkeys", address, convert_ltk_entry, TRUE);
 
-int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
-                                       uint16_t product, uint16_t version,
-                                       uint16_t source)
-{
-       return adapter_ops->set_did(adapter->dev_id, vendor, product, version,
-                                                               source);
-}
+       /* Convert classes */
+       convert_file("classes", address, convert_classes_entry, FALSE);
 
-int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       uint8_t addr_type, uint8_t io_cap)
-{
-       suspend_discovery(adapter);
-       return adapter_ops->create_bonding(adapter->dev_id, bdaddr,
-                                               addr_type, io_cap);
-}
+       /* Convert device ids */
+       convert_file("did", address, convert_did_entry, FALSE);
 
-int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr)
-{
-       return adapter_ops->cancel_bonding(adapter->dev_id, bdaddr);
-}
+       /* Convert sdp */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/sdp", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_sdp_entry, address);
 
-void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                               uint8_t status)
-{
-       struct btd_device *device;
-       char addr[18];
+       /* Convert ccc */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/ccc", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_ccc_entry, address);
 
-       ba2str(bdaddr, addr);
-       if (status == 0)
-               device = adapter_get_device(connection, adapter, addr);
-       else
-               device = adapter_find_device(adapter, addr);
+       /* Convert appearances */
+       convert_file("appearances", address, convert_appearances_entry, FALSE);
 
-       if (device != NULL)
-               device_bonding_complete(device, status);
+       /* Convert gatt */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/gatt", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_gatt_entry, address);
 
-       if (adapter->discov_suspended) {
-               adapter->discov_suspended = FALSE;
-               adapter_ops->start_discovery(adapter->dev_id);
-       }
+       /* Convert proximity */
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/proximity", address);
+       filename[PATH_MAX] = '\0';
+       textfile_foreach(filename, convert_proximity_entry, address);
 }
 
-int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
+static void convert_config(struct btd_adapter *adapter, const char *filename,
+                                                       GKeyFile *key_file)
 {
-       return adapter_ops->read_local_oob_data(adapter->dev_id);
-}
+       char address[18];
+       char str[MAX_NAME_LENGTH + 1];
+       char config_path[PATH_MAX + 1];
+       int timeout;
+       uint8_t mode;
+       char *data;
+       gsize length = 0;
+
+       ba2str(&adapter->bdaddr, address);
+       snprintf(config_path, PATH_MAX, STORAGEDIR "/%s/config", address);
+       config_path[PATH_MAX] = '\0';
+
+       if (read_pairable_timeout(address, &timeout) == 0)
+               g_key_file_set_integer(key_file, "General",
+                                               "PairableTimeout", timeout);
+
+       if (read_discoverable_timeout(address, &timeout) == 0)
+               g_key_file_set_integer(key_file, "General",
+                                               "DiscoverableTimeout", timeout);
+
+       if (read_on_mode(address, str, sizeof(str)) == 0) {
+               mode = get_mode(str);
+               g_key_file_set_boolean(key_file, "General", "Discoverable",
+                                       mode == MODE_DISCOVERABLE);
+       }
+
+       if (read_local_name(&adapter->bdaddr, str) == 0)
+               g_key_file_set_string(key_file, "General", "Alias", str);
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, data, length, NULL);
+       g_free(data);
+}
+
+static void fix_storage(struct btd_adapter *adapter)
+{
+       char filename[PATH_MAX + 1];
+       char address[18];
+       char *converted;
+
+       ba2str(&adapter->bdaddr, address);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/config", address);
+       filename[PATH_MAX] = '\0';
+       converted = textfile_get(filename, "converted");
+       if (!converted)
+               return;
+
+       free(converted);
+
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/names", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/aliases", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/trusts", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/blocked", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/profiles", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/primaries", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/linkkeys", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/longtermkeys", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/classes", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/did", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/sdp", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/ccc", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/appearances", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/gatt", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/proximity", address);
+       filename[PATH_MAX] = '\0';
+       textfile_del(filename, "converted");
+}
+
+static void load_config(struct btd_adapter *adapter)
+{
+       GKeyFile *key_file;
+       char filename[PATH_MAX + 1];
+       char address[18];
+       struct stat st;
+       GError *gerr = NULL;
+
+       ba2str(&adapter->bdaddr, address);
+
+       key_file = g_key_file_new();
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/settings", address);
+       filename[PATH_MAX] = '\0';
+
+       if (stat(filename, &st) < 0) {
+               convert_config(adapter, filename, key_file);
+               convert_device_storage(adapter);
+       }
+
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       /* Get alias */
+       adapter->stored_alias = g_key_file_get_string(key_file, "General",
+                                                               "Alias", NULL);
+       if (!adapter->stored_alias) {
+               /* fallback */
+               adapter->stored_alias = g_key_file_get_string(key_file,
+                                               "General", "Name", NULL);
+       }
+
+       /* Get pairable timeout */
+       adapter->pairable_timeout = g_key_file_get_integer(key_file, "General",
+                                               "PairableTimeout", &gerr);
+       if (gerr) {
+               adapter->pairable_timeout = main_opts.pairto;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+       /* Get discoverable mode */
+       adapter->stored_discoverable = g_key_file_get_boolean(key_file,
+                                       "General", "Discoverable", &gerr);
+       if (gerr) {
+               adapter->stored_discoverable = false;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+       /* Get discoverable timeout */
+       adapter->discoverable_timeout = g_key_file_get_integer(key_file,
+                               "General", "DiscoverableTimeout", &gerr);
+       if (gerr) {
+               adapter->discoverable_timeout = main_opts.discovto;
+               g_error_free(gerr);
+               gerr = NULL;
+       }
+
+       g_key_file_free(key_file);
+}
+
+static struct btd_adapter *btd_adapter_new(uint16_t index)
+{
+       struct btd_adapter *adapter;
+
+       adapter = g_try_new0(struct btd_adapter, 1);
+       if (!adapter)
+               return NULL;
+
+       adapter->dev_id = index;
+       adapter->mgmt = mgmt_ref(mgmt_master);
+       adapter->pincode_requested = false;
+
+       /*
+        * Setup default configuration values. These are either adapter
+        * defaults or from a system wide configuration file.
+        *
+        * Some value might be overwritten later on by adapter specific
+        * configuration. This is to make sure that sane defaults are
+        * always present.
+        */
+       adapter->system_name = g_strdup(main_opts.name);
+       adapter->major_class = (main_opts.class & 0x001f00) >> 8;
+       adapter->minor_class = (main_opts.class & 0x0000fc) >> 2;
+       adapter->modalias = bt_modalias(main_opts.did_source,
+                                               main_opts.did_vendor,
+                                               main_opts.did_product,
+                                               main_opts.did_version);
+       adapter->discoverable_timeout = main_opts.discovto;
+       adapter->pairable_timeout = main_opts.pairto;
+
+       DBG("System name: %s", adapter->system_name);
+       DBG("Major class: %u", adapter->major_class);
+       DBG("Minor class: %u", adapter->minor_class);
+       DBG("Modalias: %s", adapter->modalias);
+       DBG("Discoverable timeout: %u seconds", adapter->discoverable_timeout);
+       DBG("Pairable timeout: %u seconds", adapter->pairable_timeout);
+
+       adapter->auths = g_queue_new();
+
+       return btd_adapter_ref(adapter);
+}
+
+static void adapter_remove(struct btd_adapter *adapter)
+{
+       GSList *l;
+
+       DBG("Removing adapter %s", adapter->path);
+
+       if (adapter->discovery_idle_timeout > 0) {
+               g_source_remove(adapter->discovery_idle_timeout);
+               adapter->discovery_idle_timeout = 0;
+       }
+
+       if (adapter->temp_devices_timeout > 0) {
+               g_source_remove(adapter->temp_devices_timeout);
+               adapter->temp_devices_timeout = 0;
+       }
+
+       discovery_cleanup(adapter);
+
+       g_slist_free(adapter->connect_list);
+       adapter->connect_list = NULL;
+
+       for (l = adapter->devices; l; l = l->next)
+               device_remove(l->data, FALSE);
+
+       g_slist_free(adapter->devices);
+       adapter->devices = NULL;
+
+       unload_drivers(adapter);
+       btd_adapter_gatt_server_stop(adapter);
+
+       g_slist_free(adapter->pin_callbacks);
+       adapter->pin_callbacks = NULL;
+}
+
+const char *adapter_get_path(struct btd_adapter *adapter)
+{
+       if (!adapter)
+               return NULL;
+
+       return adapter->path;
+}
+
+const bdaddr_t *adapter_get_address(struct btd_adapter *adapter)
+{
+       return &adapter->bdaddr;
+}
+
+static gboolean confirm_name_timeout(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       error("Confirm name timed out for hci%u", adapter->dev_id);
+
+       adapter->confirm_name_timeout = 0;
+
+       mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
+       adapter->confirm_name_id = 0;
+
+       return FALSE;
+}
+
+static void confirm_name_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to confirm name for hci%u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+       }
+
+       adapter->confirm_name_id = 0;
+
+       g_source_remove(adapter->confirm_name_timeout);
+       adapter->confirm_name_timeout = 0;
+
+       DBG("Confirm name complete for hci%u", adapter->dev_id);
+}
+
+static void confirm_name(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, bool name_known)
+{
+       struct mgmt_cp_confirm_name cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s name_known %u", adapter->dev_id, addr,
+                                                               name_known);
+
+       /*
+        * If the kernel does not answer the confirm name command with
+        * a command complete or command status in time, this might
+        * race against another device found event that also requires
+        * to confirm the name. If there is a pending command, just
+        * cancel it to be safe here.
+        */
+       if (adapter->confirm_name_id > 0) {
+               warn("Found pending confirm name for hci%u", adapter->dev_id);
+               mgmt_cancel(adapter->mgmt, adapter->confirm_name_id);
+       }
+
+       if (adapter->confirm_name_timeout > 0) {
+               g_source_remove(adapter->confirm_name_timeout);
+               adapter->confirm_name_timeout = 0;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+       cp.name_known = name_known;
+
+       adapter->confirm_name_id = mgmt_reply(adapter->mgmt,
+                                       MGMT_OP_CONFIRM_NAME,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       confirm_name_complete, adapter, NULL);
+
+       if (adapter->confirm_name_id == 0) {
+               error("Failed to confirm name for hci%u", adapter->dev_id);
+               return;
+       }
+
+       /*
+        * This timeout handling is needed since the kernel is stupid
+        * and forgets to send a command complete response. However in
+        * case of failures it does send a command status.
+        */
+       adapter->confirm_name_timeout = g_timeout_add_seconds(2,
+                                               confirm_name_timeout, adapter);
+}
+
+static void update_found_devices(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t bdaddr_type, int8_t rssi,
+                                       bool confirm, bool legacy,
+                                       const uint8_t *data, uint8_t data_len)
+{
+       struct btd_device *dev;
+       struct eir_data eir_data;
+       char addr[18];
+       int err;
+       GSList *list;
+       bool name_known;
+
+       memset(&eir_data, 0, sizeof(eir_data));
+       err = eir_parse(&eir_data, data, data_len);
+       if (err < 0) {
+               error("Error parsing EIR data: %s (%d)", strerror(-err), -err);
+               return;
+       }
+
+       /* Avoid creating LE device if it's not discoverable */
+       if (bdaddr_type != BDADDR_BREDR &&
+                       !(eir_data.flags & (EIR_LIM_DISC | EIR_GEN_DISC))) {
+               eir_data_free(&eir_data);
+               return;
+       }
+
+       ba2str(bdaddr, addr);
+
+       list = g_slist_find_custom(adapter->devices, bdaddr, device_bdaddr_cmp);
+       if (!list) {
+               /*
+                * If no client has requested discovery, then do not
+                * create new device objects.
+                */
+               if (!adapter->discovery_list) {
+                       eir_data_free(&eir_data);
+                       return;
+               }
+
+               dev = adapter_create_device(adapter, bdaddr, bdaddr_type);
+       } else
+               dev = list->data;
+
+       if (!dev) {
+               error("Unable to create object for found device %s", addr);
+               eir_data_free(&eir_data);
+               return;
+       }
+
+       if (eir_data.name != NULL && eir_data.name_complete)
+               device_store_cached_name(dev, eir_data.name);
+
+       /*
+        * If no client has requested discovery, then only update
+        * already paired devices (skip temporary ones).
+        */
+       if (device_is_temporary(dev) && !adapter->discovery_list) {
+               eir_data_free(&eir_data);
+               return;
+       }
+
+       device_set_legacy(dev, legacy);
+       device_set_rssi(dev, rssi);
+
+       if (eir_data.appearance != 0)
+               device_set_appearance(dev, eir_data.appearance);
+
+       /* Report an unknown name to the kernel even if there is a short name
+        * known, but still update the name with the known short name. */
+       name_known = device_name_known(dev);
+
+       if (eir_data.name && (eir_data.name_complete || !name_known))
+               device_set_name(dev, eir_data.name);
+
+       if (eir_data.class != 0)
+               device_set_class(dev, eir_data.class);
+
+       device_add_eir_uuids(dev, eir_data.services);
+
+       eir_data_free(&eir_data);
+
+       /*
+        * Only if at least one client has requested discovery, maintain
+        * list of found devices and name confirming for legacy devices.
+        * Otherwise, this is an event from passive discovery and we
+        * should check if the device needs connecting to.
+        */
+       if (!adapter->discovery_list)
+               goto connect_le;
+
+       if (g_slist_find(adapter->discovery_found, dev))
+               return;
+
+       if (confirm)
+               confirm_name(adapter, bdaddr, bdaddr_type, name_known);
+
+       adapter->discovery_found = g_slist_prepend(adapter->discovery_found,
+                                                                       dev);
+
+       return;
+
+connect_le:
+       /*
+        * If we're in the process of stopping passive scanning and
+        * connecting another (or maybe even the same) LE device just
+        * ignore this one.
+        */
+       if (adapter->connect_le)
+               return;
+
+       /*
+        * If this is an LE device that's not connected and part of the
+        * connect_list stop passive scanning so that a connection
+        * attempt to it can be made
+        */
+       if (device_is_le(dev) && !device_is_connected(dev) &&
+                               g_slist_find(adapter->connect_list, dev)) {
+               adapter->connect_le = dev;
+               stop_passive_scanning(adapter);
+       }
+}
+
+static void device_found_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_found *ev = param;
+       struct btd_adapter *adapter = user_data;
+       const uint8_t *eir;
+       uint16_t eir_len;
+       uint32_t flags;
+       bool confirm_name;
+       bool legacy;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too short device found event (%u bytes)", length);
+               return;
+       }
+
+       eir_len = btohs(ev->eir_len);
+       if (length != sizeof(*ev) + eir_len) {
+               error("Device found event size mismatch (%u != %zu)",
+                                       length, sizeof(*ev) + eir_len);
+               return;
+       }
+
+       if (eir_len == 0)
+               eir = NULL;
+       else
+               eir = ev->eir;
+
+       flags = btohl(ev->flags);
+
+       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);
+
+       confirm_name = (flags & MGMT_DEV_FOUND_CONFIRM_NAME);
+       legacy = (flags & MGMT_DEV_FOUND_LEGACY_PAIRING);
+
+       update_found_devices(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                       ev->rssi, confirm_name, legacy,
+                                       eir, eir_len);
+}
+
+struct agent *adapter_get_agent(struct btd_adapter *adapter)
+{
+       return agent_get(NULL);
+}
+
+static void adapter_remove_connection(struct btd_adapter *adapter,
+                                               struct btd_device *device)
+{
+       DBG("");
+
+       if (!g_slist_find(adapter->connections, device)) {
+               error("No matching connection for device");
+               return;
+       }
+
+       device_remove_connection(device);
+
+       adapter->connections = g_slist_remove(adapter->connections, device);
+
+       if (device_is_authenticating(device))
+               device_cancel_authentication(device, TRUE);
+
+       if (device_is_temporary(device) && !device_is_retrying(device)) {
+               const char *path = device_get_path(device);
+
+               DBG("Removing temporary device %s", path);
+               adapter_remove_device(adapter, device);
+       }
+}
+
+static void adapter_stop(struct btd_adapter *adapter)
+{
+       /* check pending requests */
+       reply_pending_requests(adapter);
+
+       cancel_passive_scanning(adapter);
+
+       while (adapter->discovery_list) {
+               struct watch_client *client;
+
+               client = adapter->discovery_list->data;
+
+               /* g_dbus_remove_watch will remove the client from the
+                * adapter's list and free it using the discovery_destroy
+                * function.
+                */
+               g_dbus_remove_watch(dbus_conn, client->watch);
+       }
+
+       adapter->discovering = false;
+
+       while (adapter->connections) {
+               struct btd_device *device = adapter->connections->data;
+               adapter_remove_connection(adapter, device);
+       }
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                       ADAPTER_INTERFACE, "Discovering");
+
+       if (adapter->dev_class) {
+               /* the kernel should reset the class of device when powering
+                * down, but it does not. So force it here ... */
+               adapter->dev_class = 0;
+               g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Class");
+       }
+
+       g_dbus_emit_property_changed(dbus_conn, adapter->path,
+                                               ADAPTER_INTERFACE, "Powered");
+
+       DBG("adapter %s has been disabled", adapter->path);
+}
+
+int btd_register_adapter_driver(struct btd_adapter_driver *driver)
+{
+       adapter_drivers = g_slist_append(adapter_drivers, driver);
+
+       if (driver->probe == NULL)
+               return 0;
+
+       adapter_foreach(probe_driver, driver);
+
+       return 0;
+}
+
+static void unload_driver(struct btd_adapter *adapter, gpointer data)
+{
+       struct btd_adapter_driver *driver = data;
+
+       if (driver->remove)
+               driver->remove(adapter);
+
+       adapter->drivers = g_slist_remove(adapter->drivers, data);
+}
+
+void btd_unregister_adapter_driver(struct btd_adapter_driver *driver)
+{
+       adapter_drivers = g_slist_remove(adapter_drivers, driver);
+
+       adapter_foreach(unload_driver, driver);
+}
+
+static void agent_auth_cb(struct agent *agent, DBusError *derr,
+                                                       void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       struct service_auth *auth = adapter->auths->head->data;
+
+       g_queue_pop_head(adapter->auths);
+
+       auth->cb(derr, auth->user_data);
+
+       if (auth->agent)
+               agent_unref(auth->agent);
+
+       g_free(auth);
+
+       adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
+}
+
+static gboolean process_auth_queue(gpointer user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       DBusError err;
+
+       adapter->auth_idle_id = 0;
+
+       dbus_error_init(&err);
+       dbus_set_error_const(&err, ERROR_INTERFACE ".Rejected", NULL);
+
+       while (!g_queue_is_empty(adapter->auths)) {
+               struct service_auth *auth = adapter->auths->head->data;
+               struct btd_device *device = auth->device;
+               const char *dev_path;
+
+               if (device_is_trusted(device) == TRUE) {
+                       auth->cb(NULL, auth->user_data);
+                       goto next;
+               }
+
+               auth->agent = agent_get(NULL);
+               if (auth->agent == NULL) {
+                       warn("Authentication attempt without agent");
+                       auth->cb(&err, auth->user_data);
+                       goto next;
+               }
+
+               dev_path = device_get_path(device);
+
+               if (agent_authorize_service(auth->agent, dev_path, auth->uuid,
+                                       agent_auth_cb, adapter, NULL) < 0) {
+                       auth->cb(&err, auth->user_data);
+                       goto next;
+               }
+
+               break;
+
+next:
+               if (auth->agent)
+                       agent_unref(auth->agent);
+
+               g_free(auth);
+
+               g_queue_pop_head(adapter->auths);
+       }
+
+       dbus_error_free(&err);
+
+       return FALSE;
+}
+
+static int adapter_authorize(struct btd_adapter *adapter, const bdaddr_t *dst,
+                                       const char *uuid, service_auth_cb cb,
+                                       void *user_data)
+{
+       struct service_auth *auth;
+       struct btd_device *device;
+       static guint id = 0;
+
+       device = adapter_find_device(adapter, dst);
+       if (!device)
+               return 0;
+
+       /* Device connected? */
+       if (!g_slist_find(adapter->connections, device))
+               error("Authorization request for non-connected device!?");
+
+       auth = g_try_new0(struct service_auth, 1);
+       if (!auth)
+               return 0;
+
+       auth->cb = cb;
+       auth->user_data = user_data;
+       auth->uuid = uuid;
+       auth->device = device;
+       auth->adapter = adapter;
+       auth->id = ++id;
+
+       g_queue_push_tail(adapter->auths, auth);
+
+       if (adapter->auths->length != 1)
+               return auth->id;
+
+       if (adapter->auth_idle_id != 0)
+               return auth->id;
+
+       adapter->auth_idle_id = g_idle_add(process_auth_queue, adapter);
+
+       return auth->id;
+}
+
+guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
+                                       const char *uuid, service_auth_cb cb,
+                                       void *user_data)
+{
+       struct btd_adapter *adapter;
+       GSList *l;
+
+       if (bacmp(src, BDADDR_ANY) != 0) {
+               adapter = adapter_find(src);
+               if (!adapter)
+                       return 0;
+
+               return adapter_authorize(adapter, dst, uuid, cb, user_data);
+       }
+
+       for (l = adapters; l != NULL; l = g_slist_next(l)) {
+               guint id;
+
+               adapter = l->data;
+
+               id = adapter_authorize(adapter, dst, uuid, cb, user_data);
+               if (id != 0)
+                       return id;
+       }
+
+       return 0;
+}
+
+static struct service_auth *find_authorization(guint id)
+{
+       GSList *l;
+       GList *l2;
+
+       for (l = adapters; l != NULL; l = g_slist_next(l)) {
+               struct btd_adapter *adapter = l->data;
+
+               for (l2 = adapter->auths->head; l2 != NULL; l2 = l2->next) {
+                       struct service_auth *auth = l2->data;
+
+                       if (auth->id == id)
+                               return auth;
+               }
+       }
+
+       return NULL;
+}
+
+int btd_cancel_authorization(guint id)
+{
+       struct service_auth *auth;
+
+       auth = find_authorization(id);
+       if (auth == NULL)
+               return -EPERM;
+
+       g_queue_remove(auth->adapter->auths, auth);
+
+       if (auth->agent) {
+               agent_cancel(auth->agent);
+               agent_unref(auth->agent);
+       }
+
+       g_free(auth);
+
+       return 0;
+}
+
+int btd_adapter_restore_powered(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               return 0;
+
+       set_mode(adapter, MGMT_OP_SET_POWERED, 0x01);
+
+       return 0;
+}
+
+void btd_adapter_register_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_prepend(adapter->pin_callbacks, cb);
+}
+
+void btd_adapter_unregister_pin_cb(struct btd_adapter *adapter,
+                                                       btd_adapter_pin_cb_t cb)
+{
+       adapter->pin_callbacks = g_slist_remove(adapter->pin_callbacks, cb);
+}
+
+int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
+                                                       gboolean enable)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return -EINVAL;
+
+       set_mode(adapter, MGMT_OP_SET_FAST_CONNECTABLE, enable ? 0x01 : 0x00);
+
+       return 0;
+}
+
+int btd_adapter_read_clock(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                               int which, int timeout, uint32_t *clock,
+                               uint16_t *accuracy)
+{
+       if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+               return -EINVAL;
+
+       return -ENOSYS;
+}
+
+int btd_adapter_remove_bonding(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct mgmt_cp_unpair_device cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+       cp.disconnect = 1;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_UNPAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static void pincode_reply_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_device *device = user_data;
+
+       /* If the MGMT_OP_PIN_CODE_REPLY command is acknowledged, move the
+        * starting time to that point. This give a better sense of time
+        * evaluating the pincode. */
+       device_bonding_restart_timer(device);
+}
+
+int btd_adapter_pincode_reply(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       const char *pin, size_t pin_len)
+{
+       struct btd_device *device;
+       unsigned int id;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s pinlen %zu", adapter->dev_id, addr, pin_len);
+
+       if (pin == NULL) {
+               struct mgmt_cp_pin_code_neg_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_PIN_CODE_NEG_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       } else {
+               struct mgmt_cp_pin_code_reply cp;
+
+               if (pin_len > 16)
+                       return -EINVAL;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = BDADDR_BREDR;
+               cp.pin_len = pin_len;
+               memcpy(cp.pin_code, pin, pin_len);
+
+               /* Since a pincode was requested, update the starting time to
+                * the point where the pincode is provided. */
+               device = adapter_find_device(adapter, bdaddr);
+               device_bonding_restart_timer(device);
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_PIN_CODE_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       pincode_reply_complete, device, NULL);
+       }
+
+       if (id == 0)
+               return -EIO;
+
+       return 0;
+}
+
+int btd_adapter_confirm_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               gboolean success)
+{
+       struct mgmt_cp_user_confirm_reply cp;
+       uint16_t opcode;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s success %d", adapter->dev_id, addr, success);
+
+       if (success)
+               opcode = MGMT_OP_USER_CONFIRM_REPLY;
+       else
+               opcode = MGMT_OP_USER_CONFIRM_NEG_REPLY;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_reply(adapter->mgmt, opcode, adapter->dev_id, sizeof(cp), &cp,
+                                                       NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static void user_confirm_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_user_confirm_request *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       int err;
+
+       if (length < sizeof(*ev)) {
+               error("Too small user confirm request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s confirm_hint %u", adapter->dev_id, addr,
+                                                       ev->confirm_hint);
+       device = adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       err = device_confirm_passkey(device, btohl(ev->value),
+                                                       ev->confirm_hint);
+       if (err < 0) {
+               error("device_confirm_passkey: %s", strerror(-err));
+               btd_adapter_confirm_reply(adapter, &ev->addr.bdaddr,
+                                                       ev->addr.type, FALSE);
+       }
+}
+
+int btd_adapter_passkey_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               uint32_t passkey)
+{
+       unsigned int id;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u addr %s passkey %06u", adapter->dev_id, addr, passkey);
+
+       if (passkey == INVALID_PASSKEY) {
+               struct mgmt_cp_user_passkey_neg_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = bdaddr_type;
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_USER_PASSKEY_NEG_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       } else {
+               struct mgmt_cp_user_passkey_reply cp;
+
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.addr.bdaddr, bdaddr);
+               cp.addr.type = bdaddr_type;
+               cp.passkey = htobl(passkey);
+
+               id = mgmt_reply(adapter->mgmt, MGMT_OP_USER_PASSKEY_REPLY,
+                                       adapter->dev_id, sizeof(cp), &cp,
+                                       NULL, NULL, NULL);
+       }
+
+       if (id == 0)
+               return -EIO;
+
+       return 0;
+}
+
+static void user_passkey_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_user_passkey_request *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+       int err;
+
+       if (length < sizeof(*ev)) {
+               error("Too small passkey request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s", index, addr);
+
+       device = adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       err = device_request_passkey(device);
+       if (err < 0) {
+               error("device_request_passkey: %s", strerror(-err));
+               btd_adapter_passkey_reply(adapter, &ev->addr.bdaddr,
+                                       ev->addr.type, INVALID_PASSKEY);
+       }
+}
+
+static void user_passkey_notify_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_passkey_notify *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       uint32_t passkey;
+       char addr[18];
+       int err;
+
+       if (length < sizeof(*ev)) {
+               error("Too small passkey notify event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s", index, addr);
+
+       device = adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       passkey = bt_get_le32(&ev->passkey);
+
+       DBG("passkey %06u entered %u", passkey, ev->entered);
+
+       err = device_notify_passkey(device, passkey, ev->entered);
+       if (err < 0)
+               error("device_notify_passkey: %s", strerror(-err));
+}
+
+struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
+                                               struct btd_adapter *adapter)
+{
+       struct btd_adapter_pin_cb_iter *iter =
+                               g_new0(struct btd_adapter_pin_cb_iter, 1);
+
+       iter->it = adapter->pin_callbacks;
+       iter->attempt = 1;
+
+       return iter;
+}
+
+void btd_adapter_pin_cb_iter_free(struct btd_adapter_pin_cb_iter *iter)
+{
+       g_free(iter);
+}
+
+bool btd_adapter_pin_cb_iter_end(struct btd_adapter_pin_cb_iter *iter)
+{
+       return iter->it == NULL && iter->attempt == 0;
+}
+
+static ssize_t btd_adapter_pin_cb_iter_next(
+                                       struct btd_adapter_pin_cb_iter *iter,
+                                       struct btd_adapter *adapter,
+                                       struct btd_device *device,
+                                       char *pin_buf, bool *display)
+{
+       btd_adapter_pin_cb_t cb;
+       ssize_t ret;
+
+       while (iter->it != NULL) {
+               cb = iter->it->data;
+               ret = cb(adapter, device, pin_buf, display, iter->attempt);
+               iter->attempt++;
+               if (ret > 0)
+                       return ret;
+               iter->attempt = 1;
+               iter->it = g_slist_next(iter->it);
+       }
+       iter->attempt = 0;
+
+       return 0;
+}
+
+static void pin_code_request_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_pin_code_request *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       bool display = false;
+       char pin[17];
+       ssize_t pinlen;
+       char addr[18];
+       int err;
+       struct btd_adapter_pin_cb_iter *iter;
+
+       if (length < sizeof(*ev)) {
+               error("Too small PIN code request event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u %s", adapter->dev_id, addr);
+
+       device = adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       /* Flag the request of a pincode to allow a bonding retry. */
+       adapter->pincode_requested = true;
+
+       memset(pin, 0, sizeof(pin));
+
+       iter = device_bonding_iter(device);
+       if (iter == NULL)
+               pinlen = 0;
+       else
+               pinlen = btd_adapter_pin_cb_iter_next(iter, adapter, device,
+                                                               pin, &display);
+
+       if (pinlen > 0 && (!ev->secure || pinlen == 16)) {
+               if (display && device_is_bonding(device, NULL)) {
+                       err = device_notify_pincode(device, ev->secure, pin);
+                       if (err < 0) {
+                               error("device_notify_pin: %s", strerror(-err));
+                               btd_adapter_pincode_reply(adapter,
+                                                       &ev->addr.bdaddr,
+                                                       NULL, 0);
+                       }
+               } else {
+                       btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr,
+                                                               pin, pinlen);
+               }
+               return;
+       }
+
+       err = device_request_pincode(device, ev->secure);
+       if (err < 0) {
+               error("device_request_pin: %s", strerror(-err));
+               btd_adapter_pincode_reply(adapter, &ev->addr.bdaddr, NULL, 0);
+       }
+}
+
+int adapter_cancel_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                                        uint8_t addr_type)
+{
+       struct mgmt_addr_info cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %u", adapter->dev_id, addr, addr_type);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.bdaddr, bdaddr);
+       cp.type = addr_type;
+
+       if (mgmt_reply(adapter->mgmt, MGMT_OP_CANCEL_PAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static void check_oob_bonding_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr, uint8_t status)
+{
+       if (!adapter->oob_handler || !adapter->oob_handler->bonding_cb)
+               return;
+
+       if (bacmp(bdaddr, &adapter->oob_handler->remote_addr) != 0)
+               return;
+
+       adapter->oob_handler->bonding_cb(adapter, bdaddr, status,
+                                       adapter->oob_handler->user_data);
+
+       g_free(adapter->oob_handler);
+       adapter->oob_handler = NULL;
+}
+
+static void bonding_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t status)
+{
+       struct btd_device *device;
+
+       if (status == 0)
+               device = adapter_get_device(adapter, bdaddr, addr_type);
+       else
+               device = adapter_find_device(adapter, bdaddr);
+
+       if (device != NULL)
+               device_bonding_complete(device, status);
+
+       resume_discovery(adapter);
+
+       check_oob_bonding_complete(adapter, bdaddr, status);
+}
+
+/* bonding_attempt_complete() handles the end of a "bonding attempt" checking if
+ * it should begin a new attempt or complete the bonding.
+ */
+static void bonding_attempt_complete(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t status)
+{
+       struct btd_device *device;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %u status 0x%x", adapter->dev_id, addr,
+                                                       addr_type, status);
+
+       if (status == 0)
+               device = adapter_get_device(adapter, bdaddr, addr_type);
+       else
+               device = adapter_find_device(adapter, bdaddr);
+
+       if (status == MGMT_STATUS_AUTH_FAILED && adapter->pincode_requested) {
+               /* On faliure, issue a bonding_retry if possible. */
+               if (device != NULL) {
+                       if (device_bonding_attempt_retry(device) == 0)
+                               return;
+               }
+       }
+
+       /* Ignore disconnects during retry. */
+       if (status == MGMT_STATUS_DISCONNECTED &&
+                                       device && device_is_retrying(device))
+               return;
+
+       /* In any other case, finish the bonding. */
+       bonding_complete(adapter, bdaddr, addr_type, status);
+}
+
+struct pair_device_data {
+       struct btd_adapter *adapter;
+       bdaddr_t bdaddr;
+       uint8_t addr_type;
+};
+
+static void free_pair_device_data(void *user_data)
+{
+       struct pair_device_data *data = user_data;
+
+       g_free(data);
+}
+
+static gboolean pair_device_timeout(gpointer user_data)
+{
+       struct pair_device_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
+
+       error("Pair device timed out for hci%u", adapter->dev_id);
+
+       adapter->pair_device_timeout = 0;
+
+       adapter_cancel_bonding(adapter, &data->bdaddr, data->addr_type);
+
+       return FALSE;
+}
+
+static void pair_device_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_pair_device *rp = param;
+       struct pair_device_data *data = user_data;
+       struct btd_adapter *adapter = data->adapter;
+
+       DBG("%s (0x%02x)", mgmt_errstr(status), status);
+
+       adapter->pair_device_id = 0;
+
+       if (adapter->pair_device_timeout > 0) {
+               g_source_remove(adapter->pair_device_timeout);
+               adapter->pair_device_timeout = 0;
+       }
+
+       /* Workaround for a kernel bug
+        *
+        * Broken kernels may reply to device pairing command with command
+        * status instead of command complete event e.g. if adapter was not
+        * powered.
+        */
+       if (status != MGMT_STATUS_SUCCESS && length < sizeof(*rp)) {
+               error("Pair device failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+
+               bonding_attempt_complete(adapter, &data->bdaddr,
+                                               data->addr_type, status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Too small pair device response");
+               return;
+       }
+
+       bonding_attempt_complete(adapter, &rp->addr.bdaddr, rp->addr.type,
+                                                                       status);
+}
+
+int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap)
+{
+       if (adapter->pair_device_id > 0) {
+               error("Unable pair since another pairing is in progress");
+               return -EBUSY;
+       }
+
+       suspend_discovery(adapter);
+
+       return adapter_bonding_attempt(adapter, bdaddr, addr_type, io_cap);
+}
+
+/* Starts a new bonding attempt in a fresh new bonding_req or a retried one. */
+int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap)
+{
+       struct mgmt_cp_pair_device cp;
+       char addr[18];
+       struct pair_device_data *data;
+       unsigned int id;
+
+       ba2str(bdaddr, addr);
+       DBG("hci%u bdaddr %s type %d io_cap 0x%02x",
+                               adapter->dev_id, addr, addr_type, io_cap);
+
+       /* Reset the pincode_requested flag for a new bonding attempt. */
+       adapter->pincode_requested = false;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = addr_type;
+       cp.io_cap = io_cap;
+
+       data = g_new0(struct pair_device_data, 1);
+       data->adapter = adapter;
+       bacpy(&data->bdaddr, bdaddr);
+       data->addr_type = addr_type;
+
+       id = mgmt_send(adapter->mgmt, MGMT_OP_PAIR_DEVICE,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               pair_device_complete, data,
+                               free_pair_device_data);
+
+       if (id == 0) {
+               error("Failed to pair %s for hci%u", addr, adapter->dev_id);
+               free_pair_device_data(data);
+               return -EIO;
+       }
+
+       adapter->pair_device_id = id;
+
+       /* Due to a bug in the kernel it is possible that a LE pairing
+        * request never times out. Therefore, add a timer to clean up
+        * if no response arrives
+        */
+       adapter->pair_device_timeout = g_timeout_add_seconds(BONDING_TIMEOUT,
+                                               pair_device_timeout, data);
+
+       return 0;
+}
+
+static void dev_disconnected(struct btd_adapter *adapter,
+                                       const struct mgmt_addr_info *addr,
+                                       uint8_t reason)
+{
+       struct btd_device *device;
+       char dst[18];
+
+       ba2str(&addr->bdaddr, dst);
+
+       DBG("Device %s disconnected, reason %u", dst, reason);
+
+       device = adapter_find_device(adapter, &addr->bdaddr);
+       if (device)
+               adapter_remove_connection(adapter, device);
+
+       bonding_attempt_complete(adapter, &addr->bdaddr, addr->type,
+                                               MGMT_STATUS_DISCONNECTED);
+}
+
+static void disconnect_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_disconnect *rp = param;
+       struct btd_adapter *adapter = user_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to disconnect device: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Too small device disconnect response");
+               return;
+       }
+
+       dev_disconnected(adapter, &rp->addr, MGMT_DEV_DISCONN_LOCAL_HOST);
+}
+
+int btd_adapter_disconnect_device(struct btd_adapter *adapter,
+                                               const bdaddr_t *bdaddr,
+                                               uint8_t bdaddr_type)
+
+{
+       struct mgmt_cp_disconnect cp;
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       cp.addr.type = bdaddr_type;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_DISCONNECT,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               disconnect_complete, adapter, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static void auth_failed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_auth_failed *ev = param;
+       struct btd_adapter *adapter = user_data;
+
+       if (length < sizeof(*ev)) {
+               error("Too small auth failed mgmt event");
+               return;
+       }
+
+       bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                                               ev->status);
+}
+
+static void store_link_key(struct btd_adapter *adapter,
+                               struct btd_device *device, const uint8_t *key,
+                               uint8_t type, uint8_t pin_length)
+{
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       gsize length = 0;
+       char key_str[35];
+       char *str;
+       int i;
+
+       ba2str(adapter_get_address(adapter), adapter_addr);
+       ba2str(device_get_address(device), device_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       key_str[0] = '0';
+       key_str[1] = 'x';
+       for (i = 0; i < 16; i++)
+               sprintf(key_str + 2 + (i * 2), "%2.2X", key[i]);
+
+       g_key_file_set_string(key_file, "LinkKey", "Key", key_str);
+
+       g_key_file_set_integer(key_file, "LinkKey", "Type", type);
+       g_key_file_set_integer(key_file, "LinkKey", "PINLength", pin_length);
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
+
+       g_key_file_free(key_file);
+}
+
+static void new_link_key_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_new_link_key *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small new link key event");
+               return;
+       }
+
+       ba2str(&addr->bdaddr, dst);
+
+       DBG("hci%u new key for %s type %u pin_len %u", adapter->dev_id,
+                                       dst, ev->key.type, ev->key.pin_len);
+
+       if (ev->key.pin_len > 16) {
+               error("Invalid PIN length (%u) in new_key event",
+                                                       ev->key.pin_len);
+               return;
+       }
+
+       device = adapter_get_device(adapter, &addr->bdaddr, addr->type);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
+               return;
+       }
+
+       if (ev->store_hint) {
+               const struct mgmt_link_key_info *key = &ev->key;
+
+               store_link_key(adapter, device, key->val, key->type,
+                                                               key->pin_len);
+
+               device_set_bonded(device, TRUE);
+
+               if (device_is_temporary(device))
+                       device_set_temporary(device, FALSE);
+       }
+
+       bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
+}
+
+static void store_longtermkey(const bdaddr_t *local, const bdaddr_t *peer,
+                               uint8_t bdaddr_type, const unsigned char *key,
+                               uint8_t master, uint8_t authenticated,
+                               uint8_t enc_size, uint16_t ediv,
+                               const uint8_t rand[8])
+{
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char key_str[35];
+       char rand_str[19];
+       gsize length = 0;
+       char *str;
+       int i;
+
+       ba2str(local, adapter_addr);
+       ba2str(peer, device_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                                                               device_addr);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       key_str[0] = '0';
+       key_str[1] = 'x';
+       for (i = 0; i < 16; i++)
+               sprintf(key_str + 2 + (i * 2), "%2.2X", key[i]);
+
+       g_key_file_set_string(key_file, "LongTermKey", "Key", key_str);
+
+       g_key_file_set_integer(key_file, "LongTermKey", "Authenticated",
+                               authenticated);
+       g_key_file_set_integer(key_file, "LongTermKey", "Master", master);
+       g_key_file_set_integer(key_file, "LongTermKey", "EncSize", enc_size);
+       g_key_file_set_integer(key_file, "LongTermKey", "EDiv", ediv);
+
+       rand_str[0] = '0';
+       rand_str[1] = 'x';
+       for (i = 0; i < 8; i++)
+               sprintf(rand_str + 2 + (i * 2), "%2.2X", rand[i]);
+
+       g_key_file_set_string(key_file, "LongTermKey", "Rand", rand_str);
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
+
+       g_key_file_free(key_file);
+}
+
+static void new_long_term_key_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_new_long_term_key *ev = param;
+       const struct mgmt_addr_info *addr = &ev->key.addr;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char dst[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small long term key event");
+               return;
+       }
+
+       ba2str(&addr->bdaddr, dst);
+
+       DBG("hci%u new LTK for %s authenticated %u enc_size %u",
+               adapter->dev_id, dst, ev->key.authenticated, ev->key.enc_size);
+
+       device = adapter_get_device(adapter, &addr->bdaddr, addr->type);
+       if (!device) {
+               error("Unable to get device object for %s", dst);
+               return;
+       }
+
+       if (ev->store_hint) {
+               const struct mgmt_ltk_info *key = &ev->key;
+               const bdaddr_t *bdaddr = adapter_get_address(adapter);
+
+               store_longtermkey(bdaddr, &key->addr.bdaddr,
+                                       key->addr.type, key->val, key->master,
+                                       key->authenticated, key->enc_size,
+                                       key->ediv, key->rand);
+
+               device_set_bonded(device, TRUE);
+
+               if (device_is_temporary(device))
+                       device_set_temporary(device, FALSE);
+       }
+
+       if (ev->key.master)
+               bonding_complete(adapter, &addr->bdaddr, addr->type, 0);
+}
+
+int adapter_set_io_capability(struct btd_adapter *adapter, uint8_t io_cap)
+{
+       struct mgmt_cp_set_io_capability cp;
+
+       memset(&cp, 0, sizeof(cp));
+       cp.io_capability = io_cap;
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_IO_CAPABILITY,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t *hash, uint8_t *randomizer)
+{
+       struct mgmt_cp_add_remote_oob_data cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", adapter->dev_id, addr);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+       memcpy(cp.hash, hash, 16);
+
+       if (randomizer)
+               memcpy(cp.randomizer, randomizer, 16);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_ADD_REMOTE_OOB_DATA,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
+                                                       const bdaddr_t *bdaddr)
+{
+       struct mgmt_cp_remove_remote_oob_data cp;
+       char addr[18];
+
+       ba2str(bdaddr, addr);
+       DBG("hci%d bdaddr %s", adapter->dev_id, addr);
+
+       memset(&cp, 0, sizeof(cp));
+       bacpy(&cp.addr.bdaddr, bdaddr);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_REMOVE_REMOTE_OOB_DATA,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+bool btd_adapter_ssp_enabled(struct btd_adapter *adapter)
+{
+       if (adapter->current_settings & MGMT_SETTING_SSP)
+               return true;
+
+       return false;
+}
+
+void btd_adapter_set_oob_handler(struct btd_adapter *adapter,
+                                               struct oob_handler *handler)
+{
+       adapter->oob_handler = handler;
+}
+
+gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter)
+{
+       return adapter->oob_handler != NULL;
+}
+
+static void read_local_oob_data_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_local_oob_data *rp = param;
+       struct btd_adapter *adapter = user_data;
+       const uint8_t *hash, *randomizer;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Read local OOB data failed: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               hash = NULL;
+               randomizer = NULL;
+       } else if (length < sizeof(*rp)) {
+               error("Too small read local OOB data response");
+               return;
+       } else {
+               hash = rp->hash;
+               randomizer = rp->randomizer;
+       }
+
+       if (!adapter->oob_handler || !adapter->oob_handler->read_local_cb)
+               return;
+
+       adapter->oob_handler->read_local_cb(adapter, hash, randomizer,
+                                       adapter->oob_handler->user_data);
+
+       g_free(adapter->oob_handler);
+       adapter->oob_handler = NULL;
+}
+
+int btd_adapter_read_local_oob_data(struct btd_adapter *adapter)
+{
+       DBG("hci%u", adapter->dev_id);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_READ_LOCAL_OOB_DATA,
+                       adapter->dev_id, 0, NULL, read_local_oob_data_complete,
+                       adapter, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+void btd_adapter_for_each_device(struct btd_adapter *adapter,
+                       void (*cb)(struct btd_device *device, void *data),
+                       void *data)
+{
+       g_slist_foreach(adapter->devices, (GFunc) cb, data);
+}
+
+static int adapter_cmp(gconstpointer a, gconstpointer b)
+{
+       struct btd_adapter *adapter = (struct btd_adapter *) a;
+       const bdaddr_t *bdaddr = b;
+
+       return bacmp(&adapter->bdaddr, bdaddr);
+}
+
+static int adapter_id_cmp(gconstpointer a, gconstpointer b)
+{
+       struct btd_adapter *adapter = (struct btd_adapter *) a;
+       uint16_t id = GPOINTER_TO_UINT(b);
+
+       return adapter->dev_id == id ? 0 : -1;
+}
+
+struct btd_adapter *adapter_find(const bdaddr_t *sba)
+{
+       GSList *match;
+
+       match = g_slist_find_custom(adapters, sba, adapter_cmp);
+       if (!match)
+               return NULL;
+
+       return match->data;
+}
+
+struct btd_adapter *adapter_find_by_id(int id)
+{
+       GSList *match;
+
+       match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
+                                                       adapter_id_cmp);
+       if (!match)
+               return NULL;
+
+       return match->data;
+}
+
+void adapter_foreach(adapter_cb func, gpointer user_data)
+{
+       g_slist_foreach(adapters, (GFunc) func, user_data);
+}
+
+static int set_did(struct btd_adapter *adapter, uint16_t vendor,
+                       uint16_t product, uint16_t version, uint16_t source)
+{
+       struct mgmt_cp_set_device_id cp;
+
+       DBG("hci%u source %x vendor %x product %x version %x",
+                       adapter->dev_id, source, vendor, product, version);
+
+       memset(&cp, 0, sizeof(cp));
+
+       cp.source = htobs(source);
+       cp.vendor = htobs(vendor);
+       cp.product = htobs(product);
+       cp.version = htobs(version);
+
+       if (mgmt_send(adapter->mgmt, MGMT_OP_SET_DEVICE_ID,
+                               adapter->dev_id, sizeof(cp), &cp,
+                               NULL, NULL, NULL) > 0)
+               return 0;
+
+       return -EIO;
+}
+
+static int adapter_register(struct btd_adapter *adapter)
+{
+       struct agent *agent;
+
+       if (powering_down)
+               return -EBUSY;
+
+       adapter->path = g_strdup_printf("/org/bluez/hci%d", adapter->dev_id);
+
+       if (!g_dbus_register_interface(dbus_conn,
+                                       adapter->path, ADAPTER_INTERFACE,
+                                       adapter_methods, NULL,
+                                       adapter_properties, adapter,
+                                       adapter_free)) {
+               error("Adapter interface init failed on path %s",
+                                                       adapter->path);
+               g_free(adapter->path);
+               adapter->path = NULL;
+               return -EINVAL;
+       }
+
+       if (adapters == NULL)
+               adapter->is_default = true;
+
+       adapters = g_slist_append(adapters, adapter);
+
+       agent = agent_get(NULL);
+       if (agent) {
+               uint8_t io_cap = agent_get_io_capability(agent);
+               adapter_set_io_capability(adapter, io_cap);
+               agent_unref(agent);
+       }
+
+       btd_adapter_gatt_server_start(adapter);
+
+       load_config(adapter);
+       fix_storage(adapter);
+       load_drivers(adapter);
+       btd_profile_foreach(probe_profile, adapter);
+       clear_blocked(adapter);
+       load_devices(adapter);
+
+       /* retrieve the active connections: address the scenario where
+        * the are active connections before the daemon've started */
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               load_connections(adapter);
+
+       adapter->initialized = TRUE;
+
+       if (main_opts.did_source) {
+               /* DeviceID record is added by sdpd-server before any other
+                * record is registered. */
+               adapter_service_insert(adapter, sdp_record_find(0x10000));
+               set_did(adapter, main_opts.did_vendor, main_opts.did_product,
+                               main_opts.did_version, main_opts.did_source);
+       }
+
+       DBG("Adapter %s registered", adapter->path);
+
+       return 0;
+}
+
+static int adapter_unregister(struct btd_adapter *adapter)
+{
+       DBG("Unregister path: %s", adapter->path);
+
+       adapters = g_slist_remove(adapters, adapter);
+
+       if (adapter->is_default && adapters != NULL) {
+               struct btd_adapter *new_default;
+
+               new_default = adapter_find_by_id(hci_get_route(NULL));
+               if (new_default == NULL)
+                       new_default = adapters->data;
+
+               new_default->is_default = true;
+       }
+
+       adapter_list = g_list_remove(adapter_list, adapter);
+
+       adapter_remove(adapter);
+       btd_adapter_unref(adapter);
+
+       return 0;
+}
+
+static void disconnected_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_disconnected *ev = param;
+       struct btd_adapter *adapter = user_data;
+       uint8_t reason;
 
-int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
-                       bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer)
+       if (length < sizeof(struct mgmt_addr_info)) {
+               error("Too small device disconnected event");
+               return;
+       }
+
+       if (length < sizeof(*ev))
+               reason = MGMT_DEV_DISCONN_UNKNOWN;
+       else
+               reason = ev->reason;
+
+       dev_disconnected(adapter, &ev->addr, reason);
+}
+
+static void connected_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_connected *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       struct eir_data eir_data;
+       uint16_t eir_len;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small device connected event");
+               return;
+       }
+
+       eir_len = btohs(ev->eir_len);
+       if (length < sizeof(*ev) + eir_len) {
+               error("Too small device connected event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u device %s connected eir_len %u", index, addr, eir_len);
+
+       device = adapter_get_device(adapter, &ev->addr.bdaddr, ev->addr.type);
+       if (!device) {
+               error("Unable to get device object for %s", addr);
+               return;
+       }
+
+       memset(&eir_data, 0, sizeof(eir_data));
+       if (eir_len > 0)
+               eir_parse(&eir_data, ev->eir, eir_len);
+
+       if (eir_data.class != 0)
+               device_set_class(device, eir_data.class);
+
+       adapter_add_connection(adapter, device);
+
+       if (eir_data.name != NULL) {
+               device_store_cached_name(device, eir_data.name);
+               device_set_name(device, eir_data.name);
+       }
+
+       eir_data_free(&eir_data);
+}
+
+static void device_blocked_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
 {
-       return adapter_ops->add_remote_oob_data(adapter->dev_id, bdaddr, hash,
-                                                               randomizer);
+       const struct mgmt_ev_device_blocked *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small device blocked event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s blocked", index, addr);
+
+       device = adapter_find_device(adapter, &ev->addr.bdaddr);
+       if (device)
+               device_block(device, TRUE);
 }
 
-int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
-                                                       bdaddr_t *bdaddr)
+static void device_unblocked_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_unblocked *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small device unblocked event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+       DBG("hci%u %s unblocked", index, addr);
+
+       device = adapter_find_device(adapter, &ev->addr.bdaddr);
+       if (device)
+               device_unblock(device, FALSE, TRUE);
+}
+
+static void connect_failed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_connect_failed *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small connect failed event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u %s status %u", index, addr, ev->status);
+
+       device = adapter_find_device(adapter, &ev->addr.bdaddr);
+       if (device) {
+               /* If the device is in a bonding process cancel any auth request
+                * sent to the agent before proceeding, but keep the bonding
+                * request structure. */
+               if (device_is_bonding(device, NULL))
+                       device_cancel_authentication(device, FALSE);
+       }
+
+       /* In the case of security mode 3 devices */
+       bonding_attempt_complete(adapter, &ev->addr.bdaddr, ev->addr.type,
+                                                               ev->status);
+
+       /* If the device is scheduled to retry the bonding wait until the retry
+        * happens. In other case, proceed with cancel the bondig.
+        */
+       if (device && device_is_bonding(device, NULL)
+                                       && !device_is_retrying(device)) {
+               device_cancel_authentication(device, TRUE);
+               device_bonding_failed(device, ev->status);
+       }
+
+       /* In the case the bonding was canceled or did exists, remove the device
+        * when it is temporary. */
+       if (device && !device_is_bonding(device, NULL)
+                                               && device_is_temporary(device))
+               adapter_remove_device(adapter, device);
+}
+
+static void unpaired_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_ev_device_unpaired *ev = param;
+       struct btd_adapter *adapter = user_data;
+       struct btd_device *device;
+       char addr[18];
+
+       if (length < sizeof(*ev)) {
+               error("Too small device unpaired event");
+               return;
+       }
+
+       ba2str(&ev->addr.bdaddr, addr);
+
+       DBG("hci%u addr %s", index, addr);
+
+       device = adapter_find_device(adapter, &ev->addr.bdaddr);
+       if (!device) {
+               warn("No device object for unpaired device %s", addr);
+               return;
+       }
+
+       device_set_temporary(device, TRUE);
+
+       if (device_is_connected(device))
+               device_request_disconnect(device, NULL);
+       else
+               adapter_remove_device(adapter, device);
+}
+
+static void read_info_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct btd_adapter *adapter = user_data;
+       const struct mgmt_rp_read_info *rp = param;
+       int err;
+
+       DBG("index %u status 0x%02x", adapter->dev_id, status);
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read info for index %u: %s (0x%02x)",
+                               adapter->dev_id, mgmt_errstr(status), status);
+               goto failed;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Too small read info complete response");
+               goto failed;
+       }
+
+       if (bacmp(&rp->bdaddr, BDADDR_ANY) == 0) {
+               error("No Bluetooth address for index %u", adapter->dev_id);
+               goto failed;
+       }
+
+       /*
+        * Store controller information for device address, class of device,
+        * device name, short name and settings.
+        *
+        * During the lifetime of the controller these will be updated by
+        * events and the information is required to keep the current
+        * state of the controller.
+        */
+       bacpy(&adapter->bdaddr, &rp->bdaddr);
+       adapter->dev_class = rp->dev_class[0] | (rp->dev_class[1] << 8) |
+                                               (rp->dev_class[2] << 16);
+       adapter->name = g_strdup((const char *) rp->name);
+       adapter->short_name = g_strdup((const char *) rp->short_name);
+
+       adapter->supported_settings = btohs(rp->supported_settings);
+       adapter->current_settings = btohs(rp->current_settings);
+
+       clear_uuids(adapter);
+
+       err = adapter_register(adapter);
+       if (err < 0) {
+               error("Unable to register new adapter");
+               goto failed;
+       }
+
+       /*
+        * Register all event notification handlers for controller.
+        *
+        * The handlers are registered after a succcesful read of the
+        * controller info. From now on they can track updates and
+        * notifications.
+        */
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_SETTINGS, adapter->dev_id,
+                                       new_settings_callback, adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_CLASS_OF_DEV_CHANGED,
+                                               adapter->dev_id,
+                                               dev_class_changed_callback,
+                                               adapter, NULL);
+       mgmt_register(adapter->mgmt, MGMT_EV_LOCAL_NAME_CHANGED,
+                                               adapter->dev_id,
+                                               local_name_changed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DISCOVERING,
+                                               adapter->dev_id,
+                                               discovering_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_FOUND,
+                                               adapter->dev_id,
+                                               device_found_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_DISCONNECTED,
+                                               adapter->dev_id,
+                                               disconnected_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_CONNECTED,
+                                               adapter->dev_id,
+                                               connected_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_CONNECT_FAILED,
+                                               adapter->dev_id,
+                                               connect_failed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNPAIRED,
+                                               adapter->dev_id,
+                                               unpaired_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_AUTH_FAILED,
+                                               adapter->dev_id,
+                                               auth_failed_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_LINK_KEY,
+                                               adapter->dev_id,
+                                               new_link_key_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_NEW_LONG_TERM_KEY,
+                                               adapter->dev_id,
+                                               new_long_term_key_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_BLOCKED,
+                                               adapter->dev_id,
+                                               device_blocked_callback,
+                                               adapter, NULL);
+       mgmt_register(adapter->mgmt, MGMT_EV_DEVICE_UNBLOCKED,
+                                               adapter->dev_id,
+                                               device_unblocked_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_PIN_CODE_REQUEST,
+                                               adapter->dev_id,
+                                               pin_code_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_USER_CONFIRM_REQUEST,
+                                               adapter->dev_id,
+                                               user_confirm_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_USER_PASSKEY_REQUEST,
+                                               adapter->dev_id,
+                                               user_passkey_request_callback,
+                                               adapter, NULL);
+
+       mgmt_register(adapter->mgmt, MGMT_EV_PASSKEY_NOTIFY,
+                                               adapter->dev_id,
+                                               user_passkey_notify_callback,
+                                               adapter, NULL);
+
+       set_dev_class(adapter);
+
+       set_name(adapter, btd_adapter_get_name(adapter));
+
+       if ((adapter->supported_settings & MGMT_SETTING_SSP) &&
+                       !(adapter->current_settings & MGMT_SETTING_SSP))
+               set_mode(adapter, MGMT_OP_SET_SSP, 0x01);
+
+       if ((adapter->supported_settings & MGMT_SETTING_LE) &&
+                       !(adapter->current_settings & MGMT_SETTING_LE))
+               set_mode(adapter, MGMT_OP_SET_LE, 0x01);
+
+       set_mode(adapter, MGMT_OP_SET_PAIRABLE, 0x01);
+       set_mode(adapter, MGMT_OP_SET_CONNECTABLE, 0x01);
+
+       if (adapter->stored_discoverable && !adapter->discoverable_timeout)
+               set_discoverable(adapter, 0x01, 0);
+
+       if (adapter->current_settings & MGMT_SETTING_POWERED)
+               adapter_start(adapter);
+
+       return;
+
+failed:
+       /*
+        * Remove adapter from list in case of a failure.
+        *
+        * Leaving an adapter structure around for a controller that can
+        * not be initilized makes no sense at the moment.
+        *
+        * This is a simplification to avoid constant checks if the
+        * adapter is ready to do anything.
+        */
+       adapter_list = g_list_remove(adapter_list, adapter);
+
+       btd_adapter_unref(adapter);
+}
+
+static void index_added(uint16_t index, uint16_t length, const void *param,
+                                                       void *user_data)
+{
+       struct btd_adapter *adapter;
+
+       DBG("index %u", index);
+
+       adapter = btd_adapter_lookup(index);
+       if (adapter) {
+               warn("Ignoring index added for an already existing adapter");
+               return;
+       }
+
+       adapter = btd_adapter_new(index);
+       if (!adapter) {
+               error("Unable to create new adapter for index %u", index);
+               return;
+       }
+
+       /*
+        * Protect against potential two executions of read controller info.
+        *
+        * In case the start of the daemon and the action of adding a new
+        * controller coincide this function might be called twice.
+        *
+        * To avoid the double execution of reading the controller info,
+        * add the adapter already to the list. If an adapter is already
+        * present, the second notification will cause a warning. If the
+        * command fails the adapter is removed from the list again.
+        */
+       adapter_list = g_list_append(adapter_list, adapter);
+
+       DBG("sending read info command for index %u", index);
+
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_INFO, index, 0, NULL,
+                                       read_info_complete, adapter, NULL) > 0)
+               return;
+
+       error("Failed to read controller info for index %u", index);
+
+       adapter_list = g_list_remove(adapter_list, adapter);
+
+       btd_adapter_unref(adapter);
+}
+
+static void index_removed(uint16_t index, uint16_t length, const void *param,
+                                                       void *user_data)
+{
+       struct btd_adapter *adapter;
+
+       DBG("index %u", index);
+
+       adapter = btd_adapter_lookup(index);
+       if (!adapter) {
+               warn("Ignoring index removal for a non-existent adapter");
+               return;
+       }
+
+       adapter_unregister(adapter);
+}
+
+static void read_index_list_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_index_list *rp = param;
+       uint16_t num;
+       int i;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read index list: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read index list response");
+               return;
+       }
+
+       num = btohs(rp->num_controllers);
+
+       DBG("Number of controllers: %d", num);
+
+       if (num * sizeof(uint16_t) + sizeof(*rp) != length) {
+               error("Incorrect packet size for index list response");
+               return;
+       }
+
+       for (i = 0; i < num; i++) {
+               uint16_t index;
+
+               index = btohs(rp->index[i]);
+
+               DBG("Found index %u", index);
+
+               /*
+                * Pretend to be index added event notification.
+                *
+                * It is safe to just trigger the procedure for index
+                * added notification. It does check against itself.
+                */
+               index_added(index, 0, NULL, NULL);
+       }
+}
+
+static void read_commands_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_commands *rp = param;
+       uint16_t num_commands, num_events;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read supported commands: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read commands response");
+               return;
+       }
+
+       num_commands = btohs(rp->num_commands);
+       num_events = btohs(rp->num_events);
+
+       DBG("Number of commands: %d", num_commands);
+       DBG("Number of events: %d", num_events);
+}
+
+static void read_version_complete(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       const struct mgmt_rp_read_version *rp = param;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               error("Failed to read version information: %s (0x%02x)",
+                                               mgmt_errstr(status), status);
+               return;
+       }
+
+       if (length < sizeof(*rp)) {
+               error("Wrong size of read version response");
+               return;
+       }
+
+       mgmt_version = rp->version;
+       mgmt_revision = btohs(rp->revision);
+
+       info("Bluetooth management interface %u.%u initialized",
+                                               mgmt_version, mgmt_revision);
+
+       if (mgmt_version < 1) {
+               error("Version 1.0 or later of management interface required");
+               abort();
+       }
+
+       DBG("sending read supported commands command");
+
+       /*
+        * It is irrelevant if this command succeeds or fails. In case of
+        * failure safe settings are assumed.
+        */
+       mgmt_send(mgmt_master, MGMT_OP_READ_COMMANDS,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_commands_complete, NULL, NULL);
+
+       mgmt_register(mgmt_master, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                               index_added, NULL, NULL);
+       mgmt_register(mgmt_master, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                               index_removed, NULL, NULL);
+
+       DBG("sending read index list command");
+
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_INDEX_LIST,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_index_list_complete, NULL, NULL) > 0)
+               return;
+
+       error("Failed to read controller index list");
+}
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       info("%s%s", prefix, str);
+}
+
+int adapter_init(void)
+{
+       dbus_conn = btd_get_dbus_connection();
+
+       mgmt_master = mgmt_new_default();
+       if (!mgmt_master) {
+               error("Failed to access management interface");
+               return -EIO;
+       }
+
+       if (getenv("MGMT_DEBUG"))
+               mgmt_set_debug(mgmt_master, mgmt_debug, "mgmt: ", NULL);
+
+       DBG("sending read version command");
+
+       if (mgmt_send(mgmt_master, MGMT_OP_READ_VERSION,
+                               MGMT_INDEX_NONE, 0, NULL,
+                               read_version_complete, NULL, NULL) > 0)
+               return 0;
+
+       error("Failed to read management version information");
+
+       return -EIO;
+}
+
+void adapter_cleanup(void)
+{
+       g_list_free(adapter_list);
+
+       while (adapters) {
+               struct btd_adapter *adapter = adapters->data;
+
+               adapter_remove(adapter);
+               adapters = g_slist_remove(adapters, adapter);
+               btd_adapter_unref(adapter);
+       }
+
+       /*
+        * In case there is another reference active, clear out
+        * registered handlers for index added and index removed.
+        *
+        * This is just an extra precaution to be safe, and in
+        * reality should not make a difference.
+        */
+       mgmt_unregister_index(mgmt_master, MGMT_INDEX_NONE);
+
+       /*
+        * In case there is another reference active, cancel
+        * all pending global commands.
+        *
+        * This is just an extra precaution to avoid callbacks
+        * that potentially then could leak memory or access
+        * an invalid structure.
+        */
+       mgmt_cancel_index(mgmt_master, MGMT_INDEX_NONE);
+
+       mgmt_unref(mgmt_master);
+       mgmt_master = NULL;
+
+       dbus_conn = NULL;
+}
+
+void adapter_shutdown(void)
 {
-       return adapter_ops->remove_remote_oob_data(adapter->dev_id, bdaddr);
+       GList *list;
+
+       DBG("");
+
+       powering_down = true;
+
+       for (list = g_list_first(adapter_list); list;
+                                               list = g_list_next(list)) {
+               struct btd_adapter *adapter = list->data;
+
+               if (!(adapter->current_settings & MGMT_SETTING_POWERED))
+                       continue;
+
+               set_mode(adapter, MGMT_OP_SET_POWERED, 0x00);
+
+               adapter_remaining++;
+       }
+
+       if (!adapter_remaining)
+               btd_exit();
 }
index b7ea62b..5d124e7 100644 (file)
 #include <bluetooth/hci_lib.h>
 #include <dbus/dbus.h>
 #include <glib.h>
-
-#define ADAPTER_INTERFACE      "org.bluez.Adapter"
-
-#define MODE_OFF               0x00
-#define MODE_CONNECTABLE       0x01
-#define MODE_DISCOVERABLE      0x02
-#define MODE_UNKNOWN           0xff
+#include <stdbool.h>
 
 #define MAX_NAME_LENGTH                248
 
 
 struct btd_adapter;
 
+struct btd_adapter *btd_adapter_get_default(void);
+bool btd_adapter_is_default(struct btd_adapter *adapter);
+uint16_t btd_adapter_get_index(struct btd_adapter *adapter);
+
+typedef void (*adapter_cb) (struct btd_adapter *adapter, gpointer user_data);
+
+typedef void (*oob_read_local_cb_t) (struct btd_adapter *adapter,
+                                       const uint8_t *hash,
+                                       const uint8_t *randomizer,
+                                       void *user_data);
+typedef void (*oob_bonding_cb_t) (struct btd_adapter *adapter,
+                                       const bdaddr_t *bdaddr, uint8_t status,
+                                       void *user_data);
+
+struct oob_handler {
+       oob_read_local_cb_t read_local_cb;
+       oob_bonding_cb_t bonding_cb;
+       bdaddr_t remote_addr;
+       void *user_data;
+};
+
 struct link_key_info {
        bdaddr_t bdaddr;
        unsigned char key[16];
@@ -61,80 +76,42 @@ struct smp_ltk_info {
        uint8_t val[16];
 };
 
-struct remote_dev_info {
-       bdaddr_t bdaddr;
-       uint8_t bdaddr_type;
-       int8_t rssi;
-       uint32_t class;
-       char *name;
-       char *alias;
-       dbus_bool_t legacy;
-       char **uuids;
-       size_t uuid_count;
-       GSList *services;
-       uint8_t flags;
-};
-
-void btd_adapter_start(struct btd_adapter *adapter);
+int adapter_init(void);
+void adapter_cleanup(void);
+void adapter_shutdown(void);
 
-int btd_adapter_stop(struct btd_adapter *adapter);
+struct btd_adapter *adapter_find(const bdaddr_t *sba);
+struct btd_adapter *adapter_find_by_id(int id);
+struct btd_adapter *adapter_get_default(void);
+void adapter_foreach(adapter_cb func, gpointer user_data);
 
-void btd_adapter_get_mode(struct btd_adapter *adapter, uint8_t *mode,
-                                               uint8_t *on_mode,
-                                               uint16_t *discoverable_timeout,
-                                               gboolean *pairable);
+bool btd_adapter_get_pairable(struct btd_adapter *adapter);
+bool btd_adapter_get_powered(struct btd_adapter *adapter);
+bool btd_adapter_get_connectable(struct btd_adapter *adapter);
 
-void btd_adapter_get_class(struct btd_adapter *adapter, uint8_t *major,
-                                                       uint8_t *minor);
+uint32_t btd_adapter_get_class(struct btd_adapter *adapter);
 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);
-
-struct btd_device *adapter_find_device(struct btd_adapter *adapter, const char *dest);
-
-void adapter_remove_device(DBusConnection *conn, struct btd_adapter *adapter,
-                                               struct btd_device *device,
-                                               gboolean remove_storage);
-
-struct btd_adapter *adapter_create(DBusConnection *conn, int id);
-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);
-void adapter_set_discovering(struct btd_adapter *adapter,
-                                               gboolean discovering);
-uint16_t adapter_get_dev_id(struct btd_adapter *adapter);
-const gchar *adapter_get_path(struct btd_adapter *adapter);
-void adapter_get_address(struct btd_adapter *adapter, bdaddr_t *bdaddr);
-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, 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);
-void adapter_mode_changed(struct btd_adapter *adapter, uint8_t scan_mode);
+struct btd_device *adapter_get_device(struct btd_adapter *adapter,
+                                       const bdaddr_t *addr,
+                                       uint8_t addr_type);
+sdp_list_t *btd_adapter_get_services(struct btd_adapter *adapter);
+
+struct btd_device *adapter_find_device(struct btd_adapter *adapter,
+                                                       const bdaddr_t *dst);
+
+const char *adapter_get_path(struct btd_adapter *adapter);
+const bdaddr_t *adapter_get_address(struct btd_adapter *adapter);
 int adapter_set_name(struct btd_adapter *adapter, const char *name);
-void adapter_name_changed(struct btd_adapter *adapter, const char *name);
-void adapter_service_insert(struct btd_adapter *adapter, void *rec);
-void adapter_service_remove(struct btd_adapter *adapter, void *rec);
-void btd_adapter_class_changed(struct btd_adapter *adapter,
-                                                       uint32_t new_class);
-void btd_adapter_pairable_changed(struct btd_adapter *adapter,
-                                                       gboolean pairable);
+
+int adapter_service_add(struct btd_adapter *adapter, sdp_record_t *rec);
+void adapter_service_remove(struct btd_adapter *adapter, uint32_t handle);
 
 struct agent *adapter_get_agent(struct btd_adapter *adapter);
-void adapter_add_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device);
-void adapter_remove_connection(struct btd_adapter *adapter,
-                                               struct btd_device *device);
-gboolean adapter_has_discov_sessions(struct btd_adapter *adapter);
 
 struct btd_adapter *btd_adapter_ref(struct btd_adapter *adapter);
 void btd_adapter_unref(struct btd_adapter *adapter);
 
-int btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
+void btd_adapter_set_class(struct btd_adapter *adapter, uint8_t major,
                                                        uint8_t minor);
 
 struct btd_adapter_driver {
@@ -145,93 +122,28 @@ struct btd_adapter_driver {
 
 typedef void (*service_auth_cb) (DBusError *derr, void *user_data);
 
+void adapter_add_profile(struct btd_adapter *adapter, gpointer p);
+void adapter_remove_profile(struct btd_adapter *adapter, gpointer p);
 int btd_register_adapter_driver(struct btd_adapter_driver *driver);
 void btd_unregister_adapter_driver(struct btd_adapter_driver *driver);
-int btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
+guint btd_request_authorization(const bdaddr_t *src, const bdaddr_t *dst,
                const char *uuid, service_auth_cb cb, void *user_data);
-int btd_cancel_authorization(const bdaddr_t *src, const bdaddr_t *dst);
-
-const char *adapter_any_get_path(void);
-
-const char *btd_adapter_any_request_path(void);
-void btd_adapter_any_release_path(void);
-gboolean adapter_powering_down(struct btd_adapter *adapter);
+int btd_cancel_authorization(guint id);
 
 int btd_adapter_restore_powered(struct btd_adapter *adapter);
-int btd_adapter_switch_online(struct btd_adapter *adapter);
-int btd_adapter_switch_offline(struct btd_adapter *adapter);
-void btd_adapter_enable_auto_connect(struct btd_adapter *adapter);
 
 typedef ssize_t (*btd_adapter_pin_cb_t) (struct btd_adapter *adapter,
-                       struct btd_device *dev, char *out, gboolean *display);
+                       struct btd_device *dev, char *out, bool *display,
+                                                       unsigned int attempt);
 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, gboolean *display);
-
-typedef void (*bt_hci_result_t) (uint8_t status, gpointer user_data);
-
-struct btd_adapter_ops {
-       int (*setup) (void);
-       void (*cleanup) (void);
-       int (*set_powered) (int index, gboolean powered);
-       int (*set_discoverable) (int index, gboolean discoverable,
-                                                       uint16_t timeout);
-       int (*set_pairable) (int index, gboolean pairable);
-       int (*start_discovery) (int index);
-       int (*stop_discovery) (int index);
-
-       int (*set_name) (int index, const char *name);
-       int (*set_dev_class) (int index, uint8_t major, uint8_t minor);
-       int (*set_fast_connectable) (int index, gboolean enable);
-       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, 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, 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, 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 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 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, 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);
-void btd_adapter_cleanup_ops(struct btd_adapter_ops *btd_adapter_ops);
-int adapter_ops_setup(void);
-
-typedef void (*btd_adapter_powered_cb) (struct btd_adapter *adapter,
-                                               gboolean powered);
-void btd_adapter_register_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb);
-void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
-                                               btd_adapter_powered_cb cb);
+struct btd_adapter_pin_cb_iter *btd_adapter_pin_cb_iter_new(
+                                               struct btd_adapter *adapter);
+void btd_adapter_pin_cb_iter_free(struct btd_adapter_pin_cb_iter *iter);
+bool btd_adapter_pin_cb_iter_end(struct btd_adapter_pin_cb_iter *iter);
 
 /* If TRUE, enables fast connectabe, i.e. reduces page scan interval and changes
  * type. If FALSE, disables fast connectable, i.e. sets page scan interval and
@@ -239,50 +151,66 @@ void btd_adapter_unregister_powered_callback(struct btd_adapter *adapter,
 int btd_adapter_set_fast_connectable(struct btd_adapter *adapter,
                                                        gboolean enable);
 
-int btd_adapter_read_clock(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+int btd_adapter_read_clock(struct btd_adapter *adapter, const 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,
-                                                       uint8_t bdaddr_type);
-int btd_adapter_unblock_address(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint8_t bdaddr_type);
+int btd_adapter_block_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type);
+int btd_adapter_unblock_address(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type);
 
 int btd_adapter_disconnect_device(struct btd_adapter *adapter,
-                                       bdaddr_t *bdaddr, uint8_t bdaddr_type);
-
-int btd_adapter_remove_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
+                                                       const 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,
-                                       uint8_t bdaddr_type, gboolean success);
-int btd_adapter_passkey_reply(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                       uint8_t bdaddr_type, uint32_t passkey);
+int btd_adapter_remove_bonding(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type);
 
-int btd_adapter_encrypt_link(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               bt_hci_result_t cb, gpointer user_data);
+int btd_adapter_pincode_reply(struct btd_adapter *adapter,
+                                       const  bdaddr_t *bdaddr,
+                                       const char *pin, size_t pin_len);
+int btd_adapter_confirm_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               gboolean success);
+int btd_adapter_passkey_reply(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type,
+                               uint32_t passkey);
 
-int btd_adapter_set_did(struct btd_adapter *adapter, uint16_t vendor,
-                                       uint16_t product, uint16_t version,
-                                       uint16_t source);
+int adapter_create_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap);
 
-int adapter_create_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                               uint8_t bdaddr_type, uint8_t io_cap);
+int adapter_bonding_attempt(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                       uint8_t addr_type, uint8_t io_cap);
 
-int adapter_cancel_bonding(struct btd_adapter *adapter, bdaddr_t *bdaddr);
+int adapter_cancel_bonding(struct btd_adapter *adapter, const bdaddr_t *bdaddr,
+                                                       uint8_t addr_type);
 
-void adapter_bonding_complete(struct btd_adapter *adapter, bdaddr_t *bdaddr,
-                                                       uint8_t status);
+int adapter_set_io_capability(struct btd_adapter *adapter, uint8_t io_cap);
 
 int btd_adapter_read_local_oob_data(struct btd_adapter *adapter);
 
 int btd_adapter_add_remote_oob_data(struct btd_adapter *adapter,
-                       bdaddr_t *bdaddr, uint8_t *hash, uint8_t *randomizer);
+                                       const bdaddr_t *bdaddr,
+                                       uint8_t *hash, uint8_t *randomizer);
 
 int btd_adapter_remove_remote_oob_data(struct btd_adapter *adapter,
-                                                       bdaddr_t *bdaddr);
+                                                       const bdaddr_t *bdaddr);
 
 int btd_adapter_gatt_server_start(struct btd_adapter *adapter);
 void btd_adapter_gatt_server_stop(struct btd_adapter *adapter);
+
+bool btd_adapter_ssp_enabled(struct btd_adapter *adapter);
+
+int adapter_connect_list_add(struct btd_adapter *adapter,
+                                       struct btd_device *device);
+void adapter_connect_list_remove(struct btd_adapter *adapter,
+                                               struct btd_device *device);
+
+void btd_adapter_set_oob_handler(struct btd_adapter *adapter,
+                                               struct oob_handler *handler);
+gboolean btd_adapter_check_oob_handler(struct btd_adapter *adapter);
+
+void btd_adapter_for_each_device(struct btd_adapter *adapter,
+                       void (*cb)(struct btd_device *device, void *data),
+                       void *data);
index e542425..7880ba6 100644 (file)
@@ -29,6 +29,7 @@
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
+#include <stdbool.h>
 #include <sys/socket.h>
 #include <sys/ioctl.h>
 
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
-
+#include "error.h"
+#include "dbus-common.h"
 #include "adapter.h"
 #include "device.h"
 #include "agent.h"
 
+#define IO_CAPABILITY_DISPLAYONLY      0x00
+#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 REQUEST_TIMEOUT (60 * 1000)            /* 60 seconds */
+#define AGENT_INTERFACE "org.bluez.Agent1"
+
+static GHashTable *agent_list;
+static struct agent *default_agent = NULL;
 
 typedef enum {
        AGENT_REQUEST_PASSKEY,
        AGENT_REQUEST_CONFIRMATION,
+       AGENT_REQUEST_AUTHORIZATION,
        AGENT_REQUEST_PINCODE,
-       AGENT_REQUEST_AUTHORIZE,
+       AGENT_REQUEST_AUTHORIZE_SERVICE,
        AGENT_REQUEST_CONFIRM_MODE,
        AGENT_REQUEST_DISPLAY_PINCODE,
 } agent_request_type_t;
 
 struct agent {
-       struct btd_adapter *adapter;
-       char *name;
+       int ref;
+       char *owner;
        char *path;
        uint8_t capability;
        struct agent_request *request;
-       int exited;
-       agent_remove_cb remove_cb;
-       void *remove_cb_data;
-       guint listener_id;
+       guint watch;
 };
 
 struct agent_request {
@@ -78,42 +89,40 @@ struct agent_request {
        GDestroyNotify destroy;
 };
 
-static DBusConnection *connection = NULL;
-
 static void agent_release(struct agent *agent)
 {
        DBusMessage *message;
 
-       DBG("Releasing agent %s, %s", agent->name, agent->path);
+       DBG("Releasing agent %s, %s", agent->owner, agent->path);
 
        if (agent->request)
                agent_cancel(agent);
 
-       message = dbus_message_new_method_call(agent->name, agent->path,
-                       "org.bluez.Agent", "Release");
+       message = dbus_message_new_method_call(agent->owner, agent->path,
+                                               AGENT_INTERFACE, "Release");
        if (message == NULL) {
                error("Couldn't allocate D-Bus message");
                return;
        }
 
-       g_dbus_send_message(connection, message);
+       g_dbus_send_message(btd_get_dbus_connection(), message);
 }
 
 static int send_cancel_request(struct agent_request *req)
 {
        DBusMessage *message;
 
-       DBG("Sending Cancel request to %s, %s", req->agent->name,
+       DBG("Sending Cancel request to %s, %s", req->agent->owner,
                                                        req->agent->path);
 
-       message = dbus_message_new_method_call(req->agent->name, req->agent->path,
-                                               "org.bluez.Agent", "Cancel");
+       message = dbus_message_new_method_call(req->agent->owner, req->agent->path,
+                                               AGENT_INTERFACE, "Cancel");
        if (message == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
        }
 
-       g_dbus_send_message(connection, message);
+       g_dbus_send_message(btd_get_dbus_connection(), message);
 
        return 0;
 }
@@ -131,24 +140,68 @@ static void agent_request_free(struct agent_request *req, gboolean destroy)
        g_free(req);
 }
 
-static void agent_exited(DBusConnection *conn, void *user_data)
+static void set_io_cap(struct btd_adapter *adapter, gpointer user_data)
 {
        struct agent *agent = user_data;
+       uint8_t io_cap;
 
-       DBG("Agent exited without calling Unregister");
-
-       agent->exited = TRUE;
+       if (agent)
+               io_cap = agent->capability;
+       else
+               io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
 
-       agent_free(agent);
+       adapter_set_io_capability(adapter, io_cap);
 }
 
-void agent_free(struct agent *agent)
+static void set_default_agent(struct agent *agent)
 {
-       if (!agent)
+       if (default_agent == agent)
                return;
 
-       if (agent->remove_cb)
-               agent->remove_cb(agent, agent->remove_cb_data);
+       if (agent)
+               DBG("Default agent set to %s %s", agent->owner, agent->path);
+       else
+               DBG("Default agent cleared");
+
+       default_agent = agent;
+
+       adapter_foreach(set_io_cap, agent);
+}
+
+static void agent_disconnect(DBusConnection *conn, void *user_data)
+{
+       struct agent *agent = user_data;
+
+       DBG("Agent %s disconnected", agent->owner);
+
+       if (agent->watch > 0) {
+               g_dbus_remove_watch(conn, agent->watch);
+               agent->watch = 0;
+       }
+
+       if (agent == default_agent)
+               set_default_agent(NULL);
+
+       g_hash_table_remove(agent_list, agent->owner);
+}
+
+struct agent *agent_ref(struct agent *agent)
+{
+       agent->ref++;
+
+       DBG("%p: ref=%d", agent, agent->ref);
+
+       return agent;
+}
+
+void agent_unref(struct agent *agent)
+{
+       agent->ref--;
+
+       DBG("%p: ref=%d", agent, agent->ref);
+
+       if (agent->ref > 0)
+               return;
 
        if (agent->request) {
                DBusError err;
@@ -157,7 +210,8 @@ void agent_free(struct agent *agent)
                agent_cb cb;
 
                dbus_error_init(&err);
-               dbus_set_error_const(&err, "org.bluez.Error.Failed", "Canceled");
+               dbus_set_error_const(&err, ERROR_INTERFACE ".Failed",
+                                                               "Canceled");
 
                switch (agent->request->type) {
                case AGENT_REQUEST_PINCODE:
@@ -178,37 +232,44 @@ void agent_free(struct agent *agent)
                agent_cancel(agent);
        }
 
-       if (!agent->exited) {
-               g_dbus_remove_watch(connection, agent->listener_id);
-               agent_release(agent);
-       }
-
-       g_free(agent->name);
+       g_free(agent->owner);
        g_free(agent->path);
 
        g_free(agent);
 }
 
-struct agent *agent_create(struct btd_adapter *adapter, const char *name,
-                               const char *path, uint8_t capability,
-                               agent_remove_cb cb, void *remove_cb_data)
+struct agent *agent_get(const char *owner)
+{
+       struct agent *agent;
+
+       if (owner) {
+               agent = g_hash_table_lookup(agent_list, owner);
+               if (agent)
+                       return agent_ref(agent);
+       }
+
+       if (default_agent)
+               return agent_ref(default_agent);
+
+       return NULL;
+}
+
+static struct agent *agent_create( const char *name, const char *path,
+                                                       uint8_t capability)
 {
        struct agent *agent;
 
        agent = g_new0(struct agent, 1);
 
-       agent->adapter = adapter;
-       agent->name = g_strdup(name);
+       agent->owner = g_strdup(name);
        agent->path = g_strdup(path);
        agent->capability = capability;
-       agent->remove_cb = cb;
-       agent->remove_cb_data = remove_cb_data;
 
-       agent->listener_id = g_dbus_add_disconnect_watch(connection, name,
-                                                       agent_exited, agent,
-                                                       NULL);
+       agent->watch = g_dbus_add_disconnect_watch(btd_get_dbus_connection(),
+                                                       name, agent_disconnect,
+                                                       agent, NULL);
 
-       return agent;
+       return agent_ref(agent);
 }
 
 static struct agent_request *agent_request_new(struct agent *agent,
@@ -235,11 +296,10 @@ int agent_cancel(struct agent *agent)
        if (!agent->request)
                return -EINVAL;
 
-       if (agent->request->call)
+       if (agent->request->call) {
                dbus_pending_call_cancel(agent->request->call);
-
-       if (!agent->exited)
                send_cancel_request(agent->request);
+       }
 
        agent_request_free(agent->request, TRUE);
        agent->request = NULL;
@@ -261,12 +321,12 @@ static void simple_agent_reply(DBusPendingCall *call, void *user_data)
 
        dbus_error_init(&err);
        if (dbus_set_error_from_message(&err, message)) {
-               error("Agent replied with an error: %s, %s",
-                               err.name, err.message);
+               DBG("agent error reply: %s, %s", err.name, err.message);
 
                cb(agent, &err, req->user_data);
 
                if (dbus_error_has_name(&err, DBUS_ERROR_NO_REPLY)) {
+                       error("Timed out waiting for reply from agent");
                        agent_cancel(agent);
                        dbus_message_unref(message);
                        dbus_error_free(&err);
@@ -292,14 +352,14 @@ done:
        agent_request_free(req, TRUE);
 }
 
-static int agent_call_authorize(struct agent_request *req,
-                               const char *device_path,
-                               const char *uuid)
+static int agent_call_authorize_service(struct agent_request *req,
+                                               const char *device_path,
+                                               const char *uuid)
 {
        struct agent *agent = req->agent;
 
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                               "org.bluez.Agent", "Authorize");
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                                       AGENT_INTERFACE, "AuthorizeService");
        if (!req->msg) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
@@ -310,8 +370,9 @@ static int agent_call_authorize(struct agent_request *req,
                                DBUS_TYPE_STRING, &uuid,
                                DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(connection, req->msg,
-                                       &req->call, REQUEST_TIMEOUT) == FALSE) {
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(),
+                                               req->msg, &req->call,
+                                               REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                return -EIO;
        }
@@ -320,12 +381,9 @@ static int agent_call_authorize(struct agent_request *req,
        return 0;
 }
 
-int agent_authorize(struct agent *agent,
-                       const char *path,
-                       const char *uuid,
-                       agent_cb cb,
-                       void *user_data,
-                       GDestroyNotify destroy)
+int agent_authorize_service(struct agent *agent, const char *path,
+                               const char *uuid, agent_cb cb,
+                               void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
        int err;
@@ -333,10 +391,10 @@ int agent_authorize(struct agent *agent,
        if (agent->request)
                return -EBUSY;
 
-       req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE, cb,
+       req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZE_SERVICE, cb,
                                                        user_data, destroy);
 
-       err = agent_call_authorize(req, path, uuid);
+       err = agent_call_authorize_service(req, path, uuid);
        if (err < 0) {
                agent_request_free(req, FALSE);
                return -ENOMEM;
@@ -344,7 +402,7 @@ int agent_authorize(struct agent *agent,
 
        agent->request = req;
 
-       DBG("authorize request was sent for %s", path);
+       DBG("authorize service request was sent for %s", path);
 
        return 0;
 }
@@ -353,16 +411,12 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)
 {
        struct agent_request *req = user_data;
        struct agent *agent = req->agent;
-       struct btd_adapter *adapter = agent->adapter;
        agent_pincode_cb cb = req->cb;
        DBusMessage *message;
        DBusError err;
-       bdaddr_t sba;
        size_t len;
        char *pin;
 
-       adapter_get_address(adapter, &sba);
-
        /* 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);
@@ -390,7 +444,7 @@ static void pincode_reply(DBusPendingCall *call, void *user_data)
 
        if (len > 16 || len < 1) {
                error("Invalid PIN length (%zu) from agent", len);
-               dbus_set_error_const(&err, "org.bluez.Error.InvalidArgs",
+               dbus_set_error_const(&err, ERROR_INTERFACE ".InvalidArgs",
                                        "Invalid passkey length");
                cb(agent, &err, NULL, req->user_data);
                dbus_error_free(&err);
@@ -416,8 +470,8 @@ static int pincode_request_new(struct agent_request *req, const char *device_pat
        /* TODO: Add a new method or a new param to Agent interface to request
                secure pin. */
 
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                                       "org.bluez.Agent", "RequestPinCode");
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                                       AGENT_INTERFACE, "RequestPinCode");
        if (req->msg == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
@@ -426,7 +480,7 @@ static int pincode_request_new(struct agent_request *req, const char *device_pat
        dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
                                        DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(connection, req->msg,
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
                                        &req->call, REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                return -EIO;
@@ -441,7 +495,7 @@ int agent_request_pincode(struct agent *agent, struct btd_device *device,
                                void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
-       const gchar *dev_path = device_get_path(device);
+       const char *dev_path = device_get_path(device);
        int err;
 
        if (agent->request)
@@ -463,61 +517,6 @@ failed:
        return err;
 }
 
-static int confirm_mode_change_request_new(struct agent_request *req,
-                                               const char *mode)
-{
-       struct agent *agent = req->agent;
-
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                               "org.bluez.Agent", "ConfirmModeChange");
-       if (req->msg == NULL) {
-               error("Couldn't allocate D-Bus message");
-               return -ENOMEM;
-       }
-
-       dbus_message_append_args(req->msg,
-                               DBUS_TYPE_STRING, &mode,
-                               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, simple_agent_reply, req, NULL);
-       return 0;
-}
-
-int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
-                               agent_cb cb, void *user_data,
-                               GDestroyNotify destroy)
-{
-       struct agent_request *req;
-       int err;
-
-       if (agent->request)
-               return -EBUSY;
-
-       DBG("Calling Agent.ConfirmModeChange: name=%s, path=%s, mode=%s",
-                       agent->name, agent->path, new_mode);
-
-       req = agent_request_new(agent, AGENT_REQUEST_CONFIRM_MODE,
-                               cb, user_data, destroy);
-
-       err = confirm_mode_change_request_new(req, new_mode);
-       if (err < 0)
-               goto failed;
-
-       agent->request = req;
-
-       return 0;
-
-failed:
-       agent_request_free(req, FALSE);
-       return err;
-}
-
 static void passkey_reply(DBusPendingCall *call, void *user_data)
 {
        struct agent_request *req = user_data;
@@ -565,8 +564,8 @@ static int passkey_request_new(struct agent_request *req,
 {
        struct agent *agent = req->agent;
 
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                                       "org.bluez.Agent", "RequestPasskey");
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                                       AGENT_INTERFACE, "RequestPasskey");
        if (req->msg == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
@@ -575,7 +574,7 @@ static int passkey_request_new(struct agent_request *req,
        dbus_message_append_args(req->msg, DBUS_TYPE_OBJECT_PATH, &device_path,
                                        DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(connection, req->msg,
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
                                        &req->call, REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                return -EIO;
@@ -590,14 +589,14 @@ int agent_request_passkey(struct agent *agent, struct btd_device *device,
                                GDestroyNotify destroy)
 {
        struct agent_request *req;
-       const gchar *dev_path = device_get_path(device);
+       const char *dev_path = device_get_path(device);
        int err;
 
        if (agent->request)
                return -EBUSY;
 
        DBG("Calling Agent.RequestPasskey: name=%s, path=%s",
-                       agent->name, agent->path);
+                       agent->owner, agent->path);
 
        req = agent_request_new(agent, AGENT_REQUEST_PASSKEY, cb,
                                                        user_data, destroy);
@@ -621,8 +620,8 @@ static int confirmation_request_new(struct agent_request *req,
 {
        struct agent *agent = req->agent;
 
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                               "org.bluez.Agent", "RequestConfirmation");
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                               AGENT_INTERFACE, "RequestConfirmation");
        if (req->msg == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
@@ -633,7 +632,7 @@ static int confirmation_request_new(struct agent_request *req,
                                DBUS_TYPE_UINT32, &passkey,
                                DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(connection, req->msg,
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
                                &req->call, REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                return -EIO;
@@ -649,14 +648,14 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,
                                void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
-       const gchar *dev_path = device_get_path(device);
+       const char *dev_path = device_get_path(device);
        int err;
 
        if (agent->request)
                return -EBUSY;
 
        DBG("Calling Agent.RequestConfirmation: name=%s, path=%s, passkey=%06u",
-                       agent->name, agent->path, passkey);
+                       agent->owner, agent->path, passkey);
 
        req = agent_request_new(agent, AGENT_REQUEST_CONFIRMATION, cb,
                                user_data, destroy);
@@ -674,14 +673,71 @@ failed:
        return err;
 }
 
+static int authorization_request_new(struct agent_request *req,
+                                               const char *device_path)
+{
+       struct agent *agent = req->agent;
+
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                               AGENT_INTERFACE, "RequestAuthorization");
+       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_INVALID);
+
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
+                               &req->call, REQUEST_TIMEOUT) == FALSE) {
+               error("D-Bus send failed");
+               return -EIO;
+       }
+
+       dbus_pending_call_set_notify(req->call, simple_agent_reply, req, NULL);
+
+       return 0;
+}
+
+int agent_request_authorization(struct agent *agent, struct btd_device *device,
+                                               agent_cb cb, void *user_data,
+                                               GDestroyNotify destroy)
+{
+       struct agent_request *req;
+       const char *dev_path = device_get_path(device);
+       int err;
+
+       if (agent->request)
+               return -EBUSY;
+
+       DBG("Calling Agent.RequestAuthorization: name=%s, path=%s",
+                                               agent->owner, agent->path);
+
+       req = agent_request_new(agent, AGENT_REQUEST_AUTHORIZATION, cb,
+                               user_data, destroy);
+
+       err = authorization_request_new(req, dev_path);
+       if (err < 0)
+               goto failed;
+
+       agent->request = req;
+
+       return 0;
+
+failed:
+       agent_request_free(req, FALSE);
+       return err;
+}
+
 int agent_display_passkey(struct agent *agent, struct btd_device *device,
-                               uint32_t passkey)
+                               uint32_t passkey, uint16_t entered)
 {
        DBusMessage *message;
-       const gchar *dev_path = device_get_path(device);
+       const char *dev_path = device_get_path(device);
 
-       message = dbus_message_new_method_call(agent->name, agent->path,
-                               "org.bluez.Agent", "DisplayPasskey");
+       message = dbus_message_new_method_call(agent->owner, agent->path,
+                                       AGENT_INTERFACE, "DisplayPasskey");
        if (!message) {
                error("Couldn't allocate D-Bus message");
                return -1;
@@ -690,9 +746,10 @@ int agent_display_passkey(struct agent *agent, struct btd_device *device,
        dbus_message_append_args(message,
                                DBUS_TYPE_OBJECT_PATH, &dev_path,
                                DBUS_TYPE_UINT32, &passkey,
+                               DBUS_TYPE_UINT16, &entered,
                                DBUS_TYPE_INVALID);
 
-       if (!g_dbus_send_message(connection, message)) {
+       if (!g_dbus_send_message(btd_get_dbus_connection(), message)) {
                error("D-Bus send failed");
                return -1;
        }
@@ -754,8 +811,8 @@ static int display_pincode_request_new(struct agent_request *req,
 {
        struct agent *agent = req->agent;
 
-       req->msg = dbus_message_new_method_call(agent->name, agent->path,
-                                       "org.bluez.Agent", "DisplayPinCode");
+       req->msg = dbus_message_new_method_call(agent->owner, agent->path,
+                                       AGENT_INTERFACE, "DisplayPinCode");
        if (req->msg == NULL) {
                error("Couldn't allocate D-Bus message");
                return -ENOMEM;
@@ -766,7 +823,7 @@ static int display_pincode_request_new(struct agent_request *req,
                                        DBUS_TYPE_STRING, &pincode,
                                        DBUS_TYPE_INVALID);
 
-       if (dbus_connection_send_with_reply(connection, req->msg,
+       if (g_dbus_send_message_with_reply(btd_get_dbus_connection(), req->msg,
                                &req->call, REQUEST_TIMEOUT) == FALSE) {
                error("D-Bus send failed");
                return -EIO;
@@ -783,14 +840,14 @@ int agent_display_pincode(struct agent *agent, struct btd_device *device,
                                void *user_data, GDestroyNotify destroy)
 {
        struct agent_request *req;
-       const gchar *dev_path = device_get_path(device);
+       const char *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);
+                                       agent->owner, agent->path, pincode);
 
        req = agent_request_new(agent, AGENT_REQUEST_DISPLAY_PINCODE, cb,
                                                        user_data, destroy);
@@ -813,32 +870,147 @@ uint8_t agent_get_io_capability(struct agent *agent)
        return agent->capability;
 }
 
-gboolean agent_matches(struct agent *agent, const char *name, const char *path)
+static void agent_destroy(gpointer data)
 {
-       if (g_str_equal(agent->name, name) && g_str_equal(agent->path, path))
-               return TRUE;
+       struct agent *agent = data;
+
+       DBG("agent %s", agent->owner);
+
+       if (agent->watch > 0) {
+               g_dbus_remove_watch(btd_get_dbus_connection(), agent->watch);
+               agent->watch = 0;
+               agent_release(agent);
+       }
 
-       return FALSE;
+       agent_unref(agent);
 }
 
-gboolean agent_is_busy(struct agent *agent, void *user_data)
+static uint8_t parse_io_capability(const char *capability)
 {
-       if (!agent->request)
-               return FALSE;
+       if (g_str_equal(capability, ""))
+               return IO_CAPABILITY_DISPLAYYESNO;
+       if (g_str_equal(capability, "DisplayOnly"))
+               return IO_CAPABILITY_DISPLAYONLY;
+       if (g_str_equal(capability, "DisplayYesNo"))
+               return IO_CAPABILITY_DISPLAYYESNO;
+       if (g_str_equal(capability, "KeyboardOnly"))
+               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;
+}
+
+static DBusMessage *register_agent(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct agent *agent;
+       const char *sender, *path, *capability;
+       uint8_t cap;
+
+       sender = dbus_message_get_sender(msg);
+
+       agent = g_hash_table_lookup(agent_list, sender);
+       if (agent)
+               return btd_error_already_exists(msg);
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_STRING, &capability,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       cap = parse_io_capability(capability);
+       if (cap == IO_CAPABILITY_INVALID)
+               return btd_error_invalid_args(msg);
+
+       agent = agent_create(sender, path, cap);
+       if (!agent)
+               return btd_error_invalid_args(msg);
+
+       DBG("agent %s", agent->owner);
+
+       g_hash_table_replace(agent_list, agent->owner, agent);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_agent(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       struct agent *agent;
+       const char *sender, *path;
+
+       sender = dbus_message_get_sender(msg);
+
+       agent = g_hash_table_lookup(agent_list, sender);
+       if (!agent)
+               return btd_error_does_not_exist(msg);
+
+       DBG("agent %s", agent->owner);
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
+
+       if (g_str_equal(path, agent->path) == FALSE)
+               return btd_error_does_not_exist(msg);
+
+       agent_disconnect(conn, agent);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *request_default(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct agent *agent;
+       const char *sender, *path;
+
+       sender = dbus_message_get_sender(msg);
+
+       agent = g_hash_table_lookup(agent_list, sender);
+       if (!agent)
+               return btd_error_does_not_exist(msg);
+
+       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                               DBUS_TYPE_INVALID) == FALSE)
+               return btd_error_invalid_args(msg);
 
-       if (user_data && user_data != agent->request->user_data)
-               return FALSE;
+       if (g_str_equal(path, agent->path) == FALSE)
+               return btd_error_does_not_exist(msg);
 
-       return TRUE;
+       set_default_agent(agent);
+
+       return dbus_message_new_method_return(msg);
 }
 
-void agent_exit(void)
+static const GDBusMethodTable methods[] = {
+       { GDBUS_METHOD("RegisterAgent",
+                       GDBUS_ARGS({ "agent", "o"}, { "capability", "s" }),
+                       NULL, register_agent) },
+       { GDBUS_METHOD("UnregisterAgent", GDBUS_ARGS({ "agent", "o" }),
+                       NULL, unregister_agent) },
+       { GDBUS_METHOD("RequestDefaultAgent", GDBUS_ARGS({ "agent", "o" }),
+                       NULL, request_default ) },
+       { }
+};
+
+void btd_agent_init(void)
 {
-       dbus_connection_unref(connection);
-       connection = NULL;
+       agent_list = g_hash_table_new_full(g_str_hash, g_str_equal,
+                                               NULL, agent_destroy);
+
+       g_dbus_register_interface(btd_get_dbus_connection(),
+                               "/org/bluez", "org.bluez.AgentManager1",
+                               methods, NULL, NULL, NULL, NULL);
 }
 
-void agent_init(void)
+void btd_agent_cleanup(void)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                               "/org/bluez", "org.bluez.AgentManager1");
+
+       set_default_agent(NULL);
+       g_hash_table_destroy(agent_list);
 }
index 320b92d..1e46920 100644 (file)
@@ -33,26 +33,19 @@ typedef void (*agent_pincode_cb) (struct agent *agent, DBusError *err,
 typedef void (*agent_passkey_cb) (struct agent *agent, DBusError *err,
                                        uint32_t passkey, void *user_data);
 
-typedef void (*agent_remove_cb) (struct agent *agent, void *user_data);
+struct agent *agent_ref(struct agent *agent);
+void agent_unref(struct agent *agent);
 
-struct agent *agent_create(struct btd_adapter *adapter, const char *name,
-                               const char *path, uint8_t capability,
-                               agent_remove_cb cb, void *remove_cb_data);
+struct agent *agent_get(const char *owner);
 
-void agent_free(struct agent *agent);
-
-int agent_authorize(struct agent *agent, const char *path,
-                       const char *uuid, agent_cb cb, void *user_data,
-                       GDestroyNotify destroy);
+int agent_authorize_service(struct agent *agent, const char *path,
+                               const char *uuid, agent_cb cb,
+                               void *user_data, GDestroyNotify destroy);
 
 int agent_request_pincode(struct agent *agent, struct btd_device *device,
                                agent_pincode_cb cb, gboolean secure,
                                void *user_data, GDestroyNotify destroy);
 
-int agent_confirm_mode_change(struct agent *agent, const char *new_mode,
-                               agent_cb cb, void *user_data,
-                               GDestroyNotify destroy);
-
 int agent_request_passkey(struct agent *agent, struct btd_device *device,
                                agent_passkey_cb cb, void *user_data,
                                GDestroyNotify destroy);
@@ -61,8 +54,12 @@ int agent_request_confirmation(struct agent *agent, struct btd_device *device,
                                uint32_t passkey, agent_cb cb,
                                void *user_data, GDestroyNotify destroy);
 
+int agent_request_authorization(struct agent *agent, struct btd_device *device,
+                                               agent_cb cb, void *user_data,
+                                               GDestroyNotify destroy);
+
 int agent_display_passkey(struct agent *agent, struct btd_device *device,
-                               uint32_t passkey);
+                               uint32_t passkey, uint16_t entered);
 
 int agent_display_pincode(struct agent *agent, struct btd_device *device,
                                const char *pincode, agent_cb cb,
@@ -70,11 +67,7 @@ int agent_display_pincode(struct agent *agent, struct btd_device *device,
 
 int agent_cancel(struct agent *agent);
 
-gboolean agent_is_busy(struct agent *agent, void *user_data);
-
 uint8_t agent_get_io_capability(struct agent *agent);
 
-gboolean agent_matches(struct agent *agent, const char *name, const char *path);
-
-void agent_init(void);
-void agent_exit(void);
+void btd_agent_init(void);
+void btd_agent_cleanup(void);
index 5adbf92..2861a00 100644 (file)
 
 #include <errno.h>
 #include <stdint.h>
+#include <stdbool.h>
 #include <string.h>
 #include <unistd.h>
 #include <glib.h>
+#include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
+#include "lib/uuid.h"
+#include <gdbus/gdbus.h>
 #include "log.h"
-#include "gdbus.h"
-#include "btio.h"
+#include <btio/btio.h>
 #include "sdpd.h"
 #include "hcid.h"
 #include "adapter.h"
 #include "device.h"
-#include "manager.h"
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
+#include "attrib/gattrib.h"
+#include "attrib/att.h"
+#include "attrib/gatt.h"
+#include "attrib/att-database.h"
 #include "storage.h"
 
 #include "attrib-server.h"
@@ -126,22 +127,23 @@ static void gatt_server_free(struct gatt_server *server)
        g_list_free_full(server->database, attrib_free);
 
        if (server->l2cap_io != NULL) {
-               g_io_channel_unref(server->l2cap_io);
                g_io_channel_shutdown(server->l2cap_io, FALSE, NULL);
+               g_io_channel_unref(server->l2cap_io);
        }
 
        if (server->le_io != NULL) {
-               g_io_channel_unref(server->le_io);
                g_io_channel_shutdown(server->le_io, FALSE, NULL);
+               g_io_channel_unref(server->le_io);
        }
 
        g_slist_free_full(server->clients, (GDestroyNotify) channel_free);
 
        if (server->gatt_sdp_handle > 0)
-               remove_record_from_server(server->gatt_sdp_handle);
+               adapter_service_remove(server->adapter,
+                                       server->gatt_sdp_handle);
 
        if (server->gap_sdp_handle > 0)
-               remove_record_from_server(server->gap_sdp_handle);
+               adapter_service_remove(server->adapter, server->gap_sdp_handle);
 
        if (server->adapter != NULL)
                btd_adapter_unref(server->adapter);
@@ -149,18 +151,15 @@ static void gatt_server_free(struct gatt_server *server)
        g_free(server);
 }
 
-static gint adapter_cmp_addr(gconstpointer a, gconstpointer b)
+static int adapter_cmp_addr(gconstpointer a, gconstpointer b)
 {
        const struct gatt_server *server = a;
        const bdaddr_t *bdaddr = b;
-       bdaddr_t src;
-
-       adapter_get_address(server->adapter, &src);
 
-       return bacmp(&src, bdaddr);
+       return bacmp(adapter_get_address(server->adapter), bdaddr);
 }
 
-static gint adapter_cmp(gconstpointer a, gconstpointer b)
+static int adapter_cmp(gconstpointer a, gconstpointer b)
 {
        const struct gatt_server *server = a;
        const struct btd_adapter *adapter = b;
@@ -301,7 +300,6 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
        struct attribute *a;
        uint16_t end = 0;
        uuid_t svc, gap_uuid;
-       bdaddr_t addr;
 
        a = find_svc_range(server, handle, &end);
 
@@ -329,8 +327,7 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
                                "http://www.bluez.org/");
        }
 
-       adapter_get_address(server->adapter, &addr);
-       if (add_record_to_server(&addr, record) == 0)
+       if (adapter_service_add(server->adapter, record) == 0)
                return record->handle;
 
        sdp_record_free(record);
@@ -338,8 +335,9 @@ static uint32_t attrib_create_sdp_new(struct gatt_server *server,
 }
 
 static struct attribute *attrib_db_add_new(struct gatt_server *server,
-                               uint16_t handle, bt_uuid_t *uuid, int read_reqs,
-                               int write_reqs, const uint8_t *value, int len)
+                               uint16_t handle, bt_uuid_t *uuid,
+                               int read_req, int write_req,
+                               const uint8_t *value, size_t len)
 {
        struct attribute *a;
        guint h = handle;
@@ -355,8 +353,8 @@ static struct attribute *attrib_db_add_new(struct gatt_server *server,
        a->data = g_memdup(value, len);
        a->handle = handle;
        a->uuid = *uuid;
-       a->read_reqs = read_reqs;
-       a->write_reqs = write_reqs;
+       a->read_req = read_req;
+       a->write_req = write_req;
 
        server->database = g_list_insert_sorted(server->database, a,
                                                                attribute_cmp);
@@ -400,7 +398,7 @@ static uint8_t att_check_reqs(struct gatt_channel *channel, uint8_t opcode,
 
 static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                                                uint16_t end, bt_uuid_t *uuid,
-                                               uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        struct att_data_list *adl;
        struct attribute *a;
@@ -455,7 +453,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
                        break;
 
                status = att_check_reqs(channel, ATT_OP_READ_BY_GROUP_REQ,
-                                                               a->read_reqs);
+                                                               a->read_req);
 
                if (status == 0x00 && a->read_cb)
                        status = a->read_cb(a, channel->device,
@@ -492,6 +490,11 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
        length = g_slist_length(groups);
 
        adl = att_data_list_alloc(length, last_size + 4);
+       if (adl == NULL) {
+               g_slist_free_full(groups, g_free);
+               return enc_error_resp(ATT_OP_READ_BY_GROUP_REQ, start,
+                                       ATT_ECODE_UNLIKELY, pdu, len);
+       }
 
        for (i = 0, l = groups; l; l = l->next, i++) {
                uint8_t *value;
@@ -516,7 +519,7 @@ static uint16_t read_by_group(struct gatt_channel *channel, uint16_t start,
 
 static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                                                uint16_t end, bt_uuid_t *uuid,
-                                               uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        struct att_data_list *adl;
        GSList *l, *types;
@@ -545,7 +548,7 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
                        continue;
 
                status = att_check_reqs(channel, ATT_OP_READ_BY_TYPE_REQ,
-                                                               a->read_reqs);
+                                                               a->read_req);
 
                if (status == 0x00 && a->read_cb)
                        status = a->read_cb(a, channel->device,
@@ -576,6 +579,11 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
        length += 2;
 
        adl = att_data_list_alloc(num, length);
+       if (adl == NULL) {
+               g_slist_free(types);
+               return enc_error_resp(ATT_OP_READ_BY_TYPE_REQ, start,
+                                       ATT_ECODE_UNLIKELY, pdu, len);
+       }
 
        for (i = 0, l = types; l; i++, l = l->next) {
                uint8_t *value;
@@ -598,8 +606,8 @@ static uint16_t read_by_type(struct gatt_channel *channel, uint16_t start,
        return length;
 }
 
-static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
-                                                       uint8_t *pdu, int len)
+static uint16_t find_info(struct gatt_channel *channel, uint16_t start,
+                               uint16_t end, uint8_t *pdu, size_t len)
 {
        struct attribute *a;
        struct att_data_list *adl;
@@ -651,6 +659,11 @@ static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
        }
 
        adl = att_data_list_alloc(num, length + 2);
+       if (adl == NULL) {
+               g_slist_free(info);
+               return enc_error_resp(ATT_OP_FIND_INFO_REQ, start,
+                                       ATT_ECODE_UNLIKELY, pdu, len);
+       }
 
        for (i = 0, l = info; l; i++, l = l->next) {
                uint8_t *value;
@@ -673,15 +686,16 @@ static int find_info(struct gatt_channel *channel, uint16_t start, uint16_t end,
        return length;
 }
 
-static int find_by_type(struct gatt_channel *channel, uint16_t start,
-                       uint16_t end, bt_uuid_t *uuid, const uint8_t *value,
-                                       int vlen, uint8_t *opdu, int mtu)
+static uint16_t find_by_type(struct gatt_channel *channel, uint16_t start,
+                               uint16_t end, bt_uuid_t *uuid,
+                               const uint8_t *value, size_t vlen,
+                               uint8_t *opdu, size_t mtu)
 {
        struct attribute *a;
        struct att_range *range;
        GSList *matches;
        GList *dl, *database;
-       int len;
+       uint16_t len;
 
        if (start > end || start == 0x0000)
                return enc_error_resp(ATT_OP_FIND_BY_TYPE_REQ, start,
@@ -732,14 +746,47 @@ static int find_by_type(struct gatt_channel *channel, uint16_t start,
        return len;
 }
 
+static int read_device_ccc(struct btd_device *device, uint16_t handle,
+                               uint16_t *value)
+{
+       char *filename;
+       GKeyFile *key_file;
+       char group[6];
+       char *str;
+       unsigned int config;
+       int err = 0;
+
+       filename = btd_device_get_storage_path(device, "ccc");
+       if (!filename) {
+               warn("Unable to get ccc storage path for device");
+               return -ENOENT;
+       }
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       sprintf(group, "%hu", handle);
+
+       str = g_key_file_get_string(key_file, group, "Value", NULL);
+       if (!str || sscanf(str, "%04X", &config) != 1)
+               err = -ENOENT;
+       else
+               *value = config;
+
+       g_free(str);
+       g_free(filename);
+       g_key_file_free(key_file);
+
+       return err;
+}
+
 static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
-                                                       uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        struct attribute *a;
        uint8_t status;
        GList *l;
        uint16_t cccval;
-       uint8_t bdaddr_type;
        guint h = handle;
 
        l = g_list_find_custom(channel->server->database,
@@ -750,18 +797,15 @@ 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, bdaddr_type,
-                                                       handle, &cccval) == 0) {
+               read_device_ccc(channel->device, handle, &cccval) == 0) {
                uint8_t config[2];
 
                att_put_u16(cccval, config);
                return enc_read_resp(config, sizeof(config), pdu, len);
        }
 
-       status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_reqs);
+       status = att_check_reqs(channel, ATT_OP_READ_REQ, a->read_req);
 
        if (status == 0x00 && a->read_cb)
                status = a->read_cb(a, channel->device, a->cb_user_data);
@@ -774,13 +818,12 @@ static uint16_t read_value(struct gatt_channel *channel, uint16_t handle,
 }
 
 static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
-                                       uint16_t offset, uint8_t *pdu, int len)
+                               uint16_t offset, uint8_t *pdu, size_t len)
 {
        struct attribute *a;
        uint8_t status;
        GList *l;
        uint16_t cccval;
-       uint8_t bdaddr_type;
        guint h = handle;
 
        l = g_list_find_custom(channel->server->database,
@@ -795,11 +838,8 @@ 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, bdaddr_type,
-                                                       handle, &cccval) == 0) {
+               read_device_ccc(channel->device, handle, &cccval) == 0) {
                uint8_t config[2];
 
                att_put_u16(cccval, config);
@@ -807,7 +847,7 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
                                                                pdu, len);
        }
 
-       status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_reqs);
+       status = att_check_reqs(channel, ATT_OP_READ_BLOB_REQ, a->read_req);
 
        if (status == 0x00 && a->read_cb)
                status = a->read_cb(a, channel->device, a->cb_user_data);
@@ -820,8 +860,8 @@ static uint16_t read_blob(struct gatt_channel *channel, uint16_t handle,
 }
 
 static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
-                                               const uint8_t *value, int vlen,
-                                               uint8_t *pdu, int len)
+                                       const uint8_t *value, size_t vlen,
+                                       uint8_t *pdu, size_t len)
 {
        struct attribute *a;
        uint8_t status;
@@ -836,7 +876,7 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
 
        a = l->data;
 
-       status = att_check_reqs(channel, ATT_OP_WRITE_REQ, a->write_reqs);
+       status = att_check_reqs(channel, ATT_OP_WRITE_REQ, a->write_req);
        if (status)
                return enc_error_resp(ATT_OP_WRITE_REQ, handle, status, pdu,
                                                                        len);
@@ -855,17 +895,43 @@ static uint16_t write_value(struct gatt_channel *channel, uint16_t handle,
                }
        } else {
                uint16_t cccval = att_get_u16(value);
-               uint8_t bdaddr_type = device_get_addr_type(channel->device);
+               char *filename;
+               GKeyFile *key_file;
+               char group[6], value[5];
+               char *data;
+               gsize length = 0;
+
+               filename = btd_device_get_storage_path(channel->device, "ccc");
+               if (!filename) {
+                       warn("Unable to get ccc storage path for device");
+                       return enc_error_resp(ATT_OP_WRITE_REQ, handle,
+                                               ATT_ECODE_WRITE_NOT_PERM,
+                                               pdu, len);
+               }
+
+               key_file = g_key_file_new();
+               g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+               sprintf(group, "%hu", handle);
+               sprintf(value, "%hhX", cccval);
+               g_key_file_set_string(key_file, group, "Value", value);
 
-               write_device_ccc(&channel->src, &channel->dst, bdaddr_type,
-                                                               handle, cccval);
+               data = g_key_file_to_data(key_file, &length, NULL);
+               if (length > 0) {
+                       create_file(filename, S_IRUSR | S_IWUSR);
+                       g_file_set_contents(filename, data, length, NULL);
+               }
+
+               g_free(data);
+               g_free(filename);
+               g_key_file_free(key_file);
        }
 
-       return enc_write_resp(pdu, len);
+       return enc_write_resp(pdu);
 }
 
 static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
-               uint8_t *pdu, int len)
+                                               uint8_t *pdu, size_t len)
 {
        GError *gerr = NULL;
        GIOChannel *io;
@@ -877,9 +943,7 @@ static uint16_t mtu_exchange(struct gatt_channel *channel, uint16_t mtu,
 
        io = g_attrib_get_channel(channel->attrib);
 
-       bt_io_get(io, BT_IO_L2CAP, &gerr,
-                       BT_IO_OPT_IMTU, &imtu,
-                       BT_IO_OPT_INVALID);
+       bt_io_get(io, &gerr, BT_IO_OPT_IMTU, &imtu, BT_IO_OPT_INVALID);
 
        if (gerr)
                return enc_error_resp(ATT_OP_MTU_REQ, 0,
@@ -910,11 +974,12 @@ static void channel_handler(const uint8_t *ipdu, uint16_t len,
                                                        gpointer user_data)
 {
        struct gatt_channel *channel = user_data;
-       uint8_t opdu[ATT_MAX_MTU], value[ATT_MAX_MTU];
+       uint8_t opdu[channel->mtu];
        uint16_t length, start, end, mtu, offset;
        bt_uuid_t uuid;
        uint8_t status = 0;
-       int vlen;
+       size_t vlen;
+       uint8_t *value = g_attrib_get_buffer(channel->attrib, &vlen);
 
        DBG("op 0x%02x", ipdu[0]);
 
@@ -1030,8 +1095,7 @@ done:
                length = enc_error_resp(ipdu[0], 0x0000, status, opdu,
                                                                channel->mtu);
 
-       g_attrib_send(channel->attrib, 0, opdu[0], opdu, length,
-                                                       NULL, NULL, NULL);
+       g_attrib_send(channel->attrib, 0, opdu, length, NULL, NULL, NULL);
 }
 
 guint attrib_channel_attach(GAttrib *attrib)
@@ -1041,7 +1105,6 @@ guint attrib_channel_attach(GAttrib *attrib)
        struct gatt_channel *channel;
        GIOChannel *io;
        GError *gerr = NULL;
-       char addr[18];
        uint16_t cid;
        guint mtu = 0;
 
@@ -1049,7 +1112,7 @@ guint attrib_channel_attach(GAttrib *attrib)
 
        channel = g_new0(struct gatt_channel, 1);
 
-       bt_io_get(io, BT_IO_L2CAP, &gerr,
+       bt_io_get(io, &gerr,
                        BT_IO_OPT_SOURCE_BDADDR, &channel->src,
                        BT_IO_OPT_DEST_BDADDR, &channel->dst,
                        BT_IO_OPT_CID, &cid,
@@ -1074,11 +1137,22 @@ guint attrib_channel_attach(GAttrib *attrib)
 
        channel->server = server;
 
-       ba2str(&channel->dst, addr);
+       device = adapter_find_device(server->adapter, &channel->dst);
+       if (device == NULL) {
+               error("Device object not found for attrib server");
+               g_free(channel);
+               return 0;
+       }
 
-       device = adapter_find_device(server->adapter, addr);
-       if (device == NULL || device_is_bonded(device) == FALSE)
-               delete_device_ccc(&channel->src, &channel->dst);
+       if (device_is_bonded(device) == FALSE) {
+               char *filename;
+
+               filename = btd_device_get_storage_path(device, "ccc");
+               if (filename) {
+                       unlink(filename);
+                       g_free(filename);
+               }
+       }
 
        if (cid != ATT_CID) {
                channel->le = FALSE;
@@ -1090,7 +1164,7 @@ guint attrib_channel_attach(GAttrib *attrib)
 
        channel->attrib = g_attrib_ref(attrib);
        channel->id = g_attrib_register(channel->attrib, GATTRIB_ALL_REQS,
-                                       channel_handler, channel, NULL);
+                       GATTRIB_ALL_HANDLES, channel_handler, channel, NULL);
 
        channel->cleanup_id = g_io_add_watch(io, G_IO_HUP, channel_watch_cb,
                                                                channel);
@@ -1102,7 +1176,7 @@ guint attrib_channel_attach(GAttrib *attrib)
        return channel->id;
 }
 
-static gint channel_id_cmp(gconstpointer data, gconstpointer user_data)
+static int channel_id_cmp(gconstpointer data, gconstpointer user_data)
 {
        const struct gatt_channel *channel = data;
        guint id = GPOINTER_TO_UINT(user_data);
@@ -1121,8 +1195,7 @@ gboolean attrib_channel_detach(GAttrib *attrib, guint id)
 
        io = g_attrib_get_channel(attrib);
 
-       bt_io_get(io, BT_IO_L2CAP, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src,
-                                                       BT_IO_OPT_INVALID);
+       bt_io_get(io, &gerr, BT_IO_OPT_SOURCE_BDADDR, &src, BT_IO_OPT_INVALID);
 
        if (gerr != NULL) {
                error("bt_io_get: %s", gerr->message);
@@ -1151,6 +1224,8 @@ static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
 {
        GAttrib *attrib;
 
+       DBG("");
+
        if (gerr) {
                error("%s", gerr->message);
                return;
@@ -1161,19 +1236,6 @@ static void connect_event(GIOChannel *io, GError *gerr, void *user_data)
        g_attrib_unref(attrib);
 }
 
-static void confirm_event(GIOChannel *io, void *user_data)
-{
-       GError *gerr = NULL;
-
-       if (bt_io_accept(io, connect_event, user_data, NULL, &gerr) == FALSE) {
-               error("bt_io_accept: %s", gerr->message);
-               g_error_free(gerr);
-               g_io_channel_unref(io);
-       }
-
-       return;
-}
-
 static gboolean register_core_services(struct gatt_server *server)
 {
        uint8_t atval[256];
@@ -1241,19 +1303,18 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
 {
        struct gatt_server *server;
        GError *gerr = NULL;
-       bdaddr_t addr;
+       const bdaddr_t *addr;
 
-       DBG("Start GATT server in hci%d", adapter_get_dev_id(adapter));
+       DBG("Start GATT server in hci%d", btd_adapter_get_index(adapter));
 
        server = g_new0(struct gatt_server, 1);
        server->adapter = btd_adapter_ref(adapter);
 
-       adapter_get_address(server->adapter, &addr);
+       addr = adapter_get_address(server->adapter);
 
        /* BR/EDR socket */
-       server->l2cap_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
-                                       NULL, NULL, &gerr,
-                                       BT_IO_OPT_SOURCE_BDADDR, &addr,
+       server->l2cap_io = bt_io_listen(connect_event, NULL, NULL, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, addr,
                                        BT_IO_OPT_PSM, ATT_PSM,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
@@ -1271,9 +1332,10 @@ int btd_adapter_gatt_server_start(struct btd_adapter *adapter)
        }
 
        /* LE socket */
-       server->le_io = bt_io_listen(BT_IO_L2CAP, NULL, confirm_event,
+       server->le_io = bt_io_listen(connect_event, NULL,
                                        &server->le_io, NULL, &gerr,
-                                       BT_IO_OPT_SOURCE_BDADDR, &addr,
+                                       BT_IO_OPT_SOURCE_BDADDR, addr,
+                                       BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
                                        BT_IO_OPT_CID, ATT_CID,
                                        BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
                                        BT_IO_OPT_INVALID);
@@ -1297,7 +1359,7 @@ void btd_adapter_gatt_server_stop(struct btd_adapter *adapter)
        if (l == NULL)
                return;
 
-       DBG("Stop GATT server in hci%d", adapter_get_dev_id(adapter));
+       DBG("Stop GATT server in hci%d", btd_adapter_get_index(adapter));
 
        server = l->data;
        servers = g_slist_remove(servers, server);
@@ -1316,9 +1378,9 @@ uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
        return attrib_create_sdp_new(l->data, handle, name);
 }
 
-void attrib_free_sdp(uint32_t sdp_handle)
+void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle)
 {
-       remove_record_from_server(sdp_handle);
+       adapter_service_remove(adapter, sdp_handle);
 }
 
 static uint16_t find_uuid16_avail(struct btd_adapter *adapter, uint16_t nitems)
@@ -1429,8 +1491,9 @@ uint16_t attrib_db_find_avail(struct btd_adapter *adapter, bt_uuid_t *svc_uuid,
 }
 
 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)
+                                       bt_uuid_t *uuid, int read_req,
+                                       int write_req, const uint8_t *value,
+                                       size_t len)
 {
        GSList *l;
 
@@ -1438,13 +1501,13 @@ struct attribute *attrib_db_add(struct btd_adapter *adapter, uint16_t handle,
        if (l == NULL)
                return NULL;
 
-       return attrib_db_add_new(l->data, handle, uuid, read_reqs, write_reqs,
+       return attrib_db_add_new(l->data, handle, uuid, read_req, write_req,
                                                                value, len);
 }
 
 int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
                                        bt_uuid_t *uuid, const uint8_t *value,
-                                       int len, struct attribute **attr)
+                                       size_t len, struct attribute **attr)
 {
        struct gatt_server *server;
        struct attribute *a;
@@ -1513,7 +1576,7 @@ int attrib_db_del(struct btd_adapter *adapter, uint16_t handle)
 }
 
 int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
-                                               const uint8_t *value, int len)
+                                       const uint8_t *value, size_t len)
 {
        struct gatt_server *server;
        uint16_t handle;
index 7af0cfa..90ba17c 100644 (file)
 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);
+                               bt_uuid_t *uuid, int read_req,
+                               int write_req, const uint8_t *value,
+                               size_t len);
 int attrib_db_update(struct btd_adapter *adapter, uint16_t handle,
                                        bt_uuid_t *uuid, const uint8_t *value,
-                                       int len, struct attribute **attr);
+                                       size_t len, struct attribute **attr);
 int attrib_db_del(struct btd_adapter *adapter, uint16_t handle);
 int attrib_gap_set(struct btd_adapter *adapter, uint16_t uuid,
-                                               const uint8_t *value, int len);
+                                       const uint8_t *value, size_t len);
 uint32_t attrib_create_sdp(struct btd_adapter *adapter, uint16_t handle,
                                                        const char *name);
-void attrib_free_sdp(uint32_t sdp_handle);
+void attrib_free_sdp(struct btd_adapter *adapter, uint32_t sdp_handle);
 guint attrib_channel_attach(GAttrib *attrib);
 gboolean attrib_channel_detach(GAttrib *attrib, guint id);
index 664dbd9..0495200 100644 (file)
   <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"/>
+    <allow send_interface="org.bluez.Agent1"/>
+    <allow send_interface="org.bluez.MediaEndpoint1"/>
+    <allow send_interface="org.bluez.MediaPlayer1"/>
+    <allow send_interface="org.bluez.ThermometerWatcher1"/>
+    <allow send_interface="org.bluez.AlertAgent1"/>
+    <allow send_interface="org.bluez.Profile1"/>
+    <allow send_interface="org.bluez.HeartRateWatcher1"/>
+    <allow send_interface="org.bluez.CyclingSpeedWatcher1"/>
   </policy>
 
   <policy at_console="true">
index 2a576a3..2b73254 100644 (file)
@@ -1,10 +1,16 @@
 [Unit]
 Description=Bluetooth service
+Documentation=man:bluetoothd(8)
 
 [Service]
 Type=dbus
 BusName=org.bluez
-ExecStart=@prefix@/sbin/bluetoothd -n
+ExecStart=@libexecdir@/bluetoothd
+NotifyAccess=main
+#WatchdogSec=10
+#Restart=on-failure
+CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_BIND_SERVICE CAP_NET_RAW
+LimitNPROC=1
 
 [Install]
 WantedBy=bluetooth.target
index a7ae77b..0bf3914 100644 (file)
@@ -4,88 +4,56 @@
 bluetoothd \- Bluetooth daemon
 
 .SH "SYNOPSIS"
-.B bluetoothd
-[
-.B \-n
-]
+.B bluetoothd [--version] | [--help]
+
+.B bluetoothd [--nodetach] [--compat] [--experimental] [--debug=<files>] [--plugin=<plugins>] [--noplugin=<plugins>]
 
 .SH "DESCRIPTION"
 This manual page documents briefly the
 .B bluetoothd
 daemon, which manages all the Bluetooth devices.
 .B bluetoothd
-itself does not accept many command\-line options, as most of its
-configuration is done in the
-.B @CONFIGDIR@/main.conf
-file, which has its own man page.
-.B bluetoothd
 can also provide a number of services via the D-Bus message bus
 system.
 .SH "OPTIONS"
 .TP
-.BI \-n
-Don't run as daemon in background.
+.B -v, --version
+Print bluetoothd version and exit.
 .TP
-.BI \-d
-Enable debug information output.
+.B -h, --help
+Print bluetoothd options and exit.
 .TP
-.BI \-m\ mtu\-size
-Use specific MTU size for SDP server.
-
-.SH "FILES"
+.B -n, --nodetach
+Enable logging in foreground. Directs log output to the controlling terminal \
+in addition to syslog.
 .TP
-.I @CONFIGDIR@/main.conf
-Default location of the global configuration file.
+.B -d, --debug=<file1>:<file2>:...
+Sets how much information bluetoothd sends to the log destination (usually \
+syslog's "daemon" facility). If the file options are omitted, then debugging \
+information from all the source files are printed. If file options are \
+present, then only debug prints from that source file are printed. The option \
+can be a pattern containing "*" and "?" characters.
 
+Example: --debug=src/adapter.c:src/agent.c
 .TP
-.I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/linkkeys
-Default location for link keys of paired devices. The directory
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
-is the address of the local device. The file is line separated, with
-the following columns separated by whitespace:
-
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
-
-\fInnnnnnnnnnnnnnnnnnnnnnnnnnnnnnnn\fP Link key.
-
-\fIn\fP Link type integer.
-
+.B -p, --plugin=<plugin1>,<plugin2>,..
+Load these plugins only. The option can be a pattern containing "*" and "?" \
+characters.
 .TP
-.I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/names
-Default location for the device name cache. The directory
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
-is the address of the local device. The file is line separated, with
-the following columns separated by whitespace:
-
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
-
-\fIname\fP Remote device name, terminated with newline.
-
+.B -P, --noplugin=<plugin1>,<plugin2>,..
+Never load these plugins. The option can be a pattern containing "*" and "?" \
+characters.
 .TP
-.I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/features
-Default location for the features cache. The directory
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
-is the address of the local device. The file is line separated, with
-the following columns separated by whitespace:
-
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
-
-\fInnnnnnnnnnnnnnnn\fP Remote device LMP features coded as an 8 byte bitfield.
-
+.B -C, --compat
+Provide deprecated command line interfaces.
 .TP
-.I @STORAGEDIR@/nn:nn:nn:nn:nn:nn/manufacturers
-Default location for the manufacturers cache. The directory
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP
-is the address of the local device. The file is line separated, with
-the following columns separated by whitespace:
-
-\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP\fB:\fP\fInn\fP Remote device address.
-
-\fIn\fP Remote device manufacturer integer.
-
-\fIn\fP Remote device LMP version integer.
-
-\fIn\fP Remote device LMP sub-version integer.
+.B -E, -experimental
+Enable experimental interfaces. Those interfaces are not guaranteed to be
+compatible or present in future releases.
+.SH "FILES"
+.TP
+.I @CONFIGDIR@/main.conf
+Location of the global configuration file.
 
 .SH "AUTHOR"
 This manual page was written by Marcel Holtmann, Philipp Matthias Hahn and Fredrik Noring.
index 7e1bc94..d466a8f 100644 (file)
@@ -32,7 +32,7 @@
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 
@@ -118,64 +118,12 @@ void dict_append_array(DBusMessageIter *dict, const char *key, int type,
        dbus_message_iter_close_container(dict, &entry);
 }
 
-dbus_bool_t emit_property_changed(DBusConnection *conn,
-                                       const char *path,
-                                       const char *interface,
-                                       const char *name,
-                                       int type, void *value)
-{
-       DBusMessage *signal;
-       DBusMessageIter iter;
-
-       signal = dbus_message_new_signal(path, interface, "PropertyChanged");
-
-       if (!signal) {
-               error("Unable to allocate new %s.PropertyChanged signal",
-                               interface);
-               return FALSE;
-       }
-
-       dbus_message_iter_init_append(signal, &iter);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
-
-       append_variant(&iter, type, value);
-
-       return g_dbus_send_message(conn, signal);
-}
-
-dbus_bool_t emit_array_property_changed(DBusConnection *conn,
-                                       const char *path,
-                                       const char *interface,
-                                       const char *name,
-                                       int type, void *value, int num)
-{
-       DBusMessage *signal;
-       DBusMessageIter iter;
-
-       signal = dbus_message_new_signal(path, interface, "PropertyChanged");
-
-       if (!signal) {
-               error("Unable to allocate new %s.PropertyChanged signal",
-                               interface);
-               return FALSE;
-       }
-
-       dbus_message_iter_init_append(signal, &iter);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
-
-       append_array_variant(&iter, type, value, num);
-
-       return g_dbus_send_message(conn, signal);
-}
-
 void set_dbus_connection(DBusConnection *conn)
 {
        connection = conn;
 }
 
-DBusConnection *get_dbus_connection(void)
+DBusConnection *btd_get_dbus_connection(void)
 {
        return connection;
 }
@@ -247,6 +195,8 @@ const char *class_to_icon(uint32_t class)
 const char *gap_appearance_to_icon(uint16_t appearance)
 {
        switch ((appearance & 0xffc0) >> 6) {
+       case 0x00:
+               return "unknown";
        case 0x01:
                return "phone";
        case 0x02:
index b9531f2..f331b2f 100644 (file)
  *
  */
 
-#define MAX_PATH_LENGTH 64
-
 void dict_append_entry(DBusMessageIter *dict,
                        const char *key, int type, void *val);
 
 void dict_append_array(DBusMessageIter *dict, const char *key, int type,
                        void *val, int n_elements);
 
-dbus_bool_t emit_property_changed(DBusConnection *conn,
-                                       const char *path,
-                                       const char *interface,
-                                       const char *name,
-                                       int type, void *value);
-
-dbus_bool_t emit_array_property_changed(DBusConnection *conn,
-                                       const char *path,
-                                       const char *interface,
-                                       const char *name,
-                                       int type, void *value, int num);
-
 void set_dbus_connection(DBusConnection *conn);
-DBusConnection *get_dbus_connection(void);
+DBusConnection *btd_get_dbus_connection(void);
 
 const char *class_to_icon(uint32_t class);
 const char *gap_appearance_to_icon(uint16_t appearance);
index c210bcb..457ab64 100644 (file)
 #include <stdlib.h>
 #include <unistd.h>
 #include <fcntl.h>
+#include <stdbool.h>
 #include <sys/stat.h>
 #include <sys/ioctl.h>
 #include <errno.h>
+#include <dirent.h>
+#include <time.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
 #include <glib.h>
 #include <dbus/dbus.h>
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
+#include <btio/btio.h>
 
 #include "log.h"
 
-#include "att.h"
+#include "lib/uuid.h"
+#include "lib/mgmt.h"
+#include "attrib/att.h"
 #include "hcid.h"
 #include "adapter.h"
-#include "gattrib.h"
+#include "attrib/gattrib.h"
 #include "attio.h"
 #include "device.h"
+#include "profile.h"
+#include "service.h"
 #include "dbus-common.h"
 #include "error.h"
 #include "glib-helper.h"
 #include "sdp-client.h"
-#include "gatt.h"
+#include "attrib/gatt.h"
 #include "agent.h"
 #include "sdp-xml.h"
 #include "storage.h"
-#include "btio.h"
 #include "attrib-server.h"
-#include "attrib/client.h"
 
-#define DISCONNECT_TIMER       2
-#define DISCOVERY_TIMER                2
-
-#define AUTO_CONNECTION_INTERVAL       5 /* Next connection attempt */
+#define IO_CAPABILITY_NOINPUTNOOUTPUT  0x03
 
-/* When all services should trust a remote device */
-#define GLOBAL_TRUST "[all]"
+#define DISCONNECT_TIMER       2
+#define DISCOVERY_TIMER                1
 
-#define APPEARANCE_CHR_UUID 0x2a01
+static DBusConnection *dbus_conn = NULL;
+unsigned service_state_cb_id;
 
 struct btd_disconnect_data {
        guint id;
@@ -81,15 +84,27 @@ struct btd_disconnect_data {
 };
 
 struct bonding_req {
-       DBusConnection *conn;
        DBusMessage *msg;
        guint listener_id;
        struct btd_device *device;
+       struct agent *agent;
+       struct btd_adapter_pin_cb_iter *cb_iter;
+       uint8_t status;
+       guint retry_timer;
+       struct timespec attempt_start_time;
+       long last_attempt_duration_ms;
 };
 
+typedef enum {
+       AUTH_TYPE_PINCODE,
+       AUTH_TYPE_PASSKEY,
+       AUTH_TYPE_CONFIRM,
+       AUTH_TYPE_NOTIFY_PASSKEY,
+       AUTH_TYPE_NOTIFY_PINCODE,
+} auth_type_t;
+
 struct authentication_req {
        auth_type_t type;
-       void *cb;
        struct agent *agent;
        struct btd_device *device;
        uint32_t passkey;
@@ -98,18 +113,22 @@ struct authentication_req {
 };
 
 struct browse_req {
-       DBusConnection *conn;
        DBusMessage *msg;
        struct btd_device *device;
        GSList *match_uuids;
        GSList *profiles_added;
-       GSList *profiles_removed;
        sdp_list_t *records;
        int search_uuid;
        int reconnect_attempt;
        guint listener_id;
 };
 
+struct included_search {
+       struct browse_req *req;
+       GSList *services;
+       GSList *current;
+};
+
 struct attio_data {
        guint id;
        attio_connect_cb cfunc;
@@ -117,6 +136,14 @@ struct attio_data {
        gpointer user_data;
 };
 
+struct svc_callback {
+       unsigned int id;
+       guint idle_id;
+       struct btd_device *dev;
+       device_svc_cb_t func;
+       void *user_data;
+};
+
 typedef void (*attio_error_cb) (const GError *gerr, gpointer user_data);
 typedef void (*attio_success_cb) (gpointer user_data);
 
@@ -127,34 +154,44 @@ struct att_callbacks {
 };
 
 struct btd_device {
+       int ref_count;
+
        bdaddr_t        bdaddr;
        uint8_t         bdaddr_type;
-       gchar           *path;
+       char            *path;
+       bool            pending_paired;         /* "Paired" waiting for SDP */
+       bool            svc_resolved;
+       bool            svc_refreshed;
+       GSList          *svc_callbacks;
+       GSList          *eir_uuids;
        char            name[MAX_NAME_LENGTH + 1];
        char            *alias;
+       uint32_t        class;
        uint16_t        vendor_src;
        uint16_t        vendor;
        uint16_t        product;
        uint16_t        version;
+       uint16_t        appearance;
+       char            *modalias;
        struct btd_adapter      *adapter;
        GSList          *uuids;
-       GSList          *services;              /* Primary services path */
        GSList          *primaries;             /* List of primary services */
-       GSList          *drivers;               /* List of device drivers */
+       GSList          *services;              /* List of btd_service */
+       GSList          *pending;               /* Pending services */
        GSList          *watches;               /* List of disconnect_data */
        gboolean        temporary;
-       struct agent    *agent;
        guint           disconn_timer;
        guint           discov_timer;
        struct browse_req *browse;              /* service discover request */
        struct bonding_req *bonding;
        struct authentication_req *authr;       /* authentication request */
        GSList          *disconnects;           /* disconnects message */
+       DBusMessage     *connect;               /* connect message */
+       DBusMessage     *disconnect;            /* disconnect message */
        GAttrib         *attrib;
        GSList          *attios;
        GSList          *attios_offline;
        guint           attachid;               /* Attrib server attach */
-       guint           auto_id;                /* Auto connect source id */
 
        gboolean        connected;
 
@@ -165,42 +202,247 @@ struct btd_device {
        gboolean        blocked;
        gboolean        bonded;
        gboolean        auto_connect;
+       gboolean        disable_auto_connect;
+       gboolean        general_connect;
 
-       gboolean        authorizing;
-       gint            ref;
+       bool            legacy;
+       int8_t          rssi;
 
-       GIOChannel      *att_io;
+       GIOChannel      *att_io;
        guint           cleanup_id;
+       guint           store_id;
 };
 
-static uint16_t uuid_list[] = {
+static const uint16_t uuid_list[] = {
        L2CAP_UUID,
        PNP_INFO_SVCLASS_ID,
        PUBLIC_BROWSE_GROUP,
        0
 };
 
-static GSList *device_drivers = NULL;
+static int device_browse_primary(struct btd_device *device, DBusMessage *msg);
+static int device_browse_sdp(struct btd_device *device, DBusMessage *msg);
+
+static GSList *find_service_with_profile(GSList *list, struct btd_profile *p)
+{
+       GSList *l;
+
+       for (l = list; l != NULL; l = g_slist_next(l)) {
+               struct btd_service *service = l->data;
+
+               if (btd_service_get_profile(service) == p)
+                       return l;
+       }
+
+       return NULL;
+}
+
+static GSList *find_service_with_state(GSList *list,
+                                               btd_service_state_t state)
+{
+       GSList *l;
+
+       for (l = list; l != NULL; l = g_slist_next(l)) {
+               struct btd_service *service = l->data;
+
+               if (btd_service_get_state(service) == state)
+                       return l;
+       }
+
+       return NULL;
+}
+
+static gboolean store_device_info_cb(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+       GKeyFile *key_file;
+       char filename[PATH_MAX + 1];
+       char adapter_addr[18];
+       char device_addr[18];
+       char *str;
+       char class[9];
+       char **uuids = NULL;
+       gsize length = 0;
+
+       device->store_id = 0;
+
+       ba2str(adapter_get_address(device->adapter), adapter_addr);
+       ba2str(&device->bdaddr, device_addr);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/info", adapter_addr,
+                       device_addr);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+
+       g_key_file_set_string(key_file, "General", "Name", device->name);
+
+       if (device->alias != NULL)
+               g_key_file_set_string(key_file, "General", "Alias",
+                                                               device->alias);
+       else
+               g_key_file_remove_key(key_file, "General", "Alias", NULL);
+
+       if (device->class) {
+               sprintf(class, "0x%6.6x", device->class);
+               g_key_file_set_string(key_file, "General", "Class", class);
+       } else {
+               g_key_file_remove_key(key_file, "General", "Class", NULL);
+       }
+
+       if (device->appearance) {
+               sprintf(class, "0x%4.4x", device->appearance);
+               g_key_file_set_string(key_file, "General", "Appearance", class);
+       } else {
+               g_key_file_remove_key(key_file, "General", "Appearance", NULL);
+       }
+
+       switch (device->bdaddr_type) {
+       case BDADDR_BREDR:
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", "BR/EDR");
+               g_key_file_remove_key(key_file, "General",
+                                       "AddressType", NULL);
+               break;
+
+       case BDADDR_LE_PUBLIC:
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", "LE");
+               g_key_file_set_string(key_file, "General",
+                                       "AddressType", "public");
+               break;
+
+       case BDADDR_LE_RANDOM:
+               g_key_file_set_string(key_file, "General",
+                                       "SupportedTechnologies", "LE");
+               g_key_file_set_string(key_file, "General",
+                                       "AddressType", "static");
+               break;
+
+       default:
+               g_key_file_remove_key(key_file, "General",
+                                       "SupportedTechnologies", NULL);
+               g_key_file_remove_key(key_file, "General",
+                                       "AddressType", NULL);
+       }
+
+       g_key_file_set_boolean(key_file, "General", "Trusted",
+                                                       device->trusted);
+
+       g_key_file_set_boolean(key_file, "General", "Blocked",
+                                                       device->blocked);
+
+       if (device->uuids) {
+               GSList *l;
+               int i;
+
+               uuids = g_new0(char *, g_slist_length(device->uuids) + 1);
+               for (i = 0, l = device->uuids; l; l = g_slist_next(l), i++)
+                       uuids[i] = l->data;
+               g_key_file_set_string_list(key_file, "General", "Services",
+                                               (const char **)uuids, i);
+       } else {
+               g_key_file_remove_key(key_file, "General", "Services", NULL);
+       }
+
+       if (device->vendor_src) {
+               g_key_file_set_integer(key_file, "DeviceID", "Source",
+                                       device->vendor_src);
+               g_key_file_set_integer(key_file, "DeviceID", "Vendor",
+                                       device->vendor);
+               g_key_file_set_integer(key_file, "DeviceID", "Product",
+                                       device->product);
+               g_key_file_set_integer(key_file, "DeviceID", "Version",
+                                       device->version);
+       } else {
+               g_key_file_remove_group(key_file, "DeviceID", NULL);
+       }
+
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       str = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, str, length, NULL);
+       g_free(str);
+
+       g_key_file_free(key_file);
+       g_free(uuids);
+
+       return FALSE;
+}
+
+static bool device_address_is_private(struct btd_device *dev)
+{
+       if (dev->bdaddr_type != BDADDR_LE_RANDOM)
+               return false;
+
+       switch (dev->bdaddr.b[5] >> 6) {
+       case 0x00:      /* Private non-resolvable */
+       case 0x01:      /* Private resolvable */
+               return true;
+       default:
+               return false;
+       }
+}
+
+static void store_device_info(struct btd_device *device)
+{
+       if (device->temporary || device->store_id > 0)
+               return;
+
+       if (device_address_is_private(device)) {
+               warn("Can't store info for private addressed device %s",
+                                                               device->path);
+               return;
+       }
+
+       device->store_id = g_idle_add(store_device_info_cb, device);
+}
+
+void device_store_cached_name(struct btd_device *dev, const char *name)
+{
+       char filename[PATH_MAX + 1];
+       char s_addr[18], d_addr[18];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
+
+       if (device_address_is_private(dev)) {
+               warn("Can't store name for private addressed device %s",
+                                                               dev->path);
+               return;
+       }
+
+       ba2str(adapter_get_address(dev->adapter), s_addr);
+       ba2str(&dev->bdaddr, d_addr);
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", s_addr, d_addr);
+       filename[PATH_MAX] = '\0';
+       create_file(filename, S_IRUSR | S_IWUSR);
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       g_key_file_set_string(key_file, "General", "Name", name);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       g_file_set_contents(filename, data, length, NULL);
+       g_free(data);
+
+       g_key_file_free(key_file);
+}
 
 static void browse_request_free(struct browse_req *req)
 {
        if (req->listener_id)
-               g_dbus_remove_watch(req->conn, req->listener_id);
+               g_dbus_remove_watch(dbus_conn, req->listener_id);
        if (req->msg)
                dbus_message_unref(req->msg);
-       if (req->conn)
-               dbus_connection_unref(req->conn);
-       if (req->device)
-               btd_device_unref(req->device);
        g_slist_free_full(req->profiles_added, g_free);
-       g_slist_free(req->profiles_removed);
        if (req->records)
                sdp_list_free(req->records, (sdp_free_func_t) sdp_record_free);
 
        g_free(req);
 }
 
-static void att_cleanup(struct btd_device *device)
+static void attio_cleanup(struct btd_device *device)
 {
        if (device->attachid) {
                attrib_channel_detach(device->attrib, device->attachid);
@@ -219,8 +461,10 @@ static void att_cleanup(struct btd_device *device)
        }
 
        if (device->attrib) {
-               g_attrib_unref(device->attrib);
+               GAttrib *attrib = device->attrib;
                device->attrib = NULL;
+               g_attrib_cancel_all(attrib);
+               g_attrib_unref(attrib);
        }
 }
 
@@ -228,41 +472,38 @@ static void browse_request_cancel(struct browse_req *req)
 {
        struct btd_device *device = req->device;
        struct btd_adapter *adapter = device->adapter;
-       bdaddr_t src;
-
-       if (device_is_creating(device, NULL))
-               device_set_temporary(device, TRUE);
 
-       adapter_get_address(adapter, &src);
+       bt_cancel_discovery(adapter_get_address(adapter), &device->bdaddr);
 
-       bt_cancel_discovery(&src, &device->bdaddr);
-
-       att_cleanup(device);
+       attio_cleanup(device);
 
        device->browse = NULL;
        browse_request_free(req);
 }
 
-static void device_free(gpointer user_data)
+static void svc_dev_remove(gpointer user_data)
 {
-       struct btd_device *device = user_data;
-       struct btd_adapter *adapter = device->adapter;
-       struct agent *agent = adapter_get_agent(adapter);
+       struct svc_callback *cb = user_data;
+
+       if (cb->idle_id > 0)
+               g_source_remove(cb->idle_id);
+
+       cb->func(cb->dev, -ENODEV, cb->user_data);
 
-       if (device->agent)
-               agent_free(device->agent);
+       g_free(cb);
+}
 
-       if (agent && (agent_is_busy(agent, device) ||
-                               agent_is_busy(agent, device->authr)))
-               agent_cancel(agent);
+static void device_free(gpointer user_data)
+{
+       struct btd_device *device = user_data;
 
-       g_slist_free_full(device->services, g_free);
        g_slist_free_full(device->uuids, g_free);
        g_slist_free_full(device->primaries, g_free);
        g_slist_free_full(device->attios, g_free);
        g_slist_free_full(device->attios_offline, g_free);
+       g_slist_free_full(device->svc_callbacks, svc_dev_remove);
 
-       att_cleanup(device);
+       attio_cleanup(device);
 
        if (device->tmp_records)
                sdp_list_free(device->tmp_records,
@@ -274,16 +515,27 @@ static void device_free(gpointer user_data)
        if (device->discov_timer)
                g_source_remove(device->discov_timer);
 
-       if (device->auto_id)
-               g_source_remove(device->auto_id);
+       if (device->connect)
+               dbus_message_unref(device->connect);
+
+       if (device->disconnect)
+               dbus_message_unref(device->disconnect);
 
        DBG("%p", device);
 
-       if (device->authr)
+       if (device->authr) {
+               if (device->authr->agent)
+                       agent_unref(device->authr->agent);
                g_free(device->authr->pincode);
-       g_free(device->authr);
+               g_free(device->authr);
+       }
+
+       if (device->eir_uuids)
+               g_slist_free_full(device->eir_uuids, g_free);
+
        g_free(device->path);
        g_free(device->alias);
+       g_free(device->modalias);
        g_free(device);
 }
 
@@ -312,353 +564,476 @@ gboolean device_is_trusted(struct btd_device *device)
        return device->trusted;
 }
 
-static DBusMessage *get_properties(DBusConnection *conn,
-                               DBusMessage *msg, void *user_data)
+static gboolean dev_property_get_address(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct btd_device *device = user_data;
-       struct btd_adapter *adapter = device->adapter;
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       bdaddr_t src;
-       char name[MAX_NAME_LENGTH + 1], srcaddr[18], dstaddr[18];
-       char **str;
-       const char *ptr, *icon = NULL;
-       dbus_bool_t boolean;
-       uint32_t class;
-       uint16_t app;
-       int i;
-       GSList *l;
+       struct btd_device *device = data;
+       char dstaddr[18];
+       const char *ptr = dstaddr;
 
        ba2str(&device->bdaddr, dstaddr);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
 
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
+       return TRUE;
+}
 
-       dbus_message_iter_init_append(reply, &iter);
+static gboolean dev_property_get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       const char *empty = "", *ptr;
 
-       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);
+       ptr = device->name ?: empty;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
+
+       return TRUE;
+}
 
-       /* Address */
-       ptr = dstaddr;
-       dict_append_entry(&dict, "Address", DBUS_TYPE_STRING, &ptr);
+static gboolean dev_property_exists_name(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct btd_device *dev = data;
 
-       /* Name */
-       ptr = NULL;
-       memset(name, 0, sizeof(name));
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
+       return device_name_known(dev);
+}
 
-       ptr = device->name;
-       dict_append_entry(&dict, "Name", DBUS_TYPE_STRING, &ptr);
+static gboolean dev_property_get_alias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       char dstaddr[18];
+       const char *ptr;
 
        /* Alias (fallback to name or address) */
        if (device->alias != NULL)
                ptr = device->alias;
-       else if (strlen(ptr) == 0) {
+       else if (strlen(device->name) > 0) {
+               ptr = device->name;
+       } else {
+               ba2str(&device->bdaddr, dstaddr);
                g_strdelimit(dstaddr, ":", '-');
                ptr = dstaddr;
        }
 
-       dict_append_entry(&dict, "Alias", DBUS_TYPE_STRING, &ptr);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &ptr);
+
+       return TRUE;
+}
 
-       /* Class */
-       if (read_remote_class(&src, &device->bdaddr, &class) == 0) {
-               icon = class_to_icon(class);
+static void set_alias(GDBusPendingPropertySet id, const char *alias,
+                                                               void *data)
+{
+       struct btd_device *device = data;
 
-               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);
+       /* No change */
+       if ((device->alias == NULL && g_str_equal(alias, "")) ||
+                                       g_strcmp0(device->alias, alias) == 0) {
+               g_dbus_pending_property_success(id);
+               return;
+       }
 
-       dict_append_entry(&dict, "Icon", DBUS_TYPE_STRING, &icon);
+       g_free(device->alias);
+       device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias);
 
-       /* Vendor */
-       if (device->vendor)
-               dict_append_entry(&dict, "Vendor", DBUS_TYPE_UINT16,
-                                                       &device->vendor);
+       store_device_info(device);
 
-       /* Vendor Source*/
-       if (device->vendor_src)
-               dict_append_entry(&dict, "VendorSource", DBUS_TYPE_UINT16,
-                                                       &device->vendor_src);
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Alias");
 
-       /* Product */
-       if (device->product)
-               dict_append_entry(&dict, "Product", DBUS_TYPE_UINT16,
-                                                       &device->product);
+       g_dbus_pending_property_success(id);
+}
 
-       /* Version */
-       if (device->version)
-               dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
-                                                       &device->version);
+static void dev_property_set_alias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *value,
+                                       GDBusPendingPropertySet id, void *data)
+{
+       const char *alias;
 
-       /* Paired */
-       boolean = device_is_paired(device);
-       dict_append_entry(&dict, "Paired", DBUS_TYPE_BOOLEAN, &boolean);
+       if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
 
-       /* Trusted */
-       boolean = device_is_trusted(device);
-       dict_append_entry(&dict, "Trusted", DBUS_TYPE_BOOLEAN, &boolean);
+       dbus_message_iter_get_basic(value, &alias);
 
-       /* Blocked */
-       boolean = device->blocked;
-       dict_append_entry(&dict, "Blocked", DBUS_TYPE_BOOLEAN, &boolean);
+       set_alias(id, alias, data);
+}
 
-       /* Connected */
-       dict_append_entry(&dict, "Connected", DBUS_TYPE_BOOLEAN,
-                                                       &device->connected);
+static gboolean dev_property_exists_class(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct btd_device *device = data;
 
-       /* UUIDs */
-       str = g_new0(char *, g_slist_length(device->uuids) + 1);
-       for (i = 0, l = device->uuids; l; l = l->next, i++)
-               str[i] = l->data;
-       dict_append_array(&dict, "UUIDs", DBUS_TYPE_STRING, &str, i);
-       g_free(str);
+       return device->class != 0;
+}
 
-       /* Services */
-       str = g_new0(char *, g_slist_length(device->services) + 1);
-       for (i = 0, l = device->services; l; l = l->next, i++)
-               str[i] = l->data;
-       dict_append_array(&dict, "Services", DBUS_TYPE_OBJECT_PATH, &str, i);
-       g_free(str);
+static gboolean dev_property_get_class(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
 
-       /* Adapter */
-       ptr = adapter_get_path(adapter);
-       dict_append_entry(&dict, "Adapter", DBUS_TYPE_OBJECT_PATH, &ptr);
+       if (device->class == 0)
+               return FALSE;
 
-       dbus_message_iter_close_container(&iter, &dict);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &device->class);
 
-       return reply;
+       return TRUE;
 }
 
-static DBusMessage *set_alias(DBusConnection *conn, DBusMessage *msg,
-                                       const char *alias, void *data)
+static gboolean get_appearance(const GDBusPropertyTable *property, void *data,
+                                                       uint16_t *appearance)
 {
        struct btd_device *device = data;
-       struct btd_adapter *adapter = device->adapter;
-       char srcaddr[18], dstaddr[18];
-       bdaddr_t src;
-       int err;
-
-       /* No change */
-       if ((device->alias == NULL && g_str_equal(alias, "")) ||
-                       g_strcmp0(device->alias, alias) == 0)
-               return dbus_message_new_method_return(msg);
 
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       ba2str(&device->bdaddr, dstaddr);
+       if (dev_property_exists_class(property, data))
+               return FALSE;
 
-       /* Remove alias if empty string */
-       err = write_device_alias(srcaddr, dstaddr,
-                       g_str_equal(alias, "") ? NULL : alias);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       if (device->appearance) {
+               *appearance = device->appearance;
+               return TRUE;
+       }
 
-       g_free(device->alias);
-       device->alias = g_str_equal(alias, "") ? NULL : g_strdup(alias);
+       return FALSE;
+}
 
-       emit_property_changed(conn, dbus_message_get_path(msg),
-                               DEVICE_INTERFACE, "Alias",
-                               DBUS_TYPE_STRING, &alias);
+static gboolean dev_property_exists_appearance(
+                       const GDBusPropertyTable *property, void *data)
+{
+       uint16_t appearance;
 
-       return dbus_message_new_method_return(msg);
+       return get_appearance(property, data, &appearance);
 }
 
-static DBusMessage *set_trust(DBusConnection *conn, DBusMessage *msg,
-                                       gboolean value, void *data)
+static gboolean dev_property_get_appearance(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct btd_device *device = data;
-       struct btd_adapter *adapter = device->adapter;
-       char srcaddr[18], dstaddr[18];
-       bdaddr_t src;
-       int err;
+       uint16_t appearance;
 
-       if (device->trusted == value)
-               return dbus_message_new_method_return(msg);
+       if (!get_appearance(property, data, &appearance))
+               return FALSE;
 
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       ba2str(&device->bdaddr, dstaddr);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT16, &appearance);
 
-       err = write_trust(srcaddr, dstaddr, GLOBAL_TRUST, value);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
+       return TRUE;
+}
 
-       device->trusted = value;
+static const char *get_icon(const GDBusPropertyTable *property, void *data)
+{
+       struct btd_device *device = data;
+       const char *icon = NULL;
+       uint16_t appearance;
 
-       emit_property_changed(conn, dbus_message_get_path(msg),
-                               DEVICE_INTERFACE, "Trusted",
-                               DBUS_TYPE_BOOLEAN, &value);
+       if (device->class != 0)
+               icon = class_to_icon(device->class);
+       else if (get_appearance(property, data, &appearance))
+               icon = gap_appearance_to_icon(appearance);
 
-       return dbus_message_new_method_return(msg);
+       return icon;
 }
 
-static void driver_remove(struct btd_device_driver *driver,
-                                               struct btd_device *device)
+static gboolean dev_property_exists_icon(
+                       const GDBusPropertyTable *property, void *data)
 {
-       driver->remove(device);
-
-       device->drivers = g_slist_remove(device->drivers, driver);
+       return get_icon(property, data) != NULL;
 }
 
-static gboolean do_disconnect(gpointer user_data)
+static gboolean dev_property_get_icon(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       struct btd_device *device = user_data;
+       const char *icon;
 
-       device->disconn_timer = 0;
+       icon = get_icon(property, data);
+       if (icon == NULL)
+               return FALSE;
 
-       btd_adapter_disconnect_device(device->adapter, &device->bdaddr,
-                                                       device->bdaddr_type);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &icon);
 
-       return FALSE;
+       return TRUE;
 }
 
-int device_block(DBusConnection *conn, struct btd_device *device,
-                                               gboolean update_only)
+static gboolean dev_property_get_paired(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       int err = 0;
-       bdaddr_t src;
+       struct btd_device *device = data;
+       gboolean val = device_is_paired(device);
 
-       if (device->blocked)
-               return 0;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
 
-       if (device->connected)
-               do_disconnect(device);
+       return TRUE;
+}
 
-       g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
+static gboolean dev_property_get_legacy(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       dbus_bool_t val = device->legacy;
 
-       if (!update_only)
-               err = btd_adapter_block_address(device->adapter,
-                                       &device->bdaddr, device->bdaddr_type);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
 
-       if (err < 0)
-               return err;
+       return TRUE;
+}
 
-       device->blocked = TRUE;
+static gboolean dev_property_get_rssi(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *dev = data;
+       dbus_int16_t val = dev->rssi;
 
-       adapter_get_address(device->adapter, &src);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_INT16, &val);
 
-       err = write_blocked(&src, &device->bdaddr, TRUE);
-       if (err < 0)
-               error("write_blocked(): %s (%d)", strerror(-err), -err);
+       return TRUE;
+}
 
-       device_set_temporary(device, FALSE);
+static gboolean dev_property_exists_rssi(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct btd_device *dev = data;
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Blocked",
-                                       DBUS_TYPE_BOOLEAN, &device->blocked);
+       if (dev->rssi == 0)
+               return FALSE;
 
-       return 0;
+       return TRUE;
 }
 
-int device_unblock(DBusConnection *conn, struct btd_device *device,
-                               gboolean silent, gboolean update_only)
+static gboolean dev_property_get_trusted(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
-       int err = 0;
-       bdaddr_t src;
+       struct btd_device *device = data;
+       gboolean val = device_is_trusted(device);
 
-       if (!device->blocked)
-               return 0;
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &val);
 
-       if (!update_only)
-               err = btd_adapter_unblock_address(device->adapter,
-                                       &device->bdaddr, device->bdaddr_type);
+       return TRUE;
+}
 
-       if (err < 0)
-               return err;
+static void set_trust(GDBusPendingPropertySet id, gboolean value, void *data)
+{
+       struct btd_device *device = data;
 
-       device->blocked = FALSE;
+       device_set_trusted(device, value);
 
-       adapter_get_address(device->adapter, &src);
+       g_dbus_pending_property_success(id);
+}
 
-       err = write_blocked(&src, &device->bdaddr, FALSE);
-       if (err < 0)
-               error("write_blocked(): %s (%d)", strerror(-err), -err);
+static void dev_property_set_trusted(const GDBusPropertyTable *property,
+                                       DBusMessageIter *value,
+                                       GDBusPendingPropertySet id, void *data)
+{
+       dbus_bool_t b;
 
-       if (!silent) {
-               emit_property_changed(conn, device->path,
-                                       DEVICE_INTERFACE, "Blocked",
-                                       DBUS_TYPE_BOOLEAN, &device->blocked);
-               device_probe_drivers(device, device->uuids);
+       if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
        }
 
-       return 0;
+       dbus_message_iter_get_basic(value, &b);
+
+       set_trust(id, b, data);
 }
 
-static DBusMessage *set_blocked(DBusConnection *conn, DBusMessage *msg,
-                                               gboolean value, void *data)
+static gboolean dev_property_get_blocked(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
 {
        struct btd_device *device = data;
-       int err;
 
-       if (value)
-               err = device_block(conn, device, FALSE);
-       else
-               err = device_unblock(conn, device, FALSE, FALSE);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+                                                       &device->blocked);
 
-       switch (-err) {
-       case 0:
-               return dbus_message_new_method_return(msg);
+       return TRUE;
+}
+
+static void set_blocked(GDBusPendingPropertySet id, gboolean value, void *data)
+{
+       struct btd_device *device = data;
+       int err;
+
+       if (value)
+               err = device_block(device, FALSE);
+       else
+               err = device_unblock(device, FALSE, FALSE);
+
+       switch (-err) {
+       case 0:
+               g_dbus_pending_property_success(id);
+               break;
        case EINVAL:
-               return btd_error_failed(msg, "Kernel lacks blacklist support");
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                       "Kernel lacks blacklist support");
+               break;
        default:
-               return btd_error_failed(msg, strerror(-err));
+               g_dbus_pending_property_error(id, ERROR_INTERFACE ".Failed",
+                                                       strerror(-err));
+               break;
        }
 }
 
-static DBusMessage *set_property(DBusConnection *conn,
-                               DBusMessage *msg, void *data)
+
+static void dev_property_set_blocked(const GDBusPropertyTable *property,
+                                       DBusMessageIter *value,
+                                       GDBusPendingPropertySet id, void *data)
 {
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       const char *property;
+       dbus_bool_t b;
 
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
+       if (dbus_message_iter_get_arg_type(value) != DBUS_TYPE_BOOLEAN) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
+       dbus_message_iter_get_basic(value, &b);
 
-       dbus_message_iter_get_basic(&iter, &property);
-       dbus_message_iter_next(&iter);
+       set_blocked(id, b, data);
+}
 
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-       dbus_message_iter_recurse(&iter, &sub);
+static gboolean dev_property_get_connected(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN,
+                                                       &device->connected);
+
+       return TRUE;
+}
+
+static gboolean dev_property_get_uuids(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       DBusMessageIter entry;
+       GSList *l;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                               DBUS_TYPE_STRING_AS_STRING, &entry);
+
+       if (device->svc_resolved)
+               l = device->uuids;
+       else if (device->eir_uuids)
+               l = device->eir_uuids;
+       else
+               l = device->uuids;
+
+       for (; l != NULL; l = l->next)
+               dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING,
+                                                       &l->data);
+
+       dbus_message_iter_close_container(iter, &entry);
+
+       return TRUE;
+}
+
+static gboolean dev_property_get_modalias(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+
+       if (!device->modalias)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING,
+                                                       &device->modalias);
+
+       return TRUE;
+}
 
-       if (g_str_equal("Trusted", property)) {
-               dbus_bool_t value;
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
-               dbus_message_iter_get_basic(&sub, &value);
+static gboolean dev_property_exists_modalias(const GDBusPropertyTable *property,
+                                                               void *data)
+{
+       struct btd_device *device = data;
+
+       return device->modalias ? TRUE : FALSE;
+}
+
+static gboolean dev_property_get_adapter(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct btd_device *device = data;
+       const char *str = adapter_get_path(device->adapter);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &str);
+
+       return TRUE;
+}
+
+static gboolean do_disconnect(gpointer user_data)
+{
+       struct btd_device *device = user_data;
+
+       device->disconn_timer = 0;
+
+       btd_adapter_disconnect_device(device->adapter, &device->bdaddr,
+                                                       device->bdaddr_type);
+
+       return FALSE;
+}
+
+int device_block(struct btd_device *device, gboolean update_only)
+{
+       int err = 0;
+
+       if (device->blocked)
+               return 0;
+
+       if (device->connected)
+               do_disconnect(device);
+
+       while (device->services != NULL) {
+               struct btd_service *service = device->services->data;
+
+               device->services = g_slist_remove(device->services, service);
+               service_remove(service);
+       }
+
+       if (!update_only)
+               err = btd_adapter_block_address(device->adapter,
+                                       &device->bdaddr, device->bdaddr_type);
+
+       if (err < 0)
+               return err;
+
+       device->blocked = TRUE;
+
+       store_device_info(device);
+
+       device_set_temporary(device, FALSE);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Blocked");
+
+       return 0;
+}
+
+int device_unblock(struct btd_device *device, gboolean silent,
+                                                       gboolean update_only)
+{
+       int err = 0;
 
-               return set_trust(conn, msg, value, data);
-       } else if (g_str_equal("Alias", property)) {
-               const char *alias;
+       if (!device->blocked)
+               return 0;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_STRING)
-                       return btd_error_invalid_args(msg);
-               dbus_message_iter_get_basic(&sub, &alias);
+       if (!update_only)
+               err = btd_adapter_unblock_address(device->adapter,
+                                       &device->bdaddr, device->bdaddr_type);
 
-               return set_alias(conn, msg, alias, data);
-       } else if (g_str_equal("Blocked", property)) {
-               dbus_bool_t value;
+       if (err < 0)
+               return err;
 
-               if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_BOOLEAN)
-                       return btd_error_invalid_args(msg);
+       device->blocked = FALSE;
 
-               dbus_message_iter_get_basic(&sub, &value);
+       store_device_info(device);
 
-               return set_blocked(conn, msg, value, data);
+       if (!silent) {
+               g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Blocked");
+               device_probe_profiles(device, device->uuids);
        }
 
-       return btd_error_invalid_args(msg);
+       return 0;
 }
 
 static void discover_services_req_exit(DBusConnection *conn, void *user_data)
@@ -670,232 +1045,741 @@ static void discover_services_req_exit(DBusConnection *conn, void *user_data)
        browse_request_cancel(req);
 }
 
-static DBusMessage *discover_services(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
+static void bonding_request_cancel(struct bonding_req *bonding)
+{
+       struct btd_device *device = bonding->device;
+       struct btd_adapter *adapter = device->adapter;
+
+       adapter_cancel_bonding(adapter, &device->bdaddr, device->bdaddr_type);
+}
+
+static void dev_disconn_service(gpointer a, gpointer b)
+{
+       btd_service_disconnect(a);
+}
+
+void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
+{
+       if (device->bonding)
+               bonding_request_cancel(device->bonding);
+
+       if (device->browse)
+               browse_request_cancel(device->browse);
+
+       if (device->connect) {
+               DBusMessage *reply = btd_error_failed(device->connect,
+                                                               "Cancelled");
+               g_dbus_send_message(dbus_conn, reply);
+               dbus_message_unref(device->connect);
+               device->connect = NULL;
+       }
+
+       if (device->connected && msg)
+               device->disconnects = g_slist_append(device->disconnects,
+                                               dbus_message_ref(msg));
+
+       if (device->disconn_timer)
+               return;
+
+       g_slist_foreach(device->services, dev_disconn_service, NULL);
+
+       g_slist_free(device->pending);
+       device->pending = NULL;
+
+       while (device->watches) {
+               struct btd_disconnect_data *data = device->watches->data;
+
+               if (data->watch)
+                       /* temporary is set if device is going to be removed */
+                       data->watch(device, device->temporary,
+                                                       data->user_data);
+
+               /* Check if the watch has been removed by callback function */
+               if (!g_slist_find(device->watches, data))
+                       continue;
+
+               device->watches = g_slist_remove(device->watches, data);
+               g_free(data);
+       }
+
+       if (!device->connected) {
+               g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID);
+               return;
+       }
+
+       device->disconn_timer = g_timeout_add_seconds(DISCONNECT_TIMER,
+                                               do_disconnect, device);
+}
+
+static DBusMessage *dev_disconnect(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
 {
        struct btd_device *device = user_data;
-       const char *pattern;
+
+       /*
+        * Disable connections through passive scanning until
+        * Device1.Connect is called
+        */
+       if (device->auto_connect)
+               device->disable_auto_connect = TRUE;
+
+       device_request_disconnect(device, msg);
+
+       return NULL;
+}
+
+static int connect_next(struct btd_device *dev)
+{
+       struct btd_service *service;
+       int err = -ENOENT;
+
+       while (dev->pending) {
+               service = dev->pending->data;
+
+               if (btd_service_connect(service) == 0)
+                       return 0;
+
+               dev->pending = g_slist_delete_link(dev->pending, dev->pending);
+       }
+
+       return err;
+}
+
+static void device_profile_connected(struct btd_device *dev,
+                                       struct btd_profile *profile, int err)
+{
+       struct btd_service *pending;
+       GSList *l;
+
+       DBG("%s %s (%d)", profile->name, strerror(-err), -err);
+
+       if (!err)
+               device_set_temporary(dev, FALSE);
+
+       if (dev->pending == NULL)
+               return;
+
+       if (!dev->connected && err == -EHOSTDOWN)
+               goto done;
+
+       pending = dev->pending->data;
+       l = find_service_with_profile(dev->pending, profile);
+       if (l != NULL)
+               dev->pending = g_slist_delete_link(dev->pending, l);
+
+       /* Only continue connecting the next profile if it matches the first
+        * pending, otherwise it will trigger another connect to the same
+        * profile
+        */
+       if (profile != btd_service_get_profile(pending))
+               return;
+
+       if (connect_next(dev) == 0)
+               return;
+
+done:
+       if (!dev->connect)
+               return;
+
+       if (!err && dbus_message_is_method_call(dev->connect, DEVICE_INTERFACE,
+                                                               "Connect"))
+               dev->general_connect = TRUE;
+
+       DBG("returning response to %s", dbus_message_get_sender(dev->connect));
+
+       l = find_service_with_state(dev->services, BTD_SERVICE_STATE_CONNECTED);
+
+       if (err && l == NULL)
+               g_dbus_send_message(dbus_conn,
+                               btd_error_failed(dev->connect, strerror(-err)));
+       else {
+               /* Start passive SDP discovery to update known services */
+               if (device_is_bredr(dev) && !dev->svc_refreshed)
+                       device_browse_sdp(dev, NULL);
+               g_dbus_send_reply(dbus_conn, dev->connect, DBUS_TYPE_INVALID);
+       }
+
+       g_slist_free(dev->pending);
+       dev->pending = NULL;
+
+       dbus_message_unref(dev->connect);
+       dev->connect = NULL;
+}
+
+void device_add_eir_uuids(struct btd_device *dev, GSList *uuids)
+{
+       GSList *l;
+       bool added = false;
+
+       if (dev->svc_resolved)
+               return;
+
+       for (l = uuids; l != NULL; l = l->next) {
+               const char *str = l->data;
+               if (g_slist_find_custom(dev->eir_uuids, str, bt_uuid_strcmp))
+                       continue;
+               added = true;
+               dev->eir_uuids = g_slist_append(dev->eir_uuids, g_strdup(str));
+       }
+
+       if (added)
+               g_dbus_emit_property_changed(dbus_conn, dev->path,
+                                               DEVICE_INTERFACE, "UUIDs");
+}
+
+static struct btd_service *find_connectable_service(struct btd_device *dev,
+                                                       const char *uuid)
+{
+       GSList *l;
+
+       for (l = dev->services; l != NULL; l = g_slist_next(l)) {
+               struct btd_service *service = l->data;
+               struct btd_profile *p = btd_service_get_profile(service);
+
+               if (!p->connect || !p->remote_uuid)
+                       continue;
+
+               if (strcasecmp(uuid, p->remote_uuid) == 0)
+                       return service;
+       }
+
+       return NULL;
+}
+
+static int service_prio_cmp(gconstpointer a, gconstpointer b)
+{
+       struct btd_profile *p1 = btd_service_get_profile(a);
+       struct btd_profile *p2 = btd_service_get_profile(b);
+
+       return p2->priority - p1->priority;
+}
+
+static GSList *create_pending_list(struct btd_device *dev, const char *uuid)
+{
+       struct btd_service *service;
+       struct btd_profile *p;
+       GSList *l;
+
+       if (uuid) {
+               service = find_connectable_service(dev, uuid);
+               if (service)
+                       return g_slist_prepend(dev->pending, service);
+
+               return dev->pending;
+       }
+
+       for (l = dev->services; l != NULL; l = g_slist_next(l)) {
+               service = l->data;
+               p = btd_service_get_profile(service);
+
+               if (!p->auto_connect)
+                       continue;
+
+               if (g_slist_find(dev->pending, service))
+                       continue;
+
+               if (btd_service_get_state(service) !=
+                                               BTD_SERVICE_STATE_DISCONNECTED)
+                       continue;
+
+               dev->pending = g_slist_insert_sorted(dev->pending, service,
+                                                       service_prio_cmp);
+       }
+
+       return dev->pending;
+}
+
+static DBusMessage *connect_profiles(struct btd_device *dev, DBusMessage *msg,
+                                                       const char *uuid)
+{
        int err;
 
-       if (device->browse)
+       DBG("%s %s, client %s", dev->path, uuid ? uuid : "(all)",
+                                               dbus_message_get_sender(msg));
+
+       if (dev->pending || dev->connect || dev->browse)
                return btd_error_in_progress(msg);
 
-       if (dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               return btd_error_invalid_args(msg);
+       device_set_temporary(dev, FALSE);
 
-       if (strlen(pattern) == 0) {
-               err = device_browse_sdp(device, conn, msg, NULL, FALSE);
-               if (err < 0)
-                       goto fail;
-       } else {
-               uuid_t uuid;
-
-               if (bt_string2uuid(&uuid, pattern) < 0)
-                       return btd_error_invalid_args(msg);
+       if (!dev->svc_resolved)
+               goto resolve_services;
 
-               sdp_uuid128_to_uuid(&uuid);
+       dev->pending = create_pending_list(dev, uuid);
+       if (!dev->pending) {
+               if (dev->svc_refreshed) {
+                       if (find_service_with_state(dev->services,
+                                               BTD_SERVICE_STATE_CONNECTED))
+                               return dbus_message_new_method_return(msg);
+                       else
+                               return btd_error_not_available(msg);
+               }
 
-               err = device_browse_sdp(device, conn, msg, &uuid, FALSE);
-               if (err < 0)
-                       goto fail;
+               goto resolve_services;
        }
 
+       err = connect_next(dev);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       dev->connect = dbus_message_ref(msg);
+
        return NULL;
 
-fail:
-       return btd_error_failed(msg, strerror(-err));
+resolve_services:
+       DBG("Resolving services for %s", dev->path);
+
+       if (device_is_bredr(dev))
+               err = device_browse_sdp(dev, msg);
+       else
+               err = device_browse_primary(dev, msg);
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return NULL;
 }
 
-static const char *browse_request_get_requestor(struct browse_req *req)
+static DBusMessage *dev_connect(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
 {
-       if (!req->msg)
+       struct btd_device *dev = user_data;
+
+       if (device_is_le(dev)) {
+               int err;
+
+               if (device_is_connected(dev))
+                       return dbus_message_new_method_return(msg);
+
+               device_set_temporary(dev, FALSE);
+
+               dev->disable_auto_connect = FALSE;
+
+               err = device_connect_le(dev);
+               if (err < 0)
+                       return btd_error_failed(msg, strerror(-err));
+
+               dev->connect = dbus_message_ref(msg);
+
                return NULL;
+       }
 
-       return dbus_message_get_sender(req->msg);
+       return connect_profiles(dev, msg, NULL);
 }
 
-static void iter_append_record(DBusMessageIter *dict, uint32_t handle,
-                                                       const char *record)
+static DBusMessage *connect_profile(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
 {
-       DBusMessageIter entry;
+       struct btd_device *dev = user_data;
+       const char *pattern;
+       char *uuid;
+       DBusMessage *reply;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       uuid = bt_name2string(pattern);
+       reply = connect_profiles(dev, msg, uuid);
+       g_free(uuid);
 
-       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-                                                       NULL, &entry);
+       return reply;
+}
 
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_UINT32, &handle);
+static void device_profile_disconnected(struct btd_device *dev,
+                                       struct btd_profile *profile, int err)
+{
+       if (!dev->disconnect)
+               return;
 
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &record);
+       if (err)
+               g_dbus_send_message(dbus_conn,
+                                       btd_error_failed(dev->disconnect,
+                                                       strerror(-err)));
+       else
+               g_dbus_send_reply(dbus_conn, dev->disconnect,
+                                                       DBUS_TYPE_INVALID);
 
-       dbus_message_iter_close_container(dict, &entry);
+       dbus_message_unref(dev->disconnect);
+       dev->disconnect = NULL;
 }
 
-static void discover_services_reply(struct browse_req *req, int err,
-                                                       sdp_list_t *recs)
+static DBusMessage *disconnect_profile(DBusConnection *conn, DBusMessage *msg,
+                                                       void *user_data)
+{
+       struct btd_device *dev = user_data;
+       struct btd_service *service;
+       const char *pattern;
+       char *uuid;
+       int err;
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       uuid = bt_name2string(pattern);
+       if (uuid == NULL)
+               return btd_error_invalid_args(msg);
+
+       service = find_connectable_service(dev, uuid);
+       g_free(uuid);
+
+       if (!service)
+               return btd_error_invalid_args(msg);
+
+       err = btd_service_disconnect(service);
+       if (err == 0) {
+               dev->disconnect = dbus_message_ref(msg);
+               return NULL;
+       }
+
+       if (err == -ENOTSUP)
+               return btd_error_not_supported(msg);
+
+       return btd_error_failed(msg, strerror(-err));
+}
+
+static void device_svc_resolved(struct btd_device *dev, int err)
 {
        DBusMessage *reply;
-       DBusMessageIter iter, dict;
-       sdp_list_t *seq;
+       struct browse_req *req = dev->browse;
 
-       if (err) {
-               const char *err_if;
+       DBG("%s err %d", dev->path, err);
 
-               if (err == -EHOSTDOWN)
-                       err_if = ERROR_INTERFACE ".ConnectionAttemptFailed";
-               else
-                       err_if = ERROR_INTERFACE ".Failed";
+       dev->svc_resolved = true;
+       dev->browse = NULL;
 
-               reply = dbus_message_new_error(req->msg, err_if,
-                                                       strerror(-err));
-               g_dbus_send_message(req->conn, reply);
+       /* Disconnection notification can happen before this function
+        * gets called, so don't set svc_refreshed for a disconnected
+        * device.
+        */
+       if (dev->connected)
+               dev->svc_refreshed = true;
+
+       g_slist_free_full(dev->eir_uuids, g_free);
+       dev->eir_uuids = NULL;
+
+       if (dev->pending_paired) {
+               g_dbus_emit_property_changed(dbus_conn, dev->path,
+                                               DEVICE_INTERFACE, "Paired");
+               dev->pending_paired = false;
+       }
+
+       while (dev->svc_callbacks) {
+               struct svc_callback *cb = dev->svc_callbacks->data;
+
+               if (cb->idle_id > 0)
+                       g_source_remove(cb->idle_id);
+
+               cb->func(dev, err, cb->user_data);
+
+               dev->svc_callbacks = g_slist_delete_link(dev->svc_callbacks,
+                                                       dev->svc_callbacks);
+               g_free(cb);
+       }
+
+       if (!req || !req->msg)
+               return;
+
+       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
+                                                               "Pair")) {
+               g_dbus_send_reply(dbus_conn, req->msg, DBUS_TYPE_INVALID);
                return;
        }
 
-       reply = dbus_message_new_method_return(req->msg);
-       if (!reply)
+       if (err) {
+               reply = btd_error_failed(req->msg, strerror(-err));
+               g_dbus_send_message(dbus_conn, reply);
                return;
+       }
 
-       dbus_message_iter_init_append(reply, &iter);
+       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE, "Connect"))
+               reply = dev_connect(dbus_conn, req->msg, dev);
+       else if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
+                                                       "ConnectProfile"))
+               reply = connect_profile(dbus_conn, req->msg, dev);
+       else
+               return;
 
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_UINT32_AS_STRING DBUS_TYPE_STRING_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+       dbus_message_unref(req->msg);
+       req->msg = NULL;
 
-       for (seq = recs; seq; seq = seq->next) {
-               sdp_record_t *rec = (sdp_record_t *) seq->data;
-               GString *result;
+       if (reply)
+               g_dbus_send_message(dbus_conn, reply);
+}
 
-               if (!rec)
-                       break;
+static struct bonding_req *bonding_request_new(DBusMessage *msg,
+                                               struct btd_device *device,
+                                               struct agent *agent)
+{
+       struct bonding_req *bonding;
+       char addr[18];
 
-               result = g_string_new(NULL);
+       ba2str(&device->bdaddr, addr);
+       DBG("Requesting bonding for %s", addr);
 
-               convert_sdp_record_to_xml(rec, result,
-                               (void *) g_string_append);
+       bonding = g_new0(struct bonding_req, 1);
 
-               if (result->len)
-                       iter_append_record(&dict, rec->handle, result->str);
+       bonding->msg = dbus_message_ref(msg);
 
-               g_string_free(result, TRUE);
-       }
+       bonding->cb_iter = btd_adapter_pin_cb_iter_new(device->adapter);
+
+       /* Marks the bonding start time for the first attempt on request
+        * construction. The following attempts will be updated on
+        * device_bonding_retry. */
+       clock_gettime(CLOCK_MONOTONIC, &bonding->attempt_start_time);
+
+       if (agent)
+               bonding->agent = agent_ref(agent);
 
-       dbus_message_iter_close_container(&iter, &dict);
+       return bonding;
+}
 
-       g_dbus_send_message(req->conn, reply);
+void device_bonding_restart_timer(struct btd_device *device)
+{
+       if (!device || !device->bonding)
+               return;
+
+       clock_gettime(CLOCK_MONOTONIC, &device->bonding->attempt_start_time);
 }
 
-static DBusMessage *cancel_discover(DBusConnection *conn,
-                                       DBusMessage *msg, void *user_data)
+static void bonding_request_stop_timer(struct bonding_req *bonding)
+{
+       struct timespec current;
+
+       clock_gettime(CLOCK_MONOTONIC, &current);
+
+       /* Compute the time difference in ms. */
+       bonding->last_attempt_duration_ms =
+               (current.tv_sec - bonding->attempt_start_time.tv_sec) * 1000L +
+               (current.tv_nsec - bonding->attempt_start_time.tv_nsec)
+                                                               / 1000000L;
+}
+
+/* Returns the duration of the last bonding attempt in milliseconds. The
+ * duration is measured starting from the latest of the following three
+ * events and finishing when the Command complete event is received for the
+ * authentication request:
+ *  - MGMT_OP_PAIR_DEVICE is sent,
+ *  - MGMT_OP_PIN_CODE_REPLY is sent and
+ *  - Command complete event is received for the sent MGMT_OP_PIN_CODE_REPLY.
+ */
+long device_bonding_last_duration(struct btd_device *device)
+{
+       struct bonding_req *bonding = device->bonding;
+
+       if (!bonding)
+               return 0;
+
+       return bonding->last_attempt_duration_ms;
+}
+
+static void create_bond_req_exit(DBusConnection *conn, void *user_data)
 {
        struct btd_device *device = user_data;
-       const char *sender = dbus_message_get_sender(msg);
-       const char *requestor;
+       char addr[18];
 
-       if (!device->browse)
-               return btd_error_does_not_exist(msg);
+       ba2str(&device->bdaddr, addr);
+       DBG("%s: requestor exited before bonding was completed", addr);
 
-       if (!dbus_message_is_method_call(device->browse->msg, DEVICE_INTERFACE,
-                                       "DiscoverServices"))
-               return btd_error_not_authorized(msg);
+       if (device->authr)
+               device_cancel_authentication(device, FALSE);
 
-       requestor = browse_request_get_requestor(device->browse);
+       if (device->bonding) {
+               device->bonding->listener_id = 0;
+               device_request_disconnect(device, NULL);
+       }
+}
 
-       /* only the discover requestor can cancel the inquiry process */
-       if (!requestor || !g_str_equal(requestor, sender))
-               return btd_error_not_authorized(msg);
+static DBusMessage *pair_device(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct btd_device *device = data;
+       struct btd_adapter *adapter = device->adapter;
+       const char *sender;
+       struct agent *agent;
+       struct bonding_req *bonding;
+       uint8_t io_cap;
+       int err;
 
-       discover_services_reply(device->browse, -ECANCELED, NULL);
+       device_set_temporary(device, FALSE);
 
-       browse_request_cancel(device->browse);
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
 
-       return dbus_message_new_method_return(msg);
+       if (device->bonding)
+               return btd_error_in_progress(msg);
+
+       if (device_is_bonded(device))
+               return btd_error_already_exists(msg);
+
+       sender = dbus_message_get_sender(msg);
+
+       agent = agent_get(sender);
+       if (agent)
+               io_cap = agent_get_io_capability(agent);
+       else
+               io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
+
+       bonding = bonding_request_new(msg, device, agent);
+
+       if (agent)
+               agent_unref(agent);
+
+       bonding->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
+                                               sender, create_bond_req_exit,
+                                               device, NULL);
+
+       device->bonding = bonding;
+       bonding->device = device;
+
+       /* Due to a bug in the kernel we might loose out on ATT commands
+        * that arrive during the SMP procedure, so connect the ATT
+        * channel first and only then start pairing (there's code for
+        * this in the ATT connect callback)
+        */
+       if (device_is_le(device) && !device_is_connected(device))
+               err = device_connect_le(device);
+       else
+               err = adapter_create_bonding(adapter, &device->bdaddr,
+                                               device->bdaddr_type, io_cap);
+
+       if (err < 0)
+               return btd_error_failed(msg, strerror(-err));
+
+       return NULL;
+}
+
+static DBusMessage *new_authentication_return(DBusMessage *msg, uint8_t status)
+{
+       switch (status) {
+       case MGMT_STATUS_SUCCESS:
+               return dbus_message_new_method_return(msg);
+
+       case MGMT_STATUS_CONNECT_FAILED:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".ConnectionAttemptFailed",
+                               "Page Timeout");
+       case MGMT_STATUS_TIMEOUT:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".AuthenticationTimeout",
+                               "Authentication Timeout");
+       case MGMT_STATUS_BUSY:
+       case MGMT_STATUS_REJECTED:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".AuthenticationRejected",
+                               "Authentication Rejected");
+       case MGMT_STATUS_CANCELLED:
+       case MGMT_STATUS_NO_RESOURCES:
+       case MGMT_STATUS_DISCONNECTED:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".AuthenticationCanceled",
+                               "Authentication Canceled");
+       default:
+               return dbus_message_new_error(msg,
+                               ERROR_INTERFACE ".AuthenticationFailed",
+                               "Authentication Failed");
+       }
 }
 
-static void bonding_request_cancel(struct bonding_req *bonding)
+static void bonding_request_free(struct bonding_req *bonding)
 {
-       struct btd_device *device = bonding->device;
-       struct btd_adapter *adapter = device->adapter;
+       if (!bonding)
+               return;
 
-       adapter_cancel_bonding(adapter, &device->bdaddr);
-}
+       if (bonding->listener_id)
+               g_dbus_remove_watch(dbus_conn, bonding->listener_id);
 
-void device_request_disconnect(struct btd_device *device, DBusMessage *msg)
-{
-       DBusConnection *conn = get_dbus_connection();
+       if (bonding->msg)
+               dbus_message_unref(bonding->msg);
 
-       if (device->bonding)
-               bonding_request_cancel(device->bonding);
+       if (bonding->cb_iter)
+               g_free(bonding->cb_iter);
 
-       if (device->browse) {
-               discover_services_reply(device->browse, -ECANCELED, NULL);
-               browse_request_cancel(device->browse);
+       if (bonding->agent) {
+               agent_cancel(bonding->agent);
+               agent_unref(bonding->agent);
+               bonding->agent = NULL;
        }
 
-       if (msg)
-               device->disconnects = g_slist_append(device->disconnects,
-                                               dbus_message_ref(msg));
+       if (bonding->retry_timer)
+               g_source_remove(bonding->retry_timer);
 
-       if (device->disconn_timer)
-               return;
+       if (bonding->device)
+               bonding->device->bonding = NULL;
 
-       while (device->watches) {
-               struct btd_disconnect_data *data = device->watches->data;
+       g_free(bonding);
+}
 
-               if (data->watch)
-                       /* temporary is set if device is going to be removed */
-                       data->watch(device, device->temporary,
-                                                       data->user_data);
+static void device_cancel_bonding(struct btd_device *device, uint8_t status)
+{
+       struct bonding_req *bonding = device->bonding;
+       DBusMessage *reply;
+       char addr[18];
 
-               /* Check if the watch has been removed by callback function */
-               if (!g_slist_find(device->watches, data))
-                       continue;
+       if (!bonding)
+               return;
 
-               device->watches = g_slist_remove(device->watches, data);
-               g_free(data);
-       }
+       ba2str(&device->bdaddr, addr);
+       DBG("Canceling bonding request for %s", addr);
 
-       device->disconn_timer = g_timeout_add_seconds(DISCONNECT_TIMER,
-                                               do_disconnect, device);
+       if (device->authr)
+               device_cancel_authentication(device, FALSE);
 
-       g_dbus_emit_signal(conn, device->path,
-                       DEVICE_INTERFACE, "DisconnectRequested",
-                       DBUS_TYPE_INVALID);
+       reply = new_authentication_return(bonding->msg, status);
+       g_dbus_send_message(dbus_conn, reply);
+
+       bonding_request_cancel(bonding);
+       bonding_request_free(bonding);
 }
 
-static DBusMessage *disconnect(DBusConnection *conn, DBusMessage *msg,
-                                                       void *user_data)
+static DBusMessage *cancel_pairing(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
 {
-       struct btd_device *device = user_data;
+       struct btd_device *device = data;
+       struct bonding_req *req = device->bonding;
 
-       if (!device->connected)
-               return btd_error_not_connected(msg);
+       DBG("");
 
-       device_request_disconnect(device, msg);
+       if (!req)
+               return btd_error_does_not_exist(msg);
 
-       return NULL;
+       device_cancel_bonding(device, MGMT_STATUS_CANCELLED);
+
+       return dbus_message_new_method_return(msg);
 }
 
 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) },
+       { GDBUS_ASYNC_METHOD("Disconnect", NULL, NULL, dev_disconnect) },
+       { GDBUS_ASYNC_METHOD("Connect", NULL, NULL, dev_connect) },
+       { GDBUS_ASYNC_METHOD("ConnectProfile", GDBUS_ARGS({ "UUID", "s" }),
+                                               NULL, connect_profile) },
+       { GDBUS_ASYNC_METHOD("DisconnectProfile", GDBUS_ARGS({ "UUID", "s" }),
+                                               NULL, disconnect_profile) },
+       { GDBUS_ASYNC_METHOD("Pair", NULL, NULL, pair_device) },
+       { GDBUS_METHOD("CancelPairing", NULL, NULL, cancel_pairing) },
        { }
 };
 
-static const GDBusSignalTable device_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-       { GDBUS_SIGNAL("DisconnectRequested", NULL) },
+static const GDBusPropertyTable device_properties[] = {
+       { "Address", "s", dev_property_get_address },
+       { "Name", "s", dev_property_get_name, NULL, dev_property_exists_name },
+       { "Alias", "s", dev_property_get_alias, dev_property_set_alias },
+       { "Class", "u", dev_property_get_class, NULL,
+                                       dev_property_exists_class },
+       { "Appearance", "q", dev_property_get_appearance, NULL,
+                                       dev_property_exists_appearance },
+       { "Icon", "s", dev_property_get_icon, NULL,
+                                       dev_property_exists_icon },
+       { "Paired", "b", dev_property_get_paired },
+       { "Trusted", "b", dev_property_get_trusted, dev_property_set_trusted },
+       { "Blocked", "b", dev_property_get_blocked, dev_property_set_blocked },
+       { "LegacyPairing", "b", dev_property_get_legacy },
+       { "RSSI", "n", dev_property_get_rssi, NULL, dev_property_exists_rssi },
+       { "Connected", "b", dev_property_get_connected },
+       { "UUIDs", "as", dev_property_get_uuids },
+       { "Modalias", "s", dev_property_get_modalias, NULL,
+                                               dev_property_exists_modalias },
+       { "Adapter", "o", dev_property_get_adapter },
        { }
 };
 
@@ -904,7 +1788,7 @@ gboolean device_is_connected(struct btd_device *device)
        return device->connected;
 }
 
-void device_add_connection(struct btd_device *device, DBusConnection *conn)
+void device_add_connection(struct btd_device *device)
 {
        if (device->connected) {
                char addr[18];
@@ -915,12 +1799,11 @@ void device_add_connection(struct btd_device *device, DBusConnection *conn)
 
        device->connected = TRUE;
 
-       emit_property_changed(conn, device->path,
-                                       DEVICE_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &device->connected);
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Connected");
 }
 
-void device_remove_connection(struct btd_device *device, DBusConnection *conn)
+void device_remove_connection(struct btd_device *device)
 {
        if (!device->connected) {
                char addr[18];
@@ -930,6 +1813,8 @@ void device_remove_connection(struct btd_device *device, DBusConnection *conn)
        }
 
        device->connected = FALSE;
+       device->general_connect = FALSE;
+       device->svc_refreshed = false;
 
        if (device->disconn_timer > 0) {
                g_source_remove(device->disconn_timer);
@@ -939,16 +1824,16 @@ void device_remove_connection(struct btd_device *device, DBusConnection *conn)
        while (device->disconnects) {
                DBusMessage *msg = device->disconnects->data;
 
-               g_dbus_send_reply(conn, msg, DBUS_TYPE_INVALID);
+               g_dbus_send_reply(dbus_conn, msg, DBUS_TYPE_INVALID);
                device->disconnects = g_slist_remove(device->disconnects, msg);
+               dbus_message_unref(msg);
        }
 
        if (device_is_paired(device) && !device_is_bonded(device))
                device_set_paired(device, FALSE);
 
-       emit_property_changed(conn, device->path,
-                                       DEVICE_INTERFACE, "Connected",
-                                       DBUS_TYPE_BOOLEAN, &device->connected);
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Connected");
 }
 
 guint device_add_disconnect_watch(struct btd_device *device,
@@ -987,68 +1872,268 @@ void device_remove_disconnect_watch(struct btd_device *device, guint id)
        }
 }
 
-static void device_set_vendor(struct btd_device *device, uint16_t value)
+static char *load_cached_name(struct btd_device *device, const char *local,
+                               const char *peer)
 {
-       DBusConnection *conn = get_dbus_connection();
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char *str = NULL;
+       int len;
 
-       if (device->vendor == value)
-               return;
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+
+       if (!g_key_file_load_from_file(key_file, filename, 0, NULL))
+               goto failed;
+
+       str = g_key_file_get_string(key_file, "General", "Name", NULL);
+       if (str) {
+               len = strlen(str);
+               if (len > HCI_MAX_NAME_LENGTH)
+                       str[HCI_MAX_NAME_LENGTH] = '\0';
+       }
 
-       device->vendor = value;
+failed:
+       g_key_file_free(key_file);
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Vendor",
-                               DBUS_TYPE_UINT16, &value);
+       return str;
 }
 
-static void device_set_vendor_src(struct btd_device *device, uint16_t value)
+static void load_info(struct btd_device *device, const char *local,
+                       const char *peer, GKeyFile *key_file)
 {
-       DBusConnection *conn = get_dbus_connection();
+       char *str;
+       gboolean store_needed = FALSE;
+       gboolean blocked;
+       char **uuids;
+       int source, vendor, product, version;
+       char **techno, **t;
+       gboolean bredr = FALSE;
+       gboolean le = FALSE;
 
-       if (device->vendor_src == value)
-               return;
+       /* Load device name from storage info file, if that fails fall back to
+        * the cache.
+        */
+       str = g_key_file_get_string(key_file, "General", "Name", NULL);
+       if (str == NULL) {
+               str = load_cached_name(device, local, peer);
+               if (str)
+                       store_needed = TRUE;
+       }
 
-       device->vendor_src = value;
+       if (str) {
+               strcpy(device->name, str);
+               g_free(str);
+       }
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE,
-                               "VendorSource", DBUS_TYPE_UINT16, &value);
-}
+       /* Load alias */
+       device->alias = g_key_file_get_string(key_file, "General", "Alias",
+                                                                       NULL);
 
-static void device_set_product(struct btd_device *device, uint16_t value)
-{
-       DBusConnection *conn = get_dbus_connection();
+       /* Load class */
+       str = g_key_file_get_string(key_file, "General", "Class", NULL);
+       if (str) {
+               uint32_t class;
 
-       if (device->product == value)
-               return;
+               if (sscanf(str, "%x", &class) == 1)
+                       device->class = class;
+               g_free(str);
+       }
+
+       /* Load appearance */
+       str = g_key_file_get_string(key_file, "General", "Appearance", NULL);
+       if (str) {
+               device->appearance = strtol(str, NULL, 16);
+               g_free(str);
+       }
+
+       /* Load device technology */
+       techno = g_key_file_get_string_list(key_file, "General",
+                                       "SupportedTechnologies", NULL, NULL);
+       if (!techno)
+               goto next;
+
+       for (t = techno; *t; t++) {
+               if (g_str_equal(*t, "BR/EDR"))
+                       bredr = TRUE;
+               else if (g_str_equal(*t, "LE"))
+                       le = TRUE;
+               else
+                       error("Unknown device technology");
+       }
+
+       if (bredr && le) {
+               /* TODO: Add correct type for dual mode device */
+       } else if (bredr) {
+               device->bdaddr_type = BDADDR_BREDR;
+       } else if (le) {
+               str = g_key_file_get_string(key_file, "General",
+                                               "AddressType", NULL);
+
+               if (str && g_str_equal(str, "public"))
+                       device->bdaddr_type = BDADDR_LE_PUBLIC;
+               else if (str && g_str_equal(str, "static"))
+                       device->bdaddr_type = BDADDR_LE_RANDOM;
+               else
+                       error("Unknown LE device technology");
+
+               g_free(str);
+       }
+
+       g_strfreev(techno);
+
+next:
+       /* Load trust */
+       device->trusted = g_key_file_get_boolean(key_file, "General",
+                                                       "Trusted", NULL);
+
+       /* Load device blocked */
+       blocked = g_key_file_get_boolean(key_file, "General", "Blocked", NULL);
+       if (blocked)
+               device_block(device, FALSE);
+
+       /* Load device profile list */
+       uuids = g_key_file_get_string_list(key_file, "General", "Services",
+                                               NULL, NULL);
+       if (uuids) {
+               char **uuid;
+
+               for (uuid = uuids; *uuid; uuid++) {
+                       GSList *match;
+
+                       match = g_slist_find_custom(device->uuids, *uuid,
+                                                       bt_uuid_strcmp);
+                       if (match)
+                               continue;
+
+                       device->uuids = g_slist_insert_sorted(device->uuids,
+                                                               g_strdup(*uuid),
+                                                               bt_uuid_strcmp);
+               }
+               g_strfreev(uuids);
+
+               /* Discovered services restored from storage */
+               device->svc_resolved = true;
+       }
+
+       /* Load device id */
+       source = g_key_file_get_integer(key_file, "DeviceID", "Source", NULL);
+       if (source) {
+               vendor = g_key_file_get_integer(key_file, "DeviceID",
+                                                       "Vendor", NULL);
 
-       device->product = value;
+               product = g_key_file_get_integer(key_file, "DeviceID",
+                                                       "Product", NULL);
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Product",
-                               DBUS_TYPE_UINT16, &value);
+               version = g_key_file_get_integer(key_file, "DeviceID",
+                                                       "Version", NULL);
+
+               btd_device_set_pnpid(device, source, vendor, product, version);
+       }
+
+       if (store_needed)
+               store_device_info(device);
 }
 
-static void device_set_version(struct btd_device *device, uint16_t value)
+static void load_att_info(struct btd_device *device, const char *local,
+                               const char *peer)
 {
-       DBusConnection *conn = get_dbus_connection();
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char *prim_uuid, *str;
+       char **groups, **handle, *service_uuid;
+       struct gatt_primary *prim;
+       uuid_t uuid;
+       char tmp[3];
+       int i;
 
-       if (device->version == value)
-               return;
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", local,
+                       peer);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       groups = g_key_file_get_groups(key_file, NULL);
+
+       for (handle = groups; *handle; handle++) {
+               gboolean uuid_ok;
+               int end;
+
+               str = g_key_file_get_string(key_file, *handle, "UUID", NULL);
+               if (!str)
+                       continue;
+
+               uuid_ok = g_str_equal(str, prim_uuid);
+               g_free(str);
+
+               if (!uuid_ok)
+                       continue;
+
+               str = g_key_file_get_string(key_file, *handle, "Value", NULL);
+               if (!str)
+                       continue;
 
-       device->version = value;
+               end = g_key_file_get_integer(key_file, *handle,
+                                               "EndGroupHandle", NULL);
+               if (end == 0) {
+                       g_free(str);
+                       continue;
+               }
+
+               prim = g_new0(struct gatt_primary, 1);
+               prim->range.start = atoi(*handle);
+               prim->range.end = end;
+
+               switch (strlen(str)) {
+               case 4:
+                       uuid.type = SDP_UUID16;
+                       sscanf(str, "%04hx", &uuid.value.uuid16);
+               break;
+               case 8:
+                       uuid.type = SDP_UUID32;
+                       sscanf(str, "%08x", &uuid.value.uuid32);
+                       break;
+               case 32:
+                       uuid.type = SDP_UUID128;
+                       memset(tmp, 0, sizeof(tmp));
+                       for (i = 0; i < 16; i++) {
+                               memcpy(tmp, str + (i * 2), 2);
+                               uuid.value.uuid128.data[i] =
+                                               (uint8_t) strtol(tmp, NULL, 16);
+                       }
+                       break;
+               default:
+                       g_free(str);
+                       g_free(prim);
+                       continue;
+               }
+
+               service_uuid = bt_uuid2string(&uuid);
+               memcpy(prim->uuid, service_uuid, MAX_LEN_UUID_STR);
+               g_free(service_uuid);
+               g_free(str);
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Version",
-                               DBUS_TYPE_UINT16, &value);
+               device->primaries = g_slist_append(device->primaries, prim);
+       }
+
+       g_strfreev(groups);
+       g_key_file_free(key_file);
+       g_free(prim_uuid);
 }
 
-struct btd_device *device_create(DBusConnection *conn,
-                               struct btd_adapter *adapter,
-                               const gchar *address, uint8_t bdaddr_type)
+static struct btd_device *device_new(struct btd_adapter *adapter,
+                               const char *address)
 {
-       gchar *address_up;
+       char *address_up;
        struct btd_device *device;
-       const gchar *adapter_path = adapter_get_path(adapter);
-       bdaddr_t src;
-       char srcaddr[18], alias[MAX_NAME_LENGTH + 1];
-       uint16_t vendor, product, version;
+       const char *adapter_path = adapter_get_path(adapter);
+
+       DBG("address %s", address);
 
        device = g_try_malloc0(sizeof(struct btd_device));
        if (device == NULL)
@@ -1061,66 +2146,112 @@ struct btd_device *device_create(DBusConnection *conn,
 
        DBG("Creating device %s", device->path);
 
-       if (g_dbus_register_interface(conn, device->path, DEVICE_INTERFACE,
-                               device_methods, device_signals, NULL,
-                               device, device_free) == FALSE) {
+       if (g_dbus_register_interface(dbus_conn,
+                                       device->path, DEVICE_INTERFACE,
+                                       device_methods, NULL,
+                                       device_properties, device,
+                                       device_free) == FALSE) {
+               error("Unable to register device interface for %s", address);
                device_free(device);
                return NULL;
        }
 
        str2ba(address, &device->bdaddr);
        device->adapter = adapter;
-       device->bdaddr_type = bdaddr_type;
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       read_device_name(srcaddr, address, device->name);
-       if (read_device_alias(srcaddr, address, alias, sizeof(alias)) == 0)
-               device->alias = g_strdup(alias);
-       device->trusted = read_trust(&src, address, GLOBAL_TRUST);
 
-       if (read_blocked(&src, &device->bdaddr))
-               device_block(conn, device, FALSE);
+       return btd_device_ref(device);
+}
 
-       if (read_link_key(&src, &device->bdaddr, NULL, NULL) == 0) {
-               device_set_paired(device, TRUE);
-               device_set_bonded(device, TRUE);
-       }
+struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
+                               const char *address, GKeyFile *key_file)
+{
+       struct btd_device *device;
+       const bdaddr_t *src;
+       char srcaddr[18];
+
+       DBG("address %s", address);
+
+       device = device_new(adapter, address);
+       if (device == NULL)
+               return NULL;
+
+       src = adapter_get_address(adapter);
+       ba2str(src, srcaddr);
+
+       load_info(device, srcaddr, address, key_file);
+       load_att_info(device, srcaddr, address);
+
+       return device;
+}
+
+struct btd_device *device_create(struct btd_adapter *adapter,
+                               const bdaddr_t *bdaddr, uint8_t bdaddr_type)
+{
+       struct btd_device *device;
+       const bdaddr_t *sba;
+       char src[18], dst[18];
+       char *str;
+
+       ba2str(bdaddr, dst);
+       DBG("dst %s", dst);
+
+       device = device_new(adapter, dst);
+       if (device == NULL)
+               return NULL;
+
+       device->bdaddr_type = bdaddr_type;
+       sba = adapter_get_address(adapter);
+       ba2str(sba, src);
 
-       if (device_is_le(device) && has_longtermkeys(&src, &device->bdaddr,
-                                                       device->bdaddr_type)) {
-               device_set_paired(device, TRUE);
-               device_set_bonded(device, TRUE);
+       str = load_cached_name(device, src, dst);
+       if (str) {
+               strcpy(device->name, str);
+               g_free(str);
        }
 
-       if (read_device_id(srcaddr, address, NULL, &vendor, &product, &version)
-                                                                       == 0) {
-               device_set_vendor(device, vendor);
-               device_set_product(device, product);
-               device_set_version(device, version);
+       return device;
+}
+
+char *btd_device_get_storage_path(struct btd_device *device,
+                               const char *filename)
+{
+       char srcaddr[18], dstaddr[18];
+
+       if (device_address_is_private(device)) {
+               warn("Refusing storage path for private addressed device %s",
+                                                               device->path);
+               return NULL;
        }
 
-       return btd_device_ref(device);
+       ba2str(adapter_get_address(device->adapter), srcaddr);
+       ba2str(&device->bdaddr, dstaddr);
+
+       if (!filename)
+               return g_strdup_printf(STORAGEDIR "/%s/%s", srcaddr, dstaddr);
+
+       return g_strdup_printf(STORAGEDIR "/%s/%s/%s", srcaddr, dstaddr,
+                                                       filename);
 }
 
 void device_set_name(struct btd_device *device, const char *name)
 {
-       DBusConnection *conn = get_dbus_connection();
-
        if (strncmp(name, device->name, MAX_NAME_LENGTH) == 0)
                return;
 
+       DBG("%s %s", device->path, name);
+
        strncpy(device->name, name, MAX_NAME_LENGTH);
 
-       emit_property_changed(conn, device->path,
-                               DEVICE_INTERFACE, "Name",
-                               DBUS_TYPE_STRING, &name);
+       store_device_info(device);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Name");
 
        if (device->alias != NULL)
                return;
 
-       emit_property_changed(conn, device->path,
-                               DEVICE_INTERFACE, "Alias",
-                               DBUS_TYPE_STRING, &name);
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Alias");
 }
 
 void device_get_name(struct btd_device *device, char *name, size_t len)
@@ -1128,6 +2259,31 @@ void device_get_name(struct btd_device *device, char *name, size_t len)
        strncpy(name, device->name, len);
 }
 
+bool device_name_known(struct btd_device *device)
+{
+       return device->name[0] != '\0';
+}
+
+void device_set_class(struct btd_device *device, uint32_t class)
+{
+       if (device->class == class)
+               return;
+
+       DBG("%s 0x%06X", device->path, class);
+
+       device->class = class;
+
+       store_device_info(device);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Class");
+}
+
+uint32_t btd_device_get_class(struct btd_device *device)
+{
+       return device->class;
+}
+
 uint16_t btd_device_get_vendor(struct btd_device *device)
 {
        return device->vendor;
@@ -1148,88 +2304,144 @@ uint16_t btd_device_get_version(struct btd_device *device)
        return device->version;
 }
 
-static void device_remove_stored(struct btd_device *device)
+static void delete_folder_tree(const char *dirname)
 {
-       bdaddr_t src;
-       char key[20];
-       DBusConnection *conn = get_dbus_connection();
+       DIR *dir;
+       struct dirent *entry;
+       char filename[PATH_MAX + 1];
 
-       adapter_get_address(device->adapter, &src);
-       ba2str(&device->bdaddr, key);
+       dir = opendir(dirname);
+       if (dir == NULL)
+               return;
 
-       /* key: address only */
-       delete_entry(&src, "profiles", key);
-       delete_entry(&src, "trusts", key);
+       while ((entry = readdir(dir)) != NULL) {
+               if (g_str_equal(entry->d_name, ".") ||
+                               g_str_equal(entry->d_name, ".."))
+                       continue;
 
-       if (device_is_bonded(device)) {
-               delete_entry(&src, "linkkeys", key);
-               delete_entry(&src, "aliases", key);
+               snprintf(filename, PATH_MAX, "%s/%s", dirname, entry->d_name);
+               filename[PATH_MAX] = '\0';
 
-               /* key: address#type */
-               sprintf(&key[17], "#%hhu", device->bdaddr_type);
+               if (entry->d_type == DT_DIR)
+                       delete_folder_tree(filename);
+               else
+                       unlink(filename);
+       }
+       closedir(dir);
+
+       rmdir(dirname);
+}
 
-               delete_entry(&src, "longtermkeys", key);
+static void device_remove_stored(struct btd_device *device)
+{
+       const bdaddr_t *src = adapter_get_address(device->adapter);
+       uint8_t dst_type = device->bdaddr_type;
+       char adapter_addr[18];
+       char device_addr[18];
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char *data;
+       gsize length = 0;
 
+       if (device_is_bonded(device)) {
                device_set_bonded(device, FALSE);
                device->paired = FALSE;
                btd_adapter_remove_bonding(device->adapter, &device->bdaddr,
-                                                       device->bdaddr_type);
+                                                               dst_type);
        }
 
-       delete_all_records(&src, &device->bdaddr);
-       delete_device_service(&src, &device->bdaddr, device->bdaddr_type);
-
        if (device->blocked)
-               device_unblock(conn, device, TRUE, FALSE);
+               device_unblock(device, TRUE, FALSE);
+
+       ba2str(src, adapter_addr);
+       ba2str(&device->bdaddr, device_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s", adapter_addr,
+                       device_addr);
+       filename[PATH_MAX] = '\0';
+       delete_folder_tree(filename);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", adapter_addr,
+                       device_addr);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       g_key_file_remove_group(key_file, "ServiceRecords", NULL);
+
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
+       }
+
+       g_free(data);
+       g_key_file_free(key_file);
 }
 
 void device_remove(struct btd_device *device, gboolean remove_stored)
 {
-
        DBG("Removing device %s", device->path);
 
-       if (device->agent)
-               agent_free(device->agent);
-
        if (device->bonding) {
                uint8_t status;
 
                if (device->connected)
-                       status = HCI_OE_USER_ENDED_CONNECTION;
+                       status = MGMT_STATUS_DISCONNECTED;
                else
-                       status = HCI_PAGE_TIMEOUT;
+                       status = MGMT_STATUS_CONNECT_FAILED;
 
                device_cancel_bonding(device, status);
        }
 
-       if (device->browse) {
-               discover_services_reply(device->browse, -ECANCELED, NULL);
+       if (device->browse)
                browse_request_cancel(device->browse);
+
+       while (device->services != NULL) {
+               struct btd_service *service = device->services->data;
+
+               device->services = g_slist_remove(device->services, service);
+               service_remove(service);
        }
 
+       g_slist_free(device->pending);
+       device->pending = NULL;
+
        if (device->connected)
                do_disconnect(device);
 
-       if (remove_stored)
-               device_remove_stored(device);
+       if (device->store_id > 0) {
+               g_source_remove(device->store_id);
+               device->store_id = 0;
 
-       g_slist_foreach(device->drivers, (GFunc) driver_remove, device);
-       g_slist_free(device->drivers);
-       device->drivers = NULL;
+               if (!remove_stored)
+                       store_device_info_cb(device);
+       }
 
-       attrib_client_unregister(device->services);
+       if (remove_stored)
+               device_remove_stored(device);
 
        btd_device_unref(device);
 }
 
-gint device_address_cmp(struct btd_device *device, const gchar *address)
+int device_address_cmp(gconstpointer a, gconstpointer b)
 {
+       const struct btd_device *device = a;
+       const char *address = b;
        char addr[18];
 
        ba2str(&device->bdaddr, addr);
        return strcasecmp(addr, address);
 }
 
+int device_bdaddr_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct btd_device *device = a;
+       const bdaddr_t *bdaddr = b;
+
+       return bacmp(&device->bdaddr, bdaddr);
+}
+
 static gboolean record_has_uuid(const sdp_record_t *rec,
                                const char *profile_uuid)
 {
@@ -1254,179 +2466,201 @@ static gboolean record_has_uuid(const sdp_record_t *rec,
        return FALSE;
 }
 
-static GSList *device_match_pattern(struct btd_device *device,
-                                       const char *match_uuid,
-                                       GSList *profiles)
+GSList *device_get_uuids(struct btd_device *device)
 {
-       GSList *l, *uuids = NULL;
-
-       for (l = profiles; l; l = l->next) {
-               char *profile_uuid = l->data;
-               const sdp_record_t *rec;
+       return device->uuids;
+}
 
-               rec = btd_device_get_record(device, profile_uuid);
-               if (!rec)
-                       continue;
+static bool device_match_profile(struct btd_device *device,
+                                       struct btd_profile *profile,
+                                       GSList *uuids)
+{
+       if (profile->remote_uuid == NULL)
+               return false;
 
-               if (record_has_uuid(rec, match_uuid))
-                       uuids = g_slist_append(uuids, profile_uuid);
-       }
+       if (g_slist_find_custom(uuids, profile->remote_uuid,
+                                                       bt_uuid_strcmp) == NULL)
+               return false;
 
-       return uuids;
+       return true;
 }
 
-static GSList *device_match_driver(struct btd_device *device,
-                                       struct btd_device_driver *driver,
-                                       GSList *profiles)
+struct probe_data {
+       struct btd_device *dev;
+       GSList *uuids;
+       char addr[18];
+};
+
+static void dev_probe(struct btd_profile *p, void *user_data)
 {
-       const char **uuid;
-       GSList *uuids = NULL;
+       struct probe_data *d = user_data;
+       struct btd_service *service;
 
-       for (uuid = driver->uuids; *uuid; uuid++) {
-               GSList *match;
+       if (p->device_probe == NULL)
+               return;
 
-               /* skip duplicated uuids */
-               if (g_slist_find_custom(uuids, *uuid,
-                               (GCompareFunc) strcasecmp))
-                       continue;
+       if (!device_match_profile(d->dev, p, d->uuids))
+               return;
 
-               /* match profile driver */
-               match = g_slist_find_custom(profiles, *uuid,
-                                       (GCompareFunc) strcasecmp);
-               if (match) {
-                       uuids = g_slist_append(uuids, match->data);
-                       continue;
-               }
+       service = service_create(d->dev, p);
 
-               /* match pattern driver */
-               match = device_match_pattern(device, *uuid, profiles);
-               uuids = g_slist_concat(uuids, match);
+       if (service_probe(service) < 0) {
+               btd_service_unref(service);
+               return;
        }
 
-       return uuids;
+       d->dev->services = g_slist_append(d->dev->services, service);
 }
 
-void device_probe_drivers(struct btd_device *device, GSList *profiles)
+void device_probe_profile(gpointer a, gpointer b)
 {
-       GSList *list;
-       char addr[18];
-       int err;
+       struct btd_device *device = a;
+       struct btd_profile *profile = b;
+       struct btd_service *service;
 
-       ba2str(&device->bdaddr, addr);
+       if (profile->device_probe == NULL)
+               return;
 
-       if (device->blocked) {
-               DBG("Skipping drivers for blocked device %s", addr);
-               goto add_uuids;
+       if (!device_match_profile(device, profile, device->uuids))
+               return;
+
+       service = service_create(device, profile);
+
+       if (service_probe(service) < 0) {
+               btd_service_unref(service);
+               return;
        }
 
-       DBG("Probing drivers for %s", addr);
+       device->services = g_slist_append(device->services, service);
+
+       if (!profile->auto_connect || !device->general_connect)
+               return;
 
-       for (list = device_drivers; list; list = list->next) {
-               struct btd_device_driver *driver = list->data;
-               GSList *probe_uuids;
+       device->pending = g_slist_append(device->pending, service);
 
-               probe_uuids = device_match_driver(device, driver, profiles);
+       if (g_slist_length(device->pending) == 1)
+               connect_next(device);
+}
 
-               if (!probe_uuids)
-                       continue;
+void device_remove_profile(gpointer a, gpointer b)
+{
+       struct btd_device *device = a;
+       struct btd_profile *profile = b;
+       struct btd_service *service;
+       GSList *l;
+
+       l = find_service_with_profile(device->services, profile);
+       if (l == NULL)
+               return;
+
+       service = l->data;
+       device->services = g_slist_delete_link(device->services, l);
+       device->pending = g_slist_remove(device->pending, service);
+       service_remove(service);
+}
+
+void device_probe_profiles(struct btd_device *device, GSList *uuids)
+{
+       struct probe_data d = { device, uuids };
+       GSList *l;
 
-               err = driver->probe(device, probe_uuids);
-               if (err < 0) {
-                       error("%s driver probe failed for device %s",
-                                                       driver->name, addr);
-                       g_slist_free(probe_uuids);
-                       continue;
-               }
+       ba2str(&device->bdaddr, d.addr);
 
-               device->drivers = g_slist_append(device->drivers, driver);
-               g_slist_free(probe_uuids);
+       if (device->blocked) {
+               DBG("Skipping profiles for blocked device %s", d.addr);
+               goto add_uuids;
        }
 
+       DBG("Probing profiles for device %s", d.addr);
+
+       btd_profile_foreach(dev_probe, &d);
+
 add_uuids:
-       for (list = profiles; list; list = list->next) {
-               GSList *l = g_slist_find_custom(device->uuids, list->data,
-                                               (GCompareFunc) strcasecmp);
-               if (l)
+       for (l = uuids; l != NULL; l = g_slist_next(l)) {
+               GSList *match = g_slist_find_custom(device->uuids, l->data,
+                                                       bt_uuid_strcmp);
+               if (match)
                        continue;
 
                device->uuids = g_slist_insert_sorted(device->uuids,
-                                               g_strdup(list->data),
-                                               (GCompareFunc) strcasecmp);
+                                               g_strdup(l->data),
+                                               bt_uuid_strcmp);
        }
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "UUIDs");
 }
 
-static void device_remove_drivers(struct btd_device *device, GSList *uuids)
+static void store_sdp_record(GKeyFile *key_file, sdp_record_t *rec)
 {
-       struct btd_adapter *adapter = device_get_adapter(device);
-       GSList *list, *next;
-       char srcaddr[18], dstaddr[18];
-       bdaddr_t src;
-       sdp_list_t *records;
-
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
-       ba2str(&device->bdaddr, dstaddr);
+       char handle_str[11];
+       sdp_buf_t buf;
+       int size, i;
+       char *str;
 
-       records = read_records(&src, &device->bdaddr);
+       sprintf(handle_str, "0x%8.8X", rec->handle);
 
-       DBG("Removing drivers for %s", dstaddr);
+       if (sdp_gen_record_pdu(rec, &buf) < 0)
+               return;
 
-       for (list = device->drivers; list; list = next) {
-               struct btd_device_driver *driver = list->data;
-               const char **uuid;
+       size = buf.data_size;
 
-               next = list->next;
+       str = g_malloc0(size*2+1);
 
-               for (uuid = driver->uuids; *uuid; uuid++) {
-                       if (!g_slist_find_custom(uuids, *uuid,
-                                               (GCompareFunc) strcasecmp))
-                               continue;
+       for (i = 0; i < size; i++)
+               sprintf(str + (i * 2), "%02X", buf.data[i]);
 
-                       DBG("UUID %s was removed from device %s",
-                                                       *uuid, dstaddr);
+       g_key_file_set_string(key_file, "ServiceRecords", handle_str, str);
 
-                       driver->remove(device);
-                       device->drivers = g_slist_remove(device->drivers,
-                                                               driver);
-                       break;
-               }
-       }
+       free(buf.data);
+       g_free(str);
+}
 
-       for (list = uuids; list; list = list->next) {
-               sdp_record_t *rec;
+static void store_primaries_from_sdp_record(GKeyFile *key_file,
+                                               sdp_record_t *rec)
+{
+       uuid_t uuid;
+       char *att_uuid, *prim_uuid;
+       uint16_t start = 0, end = 0, psm = 0;
+       char handle[6], uuid_str[33];
+       int i;
 
-               device->uuids = g_slist_remove(device->uuids, list->data);
+       sdp_uuid16_create(&uuid, ATT_UUID);
+       att_uuid = bt_uuid2string(&uuid);
 
-               rec = find_record_in_list(records, list->data);
-               if (!rec)
-                       continue;
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
 
-               delete_record(srcaddr, dstaddr, rec->handle);
+       if (!record_has_uuid(rec, att_uuid))
+               goto done;
 
-               records = sdp_list_remove(records, rec);
-               sdp_record_free(rec);
+       if (!gatt_parse_record(rec, &uuid, &psm, &start, &end))
+               goto done;
 
+       sprintf(handle, "%hu", start);
+       switch (uuid.type) {
+       case SDP_UUID16:
+               sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+               break;
+       case SDP_UUID32:
+               sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+               break;
+       case SDP_UUID128:
+               for (i = 0; i < 16; i++)
+                       sprintf(uuid_str + (i * 2), "%2.2X",
+                                       uuid.value.uuid128.data[i]);
+               break;
+       default:
+               uuid_str[0] = '\0';
        }
 
-       if (records)
-               sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
-}
-
-static void services_changed(struct btd_device *device)
-{
-       DBusConnection *conn = get_dbus_connection();
-       char **uuids;
-       GSList *l;
-       int i;
-
-       uuids = g_new0(char *, g_slist_length(device->uuids) + 1);
-       for (i = 0, l = device->uuids; l; l = l->next, i++)
-               uuids[i] = l->data;
+       g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
+       g_key_file_set_string(key_file, handle, "Value", uuid_str);
+       g_key_file_set_integer(key_file, handle, "EndGroupHandle", end);
 
-       emit_array_property_changed(conn, device->path, DEVICE_INTERFACE,
-                                       "UUIDs", DBUS_TYPE_STRING, &uuids, i);
-
-       g_free(uuids);
+done:
+       g_free(prim_uuid);
+       g_free(att_uuid);
 }
 
 static int rec_cmp(const void *a, const void *b)
@@ -1437,23 +2671,67 @@ static int rec_cmp(const void *a, const void *b)
        return r1->handle - r2->handle;
 }
 
-static void update_services(struct browse_req *req, sdp_list_t *recs)
+static int update_record(struct browse_req *req, const char *uuid,
+                                                       sdp_record_t *rec)
+{
+       GSList *l;
+
+       /* Check for duplicates */
+       if (sdp_list_find(req->records, rec, rec_cmp))
+               return -EALREADY;
+
+       /* Copy record */
+       req->records = sdp_list_append(req->records, sdp_copy_record(rec));
+
+       /* Check if UUID is duplicated */
+       l = g_slist_find_custom(req->device->uuids, uuid, bt_uuid_strcmp);
+       if (l == NULL) {
+               l = g_slist_find_custom(req->profiles_added, uuid,
+                                                       bt_uuid_strcmp);
+               if (l != NULL)
+                       return 0;
+               req->profiles_added = g_slist_append(req->profiles_added,
+                                                       g_strdup(uuid));
+       }
+
+       return 0;
+}
+
+static void update_bredr_services(struct browse_req *req, sdp_list_t *recs)
 {
        struct btd_device *device = req->device;
-       struct btd_adapter *adapter = device_get_adapter(device);
        sdp_list_t *seq;
        char srcaddr[18], dstaddr[18];
-       bdaddr_t src;
-
-       adapter_get_address(adapter, &src);
-       ba2str(&src, srcaddr);
+       char sdp_file[PATH_MAX + 1];
+       char att_file[PATH_MAX + 1];
+       GKeyFile *sdp_key_file = NULL;
+       GKeyFile *att_key_file = NULL;
+       char *data;
+       gsize length = 0;
+
+       ba2str(adapter_get_address(device->adapter), srcaddr);
        ba2str(&device->bdaddr, dstaddr);
 
+       if (!device->temporary) {
+               snprintf(sdp_file, PATH_MAX, STORAGEDIR "/%s/cache/%s",
+                                                       srcaddr, dstaddr);
+               sdp_file[PATH_MAX] = '\0';
+
+               sdp_key_file = g_key_file_new();
+               g_key_file_load_from_file(sdp_key_file, sdp_file, 0, NULL);
+
+               snprintf(att_file, PATH_MAX, STORAGEDIR "/%s/%s/attributes",
+                                                       srcaddr, dstaddr);
+               att_file[PATH_MAX] = '\0';
+
+               att_key_file = g_key_file_new();
+               g_key_file_load_from_file(att_key_file, att_file, 0, NULL);
+       }
+
        for (seq = recs; seq; seq = seq->next) {
                sdp_record_t *rec = (sdp_record_t *) seq->data;
                sdp_list_t *svcclass = NULL;
-               gchar *profile_uuid;
-               GSList *l;
+               char *profile_uuid;
 
                if (!rec)
                        break;
@@ -1474,7 +2752,7 @@ static void update_services(struct browse_req *req, sdp_list_t *recs)
                        continue;
                }
 
-               if (!strcasecmp(profile_uuid, PNP_UUID)) {
+               if (bt_uuid_strcmp(profile_uuid, PNP_UUID) == 0) {
                        uint16_t source, vendor, product, version;
                        sdp_data_t *pdlist;
 
@@ -1484,86 +2762,83 @@ static void update_services(struct browse_req *req, sdp_list_t *recs)
                        pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
                        vendor = pdlist ? pdlist->val.uint16 : 0x0000;
 
-                       device_set_vendor(device, vendor);
-
                        pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
                        product = pdlist ? pdlist->val.uint16 : 0x0000;
 
-                       device_set_product(device, product);
-
                        pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
                        version = pdlist ? pdlist->val.uint16 : 0x0000;
 
-                       device_set_version(device, version);
-
                        if (source || vendor || product || version)
-                               store_device_id(srcaddr, dstaddr, source,
-                                               vendor, product, version);
+                               btd_device_set_pnpid(device, source, vendor,
+                                                       product, version);
                }
 
-               /* Check for duplicates */
-               if (sdp_list_find(req->records, rec, rec_cmp)) {
-                       g_free(profile_uuid);
-                       sdp_list_free(svcclass, free);
-                       continue;
-               }
-
-               store_record(srcaddr, dstaddr, rec);
+               if (update_record(req, profile_uuid, rec) < 0)
+                       goto next;
 
-               /* Copy record */
-               req->records = sdp_list_append(req->records,
-                                                       sdp_copy_record(rec));
+               if (sdp_key_file)
+                       store_sdp_record(sdp_key_file, rec);
 
-               l = g_slist_find_custom(device->uuids, profile_uuid,
-                                                       (GCompareFunc) strcmp);
-               if (!l)
-                       req->profiles_added =
-                                       g_slist_append(req->profiles_added,
-                                                       profile_uuid);
-               else {
-                       req->profiles_removed =
-                                       g_slist_remove(req->profiles_removed,
-                                                       l->data);
-                       g_free(profile_uuid);
-               }
+               if (att_key_file)
+                       store_primaries_from_sdp_record(att_key_file, rec);
 
+next:
+               g_free(profile_uuid);
                sdp_list_free(svcclass, free);
        }
-}
 
-static void store_profiles(struct btd_device *device)
-{
-       struct btd_adapter *adapter = device->adapter;
-       bdaddr_t src;
-       char *str;
+       if (sdp_key_file) {
+               data = g_key_file_to_data(sdp_key_file, &length, NULL);
+               if (length > 0) {
+                       create_file(sdp_file, S_IRUSR | S_IWUSR);
+                       g_file_set_contents(sdp_file, data, length, NULL);
+               }
+
+               g_free(data);
+               g_key_file_free(sdp_key_file);
+       }
 
-       adapter_get_address(adapter, &src);
+       if (att_key_file) {
+               data = g_key_file_to_data(att_key_file, &length, NULL);
+               if (length > 0) {
+                       create_file(att_file, S_IRUSR | S_IWUSR);
+                       g_file_set_contents(att_file, data, length, NULL);
+               }
 
-       if (!device->uuids) {
-               write_device_profiles(&src, &device->bdaddr, "");
-               return;
+               g_free(data);
+               g_key_file_free(att_key_file);
        }
+}
 
-       str = bt_list2string(device->uuids);
-       write_device_profiles(&src, &device->bdaddr, str);
-       g_free(str);
+static int primary_cmp(gconstpointer a, gconstpointer b)
+{
+       return memcmp(a, b, sizeof(struct gatt_primary));
 }
 
-static void create_device_reply(struct btd_device *device, struct browse_req *req)
+static void update_gatt_services(struct browse_req *req, GSList *current,
+                                                               GSList *found)
 {
-       DBusMessage *reply;
+       GSList *l, *lmatch;
 
-       reply = dbus_message_new_method_return(req->msg);
-       if (!reply)
-               return;
+       /* Added Profiles */
+       for (l = found; l; l = g_slist_next(l)) {
+               struct gatt_primary *prim = l->data;
+
+               /* Entry found ? */
+               lmatch = g_slist_find_custom(current, prim, primary_cmp);
+               if (lmatch)
+                       continue;
 
-       dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &device->path,
-                                       DBUS_TYPE_INVALID);
+               /* New entry */
+               req->profiles_added = g_slist_append(req->profiles_added,
+                                                       g_strdup(prim->uuid));
 
-       g_dbus_send_message(req->conn, reply);
+               DBG("UUID Added: %s", prim->uuid);
+       }
 }
 
-GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
+static GSList *device_services_from_record(struct btd_device *device,
+                                                       GSList *profiles)
 {
        GSList *l, *prim_list = NULL;
        char *att_uuid;
@@ -1602,10 +2877,17 @@ GSList *device_services_from_record(struct btd_device *device, GSList *profiles)
        return prim_list;
 }
 
+static void device_register_primaries(struct btd_device *device,
+                                               GSList *prim_list, int psm)
+{
+       device->primaries = g_slist_concat(device->primaries, prim_list);
+}
+
 static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
 {
        struct browse_req *req = user_data;
        struct btd_device *device = req->device;
+       GSList *primaries;
        char addr[18];
 
        ba2str(&device->bdaddr, addr);
@@ -1616,7 +2898,7 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
                goto send_reply;
        }
 
-       update_services(req, recs);
+       update_bredr_services(req, recs);
 
        if (device->tmp_records)
                sdp_list_free(device->tmp_records,
@@ -1625,64 +2907,27 @@ static void search_cb(sdp_list_t *recs, int err, gpointer user_data)
        device->tmp_records = req->records;
        req->records = NULL;
 
-       if (!req->profiles_added && !req->profiles_removed) {
+       if (!req->profiles_added) {
                DBG("%s: No service update", addr);
                goto send_reply;
        }
 
-       /* Probe matching drivers for services added */
-       if (req->profiles_added) {
-               GSList *list;
-
-               list = device_services_from_record(device, req->profiles_added);
-               if (list)
-                       device_register_services(req->conn, device, list,
-                                                               ATT_PSM);
+       primaries = device_services_from_record(device, req->profiles_added);
+       if (primaries)
+               device_register_primaries(device, primaries, ATT_PSM);
 
-               device_probe_drivers(device, req->profiles_added);
-       }
-
-       /* Remove drivers for services removed */
-       if (req->profiles_removed)
-               device_remove_drivers(device, req->profiles_removed);
+       device_probe_profiles(device, req->profiles_added);
 
        /* Propagate services changes */
-       services_changed(req->device);
+       g_dbus_emit_property_changed(dbus_conn, req->device->path,
+                                               DEVICE_INTERFACE, "UUIDs");
 
 send_reply:
-       if (!req->msg)
-               goto cleanup;
-
-       if (dbus_message_is_method_call(req->msg, DEVICE_INTERFACE,
-                                       "DiscoverServices"))
-               discover_services_reply(req, err, device->tmp_records);
-       else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE,
-                                               "CreatePairedDevice"))
-               create_device_reply(device, req);
-       else if (dbus_message_is_method_call(req->msg, ADAPTER_INTERFACE,
-                                               "CreateDevice")) {
-               if (err < 0) {
-                       DBusMessage *reply;
-                       reply = btd_error_failed(req->msg, strerror(-err));
-                       g_dbus_send_message(req->conn, reply);
-                       goto cleanup;
-               }
-
-               create_device_reply(device, req);
-               device_set_temporary(device, FALSE);
-       }
+       device_svc_resolved(device, err);
 
-cleanup:
-       if (!device->temporary) {
-               bdaddr_t sba, dba;
-
-               adapter_get_address(device->adapter, &sba);
-               device_get_address(device, &dba, NULL);
-
-               store_profiles(device);
-       }
+       if (!device->temporary)
+               store_device_info(device);
 
-       device->browse = NULL;
        browse_request_free(req);
 }
 
@@ -1691,7 +2936,6 @@ static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
        struct browse_req *req = user_data;
        struct btd_device *device = req->device;
        struct btd_adapter *adapter = device->adapter;
-       bdaddr_t src;
        uuid_t uuid;
 
        /* If we have a valid response and req->search_uuid == 2, then L2CAP
@@ -1704,14 +2948,13 @@ static void browse_cb(sdp_list_t *recs, int err, gpointer user_data)
                        goto done;
        }
 
-       update_services(req, recs);
-
-       adapter_get_address(adapter, &src);
+       update_bredr_services(req, recs);
 
        /* Search for mandatory uuids */
        if (uuid_list[req->search_uuid]) {
                sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
-               bt_search_service(&src, &device->bdaddr, &uuid,
+               bt_search_service(adapter_get_address(adapter),
+                                               &device->bdaddr, &uuid,
                                                browse_cb, user_data, NULL);
                return;
        }
@@ -1720,56 +2963,87 @@ done:
        search_cb(recs, err, user_data);
 }
 
-static void init_browse(struct browse_req *req, gboolean reverse)
+static void store_services(struct btd_device *device)
 {
+       struct btd_adapter *adapter = device->adapter;
+       char filename[PATH_MAX + 1];
+       char src_addr[18], dst_addr[18];
+       uuid_t uuid;
+       char *prim_uuid;
+       GKeyFile *key_file;
        GSList *l;
+       char *data;
+       gsize length = 0;
 
-       /* If we are doing reverse-SDP don't try to detect removed profiles
-        * since some devices hide their service records while they are
-        * connected
-        */
-       if (reverse)
+       if (device_address_is_private(device)) {
+               warn("Can't store services for private addressed device %s",
+                                                               device->path);
                return;
+       }
 
-       for (l = req->device->uuids; l; l = l->next)
-               req->profiles_removed = g_slist_append(req->profiles_removed,
-                                               l->data);
-}
+       sdp_uuid16_create(&uuid, GATT_PRIM_SVC_UUID);
+       prim_uuid = bt_uuid2string(&uuid);
+       if (prim_uuid == NULL)
+               return;
 
-static char *primary_list_to_string(GSList *primary_list)
-{
-       GString *services;
-       GSList *l;
+       ba2str(adapter_get_address(adapter), src_addr);
+       ba2str(&device->bdaddr, dst_addr);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/%s/attributes", src_addr,
+                                                               dst_addr);
+       filename[PATH_MAX] = '\0';
 
-       services = g_string_new(NULL);
+       key_file = g_key_file_new();
 
-       for (l = primary_list; l; l = l->next) {
+       for (l = device->primaries; l; l = l->next) {
                struct gatt_primary *primary = l->data;
-               char service[64];
+               char handle[6], uuid_str[33];
+               int i;
 
-               memset(service, 0, sizeof(service));
+               sprintf(handle, "%hu", primary->range.start);
 
-               snprintf(service, sizeof(service), "%04X#%04X#%s ",
-                               primary->range.start, primary->range.end, primary->uuid);
+               bt_string2uuid(&uuid, primary->uuid);
+               sdp_uuid128_to_uuid(&uuid);
+
+               switch (uuid.type) {
+               case SDP_UUID16:
+                       sprintf(uuid_str, "%4.4X", uuid.value.uuid16);
+                       break;
+               case SDP_UUID32:
+                       sprintf(uuid_str, "%8.8X", uuid.value.uuid32);
+                       break;
+               case SDP_UUID128:
+                       for (i = 0; i < 16; i++)
+                               sprintf(uuid_str + (i * 2), "%2.2X",
+                                               uuid.value.uuid128.data[i]);
+                       break;
+               default:
+                       uuid_str[0] = '\0';
+               }
+
+               g_key_file_set_string(key_file, handle, "UUID", prim_uuid);
+               g_key_file_set_string(key_file, handle, "Value", uuid_str);
+               g_key_file_set_integer(key_file, handle, "EndGroupHandle",
+                                       primary->range.end);
+       }
 
-               services = g_string_append(services, service);
+       data = g_key_file_to_data(key_file, &length, NULL);
+       if (length > 0) {
+               create_file(filename, S_IRUSR | S_IWUSR);
+               g_file_set_contents(filename, data, length, NULL);
        }
 
-       return g_string_free(services, FALSE);
+       g_free(prim_uuid);
+       g_free(data);
+       g_key_file_free(key_file);
 }
 
-static void store_services(struct btd_device *device)
+static bool device_get_auto_connect(struct btd_device *device)
 {
-       struct btd_adapter *adapter = device->adapter;
-       bdaddr_t dba, sba;
-       char *str = primary_list_to_string(device->primaries);
-
-       adapter_get_address(adapter, &sba);
-       device_get_address(device, &dba, NULL);
-
-       write_device_services(&sba, &dba, device->bdaddr_type, str);
+       if (device->disable_auto_connect)
+               return false;
 
-       g_free(str);
+       return device->auto_connect;
 }
 
 static void attio_connected(gpointer data, gpointer user_data)
@@ -1789,15 +3063,6 @@ static void attio_disconnected(gpointer data, gpointer user_data)
                attio->dcfunc(attio->user_data);
 }
 
-static void att_connect_dispatched(gpointer user_data)
-{
-       struct btd_device *device = user_data;
-
-       device->auto_id = 0;
-}
-
-static gboolean att_connect(gpointer user_data);
-
 static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
                                                        gpointer user_data)
 {
@@ -1812,122 +3077,165 @@ static gboolean attrib_disconnected_cb(GIOChannel *io, GIOCondition cond,
        len = sizeof(err);
        getsockopt(sock, SOL_SOCKET, SO_ERROR, &err, &len);
 
+       DBG("%s (%d)", strerror(err), err);
+
        g_slist_foreach(device->attios, attio_disconnected, NULL);
 
-       if (device->auto_connect == FALSE || err != ETIMEDOUT)
+       if (!device_get_auto_connect(device)) {
+               DBG("Automatic connection disabled");
                goto done;
+       }
 
-       device->auto_id = g_timeout_add_seconds_full(G_PRIORITY_DEFAULT_IDLE,
-                                               AUTO_CONNECTION_INTERVAL,
-                                               att_connect, device,
-                                               att_connect_dispatched);
+       /*
+        * Keep scanning/re-connection active if disconnection reason
+        * is connection timeout, remote user terminated connection or local
+        * initiated disconnection.
+        */
+       if (err == ETIMEDOUT || err == ECONNRESET || err == ECONNABORTED)
+               adapter_connect_list_add(device->adapter, device);
 
 done:
-       att_cleanup(device);
+       attio_cleanup(device);
 
        return FALSE;
 }
 
-static void appearance_cb(guint8 status, const guint8 *pdu, guint16 plen,
-                                                       gpointer user_data)
+static void register_all_services(struct browse_req *req, GSList *services)
 {
-       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;
+       struct btd_device *device = req->device;
+
+       device_set_temporary(device, FALSE);
+
+       update_gatt_services(req, device->primaries, services);
+       g_slist_free_full(device->primaries, g_free);
+       device->primaries = NULL;
+
+       device_register_primaries(device, g_slist_copy(services), -1);
+
+       device_probe_profiles(device, req->profiles_added);
+
+       if (device->attios == NULL && device->attios_offline == NULL)
+               attio_cleanup(device);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "UUIDs");
+
+       device_svc_resolved(device, 0);
+
+       store_services(device);
+
+       browse_request_free(req);
+}
+
+static int service_by_range_cmp(gconstpointer a, gconstpointer b)
+{
+       const struct gatt_primary *prim = a;
+       const struct att_range *range = b;
+
+       return memcmp(&prim->range, range, sizeof(*range));
+}
+
+static void find_included_cb(GSList *includes, uint8_t status,
+                                               gpointer user_data)
+{
+       struct included_search *search = user_data;
+       struct btd_device *device = search->req->device;
+       struct gatt_primary *prim;
+       GSList *l;
+
+       if (device->attrib == NULL) {
+               error("Disconnected while doing included discovery");
+               g_slist_free(search->services);
+               g_free(search);
+               return;
+       }
 
        if (status != 0) {
-               DBG("Read characteristics by UUID failed: %s\n",
-                                                       att_ecode2str(status));
+               error("Find included services failed: %s (%d)",
+                                       att_ecode2str(status), status);
                goto done;
        }
 
-       list = dec_read_by_type_resp(pdu, plen);
-       if (list == NULL)
+       if (includes == NULL)
                goto done;
 
-       if (list->len != 4) {
-               DBG("Appearance value: invalid data");
-               goto done;
-       }
+       for (l = includes; l; l = l->next) {
+               struct gatt_included *incl = l->data;
+
+               if (g_slist_find_custom(search->services, &incl->range,
+                                               service_by_range_cmp))
+                       continue;
 
-       /* A device shall have only one instance of the
-       Appearance characteristic. */
-       atval = list->data[0] + 2; /* skip handle value */
-       app = att_get_u16(atval);
+               prim = g_new0(struct gatt_primary, 1);
+               memcpy(prim->uuid, incl->uuid, sizeof(prim->uuid));
+               memcpy(&prim->range, &incl->range, sizeof(prim->range));
 
-       adapter_get_address(adapter, &src);
-       write_remote_appearance(&src, &device->bdaddr, device->bdaddr_type,
-                                                                       app);
+               search->services = g_slist_append(search->services, prim);
+       }
 
 done:
-       att_data_list_free(list);
-       if (device->attios == NULL && device->attios_offline == NULL)
-               att_cleanup(device);
+       search->current = search->current->next;
+       if (search->current == NULL) {
+               register_all_services(search->req, search->services);
+               g_slist_free(search->services);
+               g_free(search);
+               return;
+       }
+
+       prim = search->current->data;
+       gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+                                       find_included_cb, search);
+}
+
+static void find_included_services(struct browse_req *req, GSList *services)
+{
+       struct btd_device *device = req->device;
+       struct included_search *search;
+       struct gatt_primary *prim;
+
+       if (services == NULL)
+               return;
+
+       search = g_new0(struct included_search, 1);
+       search->req = req;
+       search->services = g_slist_copy(services);
+       search->current = search->services;
+
+       prim = search->current->data;
+       gatt_find_included(device->attrib, prim->range.start, prim->range.end,
+                                       find_included_cb, search);
 }
 
 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;
 
        if (status) {
+               struct btd_device *device = req->device;
+
                if (req->msg) {
                        DBusMessage *reply;
                        reply = btd_error_failed(req->msg,
                                                        att_ecode2str(status));
-                       g_dbus_send_message(req->conn, reply);
+                       g_dbus_send_message(dbus_conn, reply);
                }
-               goto done;
-       }
-
-       device_set_temporary(device, FALSE);
-
-       for (l = services; l; l = l->next) {
-               struct gatt_primary *prim = l->data;
-
-               if (strcmp(prim->uuid, GAP_SVC_UUID) == 0)
-                       gap_prim = prim;
 
-               uuids = g_slist_append(uuids, prim->uuid);
+               device->browse = NULL;
+               browse_request_free(req);
+               return;
        }
 
-       device_register_services(req->conn, device, g_slist_copy(services), -1);
-       device_probe_drivers(device, uuids);
-
-       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);
-       if (req->msg)
-               create_device_reply(device, req);
-
-       store_services(device);
-
-done:
-       device->browse = NULL;
-       browse_request_free(req);
+       find_included_services(req, services);
 }
 
 static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 {
        struct att_callbacks *attcb = user_data;
        struct btd_device *device = attcb->user_data;
+       DBusMessage *reply;
+       uint8_t io_cap;
        GAttrib *attrib;
+       int err = 0;
 
        g_io_channel_unref(device->att_io);
        device->att_io = NULL;
@@ -1938,6 +3246,7 @@ static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
                if (attcb->error)
                        attcb->error(gerr, user_data);
 
+               err = -ECONNABORTED;
                goto done;
        }
 
@@ -1952,7 +3261,40 @@ static void att_connect_cb(GIOChannel *io, GError *gerr, gpointer user_data)
 
        if (attcb->success)
                attcb->success(user_data);
+
+       if (!device->bonding)
+               goto done;
+
+       if (device->bonding->agent)
+               io_cap = agent_get_io_capability(device->bonding->agent);
+       else
+               io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
+
+       err = adapter_create_bonding(device->adapter, &device->bdaddr,
+                                       device->bdaddr_type, io_cap);
 done:
+       if (device->bonding && err < 0) {
+               reply = btd_error_failed(device->bonding->msg, strerror(-err));
+               g_dbus_send_message(dbus_conn, reply);
+               bonding_request_cancel(device->bonding);
+               bonding_request_free(device->bonding);
+       }
+
+       if (device->connect) {
+               if (!device->svc_resolved)
+                       device_browse_primary(device, NULL);
+
+               if (err < 0)
+                       reply = btd_error_failed(device->connect,
+                                                       strerror(-err));
+               else
+                       reply = dbus_message_new_method_return(device->connect);
+
+               g_dbus_send_message(dbus_conn, reply);
+               dbus_message_unref(device->connect);
+               device->connect = NULL;
+       }
+
        g_free(attcb);
 }
 
@@ -1961,15 +3303,13 @@ 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)
+       if (g_error_matches(gerr, BT_IO_ERROR, ECONNABORTED))
                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");
+       if (device_get_auto_connect(device)) {
+               DBG("Enabling automatic connections");
+               adapter_connect_list_add(device->adapter, device);
+       }
 }
 
 static void att_success_cb(gpointer user_data)
@@ -1980,58 +3320,76 @@ static void att_success_cb(gpointer user_data)
        if (device->attios == NULL)
                return;
 
+       /*
+        * Remove the device from the connect_list and give the passive
+        * scanning another chance to be restarted in case there are
+        * other devices in the connect_list.
+        */
+       adapter_connect_list_remove(device->adapter, device);
+
        g_slist_foreach(device->attios, attio_connected, device->attrib);
 }
 
-static gboolean att_connect(gpointer user_data)
+int device_connect_le(struct btd_device *dev)
 {
-       struct btd_device *device = user_data;
-       struct btd_adapter *adapter = device->adapter;
+       struct btd_adapter *adapter = dev->adapter;
        struct att_callbacks *attcb;
+       BtIOSecLevel sec_level;
        GIOChannel *io;
        GError *gerr = NULL;
        char addr[18];
-       bdaddr_t sba;
 
-       adapter_get_address(adapter, &sba);
-       ba2str(&device->bdaddr, addr);
+       /* There is one connection attempt going on */
+       if (dev->att_io)
+               return -EALREADY;
+
+       ba2str(&dev->bdaddr, addr);
 
        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;
+       attcb->user_data = dev;
 
-       if (device_is_bredr(device)) {
-               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_PSM, ATT_PSM,
-                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_MEDIUM,
-                                       BT_IO_OPT_INVALID);
-       } else {
-               io = bt_io_connect(BT_IO_L2CAP, att_connect_cb,
-                               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 (dev->paired)
+               sec_level = BT_IO_SEC_MEDIUM;
+       else
+               sec_level = BT_IO_SEC_LOW;
+
+       /*
+        * This connection will help us catch any PDUs that comes before
+        * pairing finishes
+        */
+       io = bt_io_connect(att_connect_cb, attcb, NULL, &gerr,
+                       BT_IO_OPT_SOURCE_BDADDR, adapter_get_address(adapter),
+                       BT_IO_OPT_SOURCE_TYPE, BDADDR_LE_PUBLIC,
+                       BT_IO_OPT_DEST_BDADDR, &dev->bdaddr,
+                       BT_IO_OPT_DEST_TYPE, dev->bdaddr_type,
+                       BT_IO_OPT_CID, ATT_CID,
+                       BT_IO_OPT_SEC_LEVEL, sec_level,
+                       BT_IO_OPT_INVALID);
 
        if (io == NULL) {
+               if (dev->bonding) {
+                       DBusMessage *reply = btd_error_failed(
+                                       dev->bonding->msg, gerr->message);
+
+                       g_dbus_send_message(dbus_conn, reply);
+                       bonding_request_cancel(dev->bonding);
+                       bonding_request_free(dev->bonding);
+               }
+
                error("ATT bt_io_connect(%s): %s", addr, gerr->message);
                g_error_free(gerr);
                g_free(attcb);
-               return FALSE;
+               return -EIO;
        }
 
-       device->att_io = io;
+       /* Keep this, so we can cancel the connection */
+       dev->att_io = io;
 
-       return FALSE;
+       return 0;
 }
 
 static void att_browse_error_cb(const GError *gerr, gpointer user_data)
@@ -2044,7 +3402,7 @@ static void att_browse_error_cb(const GError *gerr, gpointer user_data)
                DBusMessage *reply;
 
                reply = btd_error_failed(req->msg, gerr->message);
-               g_dbus_send_message(req->conn, reply);
+               g_dbus_send_message(dbus_conn, reply);
        }
 
        device->browse = NULL;
@@ -2060,29 +3418,17 @@ static void att_browse_cb(gpointer user_data)
                                                        device->browse);
 }
 
-int device_browse_primary(struct btd_device *device, DBusConnection *conn,
-                               DBusMessage *msg, gboolean secure)
+static int device_browse_primary(struct btd_device *device, DBusMessage *msg)
 {
        struct btd_adapter *adapter = device->adapter;
        struct att_callbacks *attcb;
        struct browse_req *req;
-       BtIOSecLevel sec_level;
-       bdaddr_t src;
 
        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);
+       req->device = device;
 
        device->browse = req;
 
@@ -2091,20 +3437,19 @@ int device_browse_primary(struct btd_device *device, DBusConnection *conn,
                goto done;
        }
 
-       sec_level = secure ? BT_IO_SEC_HIGH : BT_IO_SEC_LOW;
-
        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,
+       device->att_io = bt_io_connect(att_connect_cb,
                                attcb, NULL, NULL,
-                               BT_IO_OPT_SOURCE_BDADDR, &src,
+                               BT_IO_OPT_SOURCE_BDADDR,
+                               adapter_get_address(adapter),
                                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_SEC_LEVEL, BT_IO_SEC_LOW,
                                BT_IO_OPT_INVALID);
 
        if (device->att_io == NULL) {
@@ -2115,10 +3460,6 @@ int device_browse_primary(struct btd_device *device, DBusConnection *conn,
        }
 
 done:
-       if (conn == NULL)
-               conn = get_dbus_connection();
-
-       req->conn = dbus_connection_ref(conn);
 
        if (msg) {
                const char *sender = dbus_message_get_sender(msg);
@@ -2126,7 +3467,7 @@ done:
                req->msg = dbus_message_ref(msg);
                /* Track the request owner to cancel it
                 * automatically if the owner exits */
-               req->listener_id = g_dbus_add_disconnect_watch(conn,
+               req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
                                                sender,
                                                discover_services_req_exit,
                                                req, NULL);
@@ -2135,42 +3476,27 @@ done:
        return 0;
 }
 
-int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
-                       DBusMessage *msg, uuid_t *search, gboolean reverse)
+static int device_browse_sdp(struct btd_device *device, DBusMessage *msg)
 {
        struct btd_adapter *adapter = device->adapter;
        struct browse_req *req;
-       bt_callback_t cb;
-       bdaddr_t src;
        uuid_t uuid;
        int err;
 
        if (device->browse)
                return -EBUSY;
 
-       adapter_get_address(adapter, &src);
-
        req = g_new0(struct browse_req, 1);
-       req->device = btd_device_ref(device);
-       if (search) {
-               memcpy(&uuid, search, sizeof(uuid_t));
-               cb = search_cb;
-       } else {
-               sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
-               init_browse(req, reverse);
-               cb = browse_cb;
-       }
+       req->device = device;
+       sdp_uuid16_create(&uuid, uuid_list[req->search_uuid++]);
 
-       err = bt_search_service(&src, &device->bdaddr, &uuid, cb, req, NULL);
+       err = bt_search_service(adapter_get_address(adapter), &device->bdaddr,
+                                               &uuid, browse_cb, req, NULL);
        if (err < 0) {
                browse_request_free(req);
                return err;
        }
 
-       if (conn == NULL)
-               conn = get_dbus_connection();
-
-       req->conn = dbus_connection_ref(conn);
        device->browse = req;
 
        if (msg) {
@@ -2179,7 +3505,7 @@ int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
                req->msg = dbus_message_ref(msg);
                /* Track the request owner to cancel it
                 * automatically if the owner exits */
-               req->listener_id = g_dbus_add_disconnect_watch(conn,
+               req->listener_id = g_dbus_add_disconnect_watch(dbus_conn,
                                                sender,
                                                discover_services_req_exit,
                                                req, NULL);
@@ -2196,77 +3522,118 @@ struct btd_adapter *device_get_adapter(struct btd_device *device)
        return device->adapter;
 }
 
-void device_get_address(struct btd_device *device, bdaddr_t *bdaddr,
-                                                       uint8_t *bdaddr_type)
+const bdaddr_t *device_get_address(struct btd_device *device)
 {
-       bacpy(bdaddr, &device->bdaddr);
-       if (bdaddr_type != NULL)
-               *bdaddr_type = device->bdaddr_type;
+       return &device->bdaddr;
 }
 
-void device_set_addr_type(struct btd_device *device, uint8_t bdaddr_type)
+const char *device_get_path(const struct btd_device *device)
 {
-       if (device == NULL)
-               return;
+       if (!device)
+               return NULL;
 
-       device->bdaddr_type = bdaddr_type;
+       return device->path;
 }
 
-uint8_t device_get_addr_type(struct btd_device *device)
+gboolean device_is_temporary(struct btd_device *device)
 {
-       return device->bdaddr_type;
+       return device->temporary;
 }
 
-const gchar *device_get_path(struct btd_device *device)
+void device_set_temporary(struct btd_device *device, gboolean temporary)
 {
        if (!device)
-               return NULL;
+               return;
 
-       return device->path;
+       if (device->temporary == temporary)
+               return;
+
+       DBG("temporary %d", temporary);
+
+       if (temporary)
+               adapter_connect_list_remove(device->adapter, device);
+
+       device->temporary = temporary;
 }
 
-struct agent *device_get_agent(struct btd_device *device)
+void device_set_trusted(struct btd_device *device, gboolean trusted)
 {
        if (!device)
-               return NULL;
+               return;
+
+       if (device->trusted == trusted)
+               return;
 
-       if (device->agent)
-               return device->agent;
+       DBG("trusted %d", trusted);
 
-       return adapter_get_agent(device->adapter);
-}
+       device->trusted = trusted;
 
-gboolean device_is_busy(struct btd_device *device)
-{
-       return device->browse ? TRUE : FALSE;
+       store_device_info(device);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                       DEVICE_INTERFACE, "Trusted");
 }
 
-gboolean device_is_temporary(struct btd_device *device)
+void device_set_bonded(struct btd_device *device, gboolean bonded)
 {
-       return device->temporary;
+       if (!device)
+               return;
+
+       DBG("bonded %d", bonded);
+
+       device->bonded = bonded;
 }
 
-void device_set_temporary(struct btd_device *device, gboolean temporary)
+void device_set_legacy(struct btd_device *device, bool legacy)
 {
        if (!device)
                return;
 
-       DBG("temporary %d", temporary);
+       DBG("legacy %d", legacy);
 
-       device->temporary = temporary;
+       if (device->legacy == legacy)
+               return;
+
+       device->legacy = legacy;
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                       DEVICE_INTERFACE, "LegacyPairing");
 }
 
-void device_set_bonded(struct btd_device *device, gboolean bonded)
+void device_set_rssi(struct btd_device *device, int8_t rssi)
 {
        if (!device)
                return;
 
-       DBG("bonded %d", bonded);
+       if (rssi == 0 || device->rssi == 0) {
+               if (device->rssi == rssi)
+                       return;
 
-       device->bonded = bonded;
+               DBG("rssi %d", rssi);
+
+               device->rssi = rssi;
+       } else {
+               int delta;
+
+               if (device->rssi > rssi)
+                       delta = device->rssi - rssi;
+               else
+                       delta = rssi - device->rssi;
+
+               /* only report changes of 8 dBm or more */
+               if (delta < 8)
+                       return;
+
+               DBG("rssi %d delta %d", rssi, delta);
+
+               device->rssi = rssi;
+       }
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "RSSI");
 }
 
-void device_set_auto_connect(struct btd_device *device, gboolean enable)
+static void device_set_auto_connect(struct btd_device *device, gboolean enable)
 {
        char addr[18];
 
@@ -2281,26 +3648,17 @@ void device_set_auto_connect(struct btd_device *device, gboolean enable)
 
        /* Disabling auto connect */
        if (enable == FALSE) {
-               if (device->auto_id)
-                       g_source_remove(device->auto_id);
+               adapter_connect_list_remove(device->adapter, device);
                return;
        }
 
-       /* Enabling auto connect */
-       if (device->auto_id != 0)
-               return;
-
        if (device->attrib) {
                DBG("Already connected");
                return;
        }
 
-       if (device->attios == NULL && device->attios_offline == NULL)
-               return;
-
-       device->auto_id = g_idle_add_full(G_PRIORITY_DEFAULT_IDLE,
-                                               att_connect, device,
-                                               att_connect_dispatched);
+       /* Enabling auto connect */
+       adapter_connect_list_add(device->adapter, device);
 }
 
 static gboolean start_discovery(gpointer user_data)
@@ -2308,106 +3666,17 @@ static gboolean start_discovery(gpointer user_data)
        struct btd_device *device = user_data;
 
        if (device_is_bredr(device))
-               device_browse_sdp(device, NULL, NULL, NULL, TRUE);
+               device_browse_sdp(device, NULL);
        else
-               device_browse_primary(device, NULL, NULL, FALSE);
+               device_browse_primary(device, NULL);
 
        device->discov_timer = 0;
 
        return FALSE;
 }
 
-static DBusMessage *new_authentication_return(DBusMessage *msg, int status)
-{
-       switch (status) {
-       case 0x00: /* success */
-               return dbus_message_new_method_return(msg);
-
-       case 0x04: /* page timeout */
-               return dbus_message_new_error(msg,
-                               ERROR_INTERFACE ".ConnectionAttemptFailed",
-                               "Page Timeout");
-       case 0x08: /* connection timeout */
-               return dbus_message_new_error(msg,
-                               ERROR_INTERFACE ".ConnectionAttemptFailed",
-                               "Connection Timeout");
-       case 0x10: /* connection accept timeout */
-       case 0x22: /* LMP response timeout */
-       case 0x28: /* instant passed - is this a timeout? */
-               return dbus_message_new_error(msg,
-                                       ERROR_INTERFACE ".AuthenticationTimeout",
-                                       "Authentication Timeout");
-       case 0x17: /* too frequent pairing attempts */
-               return dbus_message_new_error(msg,
-                                       ERROR_INTERFACE ".RepeatedAttempts",
-                                       "Repeated Attempts");
-
-       case 0x06:
-       case 0x18: /* pairing not allowed (e.g. gw rejected attempt) */
-               return dbus_message_new_error(msg,
-                                       ERROR_INTERFACE ".AuthenticationRejected",
-                                       "Authentication Rejected");
-
-       case 0x07: /* memory capacity */
-       case 0x09: /* connection limit */
-       case 0x0a: /* synchronous connection limit */
-       case 0x0d: /* limited resources */
-       case 0x13: /* user ended the connection */
-       case 0x14: /* terminated due to low resources */
-       case 0x16: /* connection terminated */
-               return dbus_message_new_error(msg,
-                                       ERROR_INTERFACE ".AuthenticationCanceled",
-                                       "Authentication Canceled");
-
-       case 0x05: /* authentication failure */
-       case 0x0E: /* rejected due to security reasons - is this auth failure? */
-       case 0x25: /* encryption mode not acceptable - is this auth failure? */
-       case 0x26: /* link key cannot be changed - is this auth failure? */
-       case 0x29: /* pairing with unit key unsupported - is this auth failure? */
-       case 0x2f: /* insufficient security - is this auth failure? */
-       default:
-               return dbus_message_new_error(msg,
-                                       ERROR_INTERFACE ".AuthenticationFailed",
-                                       "Authentication Failed");
-       }
-}
-
-static void bonding_request_free(struct bonding_req *bonding)
-{
-       struct btd_device *device;
-
-       if (!bonding)
-               return;
-
-       if (bonding->listener_id)
-               g_dbus_remove_watch(bonding->conn, bonding->listener_id);
-
-       if (bonding->msg)
-               dbus_message_unref(bonding->msg);
-
-       if (bonding->conn)
-               dbus_connection_unref(bonding->conn);
-
-       device = bonding->device;
-       g_free(bonding);
-
-       if (!device)
-               return;
-
-       device->bonding = NULL;
-
-       if (!device->agent)
-               return;
-
-       agent_cancel(device->agent);
-       agent_free(device->agent);
-       device->agent = NULL;
-}
-
 void device_set_paired(struct btd_device *device, gboolean value)
 {
-       DBusConnection *conn = get_dbus_connection();
-
        if (device->paired == value)
                return;
 
@@ -2417,142 +3686,11 @@ void device_set_paired(struct btd_device *device, gboolean value)
 
        device->paired = value;
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Paired",
-                               DBUS_TYPE_BOOLEAN, &value);
-}
-
-static void device_agent_removed(struct agent *agent, void *user_data)
-{
-       struct btd_device *device = user_data;
-
-       device->agent = NULL;
-
-       if (device->authr)
-               device->authr->agent = NULL;
-}
-
-static struct bonding_req *bonding_request_new(DBusConnection *conn,
-                                               DBusMessage *msg,
-                                               struct btd_device *device,
-                                               const char *agent_path,
-                                               uint8_t capability)
-{
-       struct bonding_req *bonding;
-       const char *name = dbus_message_get_sender(msg);
-       char addr[18];
-
-       ba2str(&device->bdaddr, addr);
-       DBG("Requesting bonding for %s", addr);
-
-       if (!agent_path)
-               goto proceed;
-
-       device->agent = agent_create(device->adapter, name, agent_path,
-                                       capability,
-                                       device_agent_removed,
-                                       device);
-
-       DBG("Temporary agent registered for %s at %s:%s",
-                       addr, name, agent_path);
-
-proceed:
-       bonding = g_new0(struct bonding_req, 1);
-
-       bonding->conn = dbus_connection_ref(conn);
-       bonding->msg = dbus_message_ref(msg);
-
-       return bonding;
-}
-
-static void create_bond_req_exit(DBusConnection *conn, void *user_data)
-{
-       struct btd_device *device = user_data;
-       char addr[18];
-
-       ba2str(&device->bdaddr, addr);
-       DBG("%s: requestor exited before bonding was completed", addr);
-
-       if (device->authr)
-               device_cancel_authentication(device, FALSE);
-
-       if (device->bonding) {
-               device->bonding->listener_id = 0;
-               device_request_disconnect(device, NULL);
-       }
-}
-
-DBusMessage *device_create_bonding(struct btd_device *device,
-                                       DBusConnection *conn,
-                                       DBusMessage *msg,
-                                       const char *agent_path,
-                                       uint8_t capability)
-{
-       struct btd_adapter *adapter = device->adapter;
-       struct bonding_req *bonding;
-       int err;
-
-       if (device->bonding)
-               return btd_error_in_progress(msg);
-
-       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,
-                                       device->bdaddr_type, capability);
-       if (err < 0)
-               return btd_error_failed(msg, strerror(-err));
-
-       bonding = bonding_request_new(conn, msg, device, agent_path,
-                                       capability);
-
-       bonding->listener_id = g_dbus_add_disconnect_watch(conn,
-                                               dbus_message_get_sender(msg),
-                                               create_bond_req_exit, device,
-                                               NULL);
-
-       device->bonding = bonding;
-       bonding->device = device;
-
-       return NULL;
-}
-
-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_PASSKEY
-                    || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent)
-               agent_cancel(auth->agent);
+       if (device->paired && !device->svc_resolved)
+               device->pending_paired = true;
+       else
+               g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Paired");
 }
 
 static void device_auth_req_free(struct btd_device *device)
@@ -2563,6 +3701,13 @@ static void device_auth_req_free(struct btd_device *device)
        device->authr = NULL;
 }
 
+bool device_is_retrying(struct btd_device *device)
+{
+       struct bonding_req *bonding = device->bonding;
+
+       return bonding && bonding->retry_timer > 0;
+}
+
 void device_bonding_complete(struct btd_device *device, uint8_t status)
 {
        struct bonding_req *bonding = device->bonding;
@@ -2570,13 +3715,12 @@ 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_PASSKEY
-                    || auth->type == AUTH_TYPE_NOTIFY_PINCODE) && auth->agent)
+       if (auth && auth->agent)
                agent_cancel(auth->agent);
 
        if (status) {
                device_cancel_authentication(device, TRUE);
-               device_cancel_bonding(device, status);
+               device_bonding_failed(device, status);
                return;
        }
 
@@ -2588,6 +3732,15 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
 
        device_set_paired(device, TRUE);
 
+       /* If services are already resolved just reply to the pairing
+        * request
+        */
+       if (device->svc_resolved && bonding) {
+               g_dbus_send_reply(dbus_conn, bonding->msg, DBUS_TYPE_INVALID);
+               bonding_request_free(bonding);
+               return;
+       }
+
        /* If we were initiators start service discovery immediately.
         * However if the other end was the initator wait a few seconds
         * before SDP. This is due to potential IOP issues if the other
@@ -2602,14 +3755,12 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
                }
 
                if (device_is_bredr(device))
-                       device_browse_sdp(device, bonding->conn, bonding->msg,
-                                                               NULL, FALSE);
+                       device_browse_sdp(device, bonding->msg);
                else
-                       device_browse_primary(device, bonding->conn,
-                                                       bonding->msg, FALSE);
+                       device_browse_primary(device, bonding->msg);
 
                bonding_request_free(bonding);
-       } else {
+       } else if (!device->svc_resolved) {
                if (!device->browse && !device->discov_timer &&
                                main_opts.reverse_sdp) {
                        /* If we are not initiators and there is no currently
@@ -2624,94 +3775,179 @@ void device_bonding_complete(struct btd_device *device, uint8_t status)
        }
 }
 
-gboolean device_is_creating(struct btd_device *device, const char *sender)
+static gboolean svc_idle_cb(gpointer user_data)
 {
-       DBusMessage *msg;
+       struct svc_callback *cb = user_data;
+       struct btd_device *dev = cb->dev;
+
+       dev->svc_callbacks = g_slist_remove(dev->svc_callbacks, cb);
+
+       cb->func(cb->dev, 0, cb->user_data);
+
+       g_free(cb);
+
+       return FALSE;
+}
+
+unsigned int device_wait_for_svc_complete(struct btd_device *dev,
+                                                       device_svc_cb_t func,
+                                                       void *user_data)
+{
+       static unsigned int id = 0;
+       struct svc_callback *cb;
+
+       cb = g_new0(struct svc_callback, 1);
+       cb->func = func;
+       cb->user_data = user_data;
+       cb->dev = dev;
+       cb->id = ++id;
+
+       dev->svc_callbacks = g_slist_prepend(dev->svc_callbacks, cb);
+
+       if (dev->svc_resolved || !main_opts.reverse_sdp)
+               cb->idle_id = g_idle_add(svc_idle_cb, cb);
+       else if (dev->discov_timer > 0) {
+               g_source_remove(dev->discov_timer);
+               dev->discov_timer = g_idle_add(start_discovery, dev);
+       }
+
+       return cb->id;
+}
+
+bool device_remove_svc_complete_callback(struct btd_device *dev,
+                                                       unsigned int id)
+{
+       GSList *l;
+
+       for (l = dev->svc_callbacks; l != NULL; l = g_slist_next(l)) {
+               struct svc_callback *cb = l->data;
+
+               if (cb->id != id)
+                       continue;
+
+               if (cb->idle_id > 0)
+                       g_source_remove(cb->idle_id);
+
+               dev->svc_callbacks = g_slist_remove(dev->svc_callbacks, cb);
+               g_free(cb);
+
+               return true;
+       }
+
+       return false;
+}
+
+gboolean device_is_bonding(struct btd_device *device, const char *sender)
+{
+       struct bonding_req *bonding = device->bonding;
+
+       if (!device->bonding)
+               return FALSE;
+
+       if (!sender)
+               return TRUE;
+
+       return g_str_equal(sender, dbus_message_get_sender(bonding->msg));
+}
+
+static gboolean device_bonding_retry(gpointer data)
+{
+       struct btd_device *device = data;
+       struct btd_adapter *adapter = device_get_adapter(device);
+       struct bonding_req *bonding = device->bonding;
+       uint8_t io_cap;
+       int err;
 
-       if (device->bonding && device->bonding->msg)
-               msg = device->bonding->msg;
-       else if (device->browse && device->browse->msg)
-               msg = device->browse->msg;
-       else
+       if (!bonding)
                return FALSE;
 
-       if (!dbus_message_is_method_call(msg, ADAPTER_INTERFACE,
-                                               "CreatePairedDevice") &&
-                       !dbus_message_is_method_call(msg, ADAPTER_INTERFACE,
-                                                       "CreateDevice"))
-               return FALSE;
+       DBG("retrying bonding");
+       bonding->retry_timer = 0;
 
-       if (sender == NULL)
-               return TRUE;
+       /* Restart the bonding timer to the begining of the pairing. If not
+        * pincode request/reply occurs during this retry,
+        * device_bonding_last_duration() will return a consistent value from
+        * this point. */
+       device_bonding_restart_timer(device);
+
+       if (bonding->agent)
+               io_cap = agent_get_io_capability(bonding->agent);
+       else
+               io_cap = IO_CAPABILITY_NOINPUTNOOUTPUT;
+
+       err = adapter_bonding_attempt(adapter, &device->bdaddr,
+                               device->bdaddr_type, io_cap);
+       if (err < 0)
+               device_bonding_complete(device, bonding->status);
 
-       return g_str_equal(sender, dbus_message_get_sender(msg));
+       return FALSE;
 }
 
-gboolean device_is_bonding(struct btd_device *device, const char *sender)
+int device_bonding_attempt_retry(struct btd_device *device)
 {
        struct bonding_req *bonding = device->bonding;
 
-       if (!device->bonding)
-               return FALSE;
+       /* Ignore other failure events while retrying */
+       if (device_is_retrying(device))
+               return 0;
 
-       if (!sender)
-               return TRUE;
+       if (!bonding)
+               return -EINVAL;
 
-       return g_str_equal(sender, dbus_message_get_sender(bonding->msg));
+       /* Mark the end of a bonding attempt to compute the delta for the
+        * retry. */
+       bonding_request_stop_timer(bonding);
+
+       if (btd_adapter_pin_cb_iter_end(bonding->cb_iter))
+               return -EINVAL;
+
+       DBG("scheduling retry");
+       bonding->retry_timer = g_timeout_add(3000,
+                                               device_bonding_retry, device);
+       return 0;
 }
 
-void device_cancel_bonding(struct btd_device *device, uint8_t status)
+void device_bonding_failed(struct btd_device *device, uint8_t status)
 {
        struct bonding_req *bonding = device->bonding;
        DBusMessage *reply;
-       char addr[18];
+
+       DBG("status %u", status);
 
        if (!bonding)
                return;
 
-       ba2str(&device->bdaddr, addr);
-       DBG("Canceling bonding request for %s", addr);
-
        if (device->authr)
                device_cancel_authentication(device, FALSE);
 
        reply = new_authentication_return(bonding->msg, status);
-       g_dbus_send_message(bonding->conn, reply);
+       g_dbus_send_message(dbus_conn, reply);
 
-       bonding_request_cancel(bonding);
        bonding_request_free(bonding);
 }
 
-static void pincode_cb(struct agent *agent, DBusError *err,
-                                       const char *pincode, void *data)
+struct btd_adapter_pin_cb_iter *device_bonding_iter(struct btd_device *device)
 {
-       struct authentication_req *auth = data;
-       struct btd_device *device = auth->device;
-       struct btd_adapter *adapter = device_get_adapter(device);
-       struct agent *adapter_agent = adapter_get_agent(adapter);
-
-       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
-
-               if (auth->agent == adapter_agent || adapter_agent == NULL)
-                       goto done;
+       if (device->bonding == NULL)
+               return NULL;
 
-               if (agent_request_pincode(adapter_agent, device, pincode_cb,
-                                               auth->secure, auth, NULL) < 0)
-                       goto done;
+       return device->bonding->cb_iter;
+}
 
-               auth->agent = adapter_agent;
-               return;
-       }
+static void pincode_cb(struct agent *agent, DBusError *err, const char *pin,
+                                                               void *data)
+{
+       struct authentication_req *auth = data;
+       struct btd_device *device = auth->device;
 
-done:
        /* No need to reply anything if the authentication already failed */
-       if (auth->cb == NULL)
+       if (auth->agent == NULL)
                return;
 
-       ((agent_pincode_cb) auth->cb)(agent, err, pincode, device);
+       btd_adapter_pincode_reply(device->adapter, &device->bdaddr,
+                                               pin, pin ? strlen(pin) : 0);
 
-       device->authr->cb = NULL;
+       agent_unref(device->authr->agent);
        device->authr->agent = NULL;
 }
 
@@ -2719,32 +3955,16 @@ static void confirm_cb(struct agent *agent, DBusError *err, void *data)
 {
        struct authentication_req *auth = data;
        struct btd_device *device = auth->device;
-       struct btd_adapter *adapter = device_get_adapter(device);
-       struct agent *adapter_agent = adapter_get_agent(adapter);
-
-       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
-
-               if (auth->agent == adapter_agent || adapter_agent == NULL)
-                       goto done;
 
-               if (agent_request_confirmation(adapter_agent, device,
-                                               auth->passkey, confirm_cb,
-                                               auth, NULL) < 0)
-                       goto done;
-
-               auth->agent = adapter_agent;
-               return;
-       }
-
-done:
        /* No need to reply anything if the authentication already failed */
-       if (auth->cb == NULL)
+       if (auth->agent == NULL)
                return;
 
-       ((agent_cb) auth->cb)(agent, err, device);
+       btd_adapter_confirm_reply(device->adapter, &device->bdaddr,
+                                                       device->bdaddr_type,
+                                                       err ? FALSE : TRUE);
 
-       device->authr->cb = NULL;
+       agent_unref(device->authr->agent);
        device->authr->agent = NULL;
 }
 
@@ -2753,31 +3973,18 @@ static void passkey_cb(struct agent *agent, DBusError *err,
 {
        struct authentication_req *auth = data;
        struct btd_device *device = auth->device;
-       struct btd_adapter *adapter = device_get_adapter(device);
-       struct agent *adapter_agent = adapter_get_agent(adapter);
-
-       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
 
-               if (auth->agent == adapter_agent || adapter_agent == NULL)
-                       goto done;
-
-               if (agent_request_passkey(adapter_agent, device, passkey_cb,
-                                                       auth, NULL) < 0)
-                       goto done;
-
-               auth->agent = adapter_agent;
-               return;
-       }
-
-done:
        /* No need to reply anything if the authentication already failed */
-       if (auth->cb == NULL)
+       if (auth->agent == NULL)
                return;
 
-       ((agent_passkey_cb) auth->cb)(agent, err, passkey, device);
+       if (err)
+               passkey = INVALID_PASSKEY;
 
-       device->authr->cb = NULL;
+       btd_adapter_passkey_reply(device->adapter, &device->bdaddr,
+                                               device->bdaddr_type, passkey);
+
+       agent_unref(device->authr->agent);
        device->authr->agent = NULL;
 }
 
@@ -2785,99 +3992,153 @@ 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);
-
-       if (err && (g_str_equal(DBUS_ERROR_UNKNOWN_METHOD, err->name) ||
-                               g_str_equal(DBUS_ERROR_NO_REPLY, err->name))) {
-
-               /* 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;
-       }
-
-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);
+       pincode_cb(agent, err, auth->pincode, auth);
 
        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,
-                                       void *data, gboolean secure, void *cb)
+static struct authentication_req *new_auth(struct btd_device *device,
+                                       auth_type_t type, gboolean secure)
 {
        struct authentication_req *auth;
        struct agent *agent;
        char addr[18];
-       int err;
 
        ba2str(&device->bdaddr, addr);
        DBG("Requesting agent authentication for %s", addr);
 
        if (device->authr) {
                error("Authentication already requested for %s", addr);
-               return -EALREADY;
+               return NULL;
        }
 
-       agent = device_get_agent(device);
+       if (device->bonding && device->bonding->agent)
+               agent = agent_ref(device->bonding->agent);
+       else
+               agent = agent_get(NULL);
+
        if (!agent) {
                error("No agent available for request type %d", type);
-               return -EPERM;
+               return NULL;
        }
 
        auth = g_new0(struct authentication_req, 1);
        auth->agent = agent;
        auth->device = device;
-       auth->cb = cb;
        auth->type = type;
        auth->secure = secure;
        device->authr = auth;
 
-       switch (type) {
-       case AUTH_TYPE_PINCODE:
-               err = agent_request_pincode(agent, device, pincode_cb, secure,
-                                                               auth, NULL);
-               break;
-       case AUTH_TYPE_PASSKEY:
-               err = agent_request_passkey(agent, device, passkey_cb,
+       return auth;
+}
+
+int device_request_pincode(struct btd_device *device, gboolean secure)
+{
+       struct authentication_req *auth;
+       int err;
+
+       auth = new_auth(device, AUTH_TYPE_PINCODE, secure);
+       if (!auth)
+               return -EPERM;
+
+       err = agent_request_pincode(auth->agent, device, pincode_cb, secure,
                                                                auth, NULL);
-               break;
-       case AUTH_TYPE_CONFIRM:
-               auth->passkey = *((uint32_t *) data);
-               err = agent_request_confirmation(agent, device, auth->passkey,
+       if (err < 0) {
+               error("Failed requesting authentication");
+               device_auth_req_free(device);
+       }
+
+       return err;
+}
+
+int device_request_passkey(struct btd_device *device)
+{
+       struct authentication_req *auth;
+       int err;
+
+       auth = new_auth(device, AUTH_TYPE_PASSKEY, FALSE);
+       if (!auth)
+               return -EPERM;
+
+       err = agent_request_passkey(auth->agent, device, passkey_cb, auth,
+                                                                       NULL);
+       if (err < 0) {
+               error("Failed requesting authentication");
+               device_auth_req_free(device);
+       }
+
+       return err;
+}
+
+int device_confirm_passkey(struct btd_device *device, uint32_t passkey,
+                                                       uint8_t confirm_hint)
+
+{
+       struct authentication_req *auth;
+       int err;
+
+       auth = new_auth(device, AUTH_TYPE_CONFIRM, FALSE);
+       if (!auth)
+               return -EPERM;
+
+       auth->passkey = passkey;
+
+       if (confirm_hint)
+               err = agent_request_authorization(auth->agent, device,
                                                confirm_cb, auth, NULL);
-               break;
-       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;
+       else
+               err = agent_request_confirmation(auth->agent, device, passkey,
+                                               confirm_cb, auth, NULL);
+
+       if (err < 0) {
+               error("Failed requesting authentication");
+               device_auth_req_free(device);
+       }
+
+       return err;
+}
+
+int device_notify_passkey(struct btd_device *device, uint32_t passkey,
+                                                       uint8_t entered)
+{
+       struct authentication_req *auth;
+       int err;
+
+       if (device->authr) {
+               auth = device->authr;
+               if (auth->type != AUTH_TYPE_NOTIFY_PASSKEY)
+                       return -EPERM;
+       } else {
+               auth = new_auth(device, AUTH_TYPE_NOTIFY_PASSKEY, FALSE);
+               if (!auth)
+                       return -EPERM;
+       }
+
+       err = agent_display_passkey(auth->agent, device, passkey, entered);
+       if (err < 0) {
+               error("Failed requesting authentication");
+               device_auth_req_free(device);
        }
 
+       return err;
+}
+
+int device_notify_pincode(struct btd_device *device, gboolean secure,
+                                                       const char *pincode)
+{
+       struct authentication_req *auth;
+       int err;
+
+       auth = new_auth(device, AUTH_TYPE_NOTIFY_PINCODE, secure);
+       if (!auth)
+               return -EPERM;
+
+       auth->pincode = g_strdup(pincode);
+
+       err = agent_display_pincode(auth->agent, device, pincode,
+                                       display_pincode_cb, auth, NULL);
        if (err < 0) {
                error("Failed requesting authentication");
                device_auth_req_free(device);
@@ -2888,39 +4149,37 @@ int device_request_authentication(struct btd_device *device, auth_type_t type,
 
 static void cancel_authentication(struct authentication_req *auth)
 {
-       struct btd_device *device;
        struct agent *agent;
        DBusError err;
 
-       if (!auth || !auth->cb)
+       if (!auth || !auth->agent)
                return;
 
-       device = auth->device;
        agent = auth->agent;
+       auth->agent = NULL;
 
        dbus_error_init(&err);
-       dbus_set_error_const(&err, "org.bluez.Error.Canceled", NULL);
+       dbus_set_error_const(&err, ERROR_INTERFACE ".Canceled", NULL);
 
        switch (auth->type) {
        case AUTH_TYPE_PINCODE:
-               ((agent_pincode_cb) auth->cb)(agent, &err, NULL, device);
+               pincode_cb(agent, &err, NULL, auth);
                break;
        case AUTH_TYPE_CONFIRM:
-               ((agent_cb) auth->cb)(agent, &err, device);
+               confirm_cb(agent, &err, auth);
                break;
        case AUTH_TYPE_PASSKEY:
-               ((agent_passkey_cb) auth->cb)(agent, &err, 0, device);
+               passkey_cb(agent, &err, 0, auth);
                break;
        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);
+               pincode_cb(agent, &err, NULL, auth);
                break;
        }
 
        dbus_error_free(&err);
-       auth->cb = NULL;
 }
 
 void device_cancel_authentication(struct btd_device *device, gboolean aborted)
@@ -2948,22 +4207,16 @@ gboolean device_is_authenticating(struct btd_device *device)
        return (device->authr != NULL);
 }
 
-gboolean device_is_authorizing(struct btd_device *device)
+struct gatt_primary *btd_device_get_primary(struct btd_device *device,
+                                                       const char *uuid)
 {
-       return device->authorizing;
-}
+       GSList *match;
 
-void device_set_authorizing(struct btd_device *device, gboolean auth)
-{
-       device->authorizing = auth;
-}
+       match = g_slist_find_custom(device->primaries, uuid, bt_uuid_strcmp);
+       if (match)
+               return match->data;
 
-void device_register_services(DBusConnection *conn, struct btd_device *device,
-                                               GSList *prim_list, int psm)
-{
-       device->primaries = g_slist_concat(device->primaries, prim_list);
-       device->services = attrib_client_register(conn, device, psm, NULL,
-                                                               prim_list);
+       return NULL;
 }
 
 GSList *btd_device_get_primaries(struct btd_device *device)
@@ -2971,95 +4224,148 @@ GSList *btd_device_get_primaries(struct btd_device *device)
        return device->primaries;
 }
 
+void btd_device_gatt_set_service_changed(struct btd_device *device,
+                                               uint16_t start, uint16_t end)
+{
+       GSList *l;
+
+       for (l = device->primaries; l; l = g_slist_next(l)) {
+               struct gatt_primary *prim = l->data;
+
+               if (start <= prim->range.end && end >= prim->range.start)
+                       prim->changed = TRUE;
+       }
+
+       device_browse_primary(device, NULL);
+}
+
 void btd_device_add_uuid(struct btd_device *device, const char *uuid)
 {
        GSList *uuid_list;
        char *new_uuid;
 
-       if (g_slist_find_custom(device->uuids, uuid,
-                               (GCompareFunc) strcasecmp))
+       if (g_slist_find_custom(device->uuids, uuid, bt_uuid_strcmp))
                return;
 
        new_uuid = g_strdup(uuid);
        uuid_list = g_slist_append(NULL, new_uuid);
 
-       device_probe_drivers(device, uuid_list);
+       device_probe_profiles(device, uuid_list);
 
        g_free(new_uuid);
        g_slist_free(uuid_list);
 
-       store_profiles(device);
-       services_changed(device);
+       store_device_info(device);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "UUIDs");
+}
+
+static sdp_list_t *read_device_records(struct btd_device *device)
+{
+       char local[18], peer[18];
+       char filename[PATH_MAX + 1];
+       GKeyFile *key_file;
+       char **keys, **handle;
+       char *str;
+       sdp_list_t *recs = NULL;
+       sdp_record_t *rec;
+
+       ba2str(adapter_get_address(device->adapter), local);
+       ba2str(&device->bdaddr, peer);
+
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local, peer);
+       filename[PATH_MAX] = '\0';
+
+       key_file = g_key_file_new();
+       g_key_file_load_from_file(key_file, filename, 0, NULL);
+       keys = g_key_file_get_keys(key_file, "ServiceRecords", NULL, NULL);
+
+       for (handle = keys; handle && *handle; handle++) {
+               str = g_key_file_get_string(key_file, "ServiceRecords",
+                                               *handle, NULL);
+               if (!str)
+                       continue;
+
+               rec = record_from_string(str);
+               recs = sdp_list_append(recs, rec);
+               g_free(str);
+       }
+
+       g_strfreev(keys);
+       g_key_file_free(key_file);
+
+       return recs;
 }
 
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
                                                        const char *uuid)
 {
-       bdaddr_t src;
-
        if (device->tmp_records) {
                const sdp_record_t *record;
 
                record = find_record_in_list(device->tmp_records, uuid);
                if (record != NULL)
                        return record;
-       }
 
-       adapter_get_address(device->adapter, &src);
+               sdp_list_free(device->tmp_records,
+                                       (sdp_free_func_t) sdp_record_free);
+               device->tmp_records = NULL;
+       }
 
-       device->tmp_records = read_records(&src, &device->bdaddr);
+       device->tmp_records = read_device_records(device);
        if (!device->tmp_records)
                return NULL;
 
        return find_record_in_list(device->tmp_records, uuid);
 }
 
-int btd_register_device_driver(struct btd_device_driver *driver)
-{
-       device_drivers = g_slist_append(device_drivers, driver);
-
-       return 0;
-}
-
-void btd_unregister_device_driver(struct btd_device_driver *driver)
-{
-       device_drivers = g_slist_remove(device_drivers, driver);
-}
-
 struct btd_device *btd_device_ref(struct btd_device *device)
 {
-       device->ref++;
-
-       DBG("%p: ref=%d", device, device->ref);
+       __sync_fetch_and_add(&device->ref_count, 1);
 
        return device;
 }
 
 void btd_device_unref(struct btd_device *device)
 {
-       DBusConnection *conn = get_dbus_connection();
-       gchar *path;
+       if (__sync_sub_and_fetch(&device->ref_count, 1))
+               return;
 
-       device->ref--;
+       if (!device->path) {
+               error("freeing device without an object path");
+               return;
+       }
 
-       DBG("%p: ref=%d", device, device->ref);
+       DBG("Freeing device %s", device->path);
 
-       if (device->ref > 0)
-               return;
+       g_dbus_unregister_interface(dbus_conn, device->path, DEVICE_INTERFACE);
+}
 
-       path = g_strdup(device->path);
+int device_get_appearance(struct btd_device *device, uint16_t *value)
+{
+       if (device->appearance == 0)
+               return -1;
 
-       g_dbus_unregister_interface(conn, path, DEVICE_INTERFACE);
+       if (value)
+               *value = device->appearance;
 
-       g_free(path);
+       return 0;
 }
 
-void device_set_class(struct btd_device *device, uint32_t value)
+void device_set_appearance(struct btd_device *device, uint16_t value)
 {
-       DBusConnection *conn = get_dbus_connection();
+       const char *icon = gap_appearance_to_icon(value);
 
-       emit_property_changed(conn, device->path, DEVICE_INTERFACE, "Class",
-                               DBUS_TYPE_UINT32, &value);
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                       DEVICE_INTERFACE, "Appearance");
+
+       if (icon)
+               g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Icon");
+
+       device->appearance = value;
+       store_device_info(device);
 }
 
 static gboolean notify_attios(gpointer user_data)
@@ -3092,6 +4398,8 @@ guint btd_device_add_attio_callback(struct btd_device *device,
        attio->dcfunc = dcfunc;
        attio->user_data = user_data;
 
+       device_set_auto_connect(device, TRUE);
+
        if (device->attrib && cfunc) {
                device->attios_offline = g_slist_append(device->attios_offline,
                                                                        attio);
@@ -3101,11 +4409,6 @@ guint btd_device_add_attio_callback(struct btd_device *device,
 
        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);
-
        return attio->id;
 }
 
@@ -3143,22 +4446,71 @@ gboolean btd_device_remove_attio_callback(struct btd_device *device, guint id)
        if (device->attios != NULL || device->attios_offline != NULL)
                return TRUE;
 
-       if (device->auto_id) {
-               g_source_remove(device->auto_id);
-               device->auto_id = 0;
+       attio_cleanup(device);
+
+       return TRUE;
+}
+
+void btd_device_set_pnpid(struct btd_device *device, uint16_t source,
+                       uint16_t vendor, uint16_t product, uint16_t version)
+{
+       device->vendor_src = source;
+       device->vendor = vendor;
+       device->product = product;
+       device->version = version;
+
+       g_free(device->modalias);
+       device->modalias = bt_modalias(source, vendor, product, version);
+
+       g_dbus_emit_property_changed(dbus_conn, device->path,
+                                               DEVICE_INTERFACE, "Modalias");
+
+       store_device_info(device);
+}
+
+static void service_state_changed(struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state,
+                                               void *user_data)
+{
+       struct btd_profile *profile = btd_service_get_profile(service);
+       struct btd_device *device = btd_service_get_device(service);
+       int err = btd_service_get_error(service);
+
+       if (new_state == BTD_SERVICE_STATE_CONNECTING ||
+                               new_state == BTD_SERVICE_STATE_DISCONNECTING)
+               return;
+
+       if (old_state == BTD_SERVICE_STATE_CONNECTING)
+               device_profile_connected(device, profile, err);
+       else if (old_state == BTD_SERVICE_STATE_DISCONNECTING)
+               device_profile_disconnected(device, profile, err);
+}
+
+struct btd_service *btd_device_get_service(struct btd_device *dev,
+                                               const char *remote_uuid)
+{
+       GSList *l;
+
+       for (l = dev->services; l != NULL; l = g_slist_next(l)) {
+               struct btd_service *service = l->data;
+               struct btd_profile *p = btd_service_get_profile(service);
+
+               if (g_str_equal(p->remote_uuid, remote_uuid))
+                       return service;
        }
 
-       att_cleanup(device);
+       return NULL;
+}
 
-       return TRUE;
+void btd_device_init(void)
+{
+       dbus_conn = btd_get_dbus_connection();
+       service_state_cb_id = btd_service_add_state_cb(
+                                               service_state_changed, NULL);
 }
 
-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)
+void btd_device_cleanup(void)
 {
-       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);
+       btd_service_remove_state_cb(service_state_cb_id);
 }
index 26e17f7..deec8d0 100644 (file)
  *
  */
 
-#define DEVICE_INTERFACE       "org.bluez.Device"
+#define DEVICE_INTERFACE       "org.bluez.Device1"
 
 struct btd_device;
 
-typedef enum {
-       AUTH_TYPE_PINCODE,
-       AUTH_TYPE_PASSKEY,
-       AUTH_TYPE_CONFIRM,
-       AUTH_TYPE_NOTIFY_PASSKEY,
-       AUTH_TYPE_NOTIFY_PINCODE,
-} auth_type_t;
+struct btd_device *device_create(struct btd_adapter *adapter,
+                               const bdaddr_t *address, uint8_t bdaddr_type);
+struct btd_device *device_create_from_storage(struct btd_adapter *adapter,
+                               const char *address, GKeyFile *key_file);
+char *btd_device_get_storage_path(struct btd_device *device,
+                               const char *filename);
 
-struct btd_device *device_create(DBusConnection *conn,
-                                       struct btd_adapter *adapter,
-                                       const char *address, uint8_t bdaddr_type);
 void device_set_name(struct btd_device *device, const char *name);
+void device_store_cached_name(struct btd_device *dev, const char *name);
 void device_get_name(struct btd_device *device, char *name, size_t len);
+bool device_name_known(struct btd_device *device);
+void device_set_class(struct btd_device *device, uint32_t class);
+uint32_t btd_device_get_class(struct btd_device *device);
 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);
-gint device_address_cmp(struct btd_device *device, const gchar *address);
-int device_browse_primary(struct btd_device *device, DBusConnection *conn,
-                               DBusMessage *msg, gboolean secure);
-int device_browse_sdp(struct btd_device *device, DBusConnection *conn,
-                       DBusMessage *msg, uuid_t *search, gboolean reverse);
-void device_probe_drivers(struct btd_device *device, GSList *profiles);
+int device_address_cmp(gconstpointer a, gconstpointer b);
+int device_bdaddr_cmp(gconstpointer a, gconstpointer b);
+GSList *device_get_uuids(struct btd_device *device);
+void device_probe_profiles(struct btd_device *device, GSList *profiles);
 const sdp_record_t *btd_device_get_record(struct btd_device *device,
                                                const char *uuid);
+struct gatt_primary *btd_device_get_primary(struct btd_device *device,
+                                                       const char *uuid);
 GSList *btd_device_get_primaries(struct btd_device *device);
-void device_register_services(DBusConnection *conn, struct btd_device *device,
-                                               GSList *prim_list, int psm);
-GSList *device_services_from_record(struct btd_device *device,
-                                                       GSList *profiles);
+void btd_device_gatt_set_service_changed(struct btd_device *device,
+                                               uint16_t start, uint16_t end);
 void btd_device_add_uuid(struct btd_device *device, const char *uuid);
+void device_add_eir_uuids(struct btd_device *dev, GSList *uuids);
+void device_probe_profile(gpointer a, gpointer b);
+void device_remove_profile(gpointer a, gpointer b);
 struct btd_adapter *device_get_adapter(struct btd_device *device);
-void device_get_address(struct btd_device *device, bdaddr_t *bdaddr,
-                                                       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);
+const bdaddr_t *device_get_address(struct btd_device *device);
+const char *device_get_path(const struct btd_device *device);
 gboolean device_is_bredr(struct btd_device *device);
 gboolean device_is_le(struct btd_device *device);
-gboolean device_is_busy(struct btd_device *device);
 gboolean device_is_temporary(struct btd_device *device);
 gboolean device_is_paired(struct btd_device *device);
 gboolean device_is_bonded(struct btd_device *device);
 gboolean device_is_trusted(struct btd_device *device);
 void device_set_paired(struct btd_device *device, gboolean paired);
 void device_set_temporary(struct btd_device *device, gboolean temporary);
+void device_set_trusted(struct btd_device *device, gboolean trusted);
 void device_set_bonded(struct btd_device *device, gboolean bonded);
-void device_set_auto_connect(struct btd_device *device, gboolean enable);
+void device_set_legacy(struct btd_device *device, bool legacy);
+void device_set_rssi(struct btd_device *device, int8_t rssi);
 gboolean device_is_connected(struct btd_device *device);
-DBusMessage *device_create_bonding(struct btd_device *device,
-                               DBusConnection *conn, DBusMessage *msg,
-                               const char *agent_path, uint8_t capability);
+bool device_is_retrying(struct btd_device *device);
 void device_bonding_complete(struct btd_device *device, uint8_t status);
-void device_simple_pairing_complete(struct btd_device *device, uint8_t status);
-gboolean device_is_creating(struct btd_device *device, const char *sender);
 gboolean device_is_bonding(struct btd_device *device, const char *sender);
-void device_cancel_bonding(struct btd_device *device, uint8_t status);
-int device_request_authentication(struct btd_device *device, auth_type_t type,
-                                       void *data, gboolean secure, void *cb);
+void device_bonding_attempt_failed(struct btd_device *device, uint8_t status);
+void device_bonding_failed(struct btd_device *device, uint8_t status);
+struct btd_adapter_pin_cb_iter *device_bonding_iter(struct btd_device *device);
+int device_bonding_attempt_retry(struct btd_device *device);
+long device_bonding_last_duration(struct btd_device *device);
+void device_bonding_restart_timer(struct btd_device *device);
+int device_request_pincode(struct btd_device *device, gboolean secure);
+int device_request_passkey(struct btd_device *device);
+int device_confirm_passkey(struct btd_device *device, uint32_t passkey,
+                                                       uint8_t confirm_hint);
+int device_notify_passkey(struct btd_device *device, uint32_t passkey,
+                                                       uint8_t entered);
+int device_notify_pincode(struct btd_device *device, gboolean secure,
+                                                       const char *pincode);
 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);
-void device_set_authorizing(struct btd_device *device, gboolean auth);
-void device_add_connection(struct btd_device *device, DBusConnection *conn);
-void device_remove_connection(struct btd_device *device, DBusConnection *conn);
+void device_add_connection(struct btd_device *device);
+void device_remove_connection(struct btd_device *device);
 void device_request_disconnect(struct btd_device *device, DBusMessage *msg);
 
 typedef void (*disconnect_watch) (struct btd_device *device, gboolean removal,
@@ -102,27 +105,31 @@ guint device_add_disconnect_watch(struct btd_device *device,
                                disconnect_watch watch, void *user_data,
                                GDestroyNotify destroy);
 void device_remove_disconnect_watch(struct btd_device *device, guint id);
-void device_set_class(struct btd_device *device, uint32_t value);
+int device_get_appearance(struct btd_device *device, uint16_t *value);
+void device_set_appearance(struct btd_device *device, uint16_t value);
 
-#define BTD_UUIDS(args...) ((const char *[]) { args, NULL } )
+struct btd_device *btd_device_ref(struct btd_device *device);
+void btd_device_unref(struct btd_device *device);
 
-struct btd_device_driver {
-       const char *name;
-       const char **uuids;
-       int (*probe) (struct btd_device *device, GSList *uuids);
-       void (*remove) (struct btd_device *device);
-};
+int device_block(struct btd_device *device, gboolean update_only);
+int device_unblock(struct btd_device *device, gboolean silent,
+                                                       gboolean update_only);
+void btd_device_set_pnpid(struct btd_device *device, uint16_t source,
+                       uint16_t vendor, uint16_t product, uint16_t version);
 
-int btd_register_device_driver(struct btd_device_driver *driver);
-void btd_unregister_device_driver(struct btd_device_driver *driver);
+int device_connect_le(struct btd_device *dev);
 
-struct btd_device *btd_device_ref(struct btd_device *device);
-void btd_device_unref(struct btd_device *device);
+typedef void (*device_svc_cb_t) (struct btd_device *dev, int err,
+                                                       void *user_data);
+
+unsigned int device_wait_for_svc_complete(struct btd_device *dev,
+                                                       device_svc_cb_t func,
+                                                       void *user_data);
+bool device_remove_svc_complete_callback(struct btd_device *dev,
+                                                       unsigned int id);
+
+struct btd_service *btd_device_get_service(struct btd_device *dev,
+                                               const char *remote_uuid);
 
-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);
+void btd_device_init(void);
+void btd_device_cleanup(void);
index 9d42917..084884e 100644 (file)
--- a/src/eir.c
+++ b/src/eir.c
@@ -27,6 +27,7 @@
 #endif
 
 #include <errno.h>
+#include <ctype.h>
 #include <stdlib.h>
 #include <stdint.h>
 #include <glib.h>
 #include "glib-helper.h"
 #include "eir.h"
 
+#define EIR_OOB_MIN (2 + 6)
+
 void eir_data_free(struct eir_data *eir)
 {
        g_slist_free_full(eir->services, g_free);
        eir->services = NULL;
        g_free(eir->name);
        eir->name = NULL;
+       g_free(eir->hash);
+       eir->hash = NULL;
+       g_free(eir->randomizer);
+       eir->randomizer = NULL;
 }
 
-static void eir_parse_uuid16(struct eir_data *eir, void *data, uint8_t len)
+static void eir_parse_uuid16(struct eir_data *eir, const void *data,
+                                                               uint8_t len)
 {
-       uint16_t *uuid16 = data;
+       const uint16_t *uuid16 = data;
        uuid_t service;
        char *uuid_str;
        unsigned int i;
 
        service.type = SDP_UUID16;
        for (i = 0; i < len / 2; i++, uuid16++) {
-               service.value.uuid16 = btohs(bt_get_unaligned(uuid16));
+               service.value.uuid16 = bt_get_le16(uuid16);
+
                uuid_str = bt_uuid2string(&service);
                eir->services = g_slist_append(eir->services, uuid_str);
        }
 }
 
-static void eir_parse_uuid32(struct eir_data *eir, void *data, uint8_t len)
+static void eir_parse_uuid32(struct eir_data *eir, const void *data,
+                                                               uint8_t len)
 {
-       uint32_t *uuid32 = data;
+       const uint32_t *uuid32 = data;
        uuid_t service;
        char *uuid_str;
        unsigned int i;
 
        service.type = SDP_UUID32;
        for (i = 0; i < len / 4; i++, uuid32++) {
-               service.value.uuid32 = btohl(bt_get_unaligned(uuid32));
+               service.value.uuid32 = bt_get_le32(uuid32);
+
                uuid_str = bt_uuid2string(&service);
                eir->services = g_slist_append(eir->services, uuid_str);
        }
 }
 
-static void eir_parse_uuid128(struct eir_data *eir, uint8_t *data, uint8_t len)
+static void eir_parse_uuid128(struct eir_data *eir, const uint8_t *data,
+                                                               uint8_t len)
 {
-       uint8_t *uuid_ptr = data;
+       const uint8_t *uuid_ptr = data;
        uuid_t service;
        char *uuid_str;
        unsigned int i;
@@ -94,11 +106,35 @@ static void eir_parse_uuid128(struct eir_data *eir, uint8_t *data, uint8_t len)
        }
 }
 
-int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
+static char *name2utf8(const uint8_t *name, uint8_t len)
+{
+       char utf8_name[HCI_MAX_NAME_LENGTH + 2];
+       int i;
+
+       if (g_utf8_validate((const char *) name, len, NULL))
+               return g_strndup((char *) name, len);
+
+       memset(utf8_name, 0, sizeof(utf8_name));
+       strncpy(utf8_name, (char *) name, len);
+
+       /* Assume ASCII, and replace all non-ASCII with spaces */
+       for (i = 0; utf8_name[i] != '\0'; i++) {
+               if (!isascii(utf8_name[i]))
+                       utf8_name[i] = ' ';
+       }
+
+       /* Remove leading and trailing whitespace characters */
+       g_strstrip(utf8_name);
+
+       return g_strdup(utf8_name);
+}
+
+int eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len)
 {
        uint16_t len = 0;
 
        eir->flags = -1;
+       eir->tx_power = 127;
 
        /* No EIR data to parse */
        if (eir_data == NULL)
@@ -106,7 +142,8 @@ 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 data_len, *data = &eir_data[2];
+               const uint8_t *data;
+               uint8_t data_len;
 
                /* Check for the end of EIR */
                if (field_len == 0)
@@ -118,6 +155,7 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
                if (len > eir_len)
                        break;
 
+               data = &eir_data[2];
                data_len = field_len - 1;
 
                switch (eir_data[1]) {
@@ -148,19 +186,23 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
                        while (data_len > 0 && data[data_len - 1] == '\0')
                                data_len--;
 
-                       if (!g_utf8_validate((char *) data, data_len, NULL))
-                               break;
-
                        g_free(eir->name);
 
-                       eir->name = g_strndup((char *) data, data_len);
+                       eir->name = name2utf8(data, data_len);
                        eir->name_complete = eir_data[1] == EIR_NAME_COMPLETE;
                        break;
 
+               case EIR_TX_POWER:
+                       if (data_len < 1)
+                               break;
+                       eir->tx_power = (int8_t) data[0];
+                       break;
+
                case EIR_CLASS_OF_DEV:
                        if (data_len < 3)
                                break;
-                       memcpy(eir->dev_class, data, 3);
+                       eir->class = data[0] | (data[1] << 8) |
+                                                       (data[2] << 16);
                        break;
 
                case EIR_GAP_APPEARANCE:
@@ -168,6 +210,18 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
                                break;
                        eir->appearance = bt_get_le16(data);
                        break;
+
+               case EIR_SSP_HASH:
+                       if (data_len < 16)
+                               break;
+                       eir->hash = g_memdup(data, 16);
+                       break;
+
+               case EIR_SSP_RANDOMIZER:
+                       if (data_len < 16)
+                               break;
+                       eir->randomizer = g_memdup(data, 16);
+                       break;
                }
 
                eir_data += field_len + 1;
@@ -176,9 +230,33 @@ int eir_parse(struct eir_data *eir, uint8_t *eir_data, uint8_t eir_len)
        return 0;
 }
 
+int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len)
+{
+
+       if (eir_len < EIR_OOB_MIN)
+               return -1;
+
+       if (eir_len != bt_get_le16(eir_data))
+               return -1;
+
+       eir_data += sizeof(uint16_t);
+       eir_len -= sizeof(uint16_t);
+
+       memcpy(&eir->addr, eir_data, sizeof(bdaddr_t));
+       eir_data += sizeof(bdaddr_t);
+       eir_len -= sizeof(bdaddr_t);
+
+       /* optional OOB EIR data */
+       if (eir_len > 0)
+               return eir_parse(eir, eir_data, eir_len);
+
+       return 0;
+}
+
 #define SIZEOF_UUID128 16
 
-static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
+static void eir_generate_uuid128(sdp_list_t *list, uint8_t *ptr,
+                                                       uint16_t *eir_len)
 {
        int i, k, uuid_count = 0;
        uint16_t len = *eir_len;
@@ -189,10 +267,11 @@ static void eir_generate_uuid128(GSList *list, uint8_t *ptr, uint16_t *eir_len)
        uuid128 = ptr + 2;
 
        for (; list; list = list->next) {
-               struct uuid_info *uuid = list->data;
-               uint8_t *uuid128_data = uuid->uuid.value.uuid128.data;
+               sdp_record_t *rec = list->data;
+               uuid_t *uuid = &rec->svclass;
+               uint8_t *uuid128_data = uuid->value.uuid128.data;
 
-               if (uuid->uuid.type != SDP_UUID128)
+               if (uuid->type != SDP_UUID128)
                        continue;
 
                /* Stop if not enough space to put next UUID128 */
@@ -234,18 +313,63 @@ 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,
-                       uint16_t did_source, GSList *uuids, uint8_t *data)
+int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod,
+                       const uint8_t *hash, const uint8_t *randomizer,
+                       uint16_t did_vendor, uint16_t did_product,
+                       uint16_t did_version, uint16_t did_source,
+                       sdp_list_t *uuids, uint8_t *data)
 {
-       GSList *l;
+       sdp_list_t *l;
        uint8_t *ptr = data;
-       uint16_t eir_len = 0;
+       uint16_t eir_optional_len = 0;
+       uint16_t eir_total_len;
        uint16_t uuid16[HCI_MAX_EIR_LENGTH / 2];
        int i, uuid_count = 0;
        gboolean truncated = FALSE;
        size_t name_len;
 
+       eir_total_len =  sizeof(uint16_t) + sizeof(bdaddr_t);
+       ptr += sizeof(uint16_t);
+
+       memcpy(ptr, addr, sizeof(bdaddr_t));
+       ptr += sizeof(bdaddr_t);
+
+       if (cod > 0) {
+               uint8_t class[3];
+
+               class[0] = (uint8_t) cod;
+               class[1] = (uint8_t) (cod >> 8);
+               class[2] = (uint8_t) (cod >> 16);
+
+               *ptr++ = 4;
+               *ptr++ = EIR_CLASS_OF_DEV;
+
+               memcpy(ptr, class, sizeof(class));
+               ptr += sizeof(class);
+
+               eir_optional_len += sizeof(class) + 2;
+       }
+
+       if (hash) {
+               *ptr++ = 17;
+               *ptr++ = EIR_SSP_HASH;
+
+               memcpy(ptr, hash, 16);
+               ptr += 16;
+
+               eir_optional_len += 16 + 2;
+       }
+
+       if (randomizer) {
+               *ptr++ = 17;
+               *ptr++ = EIR_SSP_RANDOMIZER;
+
+               memcpy(ptr, randomizer, 16);
+               ptr += 16;
+
+               eir_optional_len += 16 + 2;
+       }
+
        name_len = strlen(name);
 
        if (name_len > 0) {
@@ -261,17 +385,10 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
 
                memcpy(ptr + 2, name, name_len);
 
-               eir_len += (name_len + 2);
+               eir_optional_len += (name_len + 2);
                ptr += (name_len + 2);
        }
 
-       if (tx_power != 0) {
-               *ptr++ = 2;
-               *ptr++ = EIR_TX_POWER;
-               *ptr++ = (uint8_t) tx_power;
-               eir_len += 3;
-       }
-
        if (did_vendor != 0x0000) {
                *ptr++ = 9;
                *ptr++ = EIR_DEVICE_ID;
@@ -283,38 +400,40 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
                *ptr++ = (did_product & 0xff00) >> 8;
                *ptr++ = (did_version & 0x00ff);
                *ptr++ = (did_version & 0xff00) >> 8;
-               eir_len += 10;
+               eir_optional_len += 10;
        }
 
        /* Group all UUID16 types */
-       for (l = uuids; l != NULL; l = g_slist_next(l)) {
-               struct uuid_info *uuid = l->data;
+       for (l = uuids; l != NULL; l = l->next) {
+               sdp_record_t *rec = l->data;
+               uuid_t *uuid = &rec->svclass;
 
-               if (uuid->uuid.type != SDP_UUID16)
+               if (uuid->type != SDP_UUID16)
                        continue;
 
-               if (uuid->uuid.value.uuid16 < 0x1100)
+               if (uuid->value.uuid16 < 0x1100)
                        continue;
 
-               if (uuid->uuid.value.uuid16 == PNP_INFO_SVCLASS_ID)
+               if (uuid->value.uuid16 == PNP_INFO_SVCLASS_ID)
                        continue;
 
                /* Stop if not enough space to put next UUID16 */
-               if ((eir_len + 2 + sizeof(uint16_t)) > HCI_MAX_EIR_LENGTH) {
+               if ((eir_optional_len + 2 + sizeof(uint16_t)) >
+                               HCI_MAX_EIR_LENGTH) {
                        truncated = TRUE;
                        break;
                }
 
                /* Check for duplicates */
                for (i = 0; i < uuid_count; i++)
-                       if (uuid16[i] == uuid->uuid.value.uuid16)
+                       if (uuid16[i] == uuid->value.uuid16)
                                break;
 
                if (i < uuid_count)
                        continue;
 
-               uuid16[uuid_count++] = uuid->uuid.value.uuid16;
-               eir_len += sizeof(uint16_t);
+               uuid16[uuid_count++] = uuid->value.uuid16;
+               eir_optional_len += sizeof(uint16_t);
        }
 
        if (uuid_count > 0) {
@@ -324,7 +443,7 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
                ptr[1] = truncated ? EIR_UUID16_SOME : EIR_UUID16_ALL;
 
                ptr += 2;
-               eir_len += 2;
+               eir_optional_len += 2;
 
                for (i = 0; i < uuid_count; i++) {
                        *ptr++ = (uuid16[i] & 0x00ff);
@@ -333,65 +452,13 @@ void eir_create(const char *name, int8_t tx_power, uint16_t did_vendor,
        }
 
        /* Group all UUID128 types */
-       if (eir_len <= HCI_MAX_EIR_LENGTH - 2)
-               eir_generate_uuid128(uuids, ptr, &eir_len);
-}
-
-gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type)
-{
-       uint8_t field_len;
-       size_t parsed = 0;
-
-       while (parsed < len - 1) {
-               field_len = data[0];
+       if (eir_optional_len <= HCI_MAX_EIR_LENGTH - 2)
+               eir_generate_uuid128(uuids, ptr, &eir_optional_len);
 
-               if (field_len == 0)
-                       break;
-
-               parsed += field_len + 1;
-
-               if (parsed > len)
-                       break;
+       eir_total_len += eir_optional_len;
 
-               if (data[1] == type)
-                       return TRUE;
-
-               data += field_len + 1;
-       }
-
-       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;
-       }
+       /* store total length */
+       bt_put_le16(eir_total_len, data);
 
-       return length;
+       return eir_total_len;
 }
index 3c81024..1b6242d 100644 (file)
--- a/src/eir.h
+++ b/src/eir.h
 #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_SSP_HASH                0x0E  /* SSP Hash */
+#define EIR_SSP_RANDOMIZER          0x0F  /* SSP Randomizer */
 #define EIR_DEVICE_ID               0x10  /* device ID */
 #define EIR_GAP_APPEARANCE          0x19  /* GAP appearance */
 
-struct uuid_info {
-       uuid_t uuid;
-       uint8_t svc_hint;
-};
-
 struct eir_data {
        GSList *services;
        int flags;
        char *name;
-       uint8_t dev_class[3];
+       uint32_t class;
        uint16_t appearance;
        gboolean name_complete;
+       int8_t tx_power;
+       uint8_t *hash;
+       uint8_t *randomizer;
+       bdaddr_t addr;
 };
 
 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,
-                       uint16_t did_source, GSList *uuids, uint8_t *data);
-
-gboolean eir_has_data_type(uint8_t *data, size_t len, uint8_t type);
-
-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);
+int eir_parse(struct eir_data *eir, const uint8_t *eir_data, uint8_t eir_len);
+int eir_parse_oob(struct eir_data *eir, uint8_t *eir_data, uint16_t eir_len);
+int eir_create_oob(const bdaddr_t *addr, const char *name, uint32_t cod,
+                       const uint8_t *hash, const uint8_t *randomizer,
+                       uint16_t did_vendor, uint16_t did_product,
+                       uint16_t did_version, uint16_t did_source,
+                       sdp_list_t *uuids, uint8_t *data);
index c2d9baa..7692790 100644 (file)
@@ -27,7 +27,7 @@
 #include <config.h>
 #endif
 
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "error.h"
 
diff --git a/src/event.c b/src/event.c
deleted file mode 100644 (file)
index ec5926f..0000000
+++ /dev/null
@@ -1,571 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#define _GNU_SOURCE
-#include <stdio.h>
-#include <ctype.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include <bluetooth/bluetooth.h>
-
-#include <glib.h>
-#include <dbus/dbus.h>
-
-#include "log.h"
-
-#include "adapter.h"
-#include "manager.h"
-#include "device.h"
-#include "error.h"
-#include "dbus-common.h"
-#include "agent.h"
-#include "storage.h"
-#include "event.h"
-
-static gboolean get_adapter_and_device(bdaddr_t *src, bdaddr_t *dst,
-                                       struct btd_adapter **adapter,
-                                       struct btd_device **device,
-                                       gboolean create)
-{
-       DBusConnection *conn = get_dbus_connection();
-       char peer_addr[18];
-
-       *adapter = manager_find_adapter(src);
-       if (!*adapter) {
-               error("Unable to find matching adapter");
-               return FALSE;
-       }
-
-       ba2str(dst, peer_addr);
-
-       if (create)
-               *device = adapter_get_device(conn, *adapter, peer_addr);
-       else
-               *device = adapter_find_device(*adapter, peer_addr);
-
-       if (create && !*device) {
-               error("Unable to get device object!");
-               return FALSE;
-       }
-
-       return TRUE;
-}
-
-/*****************************************************************
- *
- *  Section reserved to HCI commands confirmation handling and low
- *  level events(eg: device attached/dettached.
- *
- *****************************************************************/
-
-static void pincode_cb(struct agent *agent, DBusError *derr,
-                               const char *pincode, struct btd_device *device)
-{
-       struct btd_adapter *adapter = device_get_adapter(device);
-       bdaddr_t dba;
-       int err;
-
-       device_get_address(device, &dba, NULL);
-
-       if (derr) {
-               err = btd_adapter_pincode_reply(adapter, &dba, NULL, 0);
-               if (err < 0)
-                       goto fail;
-               return;
-       }
-
-       err = btd_adapter_pincode_reply(adapter, &dba, pincode,
-                                               pincode ? strlen(pincode) : 0);
-       if (err < 0)
-               goto fail;
-
-       return;
-
-fail:
-       error("Sending PIN code reply failed: %s (%d)", strerror(-err), -err);
-}
-
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure)
-{
-       struct btd_adapter *adapter;
-       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, &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, NULL,
-                                                       secure, pincode_cb);
-}
-
-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, &bdaddr_type);
-
-       return btd_adapter_confirm_reply(adapter, &bdaddr, bdaddr_type,
-                                                               success);
-}
-
-static void confirm_cb(struct agent *agent, DBusError *err, void *user_data)
-{
-       struct btd_device *device = user_data;
-       struct btd_adapter *adapter = device_get_adapter(device);
-       gboolean success = (err == NULL) ? TRUE : FALSE;
-
-       confirm_reply(adapter, device, success);
-}
-
-static void passkey_cb(struct agent *agent, DBusError *err, uint32_t passkey,
-                       void *user_data)
-{
-       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, &bdaddr_type);
-
-       if (err)
-               passkey = INVALID_PASSKEY;
-
-       btd_adapter_passkey_reply(adapter, &bdaddr, bdaddr_type, passkey);
-}
-
-int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-
-       if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
-               return -ENODEV;
-
-       return device_request_authentication(device, AUTH_TYPE_CONFIRM,
-                                               &passkey, FALSE, confirm_cb);
-}
-
-int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-
-       if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
-               return -ENODEV;
-
-       return device_request_authentication(device, AUTH_TYPE_PASSKEY, NULL,
-                                                       FALSE, passkey_cb);
-}
-
-int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-
-       if (!get_adapter_and_device(sba, dba, &adapter, &device, TRUE))
-               return -ENODEV;
-
-       return device_request_authentication(device, AUTH_TYPE_NOTIFY_PASSKEY,
-                                                       &passkey, FALSE, NULL);
-}
-
-void btd_event_simple_pairing_complete(bdaddr_t *local, bdaddr_t *peer,
-                                                               uint8_t status)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       gboolean create;
-
-       DBG("status=%02x", status);
-
-       create = status ? FALSE : TRUE;
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, create))
-               return;
-
-       if (!device)
-               return;
-
-       device_simple_pairing_complete(device, status);
-}
-
-static void update_lastseen(bdaddr_t *sba, bdaddr_t *dba)
-{
-       time_t t;
-       struct tm *tm;
-
-       t = time(NULL);
-       tm = gmtime(&t);
-
-       write_lastseen_info(sba, dba, tm);
-}
-
-static void update_lastused(bdaddr_t *sba, bdaddr_t *dba)
-{
-       time_t t;
-       struct tm *tm;
-
-       t = time(NULL);
-       tm = gmtime(&t);
-
-       write_lastused_info(sba, dba, tm);
-}
-
-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;
-
-       adapter = manager_find_adapter(local);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       update_lastseen(local, peer);
-
-       if (data)
-               write_remote_eir(local, peer, data, data_len);
-
-       adapter_update_found_devices(adapter, peer, bdaddr_type, rssi,
-                                               confirm_name, data, data_len);
-}
-
-void btd_event_set_legacy_pairing(bdaddr_t *local, bdaddr_t *peer,
-                                                       gboolean legacy)
-{
-       struct btd_adapter *adapter;
-       struct remote_dev_info *dev;
-
-       adapter = manager_find_adapter(local);
-       if (!adapter) {
-               error("No matching adapter found");
-               return;
-       }
-
-       dev = adapter_search_found_devices(adapter, peer);
-       if (dev)
-               dev->legacy = legacy;
-}
-
-void btd_event_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t class)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       uint32_t old_class = 0;
-
-       read_remote_class(local, peer, &old_class);
-
-       if (old_class == class)
-               return;
-
-       write_remote_class(local, peer, class);
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
-               return;
-
-       if (!device)
-               return;
-
-       device_set_class(device, class);
-}
-
-void btd_event_remote_name(bdaddr_t *local, bdaddr_t *peer, char *name)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       struct remote_dev_info *dev_info;
-
-       if (!g_utf8_validate(name, -1, NULL)) {
-               int i;
-
-               /* Assume ASCII, and replace all non-ASCII with spaces */
-               for (i = 0; name[i] != '\0'; i++) {
-                       if (!isascii(name[i]))
-                               name[i] = ' ';
-               }
-               /* Remove leading and trailing whitespace characters */
-               g_strstrip(name);
-       }
-
-       write_device_name(local, peer, name);
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
-               return;
-
-       dev_info = adapter_search_found_devices(adapter, peer);
-       if (dev_info) {
-               g_free(dev_info->name);
-               dev_info->name = g_strdup(name);
-               adapter_emit_device_found(adapter, dev_info);
-       }
-
-       if (device)
-               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)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       int ret;
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
-               return -ENODEV;
-
-       DBG("storing link key of type 0x%02x", key_type);
-
-       ret = write_link_key(local, peer, key, key_type, pin_length);
-
-       if (ret == 0) {
-               device_set_bonded(device, TRUE);
-
-               if (device_is_temporary(device))
-                       device_set_temporary(device, FALSE);
-       }
-
-       return ret;
-}
-
-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;
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
-               return;
-
-       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)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-       DBusConnection *conn = get_dbus_connection();
-
-       DBG("status 0x%02x", status);
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
-               return;
-
-       if (!device)
-               return;
-
-       if (device_is_bonding(device, NULL))
-               device_cancel_bonding(device, status);
-
-       if (device_is_temporary(device))
-               adapter_remove_device(conn, adapter, device, TRUE);
-}
-
-void btd_event_disconn_complete(bdaddr_t *local, bdaddr_t *peer)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-
-       DBG("");
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, FALSE))
-               return;
-
-       if (!device)
-               return;
-
-       adapter_remove_connection(adapter, device);
-}
-
-void btd_event_device_blocked(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;
-
-       if (device)
-               device_block(conn, device, TRUE);
-}
-
-void btd_event_device_unblocked(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;
-
-       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 */
-
-void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer)
-{
-       struct btd_adapter *adapter;
-       struct btd_device *device;
-
-       if (!get_adapter_and_device(local, peer, &adapter, &device, TRUE))
-               return;
-
-       device_set_paired(device, TRUE);
-}
diff --git a/src/event.h b/src/event.h
deleted file mode 100644 (file)
index dfc158d..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int btd_event_request_pin(bdaddr_t *sba, bdaddr_t *dba, gboolean secure);
-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, 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);
-void btd_event_returned_link_key(bdaddr_t *local, bdaddr_t *peer);
-int btd_event_user_confirm(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
-int btd_event_user_passkey(bdaddr_t *sba, bdaddr_t *dba);
-int btd_event_user_notify(bdaddr_t *sba, bdaddr_t *dba, uint32_t passkey);
-void btd_event_device_blocked(bdaddr_t *local, bdaddr_t *peer);
-void btd_event_device_unblocked(bdaddr_t *local, bdaddr_t *peer);
-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 419c655..4a020e9 100644 (file)
 
 #include <glib.h>
 
-#include "btio.h"
 #include "glib-helper.h"
 
+char *bt_modalias(uint16_t source, uint16_t vendor,
+                                       uint16_t product, uint16_t version)
+{
+       switch (source) {
+       case 0x0001:
+               return g_strdup_printf("%s:v%04Xp%04Xd%04X",
+                                       "bluetooth", vendor, product, version);
+       case 0x0002:
+               return g_strdup_printf("%s:v%04Xp%04Xd%04X",
+                                       "usb", vendor, product, version);
+       }
+
+       return NULL;
+}
+
 char *bt_uuid2string(uuid_t *uuid)
 {
-       gchar *str;
+       char *str;
        uuid_t uuid128;
        unsigned int data0;
        unsigned short data1;
@@ -89,7 +103,6 @@ static struct {
        const char      *name;
        uint16_t        class;
 } bt_services[] = {
-       { "vcp",        VIDEO_CONF_SVCLASS_ID           },
        { "pbap",       PBAP_SVCLASS_ID                 },
        { "sap",        SAP_SVCLASS_ID                  },
        { "ftp",        OBEX_FILETRANS_SVCLASS_ID       },
@@ -101,7 +114,18 @@ static struct {
        { "fax",        FAX_SVCLASS_ID                  },
        { "spp",        SERIAL_PORT_SVCLASS_ID          },
        { "hsp",        HEADSET_SVCLASS_ID              },
+       { "hsp-hs",     HEADSET_SVCLASS_ID              },
+       { "hsp-ag",     HEADSET_AGW_SVCLASS_ID          },
        { "hfp",        HANDSFREE_SVCLASS_ID            },
+       { "hfp-hf",     HANDSFREE_SVCLASS_ID            },
+       { "hfp-ag",     HANDSFREE_AGW_SVCLASS_ID        },
+       { "pbap-pce",   PBAP_PCE_SVCLASS_ID             },
+       { "pbap-pse",   PBAP_PSE_SVCLASS_ID             },
+       { "map-mse",    MAP_MSE_SVCLASS_ID              },
+       { "map-mas",    MAP_MSE_SVCLASS_ID              },
+       { "map-mce",    MAP_MCE_SVCLASS_ID              },
+       { "map-mns",    MAP_MCE_SVCLASS_ID              },
+       { "gnss",       GNSS_SERVER_SVCLASS_ID          },
        { }
 };
 
@@ -211,46 +235,3 @@ int bt_string2uuid(uuid_t *uuid, const char *string)
                return string2uuid16(uuid, string);
        }
 }
-
-gchar *bt_list2string(GSList *list)
-{
-       GSList *l;
-       gchar *str, *tmp;
-
-       if (!list)
-               return NULL;
-
-       str = g_strdup((const gchar *) list->data);
-
-       for (l = list->next; l; l = l->next) {
-               tmp = g_strconcat(str, " " , (const gchar *) l->data, NULL);
-               g_free(str);
-               str = tmp;
-       }
-
-       return str;
-}
-
-GSList *bt_string2list(const gchar *str)
-{
-       GSList *l = NULL;
-       gchar **uuids;
-       int i = 0;
-
-       if (!str)
-               return NULL;
-
-       /* FIXME: eglib doesn't support g_strsplit */
-       uuids = g_strsplit(str, " ", 0);
-       if (!uuids)
-               return NULL;
-
-       while (uuids[i]) {
-               l = g_slist_append(l, uuids[i]);
-               i++;
-       }
-
-       g_free(uuids);
-
-       return l;
-}
index 8836804..c0d7f9e 100644 (file)
@@ -21,8 +21,8 @@
  *
  */
 
-gchar *bt_uuid2string(uuid_t *uuid);
+char *bt_modalias(uint16_t source, uint16_t vendor,
+                                       uint16_t product, uint16_t version);
+char *bt_uuid2string(uuid_t *uuid);
 char *bt_name2string(const char *string);
 int bt_string2uuid(uuid_t *uuid, const char *string);
-gchar *bt_list2string(GSList *list);
-GSList *bt_string2list(const gchar *str);
index 1e5e15a..ea67cc2 100644 (file)
  */
 
 struct main_opts {
-       char            host_name[40];
-       unsigned long   flags;
        char            *name;
        uint32_t        class;
-       uint16_t        pageto;
        uint16_t        autoto;
-       uint32_t        discovto;
        uint32_t        pairto;
-       uint16_t        link_mode;
-       uint16_t        link_policy;
-       gboolean        remember_powered;
+       uint32_t        discovto;
        gboolean        reverse_sdp;
        gboolean        name_resolv;
        gboolean        debug_keys;
-       gboolean        gatt_enabled;
-
-       uint8_t         mode;
 
        uint16_t        did_source;
        uint16_t        did_vendor;
@@ -48,18 +39,12 @@ struct main_opts {
        uint16_t        did_version;
 };
 
-enum {
-       HCID_SET_PAGETO,
-};
-
 extern struct main_opts main_opts;
 
-void btd_start_exit_timer(void);
-void btd_stop_exit_timer(void);
-
-gboolean plugin_init(GKeyFile *config, const char *enable,
-                                                       const char *disable);
+gboolean plugin_init(const char *enable, const char *disable);
 void plugin_cleanup(void);
 
 void rfkill_init(void);
 void rfkill_exit(void);
+
+void btd_exit(void);
index 75a98a9..ca783f3 100644 (file)
--- a/src/log.c
+++ b/src/log.c
@@ -80,7 +80,7 @@ void btd_debug(const char *format, ...)
 extern struct btd_debug_desc __start___debug[];
 extern struct btd_debug_desc __stop___debug[];
 
-static gchar **enabled = NULL;
+static char **enabled = NULL;
 
 static gboolean is_enabled(struct btd_debug_desc *desc)
 {
index 3d34fa3..bf9eac2 100644 (file)
--- a/src/log.h
+++ b/src/log.h
@@ -55,5 +55,5 @@ void __btd_enable_debug(struct btd_debug_desc *start,
                .file = __FILE__, .flags = BTD_DEBUG_FLAG_DEFAULT, \
        }; \
        if (__btd_debug_desc.flags & BTD_DEBUG_FLAG_PRINT) \
-               btd_debug("%s:%s() " fmt,  __FILE__, __FUNCTION__ , ## arg); \
+               btd_debug("%s:%s() " fmt,  __FILE__, __func__ , ## arg); \
 } while (0)
index 286baa0..91d90b4 100644 (file)
 #include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
 
 #include <glib.h>
 
 #include <dbus/dbus.h>
 
-#include <gdbus.h>
+#include <gdbus/gdbus.h>
 
 #include "log.h"
 
+#include "lib/uuid.h"
 #include "hcid.h"
 #include "sdpd.h"
 #include "adapter.h"
+#include "device.h"
 #include "dbus-common.h"
 #include "agent.h"
-#include "manager.h"
+#include "profile.h"
+#include "systemd.h"
 
 #define BLUEZ_NAME "org.bluez"
 
-#define LAST_ADAPTER_EXIT_TIMEOUT 30
-
+#define DEFAULT_PAIRABLE_TIMEOUT       0 /* disabled */
 #define DEFAULT_DISCOVERABLE_TIMEOUT 180 /* 3 minutes */
-#define DEFAULT_AUTO_CONNECT_TIMEOUT  60 /* 60 seconds */
+
+#define SHUTDOWN_GRACE_SECONDS 10
 
 struct main_opts main_opts;
 
+static const char * const supported_options[] = {
+       "Name",
+       "Class",
+       "DiscoverableTimeout",
+       "PairableTimeout",
+       "AutoConnectTimeout",
+       "DeviceID",
+       "ReverseServiceDiscovery",
+       "NameResolving",
+       "DebugKeys",
+};
+
 static GKeyFile *load_config(const char *file)
 {
        GError *err = NULL;
@@ -74,7 +88,8 @@ static GKeyFile *load_config(const char *file)
        g_key_file_set_list_separator(keyfile, ',');
 
        if (!g_key_file_load_from_file(keyfile, file, 0, &err)) {
-               error("Parsing %s failed: %s", file, err->message);
+               if (!g_error_matches(err, G_FILE_ERROR, G_FILE_ERROR_NOENT))
+                       error("Parsing %s failed: %s", file, err->message);
                g_error_free(err);
                g_key_file_free(keyfile);
                return NULL;
@@ -92,13 +107,15 @@ static void parse_did(const char *did)
        version = 0x0000;
        source = 0x0002;
 
-       result = sscanf(did, "bluetooth:%4hx:%4hx:%4hx", &vendor, &product, &version);
+       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);
+       result = sscanf(did, "usb:%4hx:%4hx:%4hx",
+                                       &vendor, &product, &version);
        if (result != EOF && result >= 2)
                goto done;
 
@@ -113,6 +130,44 @@ done:
        main_opts.did_version = version;
 }
 
+static void check_config(GKeyFile *config)
+{
+       char **keys;
+       int i;
+
+       if (!config)
+               return;
+
+       keys = g_key_file_get_groups(config, NULL);
+
+       for (i = 0; keys != NULL && keys[i] != NULL; i++) {
+               if (!g_str_equal(keys[i], "General"))
+                       warn("Unknown group %s in main.conf", keys[i]);
+       }
+
+       g_strfreev(keys);
+
+       keys = g_key_file_get_keys(config, "General", NULL, NULL);
+
+       for (i = 0; keys != NULL && keys[i] != NULL; i++) {
+               bool found;
+               unsigned int j;
+
+               found = false;
+               for (j = 0; j < G_N_ELEMENTS(supported_options); j++) {
+                       if (g_str_equal(keys[i], supported_options[j])) {
+                               found = true;
+                               break;
+                       }
+               }
+
+               if (!found)
+                       warn("Unknown key %s in main.conf", keys[i]);
+       }
+
+       g_strfreev(keys);
+}
+
 static void parse_config(GKeyFile *config)
 {
        GError *err = NULL;
@@ -123,6 +178,8 @@ static void parse_config(GKeyFile *config)
        if (!config)
                return;
 
+       check_config(config);
+
        DBG("parsing main.conf");
 
        val = g_key_file_get_integer(config, "General",
@@ -145,16 +202,6 @@ static void parse_config(GKeyFile *config)
                main_opts.pairto = val;
        }
 
-       val = g_key_file_get_integer(config, "General", "PageTimeout", &err);
-       if (err) {
-               DBG("%s", err->message);
-               g_clear_error(&err);
-       } else {
-               DBG("pageto=%d", val);
-               main_opts.pageto = val;
-               main_opts.flags |= 1 << HCID_SET_PAGETO;
-       }
-
        val = g_key_file_get_integer(config, "General", "AutoConnectTimeout",
                                                                        &err);
        if (err) {
@@ -172,8 +219,7 @@ static void parse_config(GKeyFile *config)
        } else {
                DBG("name=%s", str);
                g_free(main_opts.name);
-               main_opts.name = g_strdup(str);
-               g_free(str);
+               main_opts.name = str;
        }
 
        str = g_key_file_get_string(config, "General", "Class", &err);
@@ -186,22 +232,6 @@ static void parse_config(GKeyFile *config)
                g_free(str);
        }
 
-       boolean = g_key_file_get_boolean(config, "General",
-                                               "InitiallyPowered", &err);
-       if (err) {
-               DBG("%s", err->message);
-               g_clear_error(&err);
-       } else if (boolean == FALSE)
-               main_opts.mode = MODE_OFF;
-
-       boolean = g_key_file_get_boolean(config, "General",
-                                               "RememberPowered", &err);
-       if (err) {
-               DBG("%s", err->message);
-               g_clear_error(&err);
-       } else
-               main_opts.remember_powered = boolean;
-
        str = g_key_file_get_string(config, "General", "DeviceID", &err);
        if (err) {
                DBG("%s", err->message);
@@ -233,43 +263,48 @@ static void parse_config(GKeyFile *config)
                g_clear_error(&err);
        else
                main_opts.debug_keys = boolean;
-
-       boolean = g_key_file_get_boolean(config, "General",
-                                               "EnableGatt", &err);
-       if (err)
-               g_clear_error(&err);
-       else
-               main_opts.gatt_enabled = boolean;
-
-       main_opts.link_mode = HCI_LM_ACCEPT;
-
-       main_opts.link_policy = HCI_LP_RSWITCH | HCI_LP_SNIFF |
-                                               HCI_LP_HOLD | HCI_LP_PARK;
 }
 
 static void init_defaults(void)
 {
+       uint8_t major, minor;
+
        /* Default HCId settings */
        memset(&main_opts, 0, sizeof(main_opts));
-       main_opts.mode  = MODE_CONNECTABLE;
-       main_opts.name  = g_strdup("BlueZ");
-       main_opts.discovto      = DEFAULT_DISCOVERABLE_TIMEOUT;
-       main_opts.autoto = DEFAULT_AUTO_CONNECT_TIMEOUT;
-       main_opts.remember_powered = TRUE;
+       main_opts.name = g_strdup_printf("BlueZ %s", VERSION);
+       main_opts.class = 0x000000;
+       main_opts.pairto = DEFAULT_PAIRABLE_TIMEOUT;
+       main_opts.discovto = DEFAULT_DISCOVERABLE_TIMEOUT;
        main_opts.reverse_sdp = TRUE;
        main_opts.name_resolv = TRUE;
+       main_opts.debug_keys = FALSE;
+
+       if (sscanf(VERSION, "%hhu.%hhu", &major, &minor) != 2)
+               return;
 
-       if (gethostname(main_opts.host_name, sizeof(main_opts.host_name) - 1) < 0)
-               strcpy(main_opts.host_name, "noname");
+       main_opts.did_source = 0x0002;          /* USB */
+       main_opts.did_vendor = 0x1d6b;          /* Linux Foundation */
+       main_opts.did_product = 0x0246;         /* BlueZ */
+       main_opts.did_version = (major << 8 | minor);
 }
 
 static GMainLoop *event_loop;
 
-static unsigned int __terminated = 0;
+void btd_exit(void)
+{
+       g_main_loop_quit(event_loop);
+}
+
+static gboolean quit_eventloop(gpointer user_data)
+{
+       btd_exit();
+       return FALSE;
+}
 
 static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
                                                        gpointer user_data)
 {
+       static unsigned int __terminated = 0;
        struct signalfd_siginfo si;
        ssize_t result;
        int fd;
@@ -288,7 +323,11 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
        case SIGTERM:
                if (__terminated == 0) {
                        info("Terminating");
-                       g_main_loop_quit(event_loop);
+                       g_timeout_add_seconds(SHUTDOWN_GRACE_SECONDS,
+                                                       quit_eventloop, NULL);
+
+                       sd_notify(0, "STATUS=Powering down");
+                       adapter_shutdown();
                }
 
                __terminated = 1;
@@ -296,9 +335,6 @@ static gboolean signal_handler(GIOChannel *channel, GIOCondition cond,
        case SIGUSR2:
                __btd_toggle_debug();
                break;
-       case SIGPIPE:
-               /* ignore */
-               break;
        }
 
        return TRUE;
@@ -315,7 +351,6 @@ static guint setup_signalfd(void)
        sigaddset(&mask, SIGINT);
        sigaddset(&mask, SIGTERM);
        sigaddset(&mask, SIGUSR2);
-       sigaddset(&mask, SIGPIPE);
 
        if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
                perror("Failed to set signal mask");
@@ -343,57 +378,45 @@ static guint setup_signalfd(void)
        return source;
 }
 
-static gchar *option_debug = NULL;
-static gchar *option_plugin = NULL;
-static gchar *option_noplugin = NULL;
+static char *option_debug = NULL;
+static char *option_plugin = NULL;
+static char *option_noplugin = NULL;
+static gboolean option_compat = FALSE;
 static gboolean option_detach = TRUE;
 static gboolean option_version = FALSE;
-static gboolean option_udev = FALSE;
-
-static guint last_adapter_timeout = 0;
+static gboolean option_experimental = FALSE;
 
-static gboolean exit_timeout(gpointer data)
+static void free_options(void)
 {
-       g_main_loop_quit(event_loop);
-       last_adapter_timeout = 0;
-       return FALSE;
-}
-
-void btd_start_exit_timer(void)
-{
-       if (option_udev == FALSE)
-               return;
+       g_free(option_debug);
+       option_debug = NULL;
 
-       if (last_adapter_timeout > 0)
-               g_source_remove(last_adapter_timeout);
+       g_free(option_plugin);
+       option_plugin = NULL;
 
-       last_adapter_timeout = g_timeout_add_seconds(LAST_ADAPTER_EXIT_TIMEOUT,
-                                               exit_timeout, NULL);
-}
-
-void btd_stop_exit_timer(void)
-{
-       if (last_adapter_timeout == 0)
-               return;
-
-       g_source_remove(last_adapter_timeout);
-       last_adapter_timeout = 0;
+       g_free(option_noplugin);
+       option_noplugin = NULL;
 }
 
 static void disconnect_dbus(void)
 {
-       DBusConnection *conn = get_dbus_connection();
+       DBusConnection *conn = btd_get_dbus_connection();
 
        if (!conn || !dbus_connection_get_is_connected(conn))
                return;
 
-       manager_cleanup(conn, "/");
-
+       g_dbus_detach_object_manager(conn);
        set_dbus_connection(NULL);
 
        dbus_connection_unref(conn);
 }
 
+static void disconnected_dbus(DBusConnection *conn, void *data)
+{
+       info("Disconnected from D-Bus. Exiting.");
+       g_main_loop_quit(event_loop);
+}
+
 static int connect_dbus(void)
 {
        DBusConnection *conn;
@@ -411,14 +434,21 @@ static int connect_dbus(void)
                return -EALREADY;
        }
 
-       if (!manager_init(conn, "/"))
-               return -EIO;
-
        set_dbus_connection(conn);
 
+       g_dbus_set_disconnect_function(conn, disconnected_dbus, NULL, NULL);
+       g_dbus_attach_object_manager(conn);
+
        return 0;
 }
 
+static gboolean watchdog_callback(gpointer user_data)
+{
+       sd_notify(0, "WATCHDOG=1");
+
+       return TRUE;
+}
+
 static gboolean parse_debug(const char *key, const char *value,
                                gpointer user_data, GError **error)
 {
@@ -438,13 +468,15 @@ static GOptionEntry options[] = {
                                "Specify plugins to load", "NAME,..," },
        { "noplugin", 'P', 0, G_OPTION_ARG_STRING, &option_noplugin,
                                "Specify plugins not to load", "NAME,..." },
+       { "compat", 'C', 0, G_OPTION_ARG_NONE, &option_compat,
+                               "Provide deprecated command line interfaces" },
+       { "experimental", 'E', 0, G_OPTION_ARG_NONE, &option_experimental,
+                               "Enable experimental interfaces" },
        { "nodetach", 'n', G_OPTION_FLAG_REVERSE,
                                G_OPTION_ARG_NONE, &option_detach,
-                               "Don't run as daemon in background" },
+                               "Run with logging in foreground" },
        { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
                                "Show version information and exit" },
-       { "udev", 'u', 0, G_OPTION_ARG_NONE, &option_udev,
-                               "Run from udev mode of operation" },
        { NULL },
 };
 
@@ -452,9 +484,12 @@ int main(int argc, char *argv[])
 {
        GOptionContext *context;
        GError *err = NULL;
-       uint16_t mtu = 0;
+       uint16_t sdp_mtu = 0;
+       uint32_t sdp_flags = 0;
+       int gdbus_flags = 0;
        GKeyFile *config;
-       guint signal;
+       guint signal, watchdog;
+       const char *watchdog_usec;
 
        init_defaults();
 
@@ -477,25 +512,6 @@ int main(int argc, char *argv[])
                exit(0);
        }
 
-       if (option_udev == TRUE) {
-               int err;
-
-               option_detach = TRUE;
-               err = connect_dbus();
-               if (err < 0) {
-                       if (err == -EALREADY)
-                               exit(0);
-                       exit(1);
-               }
-       }
-
-       if (option_detach == TRUE && option_udev == FALSE) {
-               if (daemon(0, 0)) {
-                       perror("Can't start daemon");
-                       exit(1);
-               }
-       }
-
        umask(0077);
 
        event_loop = g_main_loop_new(NULL, FALSE);
@@ -504,62 +520,100 @@ int main(int argc, char *argv[])
 
        __btd_log_init(option_debug, option_detach);
 
+       sd_notify(0, "STATUS=Starting up");
+
        config = load_config(CONFIGDIR "/main.conf");
 
        parse_config(config);
 
-       agent_init();
+       if (connect_dbus() < 0) {
+               error("Unable to get on D-Bus");
+               exit(1);
+       }
 
-       if (option_udev == FALSE) {
-               if (connect_dbus() < 0) {
-                       error("Unable to get on D-Bus");
-                       exit(1);
-               }
-       } else {
-               if (daemon(0, 0)) {
-                       perror("Can't start daemon");
-                       exit(1);
-               }
+       if (adapter_init() < 0) {
+               error("Adapter handling initialization failed");
+               exit(1);
        }
 
-       start_sdp_server(mtu, SDP_SERVER_COMPAT);
+       btd_device_init();
+       btd_agent_init();
+       btd_profile_init();
+
+       if (option_experimental)
+               gdbus_flags = G_DBUS_FLAG_ENABLE_EXPERIMENTAL;
+
+       g_dbus_set_flags(gdbus_flags);
+
+       if (option_compat == TRUE)
+               sdp_flags |= SDP_SERVER_COMPAT;
+
+       start_sdp_server(sdp_mtu, sdp_flags);
+
+       if (main_opts.did_source > 0)
+               register_device_id(main_opts.did_source, main_opts.did_vendor,
+                               main_opts.did_product, main_opts.did_version);
 
        /* Loading plugins has to be done after D-Bus has been setup since
         * the plugins might wanna expose some paths on the bus. However the
         * best order of how to init various subsystems of the Bluetooth
         * daemon needs to be re-worked. */
-       plugin_init(config, option_plugin, option_noplugin);
+       plugin_init(option_plugin, option_noplugin);
 
-       if (adapter_ops_setup() < 0) {
-               error("adapter_ops_setup failed");
-               exit(1);
-       }
+       /* no need to keep parsed option in memory */
+       free_options();
 
        rfkill_init();
 
        DBG("Entering main loop");
 
+       sd_notify(0, "STATUS=Running");
+       sd_notify(0, "READY=1");
+
+       watchdog_usec = getenv("WATCHDOG_USEC");
+       if (watchdog_usec) {
+               unsigned int seconds;
+
+               seconds = atoi(watchdog_usec) / (1000 * 1000);
+               info("Watchdog timeout is %d seconds", seconds);
+
+               watchdog = g_timeout_add_seconds_full(G_PRIORITY_HIGH,
+                                                       seconds / 2,
+                                                       watchdog_callback,
+                                                       NULL, NULL);
+       } else
+               watchdog = 0;
+
        g_main_loop_run(event_loop);
 
+       sd_notify(0, "STATUS=Quitting");
+
        g_source_remove(signal);
 
-       disconnect_dbus();
+       plugin_cleanup();
 
-       rfkill_exit();
+       btd_profile_cleanup();
+       btd_agent_cleanup();
+       btd_device_cleanup();
 
-       plugin_cleanup();
+       adapter_cleanup();
 
-       stop_sdp_server();
+       rfkill_exit();
 
-       agent_exit();
+       stop_sdp_server();
 
        g_main_loop_unref(event_loop);
 
        if (config)
                g_key_file_free(config);
 
+       disconnect_dbus();
+
        info("Exit");
 
+       if (watchdog > 0)
+               g_source_remove(watchdog);
+
        __btd_log_cleanup();
 
        return 0;
index 787ef4f..a94274a 100644 (file)
@@ -1,43 +1,30 @@
 [General]
 
-# List of plugins that should not be loaded on bluetoothd startup
-#DisablePlugins = network,input
-
 # Default adaper name
 # %h - substituted for hostname
 # %d - substituted for adapter id
-Name = %h-%d
+# Defaults to 'BlueZ'
+#Name = %h-%d
 
 # Default device class. Only the major and minor device class bits are
-# considered.
-Class = 0x000100
+# considered. Defaults to '0x000000'.
+#Class = 0x000100
 
 # How long to stay in discoverable mode before going back to non-discoverable
 # The value is in seconds. Default is 180, i.e. 3 minutes.
 # 0 = disable timer, i.e. stay discoverable forever
-DiscoverableTimeout = 0
+#DiscoverableTimeout = 0
 
 # How long to stay in pairable mode before going back to non-discoverable
 # The value is in seconds. Default is 0.
 # 0 = disable timer, i.e. stay pairable forever
-PairableTimeout = 0
-
-# Use some other page timeout than the controller default one
-# which is 16384 (10 seconds).
-PageTimeout = 8192
+#PairableTimeout = 0
 
 # Automatic connection for bonded devices driven by platform/user events.
 # If a platform plugin uses this mechanism, automatic connections will be
 # enabled during the interval defined below. Initially, this feature
-# intends to be used to establish connections to ATT channels.
-AutoConnectTimeout = 60
-
-# What value should be assumed for the adapter Powered property when
-# SetProperty(Powered, ...) hasn't been called yet. Defaults to true
-InitiallyPowered = true
-
-# Remember the previously stored Powered state when initializing adapters
-RememberPowered = true
+# intends to be used to establish connections to ATT channels. Default is 60.
+#AutoConnectTimeout = 60
 
 # Use vendor id source (assigner), vendor, product and version information for
 # DID profile support. The values are separated by ":" and assigner, VID, PID
@@ -48,17 +35,14 @@ RememberPowered = true
 # Do reverse service discovery for previously unknown devices that connect to
 # us. This option is really only needed for qualification since the BITE tester
 # doesn't like us doing reverse SDP for some test cases (though there could in
-# theory be other useful purposes for this too). Defaults to true.
-ReverseServiceDiscovery = true
+# theory be other useful purposes for this too). Defaults to 'true'.
+#ReverseServiceDiscovery = true
 
 # Enable name resolving after inquiry. Set it to 'false' if you don't need
 # remote devices name and want shorter discovery cycle. Defaults to 'true'.
-NameResolving = true
+#NameResolving = true
 
 # Enable runtime persistency of debug link keys. Default is false which
 # makes debug link keys valid only for the duration of the connection
 # that they were created for.
-DebugKeys = false
-
-# Enable the GATT functionality. Default is false
-EnableGatt = false
+#DebugKeys = false
diff --git a/src/manager.c b/src/manager.c
deleted file mode 100644 (file)
index 385354d..0000000
+++ /dev/null
@@ -1,455 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-#include <glib.h>
-
-#include <dbus/dbus.h>
-
-#include <gdbus.h>
-
-#include "glib-helper.h"
-#include "hcid.h"
-#include "dbus-common.h"
-#include "log.h"
-#include "adapter.h"
-#include "error.h"
-#include "manager.h"
-
-static char base_path[50] = "/org/bluez";
-
-static DBusConnection *connection = NULL;
-static int default_adapter_id = -1;
-static GSList *adapters = NULL;
-
-const char *manager_get_base_path(void)
-{
-       return base_path;
-}
-
-static DBusMessage *default_adapter(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       struct btd_adapter *adapter;
-       const gchar *path;
-
-       adapter = manager_find_adapter_by_id(default_adapter_id);
-       if (!adapter)
-               return btd_error_no_such_adapter(msg);
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       path = adapter_get_path(adapter);
-
-       dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *find_adapter(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       struct btd_adapter *adapter;
-       const char *pattern;
-       int dev_id;
-       const gchar *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_STRING, &pattern,
-                                                       DBUS_TYPE_INVALID))
-               return NULL;
-
-       /* hci_devid() would make sense to use here, except it is
-        * restricted to devices which are up */
-       if (!strcmp(pattern, "any") || !strcmp(pattern, "00:00:00:00:00:00")) {
-               path = adapter_any_get_path();
-               if (path != NULL)
-                       goto done;
-               return btd_error_no_such_adapter(msg);
-       } else if (!strncmp(pattern, "hci", 3) && strlen(pattern) >= 4) {
-               dev_id = atoi(pattern + 3);
-               adapter = manager_find_adapter_by_id(dev_id);
-       } else {
-               bdaddr_t bdaddr;
-               str2ba(pattern, &bdaddr);
-               adapter = manager_find_adapter(&bdaddr);
-       }
-
-       if (!adapter)
-               return btd_error_no_such_adapter(msg);
-
-       path = adapter_get_path(adapter);
-
-done:
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_append_args(reply, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID);
-
-       return reply;
-}
-
-static DBusMessage *list_adapters(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       DBusMessageIter iter;
-       DBusMessageIter array_iter;
-       DBusMessage *reply;
-       GSList *l;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                               DBUS_TYPE_OBJECT_PATH_AS_STRING, &array_iter);
-
-       for (l = adapters; l; l = l->next) {
-               struct btd_adapter *adapter = l->data;
-               const gchar *path = adapter_get_path(adapter);
-
-               dbus_message_iter_append_basic(&array_iter,
-                                       DBUS_TYPE_OBJECT_PATH, &path);
-       }
-
-       dbus_message_iter_close_container(&iter, &array_iter);
-
-       return reply;
-}
-
-static DBusMessage *get_properties(DBusConnection *conn,
-                                       DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       GSList *list;
-       char **array;
-       int i;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       array = g_new0(char *, g_slist_length(adapters) + 1);
-       for (i = 0, list = adapters; list; list = list->next) {
-               struct btd_adapter *adapter = list->data;
-
-               array[i] = (char *) adapter_get_path(adapter);
-               i++;
-       }
-       dict_append_array(&dict, "Adapters", DBUS_TYPE_OBJECT_PATH, &array, i);
-       g_free(array);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-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 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" })) },
-       { }
-};
-
-dbus_bool_t manager_init(DBusConnection *conn, const char *path)
-{
-       connection = conn;
-
-       snprintf(base_path, sizeof(base_path), "/org/bluez/%d", getpid());
-
-       return g_dbus_register_interface(conn, "/", MANAGER_INTERFACE,
-                                       manager_methods, manager_signals,
-                                       NULL, NULL, NULL);
-}
-
-static void manager_update_adapters(void)
-{
-       GSList *list;
-       char **array;
-       int i;
-
-       array = g_new0(char *, g_slist_length(adapters) + 1);
-       for (i = 0, list = adapters; list; list = list->next) {
-               struct btd_adapter *adapter = list->data;
-
-               array[i] = (char *) adapter_get_path(adapter);
-               i++;
-       }
-
-       emit_array_property_changed(connection, "/",
-                                       MANAGER_INTERFACE, "Adapters",
-                                       DBUS_TYPE_OBJECT_PATH, &array, i);
-
-       g_free(array);
-}
-
-static void manager_set_default_adapter(int id)
-{
-       struct btd_adapter *adapter;
-       const gchar *path;
-
-       default_adapter_id = id;
-
-       adapter = manager_find_adapter_by_id(id);
-       if (!adapter)
-               return;
-
-       path = adapter_get_path(adapter);
-
-       g_dbus_emit_signal(connection, "/",
-                       MANAGER_INTERFACE,
-                       "DefaultAdapterChanged",
-                       DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_INVALID);
-}
-
-struct btd_adapter *manager_get_default_adapter(void)
-{
-       return manager_find_adapter_by_id(default_adapter_id);
-}
-
-static void manager_remove_adapter(struct btd_adapter *adapter)
-{
-       uint16_t dev_id = adapter_get_dev_id(adapter);
-       const gchar *path = adapter_get_path(adapter);
-
-       adapters = g_slist_remove(adapters, adapter);
-
-       manager_update_adapters();
-
-       if (default_adapter_id == dev_id || default_adapter_id < 0) {
-               int new_default = hci_get_route(NULL);
-
-               manager_set_default_adapter(new_default);
-       }
-
-       g_dbus_emit_signal(connection, "/",
-                       MANAGER_INTERFACE, "AdapterRemoved",
-                       DBUS_TYPE_OBJECT_PATH, &path,
-                       DBUS_TYPE_INVALID);
-
-       adapter_remove(adapter);
-       btd_adapter_unref(adapter);
-
-       if (adapters == NULL)
-               btd_start_exit_timer();
-}
-
-void manager_cleanup(DBusConnection *conn, const char *path)
-{
-       while (adapters) {
-               struct btd_adapter *adapter = adapters->data;
-
-               adapters = g_slist_remove(adapters, adapter);
-               adapter_remove(adapter);
-               btd_adapter_unref(adapter);
-       }
-
-       btd_start_exit_timer();
-
-       g_dbus_unregister_interface(conn, "/", MANAGER_INTERFACE);
-}
-
-static gint adapter_id_cmp(gconstpointer a, gconstpointer b)
-{
-       struct btd_adapter *adapter = (struct btd_adapter *) a;
-       uint16_t id = GPOINTER_TO_UINT(b);
-       uint16_t dev_id = adapter_get_dev_id(adapter);
-
-       return dev_id == id ? 0 : -1;
-}
-
-static gint adapter_cmp(gconstpointer a, gconstpointer b)
-{
-       struct btd_adapter *adapter = (struct btd_adapter *) a;
-       const bdaddr_t *bdaddr = b;
-       bdaddr_t src;
-
-       adapter_get_address(adapter, &src);
-
-       return bacmp(&src, bdaddr);
-}
-
-struct btd_adapter *manager_find_adapter(const bdaddr_t *sba)
-{
-       GSList *match;
-
-       match = g_slist_find_custom(adapters, sba, adapter_cmp);
-       if (!match)
-               return NULL;
-
-       return match->data;
-}
-
-struct btd_adapter *manager_find_adapter_by_id(int id)
-{
-       GSList *match;
-
-       match = g_slist_find_custom(adapters, GINT_TO_POINTER(id),
-                                                       adapter_id_cmp);
-       if (!match)
-               return NULL;
-
-       return match->data;
-}
-
-void manager_foreach_adapter(adapter_cb func, gpointer user_data)
-{
-       g_slist_foreach(adapters, (GFunc) func, user_data);
-}
-
-GSList *manager_get_adapters(void)
-{
-       return adapters;
-}
-
-void manager_add_adapter(const char *path)
-{
-       g_dbus_emit_signal(connection, "/",
-                               MANAGER_INTERFACE, "AdapterAdded",
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-
-       manager_update_adapters();
-
-       btd_stop_exit_timer();
-}
-
-struct btd_adapter *btd_manager_register_adapter(int id, gboolean up)
-{
-       struct btd_adapter *adapter;
-       const char *path;
-
-       adapter = manager_find_adapter_by_id(id);
-       if (adapter) {
-               error("Unable to register adapter: hci%d already exist", id);
-               return NULL;
-       }
-
-       adapter = adapter_create(connection, id);
-       if (!adapter)
-               return NULL;
-
-       adapters = g_slist_append(adapters, adapter);
-
-       if (!adapter_init(adapter, up)) {
-               adapters = g_slist_remove(adapters, adapter);
-               btd_adapter_unref(adapter);
-               return NULL;
-       }
-
-       path = adapter_get_path(adapter);
-       g_dbus_emit_signal(connection, "/",
-                               MANAGER_INTERFACE, "AdapterAdded",
-                               DBUS_TYPE_OBJECT_PATH, &path,
-                               DBUS_TYPE_INVALID);
-
-       manager_update_adapters();
-
-       btd_stop_exit_timer();
-
-       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);
-}
-
-int btd_manager_unregister_adapter(int id)
-{
-       struct btd_adapter *adapter;
-       const gchar *path;
-
-       adapter = manager_find_adapter_by_id(id);
-       if (!adapter)
-               return -1;
-
-       path = adapter_get_path(adapter);
-
-       info("Unregister path: %s", path);
-
-       manager_remove_adapter(adapter);
-
-       return 0;
-}
diff --git a/src/manager.h b/src/manager.h
deleted file mode 100644 (file)
index 264cd25..0000000
+++ /dev/null
@@ -1,43 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <bluetooth/bluetooth.h>
-#include <dbus/dbus.h>
-
-#define MANAGER_INTERFACE "org.bluez.Manager"
-
-typedef void (*adapter_cb) (struct btd_adapter *adapter, gpointer user_data);
-
-dbus_bool_t manager_init(DBusConnection *conn, const char *path);
-void manager_cleanup(DBusConnection *conn, const char *path);
-
-const char *manager_get_base_path(void);
-struct btd_adapter *manager_find_adapter(const bdaddr_t *sba);
-struct btd_adapter *manager_find_adapter_by_id(int id);
-struct btd_adapter *manager_get_default_adapter(void);
-void manager_foreach_adapter(adapter_cb func, gpointer user_data);
-GSList *manager_get_adapters(void);
-struct btd_adapter *btd_manager_register_adapter(int id, gboolean up);
-int btd_manager_unregister_adapter(int id);
-void manager_add_adapter(const char *path);
diff --git a/src/oob.c b/src/oob.c
deleted file mode 100644 (file)
index 75798fb..0000000
--- a/src/oob.c
+++ /dev/null
@@ -1,41 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  ST-Ericsson SA
- *
- *  Author: Szymon Janc <szymon.janc@tieto.com> for ST-Ericsson
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include "adapter.h"
-#include "oob.h"
-
-static oob_read_cb_t local_oob_read_cb = NULL;
-
-void oob_register_cb(oob_read_cb_t cb)
-{
-       local_oob_read_cb = cb;
-}
-
-void oob_read_local_data_complete(struct btd_adapter *adapter, uint8_t *hash,
-                                                       uint8_t *randomizer)
-{
-       if (local_oob_read_cb)
-               local_oob_read_cb(adapter, hash, randomizer);
-}
index 80bb3d3..8422986 100644 (file)
--- a/src/oui.c
+++ b/src/oui.c
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sys/stat.h>
-#include <sys/mman.h>
-
 #include "oui.h"
 
-/* http://standards.ieee.org/regauth/oui/oui.txt */
+#ifdef HAVE_UDEV_HWDB_NEW
+#include <libudev.h>
 
-char *ouitocomp(const char *oui)
+char *batocomp(const bdaddr_t *ba)
 {
-       struct stat st;
-       char *str, *map, *off, *end;
-       int fd;
+       struct udev *udev;
+       struct udev_hwdb *hwdb;
+       struct udev_list_entry *head, *entry;
+       char modalias[11], *comp = NULL;
 
-       fd = open(OUIFILE, O_RDONLY);
-       if (fd < 0)
-               return NULL;
+       sprintf(modalias, "OUI:%2.2X%2.2X%2.2X", ba->b[5], ba->b[4], ba->b[3]);
 
-       if (fstat(fd, &st) < 0) {
-               close(fd);
+       udev = udev_new();
+       if (!udev)
                return NULL;
-       }
 
-       str = malloc(128);
-       if (!str) {
-               close(fd);
-               return NULL;
-       }
+       hwdb = udev_hwdb_new(udev);
+       if (!hwdb)
+               goto done;
 
-       memset(str, 0, 128);
+       head = udev_hwdb_get_properties_list_entry(hwdb, modalias, 0);
 
-       map = mmap(0, st.st_size, PROT_READ, MAP_SHARED, fd, 0);
-       if (!map || map == MAP_FAILED) {
-               free(str);
-               close(fd);
-               return NULL;
-       }
+       udev_list_entry_foreach(entry, head) {
+               const char *name = udev_list_entry_get_name(entry);
 
-       off = strstr(map, oui);
-       if (off) {
-               off += 18;
-               end = strpbrk(off, "\r\n");
-               strncpy(str, off, end - off);
-       } else {
-               free(str);
-               str = NULL;
+               if (name && !strcmp(name, "ID_OUI_FROM_DATABASE")) {
+                       comp = strdup(udev_list_entry_get_value(entry));
+                       break;
+               }
        }
 
-       munmap(map, st.st_size);
+       hwdb = udev_hwdb_unref(hwdb);
 
-       close(fd);
+done:
+       udev = udev_unref(udev);
 
-       return str;
+       return comp;
 }
-
-int oui2comp(const char *oui, char *comp, size_t size)
+#else
+char *batocomp(const bdaddr_t *ba)
 {
-       char *tmp;
-
-       tmp = ouitocomp(oui);
-       if (!tmp)
-               return -1;
-
-       snprintf(comp, size, "%s", tmp);
-
-       free(tmp);
-
-       return 0;
+       return NULL;
 }
+#endif
index ad66e56..abd0386 100644 (file)
--- a/src/oui.h
+++ b/src/oui.h
@@ -21,5 +21,6 @@
  *
  */
 
-char *ouitocomp(const char *oui);
-int oui2comp(const char *oui, char *comp, size_t size);
+#include <bluetooth/bluetooth.h>
+
+char *batocomp(const bdaddr_t *ba);
index 2a86e68..085e7a5 100644 (file)
 #include <bluetooth/bluetooth.h>
 
 #include <glib.h>
+#include <btio/btio.h>
 
 #include "plugin.h"
 #include "log.h"
 #include "hcid.h"
-#include "btio.h"
 
 static GSList *plugins = NULL;
 
@@ -47,7 +47,7 @@ struct bluetooth_plugin {
        struct bluetooth_plugin_desc *desc;
 };
 
-static gint compare_priority(gconstpointer a, gconstpointer b)
+static int compare_priority(gconstpointer a, gconstpointer b)
 {
        const struct bluetooth_plugin *plugin1 = a;
        const struct bluetooth_plugin *plugin2 = b;
@@ -84,19 +84,9 @@ static gboolean add_plugin(void *handle, struct bluetooth_plugin_desc *desc)
        return TRUE;
 }
 
-static gboolean enable_plugin(const char *name, char **conf_disable,
-                                       char **cli_enable, char **cli_disable)
+static gboolean enable_plugin(const char *name, char **cli_enable,
+                                                       char **cli_disable)
 {
-       if (conf_disable) {
-               for (; *conf_disable; conf_disable++)
-                       if (g_pattern_match_simple(*conf_disable, name))
-                               break;
-               if (*conf_disable) {
-                       info("Excluding (conf) %s", name);
-                       return FALSE;
-               }
-       }
-
        if (cli_disable) {
                for (; *cli_disable; cli_disable++)
                        if (g_pattern_match_simple(*cli_disable, name))
@@ -122,25 +112,18 @@ static gboolean enable_plugin(const char *name, char **conf_disable,
 
 #include "builtin.h"
 
-gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
+gboolean plugin_init(const char *enable, const char *disable)
 {
        GSList *list;
        GDir *dir;
-       const gchar *file;
-       char **conf_disabled, **cli_disabled, **cli_enabled;
+       const char *file;
+       char **cli_disabled, **cli_enabled;
        unsigned int i;
 
        /* Make a call to BtIO API so its symbols got resolved before the
         * plugins are loaded. */
        bt_io_error_quark();
 
-       if (config)
-               conf_disabled = g_key_file_get_string_list(config, "General",
-                                                       "DisablePlugins",
-                                                       NULL, NULL);
-       else
-               conf_disabled = NULL;
-
        if (enable)
                cli_enabled = g_strsplit_set(enable, ", ", -1);
        else
@@ -154,8 +137,8 @@ gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
        DBG("Loading builtin plugins");
 
        for (i = 0; __bluetooth_builtin[i]; i++) {
-               if (!enable_plugin(__bluetooth_builtin[i]->name, conf_disabled,
-                                               cli_enabled, cli_disabled))
+               if (!enable_plugin(__bluetooth_builtin[i]->name, cli_enabled,
+                                                               cli_disabled))
                        continue;
 
                add_plugin(NULL,  __bluetooth_builtin[i]);
@@ -173,7 +156,7 @@ gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
        while ((file = g_dir_read_name(dir)) != NULL) {
                struct bluetooth_plugin_desc *desc;
                void *handle;
-               gchar *filename;
+               char *filename;
 
                if (g_str_has_prefix(file, "lib") == TRUE ||
                                g_str_has_suffix(file, ".so") == FALSE)
@@ -198,8 +181,7 @@ gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
                        continue;
                }
 
-               if (!enable_plugin(desc->name, conf_disabled,
-                                               cli_enabled, cli_disabled)) {
+               if (!enable_plugin(desc->name, cli_enabled, cli_disabled)) {
                        dlclose(handle);
                        continue;
                }
@@ -213,16 +195,22 @@ gboolean plugin_init(GKeyFile *config, const char *enable, const char *disable)
 start:
        for (list = plugins; list; list = list->next) {
                struct bluetooth_plugin *plugin = list->data;
-
-               if (plugin->desc->init() < 0) {
-                       error("Failed to init %s plugin", plugin->desc->name);
+               int err;
+
+               err = plugin->desc->init();
+               if (err < 0) {
+                       if (err == -ENOSYS)
+                               warn("System does not support %s plugin",
+                                                       plugin->desc->name);
+                       else
+                               error("Failed to init %s plugin",
+                                                       plugin->desc->name);
                        continue;
                }
 
                plugin->active = TRUE;
        }
 
-       g_strfreev(conf_disabled);
        g_strfreev(cli_enabled);
        g_strfreev(cli_disabled);
 
diff --git a/src/ppoll.h b/src/ppoll.h
deleted file mode 100644 (file)
index 7d09d44..0000000
+++ /dev/null
@@ -1,16 +0,0 @@
-#ifdef ppoll
-#undef ppoll
-#endif
-
-#define ppoll compat_ppoll
-
-static inline int compat_ppoll(struct pollfd *fds, nfds_t nfds,
-               const struct timespec *timeout, const sigset_t *sigmask)
-{
-       if (timeout == NULL)
-               return poll(fds, nfds, -1);
-       else if (timeout->tv_sec == 0)
-               return poll(fds, nfds, 500);
-       else
-               return poll(fds, nfds, timeout->tv_sec * 1000);
-}
diff --git a/src/profile.c b/src/profile.c
new file mode 100644 (file)
index 0000000..d8cbe6a
--- /dev/null
@@ -0,0 +1,2457 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <stdint.h>
+#include <stdlib.h>
+#include <errno.h>
+
+#include <glib.h>
+#include <dbus/dbus.h>
+#include <gdbus/gdbus.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/sdp.h>
+#include <bluetooth/sdp_lib.h>
+
+#include "btio/btio.h"
+#include "lib/uuid.h"
+#include "sdpd.h"
+#include "log.h"
+#include "error.h"
+#include "glib-helper.h"
+#include "dbus-common.h"
+#include "sdp-client.h"
+#include "sdp-xml.h"
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+
+#define DUN_DEFAULT_CHANNEL    1
+#define SPP_DEFAULT_CHANNEL    3
+#define HFP_HF_DEFAULT_CHANNEL 7
+#define OPP_DEFAULT_CHANNEL    9
+#define FTP_DEFAULT_CHANNEL    10
+#define BIP_DEFAULT_CHANNEL    11
+#define HSP_AG_DEFAULT_CHANNEL 12
+#define HFP_AG_DEFAULT_CHANNEL 13
+#define SYNC_DEFAULT_CHANNEL   14
+#define PBAP_DEFAULT_CHANNEL   15
+#define MAS_DEFAULT_CHANNEL    16
+#define MNS_DEFAULT_CHANNEL    17
+
+#define BTD_PROFILE_PSM_AUTO   -1
+#define BTD_PROFILE_CHAN_AUTO  -1
+
+#define HFP_HF_RECORD                                                  \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x111e\" />               \
+                               <uuid value=\"0x1203\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x111e\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+               <attribute id=\"0x0311\">                               \
+                       <uint16 value=\"0x%04x\" />                     \
+               </attribute>                                            \
+       </record>"
+
+#define HFP_AG_RECORD                                                  \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x111f\" />               \
+                               <uuid value=\"0x1203\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x111e\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+               <attribute id=\"0x0311\">                               \
+                       <uint16 value=\"0x%04x\" />                     \
+               </attribute>                                            \
+               <attribute id=\"0x0301\" >                              \
+                       <uint8 value=\"0x01\" />                        \
+               </attribute>                                            \
+       </record>"
+
+#define SPP_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1101\" />               \
+                               %s                                      \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1101\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+#define DUN_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1103\" />               \
+                               <uuid value=\"0x1201\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1103\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+#define OPP_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1105\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1105\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0303\">                               \
+                       <sequence>                                      \
+                               <uint8 value=\"0x01\"/>                 \
+                               <uint8 value=\"0x02\"/>                 \
+                               <uint8 value=\"0x03\"/>                 \
+                               <uint8 value=\"0x04\"/>                 \
+                               <uint8 value=\"0x05\"/>                 \
+                               <uint8 value=\"0x06\"/>                 \
+                               <uint8 value=\"0xff\"/>                 \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0200\">                               \
+                       <uint16 value=\"%u\" name=\"psm\"/>             \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+#define FTP_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1106\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1106\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0200\">                               \
+                       <uint16 value=\"%u\" name=\"psm\"/>             \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+#define PCE_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x112e\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1130\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+#define PSE_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x112f\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\" />       \
+                                       <uint8 value=\"0x%02x\" />      \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1130\" />       \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+               <attribute id=\"0x0314\">                               \
+                       <uint8 value=\"0x01\"/>                         \
+               </attribute>                                            \
+       </record>"
+
+#define MAS_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1132\"/>                \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\"/>        \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\"/>        \
+                                       <uint8 value=\"0x%02x\"/>       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1134\"/>        \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\"/>                            \
+               </attribute>                                            \
+               <attribute id=\"0x0315\">                               \
+                       <uint8 value=\"0x00\"/>                         \
+               </attribute>                                            \
+               <attribute id=\"0x0316\">                               \
+                       <uint8 value=\"0x0F\"/>                         \
+               </attribute>                                            \
+       </record>"
+
+#define MNS_RECORD                                                     \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1133\"/>                \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\"/>        \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\"/>        \
+                                       <uint8 value=\"0x%02x\"/>       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1134\"/>        \
+                                       <uint16 value=\"0x%04x\"/>      \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\"/>                            \
+               </attribute>                                            \
+               <attribute id=\"0x0200\">                               \
+                       <uint16 value=\"%u\" name=\"psm\"/>             \
+               </attribute>                                            \
+       </record>"
+
+#define SYNC_RECORD                                                    \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1104\"/>                \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\"/>        \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0003\"/>        \
+                                       <uint8 value=\"0x%02x\"/>       \
+                               </sequence>                             \
+                               <sequence>                              \
+                                       <uuid value=\"0x0008\"/>        \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0009\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x1104\"/>        \
+                                       <uint16 value=\"0x%04x\" />     \
+                                </sequence>                            \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\"/>                            \
+               </attribute>                                            \
+               <attribute id=\"0x0301\">                               \
+                       <sequence>                                      \
+                               <uint8 value=\"0x01\"/>                 \
+                       </sequence>                                     \
+               </attribute>                                            \
+       </record>"
+
+#define GENERIC_RECORD                                                 \
+       "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>                    \
+       <record>                                                        \
+               <attribute id=\"0x0001\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"%s\" />                   \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0004\">                               \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"0x0100\" />       \
+                                       %s                              \
+                               </sequence>                             \
+                               %s                                      \
+                       </sequence>                                     \
+               </attribute>                                            \
+               <attribute id=\"0x0005\">                               \
+                       <sequence>                                      \
+                               <uuid value=\"0x1002\" />               \
+                       </sequence>                                     \
+               </attribute>                                            \
+               %s                                                      \
+               <attribute id=\"0x0100\">                               \
+                       <text value=\"%s\" />                           \
+               </attribute>                                            \
+       </record>"
+
+struct ext_io;
+
+struct ext_profile {
+       struct btd_profile p;
+
+       char *name;
+       char *owner;
+       char *path;
+       char *uuid;
+       char *service;
+       char *role;
+
+       char *record;
+       char *(*get_record)(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm);
+
+       char *remote_uuid;
+
+       guint id;
+
+       BtIOMode mode;
+       BtIOSecLevel sec_level;
+       bool authorize;
+
+       bool enable_client;
+       bool enable_server;
+
+       int local_psm;
+       int local_chan;
+
+       uint16_t remote_psm;
+       uint8_t remote_chan;
+
+       uint16_t version;
+       uint16_t features;
+
+       GSList *records;
+       GSList *servers;
+       GSList *conns;
+
+       GSList *connects;
+};
+
+struct ext_io {
+       struct ext_profile *ext;
+       int proto;
+       GIOChannel *io;
+       guint io_id;
+       struct btd_adapter *adapter;
+       struct btd_device *device;
+       struct btd_service *service;
+
+       bool resolving;
+       bool connected;
+
+       uint16_t version;
+       uint16_t features;
+
+       uint16_t psm;
+       uint8_t chan;
+
+       guint auth_id;
+       unsigned int svc_id;
+       DBusPendingCall *pending;
+};
+
+struct ext_record {
+       struct btd_adapter *adapter;
+       uint32_t handle;
+};
+
+struct btd_profile_custom_property {
+       char *uuid;
+       char *type;
+       char *name;
+       btd_profile_prop_exists exists;
+       btd_profile_prop_get get;
+       void *user_data;
+};
+
+static GSList *custom_props = NULL;
+
+static GSList *profiles = NULL;
+static GSList *ext_profiles = NULL;
+
+void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
+                                                               void *data)
+{
+       GSList *l, *next;
+
+       for (l = profiles; l != NULL; l = next) {
+               struct btd_profile *profile = l->data;
+
+               next = g_slist_next(l);
+
+               func(profile, data);
+       }
+
+       for (l = ext_profiles; l != NULL; l = next) {
+               struct ext_profile *profile = l->data;
+
+               next = g_slist_next(l);
+
+               func(&profile->p, data);
+       }
+}
+
+int btd_profile_register(struct btd_profile *profile)
+{
+       profiles = g_slist_append(profiles, profile);
+       return 0;
+}
+
+void btd_profile_unregister(struct btd_profile *profile)
+{
+       profiles = g_slist_remove(profiles, profile);
+}
+
+static struct ext_profile *find_ext_profile(const char *owner,
+                                               const char *path)
+{
+       GSList *l;
+
+       for (l = ext_profiles; l != NULL; l = g_slist_next(l)) {
+               struct ext_profile *ext = l->data;
+
+               if (!g_str_equal(ext->owner, owner))
+                       continue;
+
+               if (g_str_equal(ext->path, path))
+                       return ext;
+       }
+
+       return NULL;
+}
+
+static void ext_io_destroy(gpointer p)
+{
+       struct ext_io *ext_io = p;
+
+       if (ext_io->io_id > 0)
+               g_source_remove(ext_io->io_id);
+
+       if (ext_io->io) {
+               g_io_channel_shutdown(ext_io->io, FALSE, NULL);
+               g_io_channel_unref(ext_io->io);
+       }
+
+       if (ext_io->auth_id != 0)
+               btd_cancel_authorization(ext_io->auth_id);
+
+       if (ext_io->svc_id != 0)
+               device_remove_svc_complete_callback(ext_io->device,
+                                                       ext_io->svc_id);
+
+       if (ext_io->pending) {
+               dbus_pending_call_cancel(ext_io->pending);
+               dbus_pending_call_unref(ext_io->pending);
+       }
+
+       if (ext_io->resolving)
+               bt_cancel_discovery(adapter_get_address(ext_io->adapter),
+                                       device_get_address(ext_io->device));
+
+       if (ext_io->adapter)
+               btd_adapter_unref(ext_io->adapter);
+
+       if (ext_io->device)
+               btd_device_unref(ext_io->device);
+
+       if (ext_io->service)
+               btd_service_unref(ext_io->service);
+
+       g_free(ext_io);
+}
+
+static gboolean ext_io_disconnected(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       GError *gerr = NULL;
+       char addr[18];
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       bt_io_get(io, &gerr, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID);
+       if (gerr != NULL) {
+               error("Unable to get io data for %s: %s",
+                                               ext->name, gerr->message);
+               g_error_free(gerr);
+               goto drop;
+       }
+
+       DBG("%s disconnected from %s", ext->name, addr);
+drop:
+       btd_service_disconnecting_complete(conn->service, 0);
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+       return FALSE;
+}
+
+static void new_conn_reply(DBusPendingCall *call, void *user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError err;
+
+       dbus_error_init(&err);
+       dbus_set_error_from_message(&err, reply);
+
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(conn->pending);
+       conn->pending = NULL;
+
+       if (!dbus_error_is_set(&err)) {
+               btd_service_connecting_complete(conn->service, 0);
+               conn->connected = true;
+               return;
+       }
+
+       error("%s replied with an error: %s, %s", ext->name,
+                                               err.name, err.message);
+
+       btd_service_connecting_complete(conn->service, -ECONNREFUSED);
+
+       dbus_error_free(&err);
+
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+static void disconn_reply(DBusPendingCall *call, void *user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusError err;
+
+       dbus_error_init(&err);
+       dbus_set_error_from_message(&err, reply);
+
+       dbus_message_unref(reply);
+
+       dbus_pending_call_unref(conn->pending);
+       conn->pending = NULL;
+
+       if (!dbus_error_is_set(&err)) {
+               btd_service_disconnecting_complete(conn->service, 0);
+               goto disconnect;
+       }
+
+       error("%s replied with an error: %s, %s", ext->name,
+                                               err.name, err.message);
+
+       btd_service_disconnecting_complete(conn->service, -ECONNREFUSED);
+
+       dbus_error_free(&err);
+
+disconnect:
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+struct prop_append_data {
+       DBusMessageIter *dict;
+       struct ext_io *io;
+};
+
+static void append_prop(gpointer a, gpointer b)
+{
+       struct btd_profile_custom_property *p = a;
+       struct prop_append_data *data = b;
+       DBusMessageIter entry, value, *dict = data->dict;
+       struct btd_device *dev = data->io->device;
+       struct ext_profile *ext = data->io->ext;
+       const char *uuid = ext->service ? ext->service : ext->uuid;
+
+       if (strcasecmp(p->uuid, uuid) != 0)
+               return;
+
+       if (p->exists && !p->exists(p->uuid, dev, p->user_data))
+               return;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &p->name);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_VARIANT, p->type,
+                                                               &value);
+
+       p->get(p->uuid, dev, &value, p->user_data);
+
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static uint16_t get_supported_features(const sdp_record_t *rec)
+{
+       sdp_data_t *data;
+
+       data = sdp_data_get(rec, SDP_ATTR_SUPPORTED_FEATURES);
+       if (!data || data->dtd != SDP_UINT16)
+               return 0;
+
+       return data->val.uint16;
+}
+
+static uint16_t get_profile_version(const sdp_record_t *rec)
+{
+       sdp_list_t *descs;
+       uint16_t version;
+
+       if (sdp_get_profile_descs(rec, &descs) < 0)
+               return 0;
+
+       if (descs && descs->data) {
+               sdp_profile_desc_t *desc = descs->data;
+               version = desc->version;
+       } else {
+               version = 0;
+       }
+
+       sdp_list_free(descs, free);
+
+       return version;
+}
+
+static bool send_new_connection(struct ext_profile *ext, struct ext_io *conn)
+{
+       DBusMessage *msg;
+       DBusMessageIter iter, dict;
+       struct prop_append_data data = { &dict, conn };
+       const char *remote_uuid = ext->remote_uuid;
+       const sdp_record_t *rec;
+       const char *path;
+       int fd;
+
+       msg = dbus_message_new_method_call(ext->owner, ext->path,
+                                                       "org.bluez.Profile1",
+                                                       "NewConnection");
+       if (!msg) {
+               error("Unable to create NewConnection call for %s", ext->name);
+               return false;
+       }
+
+       if (remote_uuid) {
+               rec = btd_device_get_record(conn->device, remote_uuid);
+               if (rec) {
+                       conn->features = get_supported_features(rec);
+                       conn->version = get_profile_version(rec);
+               }
+       }
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       path = device_get_path(conn->device);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       fd = g_io_channel_unix_get_fd(conn->io);
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_UNIX_FD, &fd);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "{sv}", &dict);
+
+       if (conn->version)
+               dict_append_entry(&dict, "Version", DBUS_TYPE_UINT16,
+                                                       &conn->version);
+
+       if (conn->features)
+               dict_append_entry(&dict, "Features", DBUS_TYPE_UINT16,
+                                                       &conn->features);
+
+       g_slist_foreach(custom_props, append_prop, &data);
+
+       dbus_message_iter_close_container(&iter, &dict);
+
+       if (!g_dbus_send_message_with_reply(btd_get_dbus_connection(),
+                                               msg, &conn->pending, -1)) {
+               error("%s: sending NewConnection failed", ext->name);
+               dbus_message_unref(msg);
+               return false;
+       }
+
+       dbus_message_unref(msg);
+
+       dbus_pending_call_set_notify(conn->pending, new_conn_reply, conn, NULL);
+
+       return true;
+}
+
+static void ext_connect(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       GError *io_err = NULL;
+       char addr[18];
+
+       if (!bt_io_get(io, &io_err,
+                               BT_IO_OPT_DEST, addr,
+                               BT_IO_OPT_INVALID)) {
+               error("Unable to get connect data for %s: %s", ext->name,
+                                                       io_err->message);
+               if (err) {
+                       g_error_free(io_err);
+                       io_err = NULL;
+               } else {
+                       err = io_err;
+               }
+               goto drop;
+       }
+
+       if (err != NULL) {
+               error("%s failed to connect to %s: %s", ext->name, addr,
+                                                               err->message);
+               goto drop;
+       }
+
+       DBG("%s connected to %s", ext->name, addr);
+
+       if (conn->io_id == 0) {
+               GIOCondition cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+               conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected,
+                                                                       conn);
+       }
+
+       if (send_new_connection(ext, conn))
+               return;
+
+drop:
+       btd_service_connecting_complete(conn->service, err ? -err->code : -EIO);
+       if (io_err)
+               g_error_free(io_err);
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+static void ext_auth(DBusError *err, void *user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       GError *gerr = NULL;
+       char addr[18];
+
+       conn->auth_id = 0;
+
+       bt_io_get(conn->io, &gerr, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID);
+       if (gerr != NULL) {
+               error("Unable to get connect data for %s: %s",
+                                               ext->name, gerr->message);
+               g_error_free(gerr);
+               goto drop;
+       }
+
+       if (err && dbus_error_is_set(err)) {
+               error("%s rejected %s: %s", ext->name, addr, err->message);
+               goto drop;
+       }
+
+       if (conn->svc_id > 0) {
+               DBG("Connection from %s authorized but still waiting for SDP",
+                                                                       addr);
+               return;
+       }
+
+       if (!bt_io_accept(conn->io, ext_connect, conn, NULL, &gerr)) {
+               error("bt_io_accept: %s", gerr->message);
+               g_error_free(gerr);
+               goto drop;
+       }
+
+       DBG("%s authorized to connect to %s", addr, ext->name);
+
+       return;
+
+drop:
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+static struct ext_io *create_conn(struct ext_io *server, GIOChannel *io,
+                                               bdaddr_t *src, bdaddr_t *dst)
+{
+       struct btd_device *device;
+       struct btd_service *service;
+       struct ext_io *conn;
+       GIOCondition cond;
+       char addr[18];
+
+       device = adapter_find_device(server->adapter, dst);
+       if (device == NULL) {
+               ba2str(dst, addr);
+               error("%s device %s not found", server->ext->name, addr);
+               return NULL;
+       }
+
+       btd_device_add_uuid(device, server->ext->remote_uuid);
+       service = btd_device_get_service(device, server->ext->remote_uuid);
+       if (service == NULL) {
+               ba2str(dst, addr);
+               error("%s service not found for device %s", server->ext->name,
+                                                                       addr);
+               return NULL;
+       }
+
+       conn = g_new0(struct ext_io, 1);
+       conn->io = g_io_channel_ref(io);
+       conn->proto = server->proto;
+       conn->ext = server->ext;
+       conn->adapter = btd_adapter_ref(server->adapter);
+       conn->device = btd_device_ref(device);
+       conn->service = btd_service_ref(service);
+
+       cond = G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       conn->io_id = g_io_add_watch(io, cond, ext_io_disconnected, conn);
+
+       return conn;
+}
+
+static void ext_svc_complete(struct btd_device *dev, int err, void *user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       const bdaddr_t *bdaddr;
+       GError *gerr = NULL;
+       char addr[18];
+
+       conn->svc_id = 0;
+
+       bdaddr = device_get_address(dev);
+       ba2str(bdaddr, addr);
+
+       if (err < 0) {
+               error("Service resolving failed for %s: %s (%d)",
+                                               addr, strerror(-err), -err);
+               goto drop;
+       }
+
+       DBG("Services resolved for %s", addr);
+
+       if (conn->auth_id > 0) {
+               DBG("Services resolved but still waiting for authorization");
+               return;
+       }
+
+       if (!bt_io_accept(conn->io, ext_connect, conn, NULL, &gerr)) {
+               error("bt_io_accept: %s", gerr->message);
+               g_error_free(gerr);
+               goto drop;
+       }
+
+       DBG("%s authorized to connect to %s", addr, ext->name);
+
+       return;
+
+drop:
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+static void ext_confirm(GIOChannel *io, gpointer user_data)
+{
+       struct ext_io *server = user_data;
+       struct ext_profile *ext = server->ext;
+       const char *uuid = ext->service ? ext->service : ext->uuid;
+       struct ext_io *conn;
+       GError *gerr = NULL;
+       bdaddr_t src, dst;
+       char addr[18];
+
+       bt_io_get(io, &gerr,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_DEST, addr,
+                       BT_IO_OPT_INVALID);
+       if (gerr != NULL) {
+               error("%s failed to get connect data: %s", ext->name,
+                                                               gerr->message);
+               g_error_free(gerr);
+               return;
+       }
+
+       DBG("incoming connect from %s", addr);
+
+       conn = create_conn(server, io, &src, &dst);
+       if (conn == NULL)
+               return;
+
+       conn->auth_id = btd_request_authorization(&src, &dst, uuid, ext_auth,
+                                                                       conn);
+       if (conn->auth_id == 0) {
+               error("%s authorization failure", ext->name);
+               ext_io_destroy(conn);
+               return;
+       }
+
+       ext->conns = g_slist_append(ext->conns, conn);
+
+       conn->svc_id = device_wait_for_svc_complete(conn->device,
+                                                       ext_svc_complete,
+                                                       conn);
+
+       DBG("%s authorizing connection from %s", ext->name, addr);
+}
+
+static void ext_direct_connect(GIOChannel *io, GError *err, gpointer user_data)
+{
+       struct ext_io *server = user_data;
+       struct ext_profile *ext = server->ext;
+       GError *gerr = NULL;
+       struct ext_io *conn;
+       bdaddr_t src, dst;
+
+       bt_io_get(io, &gerr,
+                       BT_IO_OPT_SOURCE_BDADDR, &src,
+                       BT_IO_OPT_DEST_BDADDR, &dst,
+                       BT_IO_OPT_INVALID);
+       if (gerr != NULL) {
+               error("%s failed to get connect data: %s", ext->name,
+                                                               gerr->message);
+               g_error_free(gerr);
+               return;
+       }
+
+       conn = create_conn(server, io, &src, &dst);
+       if (conn == NULL)
+               return;
+
+       ext->conns = g_slist_append(ext->conns, conn);
+
+       ext_connect(io, err, conn);
+}
+
+static uint32_t ext_register_record(struct ext_profile *ext,
+                                                       struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm,
+                                                       struct btd_adapter *a)
+{
+       sdp_record_t *rec;
+       char *dyn_record = NULL;
+       const char *record = ext->record;
+
+       if (!record && ext->get_record) {
+               dyn_record = ext->get_record(ext, l2cap, rfcomm);
+               record = dyn_record;
+       }
+
+       if (!record)
+               return 0;
+
+       rec = sdp_xml_parse_record(record, strlen(record));
+
+       g_free(dyn_record);
+
+       if (!rec) {
+               error("Unable to parse record for %s", ext->name);
+               return 0;
+       }
+
+       if (adapter_service_add(a, rec) < 0) {
+               error("Failed to register service record");
+               sdp_record_free(rec);
+               return 0;
+       }
+
+       return rec->handle;
+}
+
+static uint32_t ext_start_servers(struct ext_profile *ext,
+                                               struct btd_adapter *adapter)
+{
+       struct ext_io *l2cap = NULL;
+       struct ext_io *rfcomm = NULL;
+       BtIOConfirm confirm;
+       BtIOConnect connect;
+       GError *err = NULL;
+       GIOChannel *io;
+
+       if (ext->authorize) {
+               confirm = ext_confirm;
+               connect = NULL;
+       } else {
+               confirm = NULL;
+               connect = ext_direct_connect;
+       }
+
+       if (ext->local_psm) {
+               uint16_t psm;
+
+               if (ext->local_psm > 0)
+                       psm = ext->local_psm;
+               else
+                       psm = 0;
+
+               l2cap = g_new0(struct ext_io, 1);
+               l2cap->ext = ext;
+
+               io = bt_io_listen(connect, confirm, l2cap, NULL, &err,
+                                       BT_IO_OPT_SOURCE_BDADDR,
+                                       adapter_get_address(adapter),
+                                       BT_IO_OPT_MODE, ext->mode,
+                                       BT_IO_OPT_PSM, psm,
+                                       BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                       BT_IO_OPT_INVALID);
+               if (err != NULL) {
+                       error("L2CAP server failed for %s: %s",
+                                               ext->name, err->message);
+                       g_free(l2cap);
+                       l2cap = NULL;
+                       g_clear_error(&err);
+                       goto failed;
+               } else {
+                       if (psm == 0)
+                               bt_io_get(io, NULL, BT_IO_OPT_PSM, &psm,
+                                                       BT_IO_OPT_INVALID);
+                       l2cap->io = io;
+                       l2cap->proto = BTPROTO_L2CAP;
+                       l2cap->psm = psm;
+                       l2cap->adapter = btd_adapter_ref(adapter);
+                       ext->servers = g_slist_append(ext->servers, l2cap);
+                       DBG("%s listening on PSM %u", ext->name, psm);
+               }
+       }
+
+       if (ext->local_chan) {
+               uint8_t chan;
+
+               if (ext->local_chan > 0)
+                       chan = ext->local_chan;
+               else
+                       chan = 0;
+
+               rfcomm = g_new0(struct ext_io, 1);
+               rfcomm->ext = ext;
+
+               io = bt_io_listen(connect, confirm, rfcomm, NULL, &err,
+                                       BT_IO_OPT_SOURCE_BDADDR,
+                                       adapter_get_address(adapter),
+                                       BT_IO_OPT_CHANNEL, chan,
+                                       BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                       BT_IO_OPT_INVALID);
+               if (err != NULL) {
+                       error("RFCOMM server failed for %s: %s",
+                                               ext->name, err->message);
+                       g_free(rfcomm);
+                       rfcomm = NULL;
+                       g_clear_error(&err);
+                       goto failed;
+               } else {
+                       if (chan == 0)
+                               bt_io_get(io, NULL, BT_IO_OPT_CHANNEL, &chan,
+                                                       BT_IO_OPT_INVALID);
+                       rfcomm->io = io;
+                       rfcomm->proto = BTPROTO_RFCOMM;
+                       rfcomm->chan = chan;
+                       rfcomm->adapter = btd_adapter_ref(adapter);
+                       ext->servers = g_slist_append(ext->servers, rfcomm);
+                       DBG("%s listening on chan %u", ext->name, chan);
+               }
+       }
+
+       return ext_register_record(ext, l2cap, rfcomm, adapter);
+
+failed:
+       if (l2cap) {
+               ext->servers = g_slist_remove(ext->servers, l2cap);
+               ext_io_destroy(l2cap);
+       }
+       if (rfcomm) {
+               ext->servers = g_slist_remove(ext->servers, rfcomm);
+               ext_io_destroy(rfcomm);
+       }
+
+       return 0;
+}
+
+static struct ext_profile *find_ext(struct btd_profile *p)
+{
+       GSList *l;
+
+       l = g_slist_find(ext_profiles, p);
+       if (!l)
+               return NULL;
+
+       return l->data;
+}
+
+static int ext_adapter_probe(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct ext_profile *ext;
+       struct ext_record *rec;
+       uint32_t handle;
+
+       ext = find_ext(p);
+       if (!ext)
+               return -ENOENT;
+
+       DBG("\"%s\" probed", ext->name);
+
+       handle = ext_start_servers(ext, adapter);
+       if (!handle)
+               return 0;
+
+       rec = g_new0(struct ext_record, 1);
+       rec->adapter = btd_adapter_ref(adapter);
+       rec->handle = handle;
+
+       ext->records = g_slist_append(ext->records, rec);
+
+       return 0;
+}
+
+static void ext_remove_records(struct ext_profile *ext,
+                                               struct btd_adapter *adapter)
+{
+       GSList *l, *next;
+
+       for (l = ext->records; l != NULL; l = next) {
+               struct ext_record *r = l->data;
+
+               next = g_slist_next(l);
+
+               if (adapter && r->adapter != adapter)
+                       continue;
+
+               ext->records = g_slist_remove(ext->records, r);
+
+               adapter_service_remove(adapter, r->handle);
+               btd_adapter_unref(r->adapter);
+               g_free(r);
+       }
+}
+
+static void ext_adapter_remove(struct btd_profile *p,
+                                               struct btd_adapter *adapter)
+{
+       struct ext_profile *ext;
+       GSList *l, *next;
+
+       ext = find_ext(p);
+       if (!ext)
+               return;
+
+       DBG("\"%s\" removed", ext->name);
+
+       ext_remove_records(ext, adapter);
+
+       for (l = ext->servers; l != NULL; l = next) {
+               struct ext_io *server = l->data;
+
+               next = g_slist_next(l);
+
+               if (server->adapter != adapter)
+                       continue;
+
+               ext->servers = g_slist_remove(ext->servers, server);
+               ext_io_destroy(server);
+       }
+}
+
+static int ext_device_probe(struct btd_service *service)
+{
+       struct btd_profile *p = btd_service_get_profile(service);
+       struct ext_profile *ext;
+
+       ext = find_ext(p);
+       if (!ext)
+               return -ENOENT;
+
+       DBG("%s probed with UUID %s", ext->name, p->remote_uuid);
+
+       return 0;
+}
+
+static struct ext_io *find_connection(struct ext_profile *ext,
+                                                       struct btd_device *dev)
+{
+       GSList *l;
+
+       for (l = ext->conns; l != NULL; l = g_slist_next(l)) {
+               struct ext_io *conn = l->data;
+
+               if (conn->device == dev)
+                       return conn;
+       }
+
+       return NULL;
+}
+
+static void ext_device_remove(struct btd_service *service)
+{
+       struct btd_profile *p = btd_service_get_profile(service);
+       struct btd_device *dev = btd_service_get_device(service);
+       struct ext_profile *ext;
+       struct ext_io *conn;
+
+       ext = find_ext(p);
+       if (!ext)
+               return;
+
+       DBG("%s", ext->name);
+
+       conn = find_connection(ext, dev);
+       if (conn) {
+               ext->conns = g_slist_remove(ext->conns, conn);
+               ext_io_destroy(conn);
+       }
+}
+
+static int connect_io(struct ext_io *conn, const bdaddr_t *src,
+                                                       const bdaddr_t *dst)
+{
+       struct ext_profile *ext = conn->ext;
+       GError *gerr = NULL;
+       GIOChannel *io;
+
+       if (conn->psm) {
+               conn->proto = BTPROTO_L2CAP;
+               io = bt_io_connect(ext_connect, conn, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, src,
+                                       BT_IO_OPT_DEST_BDADDR, dst,
+                                       BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                       BT_IO_OPT_PSM, conn->psm,
+                                       BT_IO_OPT_INVALID);
+       } else {
+               conn->proto = BTPROTO_RFCOMM;
+               io = bt_io_connect(ext_connect, conn, NULL, &gerr,
+                                       BT_IO_OPT_SOURCE_BDADDR, src,
+                                       BT_IO_OPT_DEST_BDADDR, dst,
+                                       BT_IO_OPT_SEC_LEVEL, ext->sec_level,
+                                       BT_IO_OPT_CHANNEL, conn->chan,
+                                       BT_IO_OPT_INVALID);
+       }
+
+       if (gerr != NULL) {
+               error("Unable to connect %s: %s", ext->name, gerr->message);
+               g_error_free(gerr);
+               return -EIO;
+       }
+
+       conn->io = io;
+
+       return 0;
+}
+
+static uint16_t get_goep_l2cap_psm(sdp_record_t *rec)
+{
+       sdp_data_t *data;
+
+       data = sdp_data_get(rec, SDP_ATTR_GOEP_L2CAP_PSM);
+       if (!data)
+               return 0;
+
+       if (data->dtd != SDP_UINT16)
+               return 0;
+
+       /* PSM must be odd and lsb of upper byte must be 0 */
+       if ((data->val.uint16 & 0x0101) != 0x0001)
+               return 0;
+
+       return data->val.uint16;
+}
+
+static void record_cb(sdp_list_t *recs, int err, gpointer user_data)
+{
+       struct ext_io *conn = user_data;
+       struct ext_profile *ext = conn->ext;
+       sdp_list_t *r;
+
+       conn->resolving = false;
+
+       if (err < 0) {
+               error("Unable to get %s SDP record: %s", ext->name,
+                                                       strerror(-err));
+               goto failed;
+       }
+
+       if (!recs || !recs->data) {
+               error("No SDP records found for %s", ext->name);
+               goto failed;
+       }
+
+       for (r = recs; r != NULL; r = r->next) {
+               sdp_record_t *rec = r->data;
+               sdp_list_t *protos;
+               int port;
+
+               if (sdp_get_access_protos(rec, &protos) < 0) {
+                       error("Unable to get proto list from %s record",
+                                                               ext->name);
+                       goto failed;
+               }
+
+               port = sdp_get_proto_port(protos, L2CAP_UUID);
+               if (port > 0)
+                       conn->psm = port;
+
+               port = sdp_get_proto_port(protos, RFCOMM_UUID);
+               if (port > 0)
+                       conn->chan = port;
+
+               if (conn->psm == 0 && sdp_get_proto_desc(protos, OBEX_UUID))
+                       conn->psm = get_goep_l2cap_psm(rec);
+
+               conn->features = get_supported_features(rec);
+               conn->version = get_profile_version(rec);
+
+               sdp_list_foreach(protos, (sdp_list_func_t) sdp_list_free,
+                                                                       NULL);
+               sdp_list_free(protos, NULL);
+
+               if (conn->chan || conn->psm)
+                       break;
+       }
+
+       if (!conn->chan && !conn->psm) {
+               error("Failed to find L2CAP PSM or RFCOMM channel for %s",
+                                                               ext->name);
+               goto failed;
+       }
+
+       err = connect_io(conn, adapter_get_address(conn->adapter),
+                                       device_get_address(conn->device));
+       if (err < 0) {
+               error("Connecting %s failed: %s", ext->name, strerror(-err));
+               goto failed;
+       }
+
+       return;
+
+failed:
+       btd_service_connecting_complete(conn->service, err);
+       ext->conns = g_slist_remove(ext->conns, conn);
+       ext_io_destroy(conn);
+}
+
+static int resolve_service(struct ext_io *conn, const bdaddr_t *src,
+                                                       const bdaddr_t *dst)
+{
+       struct ext_profile *ext = conn->ext;
+       uuid_t uuid;
+       int err;
+
+       bt_string2uuid(&uuid, ext->remote_uuid);
+       sdp_uuid128_to_uuid(&uuid);
+
+       err = bt_search_service(src, dst, &uuid, record_cb, conn, NULL);
+       if (err == 0)
+               conn->resolving = true;
+
+       return err;
+}
+
+static int ext_connect_dev(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct btd_profile *profile = btd_service_get_profile(service);
+       struct btd_adapter *adapter;
+       struct ext_io *conn;
+       struct ext_profile *ext;
+       int err;
+
+       ext = find_ext(profile);
+       if (!ext)
+               return -ENOENT;
+
+       conn = find_connection(ext, dev);
+       if (conn)
+               return -EALREADY;
+
+       adapter = device_get_adapter(dev);
+
+       conn = g_new0(struct ext_io, 1);
+       conn->ext = ext;
+
+       if (ext->remote_psm || ext->remote_chan) {
+               conn->psm = ext->remote_psm;
+               conn->chan = ext->remote_chan;
+               err = connect_io(conn, adapter_get_address(adapter),
+                                               device_get_address(dev));
+       } else {
+               err = resolve_service(conn, adapter_get_address(adapter),
+                                               device_get_address(dev));
+       }
+
+       if (err < 0)
+               goto failed;
+
+       conn->adapter = btd_adapter_ref(adapter);
+       conn->device = btd_device_ref(dev);
+       conn->service = btd_service_ref(service);
+
+       ext->conns = g_slist_append(ext->conns, conn);
+
+       return 0;
+
+failed:
+       g_free(conn);
+       return err;
+}
+
+static int send_disconn_req(struct ext_profile *ext, struct ext_io *conn)
+{
+       DBusMessage *msg;
+       const char *path;
+
+       msg = dbus_message_new_method_call(ext->owner, ext->path,
+                                               "org.bluez.Profile1",
+                                               "RequestDisconnection");
+       if (!msg) {
+               error("Unable to create RequestDisconnection call for %s",
+                                                               ext->name);
+               return -ENOMEM;
+       }
+
+       path = device_get_path(conn->device);
+       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID);
+
+       if (!g_dbus_send_message_with_reply(btd_get_dbus_connection(),
+                                               msg, &conn->pending, -1)) {
+               error("%s: sending RequestDisconnection failed", ext->name);
+               dbus_message_unref(msg);
+               return -EIO;
+       }
+
+       dbus_message_unref(msg);
+
+       dbus_pending_call_set_notify(conn->pending, disconn_reply, conn, NULL);
+
+       return 0;
+}
+
+static int ext_disconnect_dev(struct btd_service *service)
+{
+       struct btd_device *dev = btd_service_get_device(service);
+       struct btd_profile *profile = btd_service_get_profile(service);
+       struct ext_profile *ext;
+       struct ext_io *conn;
+       int err;
+
+       ext = find_ext(profile);
+       if (!ext)
+               return -ENOENT;
+
+       conn = find_connection(ext, dev);
+       if (!conn || !conn->connected)
+               return -ENOTCONN;
+
+       if (conn->pending)
+               return -EBUSY;
+
+       err = send_disconn_req(ext, conn);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static char *get_hfp_hf_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(HFP_HF_RECORD, rfcomm->chan, ext->version,
+                                               ext->name, ext->features);
+}
+
+static char *get_hfp_ag_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(HFP_AG_RECORD, rfcomm->chan, ext->version,
+                                               ext->name, ext->features);
+}
+
+static char *get_spp_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       char *svc, *rec;
+
+       if (ext->service)
+               svc = g_strdup_printf("<uuid value=\"%s\" />", ext->service);
+       else
+               svc = g_strdup("");
+
+       rec = g_strdup_printf(SPP_RECORD, svc, rfcomm->chan, ext->version,
+                                                               ext->name);
+       g_free(svc);
+       return rec;
+}
+
+static char *get_dun_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(DUN_RECORD, rfcomm->chan, ext->version,
+                                                               ext->name);
+}
+
+static char *get_pce_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(PCE_RECORD, ext->version, ext->name);
+}
+
+static char *get_pse_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(PSE_RECORD, rfcomm->chan, ext->version,
+                                                               ext->name);
+}
+
+static char *get_mas_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(MAS_RECORD, rfcomm->chan, ext->version,
+                                                               ext->name);
+}
+
+static char *get_mns_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       uint16_t psm = 0;
+       uint8_t chan = 0;
+
+       if (l2cap)
+               psm = l2cap->psm;
+       if (rfcomm)
+               chan = rfcomm->chan;
+
+       return g_strdup_printf(MNS_RECORD, chan, ext->version, ext->name, psm);
+}
+
+static char *get_sync_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       return g_strdup_printf(SYNC_RECORD, rfcomm->chan, ext->version,
+                                                               ext->name);
+}
+
+static char *get_opp_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       uint16_t psm = 0;
+       uint8_t chan = 0;
+
+       if (l2cap)
+               psm = l2cap->psm;
+       if (rfcomm)
+               chan = rfcomm->chan;
+
+       return g_strdup_printf(OPP_RECORD, chan, ext->version, psm, ext->name);
+}
+
+static char *get_ftp_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       uint16_t psm = 0;
+       uint8_t chan = 0;
+
+       if (l2cap)
+               psm = l2cap->psm;
+       if (rfcomm)
+               chan = rfcomm->chan;
+
+       return g_strdup_printf(FTP_RECORD, chan, ext->version, psm, ext->name);
+}
+
+#define RFCOMM_SEQ     "<sequence>                             \
+                               <uuid value=\"0x0003\" />       \
+                               <uint8 value=\"0x%02x\" />      \
+                       </sequence>"
+
+#define VERSION_ATTR                                                   \
+               "<attribute id=\"0x0009\">                              \
+                       <sequence>                                      \
+                               <sequence>                              \
+                                       <uuid value=\"%s\" />           \
+                                       <uint16 value=\"0x%04x\" />     \
+                               </sequence>                             \
+                       </sequence>                                     \
+               </attribute>"
+
+static char *get_generic_record(struct ext_profile *ext, struct ext_io *l2cap,
+                                                       struct ext_io *rfcomm)
+{
+       char uuid_str[MAX_LEN_UUID_STR], svc_str[MAX_LEN_UUID_STR], psm[30];
+       char *rf_seq, *ver_attr, *rec;
+       uuid_t uuid;
+
+       bt_string2uuid(&uuid, ext->uuid);
+       sdp_uuid2strn(&uuid, uuid_str, sizeof(uuid_str));
+
+       if (ext->service) {
+               bt_string2uuid(&uuid, ext->service);
+               sdp_uuid2strn(&uuid, svc_str, sizeof(svc_str));
+       } else {
+               strncpy(svc_str, uuid_str, sizeof(svc_str));
+       }
+
+       if (l2cap)
+               snprintf(psm, sizeof(psm), "<uint16 value=\"0x%04x\" />",
+                                                               l2cap->psm);
+       else
+               psm[0] = '\0';
+
+       if (rfcomm)
+               rf_seq = g_strdup_printf(RFCOMM_SEQ, rfcomm->chan);
+       else
+               rf_seq = g_strdup("");
+
+       if (ext->version)
+               ver_attr = g_strdup_printf(VERSION_ATTR, uuid_str,
+                                                               ext->version);
+       else
+               ver_attr = g_strdup("");
+
+       rec = g_strdup_printf(GENERIC_RECORD, svc_str, psm, rf_seq, ver_attr,
+                                                               ext->name);
+
+       g_free(rf_seq);
+       g_free(ver_attr);
+
+       return rec;
+}
+
+static struct default_settings {
+       const char      *uuid;
+       const char      *name;
+       int             priority;
+       const char      *remote_uuid;
+       int             channel;
+       int             psm;
+       BtIOMode        mode;
+       BtIOSecLevel    sec_level;
+       bool            authorize;
+       bool            auto_connect;
+       char *          (*get_record)(struct ext_profile *ext,
+                                       struct ext_io *l2cap,
+                                       struct ext_io *rfcomm);
+       uint16_t        version;
+       uint16_t        features;
+} defaults[] = {
+       {
+               .uuid           = SPP_UUID,
+               .name           = "Serial Port",
+               .channel        = SPP_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .get_record     = get_spp_record,
+               .version        = 0x0102,
+       }, {
+               .uuid           = DUN_GW_UUID,
+               .name           = "Dial-Up Networking",
+               .channel        = DUN_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .get_record     = get_dun_record,
+               .version        = 0x0102,
+       }, {
+               .uuid           = HFP_HS_UUID,
+               .name           = "Hands-Free unit",
+               .priority       = BTD_PROFILE_PRIORITY_HIGH,
+               .remote_uuid    = HFP_AG_UUID,
+               .channel        = HFP_HF_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .auto_connect   = true,
+               .get_record     = get_hfp_hf_record,
+               .version        = 0x0105,
+       }, {
+               .uuid           = HFP_AG_UUID,
+               .name           = "Hands-Free Voice gateway",
+               .priority       = BTD_PROFILE_PRIORITY_HIGH,
+               .remote_uuid    = HFP_HS_UUID,
+               .channel        = HFP_AG_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .auto_connect   = true,
+               .get_record     = get_hfp_ag_record,
+               .version        = 0x0105,
+       }, {
+               .uuid           = HSP_AG_UUID,
+               .name           = "Headset Voice gateway",
+               .priority       = BTD_PROFILE_PRIORITY_HIGH,
+               .remote_uuid    = HSP_HS_UUID,
+               .channel        = HSP_AG_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .auto_connect   = true,
+       }, {
+               .uuid           = OBEX_OPP_UUID,
+               .name           = "Object Push",
+               .channel        = OPP_DEFAULT_CHANNEL,
+               .psm            = BTD_PROFILE_PSM_AUTO,
+               .mode           = BT_IO_MODE_ERTM,
+               .sec_level      = BT_IO_SEC_LOW,
+               .authorize      = false,
+               .get_record     = get_opp_record,
+               .version        = 0x0102,
+       }, {
+               .uuid           = OBEX_FTP_UUID,
+               .name           = "File Transfer",
+               .channel        = FTP_DEFAULT_CHANNEL,
+               .psm            = BTD_PROFILE_PSM_AUTO,
+               .mode           = BT_IO_MODE_ERTM,
+               .authorize      = true,
+               .get_record     = get_ftp_record,
+               .version        = 0x0102,
+       }, {
+               .uuid           = OBEX_SYNC_UUID,
+               .name           = "Synchronization",
+               .channel        = SYNC_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .get_record     = get_sync_record,
+               .version        = 0x0100,
+       }, {
+               .uuid           = OBEX_PSE_UUID,
+               .name           = "Phone Book Access",
+               .channel        = PBAP_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .get_record     = get_pse_record,
+               .version        = 0x0101,
+       }, {
+               .uuid           = OBEX_PCE_UUID,
+               .name           = "Phone Book Access Client",
+               .remote_uuid    = OBEX_PSE_UUID,
+               .authorize      = true,
+               .get_record     = get_pce_record,
+               .version        = 0x0101,
+       }, {
+               .uuid           = OBEX_MAS_UUID,
+               .name           = "Message Access",
+               .channel        = MAS_DEFAULT_CHANNEL,
+               .authorize      = true,
+               .get_record     = get_mas_record,
+               .version        = 0x0100
+       }, {
+               .uuid           = OBEX_MNS_UUID,
+               .name           = "Message Notification",
+               .channel        = MNS_DEFAULT_CHANNEL,
+               .psm            = BTD_PROFILE_PSM_AUTO,
+               .mode           = BT_IO_MODE_ERTM,
+               .authorize      = true,
+               .get_record     = get_mns_record,
+               .version        = 0x0102
+       },
+};
+
+static void ext_set_defaults(struct ext_profile *ext)
+{
+       unsigned int i;
+
+       ext->mode = BT_IO_MODE_BASIC;
+       ext->sec_level = BT_IO_SEC_MEDIUM;
+       ext->authorize = true;
+       ext->enable_client = true;
+       ext->enable_server = true;
+       ext->remote_uuid = NULL;
+
+       for (i = 0; i < G_N_ELEMENTS(defaults); i++) {
+               struct default_settings *settings = &defaults[i];
+               const char *remote_uuid;
+
+               if (strcasecmp(ext->uuid, settings->uuid) != 0)
+                       continue;
+
+               if (settings->remote_uuid)
+                       remote_uuid = settings->remote_uuid;
+               else
+                       remote_uuid = ext->uuid;
+
+               ext->remote_uuid = g_strdup(remote_uuid);
+
+               if (settings->channel)
+                       ext->local_chan = settings->channel;
+
+               if (settings->psm)
+                       ext->local_psm = settings->psm;
+
+               if (settings->sec_level)
+                       ext->sec_level = settings->sec_level;
+
+               if (settings->mode)
+                       ext->mode = settings->mode;
+
+               ext->authorize = settings->authorize;
+
+               if (settings->auto_connect)
+                       ext->p.auto_connect = true;
+
+               if (settings->priority)
+                       ext->p.priority = settings->priority;
+
+               if (settings->get_record)
+                       ext->get_record = settings->get_record;
+
+               if (settings->version)
+                       ext->version = settings->version;
+
+               if (settings->features)
+                       ext->features = settings->features;
+
+               if (settings->name)
+                       ext->name = g_strdup(settings->name);
+       }
+}
+
+static int parse_ext_opt(struct ext_profile *ext, const char *key,
+                                                       DBusMessageIter *value)
+{
+       int type = dbus_message_iter_get_arg_type(value);
+       const char *str;
+       uint16_t u16;
+       dbus_bool_t b;
+
+       if (strcasecmp(key, "Name") == 0) {
+               if (type != DBUS_TYPE_STRING)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &str);
+               g_free(ext->name);
+               ext->name = g_strdup(str);
+       } else if (strcasecmp(key, "AutoConnect") == 0) {
+               if (type != DBUS_TYPE_BOOLEAN)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &b);
+               ext->p.auto_connect = b;
+       } else if (strcasecmp(key, "PSM") == 0) {
+               if (type != DBUS_TYPE_UINT16)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &u16);
+               ext->local_psm = u16 ? u16 : BTD_PROFILE_PSM_AUTO;
+       } else if (strcasecmp(key, "Channel") == 0) {
+               if (type != DBUS_TYPE_UINT16)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(value, &u16);
+               if (u16 > 31)
+                       return -EINVAL;
+               ext->local_chan = u16 ? u16 : BTD_PROFILE_CHAN_AUTO;
+       } else if (strcasecmp(key, "RequireAuthentication") == 0) {
+               if (type != DBUS_TYPE_BOOLEAN)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(value, &b);
+               if (b)
+                       ext->sec_level = BT_IO_SEC_MEDIUM;
+               else
+                       ext->sec_level = BT_IO_SEC_LOW;
+       } else if (strcasecmp(key, "RequireAuthorization") == 0) {
+               if (type != DBUS_TYPE_BOOLEAN)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &b);
+               ext->authorize = b;
+       } else if (strcasecmp(key, "Role") == 0) {
+               if (type != DBUS_TYPE_STRING)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &str);
+               g_free(ext->role);
+               ext->role = g_strdup(str);
+
+               if (g_str_equal(ext->role, "client")) {
+                       ext->enable_server = false;
+                       ext->enable_client = true;
+               } else if (g_str_equal(ext->role, "server")) {
+                       ext->enable_server = true;
+                       ext->enable_client = false;
+               }
+       } else if (strcasecmp(key, "ServiceRecord") == 0) {
+               if (type != DBUS_TYPE_STRING)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &str);
+               g_free(ext->record);
+               ext->record = g_strdup(str);
+               ext->enable_server = true;
+       } else if (strcasecmp(key, "Version") == 0) {
+               uint16_t ver;
+
+               if (type != DBUS_TYPE_UINT16)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(value, &ver);
+               ext->version = ver;
+       } else if (strcasecmp(key, "Features") == 0) {
+               uint16_t feat;
+
+               if (type != DBUS_TYPE_UINT16)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(value, &feat);
+               ext->features = feat;
+       } else if (strcasecmp(key, "Service") == 0) {
+               if (type != DBUS_TYPE_STRING)
+                       return -EINVAL;
+               dbus_message_iter_get_basic(value, &str);
+               g_free(ext->service);
+               ext->service = bt_name2string(str);
+       }
+
+       return 0;
+}
+
+static void set_service(struct ext_profile *ext)
+{
+       if (strcasecmp(ext->uuid, HSP_HS_UUID) == 0) {
+               ext->service = g_strdup(ext->uuid);
+       } else if (strcasecmp(ext->uuid, HSP_AG_UUID) == 0) {
+               ext->service = ext->uuid;
+               ext->uuid = g_strdup(HSP_HS_UUID);
+       } else if (strcasecmp(ext->uuid, HFP_HS_UUID) == 0) {
+               ext->service = g_strdup(ext->uuid);
+       } else if (strcasecmp(ext->uuid, HFP_AG_UUID) == 0) {
+               ext->service = ext->uuid;
+               ext->uuid = g_strdup(HFP_HS_UUID);
+       } else if (strcasecmp(ext->uuid, OBEX_SYNC_UUID) == 0 ||
+                       strcasecmp(ext->uuid, OBEX_OPP_UUID) == 0 ||
+                       strcasecmp(ext->uuid, OBEX_FTP_UUID) == 0) {
+               ext->service = g_strdup(ext->uuid);
+       } else if (strcasecmp(ext->uuid, OBEX_PSE_UUID) == 0 ||
+                       strcasecmp(ext->uuid, OBEX_PCE_UUID) ==  0) {
+               ext->service = ext->uuid;
+               ext->uuid = g_strdup(OBEX_PBAP_UUID);
+       } else if (strcasecmp(ext->uuid, OBEX_MAS_UUID) == 0 ||
+                       strcasecmp(ext->uuid, OBEX_MNS_UUID) == 0) {
+               ext->service = ext->uuid;
+               ext->uuid = g_strdup(OBEX_MAP_UUID);
+       }
+}
+
+static struct ext_profile *create_ext(const char *owner, const char *path,
+                                       const char *uuid,
+                                       DBusMessageIter *opts)
+{
+       struct btd_profile *p;
+       struct ext_profile *ext;
+
+       ext = g_new0(struct ext_profile, 1);
+
+       ext->uuid = bt_name2string(uuid);
+       if (ext->uuid == NULL) {
+               g_free(ext);
+               return NULL;
+       }
+
+       ext->owner = g_strdup(owner);
+       ext->path = g_strdup(path);
+
+       ext_set_defaults(ext);
+
+       while (dbus_message_iter_get_arg_type(opts) == DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter value, entry;
+               const char *key;
+
+               dbus_message_iter_recurse(opts, &entry);
+               dbus_message_iter_get_basic(&entry, &key);
+
+               dbus_message_iter_next(&entry);
+               dbus_message_iter_recurse(&entry, &value);
+
+               if (parse_ext_opt(ext, key, &value) < 0)
+                       error("Invalid value for profile option %s", key);
+
+               dbus_message_iter_next(opts);
+       }
+
+       if (!ext->service)
+               set_service(ext);
+
+       if (ext->enable_server && !(ext->record || ext->get_record))
+               ext->get_record = get_generic_record;
+
+       if (!ext->name)
+               ext->name = g_strdup_printf("%s%s/%s", owner, path, uuid);
+
+       if (!ext->remote_uuid) {
+               if (ext->service)
+                       ext->remote_uuid = g_strdup(ext->service);
+               else
+                       ext->remote_uuid = g_strdup(ext->uuid);
+       }
+
+       p = &ext->p;
+
+       p->name = ext->name;
+       p->local_uuid = ext->service ? ext->service : ext->uuid;
+       p->remote_uuid = ext->remote_uuid;
+
+       if (ext->enable_server || ext->record || ext->get_record) {
+               p->adapter_probe = ext_adapter_probe;
+               p->adapter_remove = ext_adapter_remove;
+       }
+
+       if (ext->enable_client) {
+               p->device_probe = ext_device_probe;
+               p->device_remove = ext_device_remove;
+               p->connect = ext_connect_dev;
+               p->disconnect = ext_disconnect_dev;
+       }
+
+       DBG("Created \"%s\"", ext->name);
+
+       ext_profiles = g_slist_append(ext_profiles, ext);
+
+       adapter_foreach(adapter_add_profile, &ext->p);
+
+       return ext;
+}
+
+static void remove_ext(struct ext_profile *ext)
+{
+       adapter_foreach(adapter_remove_profile, &ext->p);
+
+       ext_profiles = g_slist_remove(ext_profiles, ext);
+
+       DBG("Removed \"%s\"", ext->name);
+
+       ext_remove_records(ext, NULL);
+
+       g_slist_free_full(ext->servers, ext_io_destroy);
+       g_slist_free_full(ext->conns, ext_io_destroy);
+
+       g_free(ext->remote_uuid);
+       g_free(ext->name);
+       g_free(ext->owner);
+       g_free(ext->uuid);
+       g_free(ext->service);
+       g_free(ext->role);
+       g_free(ext->path);
+       g_free(ext->record);
+
+       g_free(ext);
+}
+
+static void ext_exited(DBusConnection *conn, void *user_data)
+{
+       struct ext_profile *ext = user_data;
+
+       DBG("\"%s\" exited", ext->name);
+
+       remove_ext(ext);
+}
+
+static DBusMessage *register_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *path, *sender, *uuid;
+       DBusMessageIter args, opts;
+       struct ext_profile *ext;
+
+       sender = dbus_message_get_sender(msg);
+
+       DBG("sender %s", sender);
+
+       dbus_message_iter_init(msg, &args);
+
+       dbus_message_iter_get_basic(&args, &path);
+       dbus_message_iter_next(&args);
+
+       ext = find_ext_profile(sender, path);
+       if (ext)
+               return btd_error_already_exists(msg);
+
+       dbus_message_iter_get_basic(&args, &uuid);
+       dbus_message_iter_next(&args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return btd_error_invalid_args(msg);
+
+       dbus_message_iter_recurse(&args, &opts);
+
+       ext = create_ext(sender, path, uuid, &opts);
+       if (!ext)
+               return btd_error_invalid_args(msg);
+
+       ext->id = g_dbus_add_disconnect_watch(conn, sender, ext_exited, ext,
+                                                                       NULL);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static DBusMessage *unregister_profile(DBusConnection *conn,
+                                       DBusMessage *msg, void *user_data)
+{
+       const char *path, *sender;
+       struct ext_profile *ext;
+
+       sender = dbus_message_get_sender(msg);
+
+       DBG("sender %s", sender);
+
+       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
+                                                       DBUS_TYPE_INVALID))
+               return btd_error_invalid_args(msg);
+
+       ext = find_ext_profile(sender, path);
+       if (!ext)
+               return btd_error_does_not_exist(msg);
+
+       g_dbus_remove_watch(conn, ext->id);
+       remove_ext(ext);
+
+       return dbus_message_new_method_return(msg);
+}
+
+static const GDBusMethodTable methods[] = {
+       { GDBUS_METHOD("RegisterProfile",
+                       GDBUS_ARGS({ "profile", "o"}, { "UUID", "s" },
+                                               { "options", "a{sv}" }),
+                       NULL, register_profile) },
+       { GDBUS_METHOD("UnregisterProfile", GDBUS_ARGS({ "profile", "o" }),
+                       NULL, unregister_profile) },
+       { }
+};
+
+static struct btd_profile_custom_property *find_custom_prop(const char *uuid,
+                                                       const char *name)
+{
+       GSList *l;
+
+       for (l = custom_props; l; l = l->next) {
+               struct btd_profile_custom_property *prop = l->data;
+
+               if (strcasecmp(prop->uuid, uuid) != 0)
+                       continue;
+
+               if (g_strcmp0(prop->name, name) == 0)
+                       return prop;
+       }
+
+       return NULL;
+}
+
+bool btd_profile_add_custom_prop(const char *uuid, const char *type,
+                                       const char *name,
+                                       btd_profile_prop_exists exists,
+                                       btd_profile_prop_get get,
+                                       void *user_data)
+{
+       struct btd_profile_custom_property *prop;
+
+       prop = find_custom_prop(uuid, name);
+       if (prop != NULL)
+               return false;
+
+       prop = g_new0(struct btd_profile_custom_property, 1);
+
+       prop->uuid = g_strdup(uuid);
+       prop->type = g_strdup(type);
+       prop->name = g_strdup(name);
+       prop->exists = exists;
+       prop->get = get;
+       prop->user_data = user_data;
+
+       custom_props = g_slist_append(custom_props, prop);
+
+       return true;
+}
+
+static void free_property(gpointer data)
+{
+       struct btd_profile_custom_property *p = data;
+
+       g_free(p->uuid);
+       g_free(p->type);
+       g_free(p->name);
+
+       g_free(p);
+}
+
+bool btd_profile_remove_custom_prop(const char *uuid, const char *name)
+{
+       struct btd_profile_custom_property *prop;
+
+       prop = find_custom_prop(uuid, name);
+       if (prop == NULL)
+               return false;
+
+       custom_props = g_slist_remove(custom_props, prop);
+       free_property(prop);
+
+       return false;
+}
+
+void btd_profile_init(void)
+{
+       g_dbus_register_interface(btd_get_dbus_connection(),
+                               "/org/bluez", "org.bluez.ProfileManager1",
+                               methods, NULL, NULL, NULL, NULL);
+}
+
+void btd_profile_cleanup(void)
+{
+       while (ext_profiles) {
+               struct ext_profile *ext = ext_profiles->data;
+               DBusConnection *conn = btd_get_dbus_connection();
+               DBusMessage *msg;
+
+               DBG("Releasing \"%s\"", ext->name);
+
+               g_slist_free_full(ext->conns, ext_io_destroy);
+               ext->conns = NULL;
+
+               msg = dbus_message_new_method_call(ext->owner, ext->path,
+                                                       "org.bluez.Profile1",
+                                                       "Release");
+               if (msg)
+                       g_dbus_send_message(conn, msg);
+
+               g_dbus_remove_watch(conn, ext->id);
+               remove_ext(ext);
+
+       }
+
+       g_slist_free_full(custom_props, free_property);
+       custom_props = NULL;
+
+       g_dbus_unregister_interface(btd_get_dbus_connection(),
+                               "/org/bluez", "org.bluez.ProfileManager1");
+}
diff --git a/src/profile.h b/src/profile.h
new file mode 100644 (file)
index 0000000..9aec27e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *
+ *  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
+ *
+ */
+
+#define BTD_PROFILE_PRIORITY_LOW       0
+#define BTD_PROFILE_PRIORITY_MEDIUM    1
+#define BTD_PROFILE_PRIORITY_HIGH      2
+
+struct btd_service;
+
+struct btd_profile {
+       const char *name;
+       int priority;
+
+       const char *local_uuid;
+       const char *remote_uuid;
+
+       bool auto_connect;
+
+       int (*device_probe) (struct btd_service *service);
+       void (*device_remove) (struct btd_service *service);
+
+       int (*connect) (struct btd_service *service);
+       int (*disconnect) (struct btd_service *service);
+
+       int (*adapter_probe) (struct btd_profile *p,
+                                               struct btd_adapter *adapter);
+       void (*adapter_remove) (struct btd_profile *p,
+                                               struct btd_adapter *adapter);
+};
+
+void btd_profile_foreach(void (*func)(struct btd_profile *p, void *data),
+                                                               void *data);
+
+int btd_profile_register(struct btd_profile *profile);
+void btd_profile_unregister(struct btd_profile *profile);
+
+typedef bool (*btd_profile_prop_exists)(const char *uuid,
+                                               struct btd_device *dev,
+                                               void *user_data);
+
+typedef bool (*btd_profile_prop_get)(const char *uuid,
+                                               struct btd_device *dev,
+                                               DBusMessageIter *iter,
+                                               void *user_data);
+
+bool btd_profile_add_custom_prop(const char *uuid, const char *type,
+                                       const char *name,
+                                       btd_profile_prop_exists exists,
+                                       btd_profile_prop_get get,
+                                       void *user_data);
+bool btd_profile_remove_custom_prop(const char *uuid, const char *name);
+
+void btd_profile_init(void);
+void btd_profile_cleanup(void);
index b40c6e7..70588c0 100644 (file)
@@ -37,7 +37,6 @@
 
 #include "log.h"
 #include "adapter.h"
-#include "manager.h"
 #include "hcid.h"
 
 enum rfkill_type {
@@ -114,7 +113,7 @@ static gboolean rfkill_event(GIOChannel *chan,
 
        memset(sysname, 0, sizeof(sysname));
 
-       if (read(fd, sysname, sizeof(sysname)) < 4) {
+       if (read(fd, sysname, sizeof(sysname) - 1) < 4) {
                close(fd);
                return TRUE;
        }
@@ -128,7 +127,7 @@ static gboolean rfkill_event(GIOChannel *chan,
        if (id < 0)
                return TRUE;
 
-       adapter = manager_find_adapter_by_id(id);
+       adapter = adapter_find_by_id(id);
        if (!adapter)
                return TRUE;
 
@@ -139,14 +138,12 @@ static gboolean rfkill_event(GIOChannel *chan,
        return TRUE;
 }
 
-static GIOChannel *channel = NULL;
+static guint watch = 0;
 
 void rfkill_init(void)
 {
        int fd;
-
-       if (!main_opts.remember_powered)
-               return;
+       GIOChannel *channel;
 
        fd = open("/dev/rfkill", O_RDWR);
        if (fd < 0) {
@@ -157,17 +154,18 @@ void rfkill_init(void)
        channel = g_io_channel_unix_new(fd);
        g_io_channel_set_close_on_unref(channel, TRUE);
 
-       g_io_add_watch(channel, G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
-                                                       rfkill_event, NULL);
+       watch = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_NVAL | G_IO_HUP | G_IO_ERR,
+                               rfkill_event, NULL);
+
+       g_io_channel_unref(channel);
 }
 
 void rfkill_exit(void)
 {
-       if (!channel)
+       if (watch == 0)
                return;
 
-       g_io_channel_shutdown(channel, TRUE, NULL);
-       g_io_channel_unref(channel);
-
-       channel = NULL;
+       g_source_remove(watch);
+       watch = 0;
 }
index 55e59c2..2789db6 100644 (file)
@@ -33,7 +33,8 @@
 
 #include <glib.h>
 
-#include "btio.h"
+#include <btio/btio.h>
+#include "log.h"
 #include "sdp-client.h"
 
 /* Number of seconds to keep a sdp_session_t in the cache */
@@ -285,6 +286,8 @@ static int create_search_context(struct search_context **ctxt,
 {
        sdp_session_t *s;
        GIOChannel *chan;
+       uint32_t prio = 1;
+       int sk;
 
        if (!ctxt)
                return -EINVAL;
@@ -304,7 +307,15 @@ static int create_search_context(struct search_context **ctxt,
        (*ctxt)->session = s;
        (*ctxt)->uuid = *uuid;
 
-       chan = g_io_channel_unix_new(sdp_get_socket(s));
+       sk = sdp_get_socket(s);
+       /* Set low priority for the SDP connection not to interfere with
+        * other potential traffic.
+        */
+       if (setsockopt(sk, SOL_SOCKET, SO_PRIORITY, &prio, sizeof(prio)) < 0)
+               warn("Setting SDP priority failed: %s (%d)",
+                                               strerror(errno), errno);
+
+       chan = g_io_channel_unix_new(sk);
        (*ctxt)->io_id = g_io_add_watch(chan,
                                G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
                                connect_watch, *ctxt);
@@ -336,7 +347,7 @@ int bt_search_service(const bdaddr_t *src, const bdaddr_t *dst,
        return 0;
 }
 
-static gint find_by_bdaddr(gconstpointer data, gconstpointer user_data)
+static int find_by_bdaddr(gconstpointer data, gconstpointer user_data)
 {
        const struct search_context *ctxt = data, *search = user_data;
        int ret;
index d7b2aef..6492781 100644 (file)
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
 #include <limits.h>
 #include <stdlib.h>
 
+#include <glib.h>
+
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
 #include "sdp-xml.h"
 
+#define DBG(...) (void)(0)
+#define error(...) (void)(0)
+
+#define SDP_XML_ENCODING_NORMAL        0
+#define SDP_XML_ENCODING_HEX   1
+
 #define STRBUFSIZE 1024
 #define MAXINDENT 64
 
-static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
-               void *data, void (*appender)(void *, const char *))
-{
-       int i, hex;
-       char buf[STRBUFSIZE];
-       char indent[MAXINDENT];
+struct sdp_xml_data {
+       char *text;                     /* Pointer to the current buffer */
+       int size;                       /* Size of the current buffer */
+       sdp_data_t *data;               /* The current item being built */
+       struct sdp_xml_data *next;      /* Next item on the stack */
+       char type;                      /* 0 = Text or Hexadecimal */
+       char *name;                     /* Name, optional in the dtd */
+       /* TODO: What is it used for? */
+};
 
-       if (!value)
-               return;
+struct context_data {
+       sdp_record_t *record;
+       sdp_data_t attr_data;
+       struct sdp_xml_data *stack_head;
+       uint16_t attr_id;
+};
 
-       if (indent_level >= MAXINDENT)
-               indent_level = MAXINDENT - 2;
+static int compute_seq_size(sdp_data_t *data)
+{
+       int unit_size = data->unitSize;
+       sdp_data_t *seq = data->val.dataseq;
 
-       for (i = 0; i < indent_level; i++)
-               indent[i] = '\t';
+       for (; seq; seq = seq->next)
+               unit_size += seq->unitSize;
 
-       indent[i] = '\0';
-       buf[STRBUFSIZE - 1] = '\0';
+       return unit_size;
+}
 
-       switch (value->dtd) {
-       case SDP_DATA_NIL:
-               appender(data, indent);
-               appender(data, "<nil/>\n");
-               break;
+#define DEFAULT_XML_DATA_SIZE 1024
 
-       case SDP_BOOL:
-               appender(data, indent);
-               appender(data, "<boolean value=\"");
-               appender(data, value->val.uint8 ? "true" : "false");
-               appender(data, "\" />\n");
-               break;
+static struct sdp_xml_data *sdp_xml_data_alloc(void)
+{
+       struct sdp_xml_data *elem;
 
-       case SDP_UINT8:
-               appender(data, indent);
-               appender(data, "<uint8 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       elem = malloc(sizeof(struct sdp_xml_data));
+       if (!elem)
+               return NULL;
 
-       case SDP_UINT16:
-               appender(data, indent);
-               appender(data, "<uint16 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       memset(elem, 0, sizeof(struct sdp_xml_data));
 
-       case SDP_UINT32:
-               appender(data, indent);
-               appender(data, "<uint32 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       /* Null terminate the text */
+       elem->size = DEFAULT_XML_DATA_SIZE;
+       elem->text = malloc(DEFAULT_XML_DATA_SIZE);
+       elem->text[0] = '\0';
 
-       case SDP_UINT64:
-               appender(data, indent);
-               appender(data, "<uint64 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       return elem;
+}
 
-       case SDP_UINT128:
-               appender(data, indent);
-               appender(data, "<uint128 value=\"");
+static struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
+{
+       char *newbuf;
 
-               for (i = 0; i < 16; i++) {
-                       sprintf(&buf[i * 2], "%02x",
-                               (unsigned char) value->val.uint128.data[i]);
-               }
+       newbuf = malloc(elem->size * 2);
+       if (!newbuf)
+               return NULL;
 
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       memcpy(newbuf, elem->text, elem->size);
+       elem->size *= 2;
+       free(elem->text);
 
-       case SDP_INT8:
-               appender(data, indent);
-               appender(data, "<int8 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       elem->text = newbuf;
 
-       case SDP_INT16:
-               appender(data, indent);
-               appender(data, "<int16 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       return elem;
+}
 
-       case SDP_INT32:
-               appender(data, indent);
-               appender(data, "<int32 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
+{
+       uint128_t val;
+       unsigned int i, j;
 
-       case SDP_INT64:
-               appender(data, indent);
-               appender(data, "<int64 value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       char buf[3];
 
-       case SDP_INT128:
-               appender(data, indent);
-               appender(data, "<int128 value=\"");
+       memset(&val, 0, sizeof(val));
 
-               for (i = 0; i < 16; i++) {
-                       sprintf(&buf[i * 2], "%02x",
-                               (unsigned char) value->val.int128.data[i]);
-               }
-               appender(data, buf);
+       buf[2] = '\0';
 
-               appender(data, "\" />\n");
-               break;
+       for (j = 0, i = 0; i < strlen(data);) {
+               if (data[i] == '-') {
+                       i++;
+                       continue;
+               }
 
-       case SDP_UUID16:
-               appender(data, indent);
-               appender(data, "<uuid value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+               buf[0] = data[i];
+               buf[1] = data[i + 1];
 
-       case SDP_UUID32:
-               appender(data, indent);
-               appender(data, "<uuid value=\"");
-               snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+               val.data[j++] = strtoul(buf, 0, 16);
+               i += 2;
+       }
 
-       case SDP_UUID128:
-               appender(data, indent);
-               appender(data, "<uuid value=\"");
+       return sdp_data_alloc(SDP_UUID128, &val);
+}
 
-               snprintf(buf, STRBUFSIZE - 1,
-                        "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[0],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[1],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[2],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[3],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[4],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[5],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[6],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[7],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[8],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[9],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[10],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[11],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[12],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[13],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[14],
-                        (unsigned char) value->val.uuid.value.
-                        uuid128.data[15]);
+static sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
+{
+       sdp_data_t *ret;
+       char *endptr;
+       uint32_t val;
+       uint16_t val2;
+       int len;
 
-               appender(data, buf);
-               appender(data, "\" />\n");
-               break;
+       len = strlen(data);
 
-       case SDP_TEXT_STR8:
-       case SDP_TEXT_STR16:
-       case SDP_TEXT_STR32:
-       {
-               int num_chars_to_escape = 0;
-               int length = value->unitSize - 1;
-               char *strBuf = 0;
+       if (len == 36) {
+               ret = sdp_xml_parse_uuid128(data);
+               goto result;
+       }
 
-               hex = 0;
+       val = strtoll(data, &endptr, 16);
 
-               for (i = 0; i < length; i++) {
-                       if (!isprint(value->val.str[i]) &&
-                                       value->val.str[i] != '\0') {
-                               hex = 1;
-                               break;
-                       }
+       /* Couldn't parse */
+       if (*endptr != '\0')
+               return NULL;
 
-                       /* XML is evil, must do this... */
-                       if ((value->val.str[i] == '<') ||
-                                       (value->val.str[i] == '>') ||
-                                       (value->val.str[i] == '"') ||
-                                       (value->val.str[i] == '&'))
-                               num_chars_to_escape++;
-               }
+       if (val > USHRT_MAX) {
+               ret = sdp_data_alloc(SDP_UUID32, &val);
+               goto result;
+       }
 
-               appender(data, indent);
+       val2 = val;
 
-               appender(data, "<text ");
+       ret = sdp_data_alloc(SDP_UUID16, &val2);
 
-               if (hex) {
-                       appender(data, "encoding=\"hex\" ");
-                       strBuf = malloc(sizeof(char)
-                                                * ((value->unitSize-1) * 2 + 1));
-
-                       /* Unit Size seems to include the size for dtd
-                          It is thus off by 1
-                          This is safe for Normal strings, but not
-                          hex encoded data */
-                       for (i = 0; i < (value->unitSize-1); i++)
-                               sprintf(&strBuf[i*sizeof(char)*2],
-                                       "%02x",
-                                       (unsigned char) value->val.str[i]);
-
-                       strBuf[(value->unitSize-1) * 2] = '\0';
-               }
-               else {
-                       int j;
-                       /* escape the XML disallowed chars */
-                       strBuf = malloc(sizeof(char) *
-                                       (value->unitSize + 1 + num_chars_to_escape * 4));
-                       for (i = 0, j = 0; i < length; i++) {
-                               if (value->val.str[i] == '&') {
-                                       strBuf[j++] = '&';
-                                       strBuf[j++] = 'a';
-                                       strBuf[j++] = 'm';
-                                       strBuf[j++] = 'p';
-                               }
-                               else if (value->val.str[i] == '<') {
-                                       strBuf[j++] = '&';
-                                       strBuf[j++] = 'l';
-                                       strBuf[j++] = 't';
-                               }
-                               else if (value->val.str[i] == '>') {
-                                       strBuf[j++] = '&';
-                                       strBuf[j++] = 'g';
-                                       strBuf[j++] = 't';
-                               }
-                               else if (value->val.str[i] == '"') {
-                                       strBuf[j++] = '&';
-                                       strBuf[j++] = 'q';
-                                       strBuf[j++] = 'u';
-                                       strBuf[j++] = 'o';
-                                       strBuf[j++] = 't';
-                               }
-                               else if (value->val.str[i] == '\0') {
-                                       strBuf[j++] = ' ';
-                               } else {
-                                       strBuf[j++] = value->val.str[i];
-                               }
-                       }
-
-                       strBuf[j] = '\0';
-               }
-
-               appender(data, "value=\"");
-               appender(data, strBuf);
-               appender(data, "\" />\n");
-               free(strBuf);
-               break;
-       }
-
-       case SDP_URL_STR8:
-       case SDP_URL_STR16:
-       case SDP_URL_STR32:
-       {
-               char *strBuf;
-
-               appender(data, indent);
-               appender(data, "<url value=\"");
-               strBuf = strndup(value->val.str, value->unitSize - 1);
-               appender(data, strBuf);
-               free(strBuf);
-               appender(data, "\" />\n");
-               break;
-       }
-
-       case SDP_SEQ8:
-       case SDP_SEQ16:
-       case SDP_SEQ32:
-               appender(data, indent);
-               appender(data, "<sequence>\n");
-
-               convert_raw_data_to_xml(value->val.dataseq,
-                                       indent_level + 1, data, appender);
-
-               appender(data, indent);
-               appender(data, "</sequence>\n");
-
-               break;
-
-       case SDP_ALT8:
-       case SDP_ALT16:
-       case SDP_ALT32:
-               appender(data, indent);
-
-               appender(data, "<alternate>\n");
-
-               convert_raw_data_to_xml(value->val.dataseq,
-                                       indent_level + 1, data, appender);
-               appender(data, indent);
-
-               appender(data, "</alternate>\n");
-
-               break;
-       }
-
-       convert_raw_data_to_xml(value->next, indent_level, data, appender);
-}
-
-struct conversion_data {
-       void *data;
-       void (*appender)(void *data, const char *);
-};
-
-static void convert_raw_attr_to_xml_func(void *val, void *data)
-{
-       struct conversion_data *cd = data;
-       sdp_data_t *value = val;
-       char buf[STRBUFSIZE];
-
-       buf[STRBUFSIZE - 1] = '\0';
-       snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
-                value->attrId);
-       cd->appender(cd->data, buf);
-
-       if (data)
-               convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
-       else
-               cd->appender(cd->data, "\t\tNULL\n");
-
-       cd->appender(cd->data, "\t</attribute>\n");
-}
-
-/*
- * Will convert the sdp record to XML.  The appender and data can be used
- * to control where to output the record (e.g. file or a data buffer).  The
- * appender will be called repeatedly with data and the character buffer
- * (containing parts of the generated XML) to append.
- */
-void convert_sdp_record_to_xml(sdp_record_t *rec,
-                       void *data, void (*appender)(void *, const char *))
-{
-       struct conversion_data cd;
-
-       cd.data = data;
-       cd.appender = appender;
-
-       if (rec && rec->attrlist) {
-               appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
-               appender(data, "<record>\n");
-               sdp_list_foreach(rec->attrlist,
-                                convert_raw_attr_to_xml_func, &cd);
-               appender(data, "</record>\n");
-       }
-}
-
-static sdp_data_t *sdp_xml_parse_uuid128(const char *data)
-{
-       uint128_t val;
-       unsigned int i, j;
-
-       char buf[3];
-
-       memset(&val, 0, sizeof(val));
-
-       buf[2] = '\0';
-
-       for (j = 0, i = 0; i < strlen(data);) {
-               if (data[i] == '-') {
-                       i++;
-                       continue;
-               }
-
-               buf[0] = data[i];
-               buf[1] = data[i + 1];
-
-               val.data[j++] = strtoul(buf, 0, 16);
-               i += 2;
-       }
-
-       return sdp_data_alloc(SDP_UUID128, &val);
-}
-
-sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record)
-{
-       sdp_data_t *ret;
-       char *endptr;
-       uint32_t val;
-       uint16_t val2;
-       int len;
-
-       len = strlen(data);
-
-       if (len == 36) {
-               ret = sdp_xml_parse_uuid128(data);
-               goto result;
-       }
-
-       val = strtoll(data, &endptr, 16);
-
-       /* Couldn't parse */
-       if (*endptr != '\0')
-               return NULL;
-
-       if (val > USHRT_MAX) {
-               ret = sdp_data_alloc(SDP_UUID32, &val);
-               goto result;
-       }
-
-       val2 = val;
-
-       ret = sdp_data_alloc(SDP_UUID16, &val2);
-
-result:
-       if (record && ret)
-               sdp_pattern_add_uuid(record, &ret->val.uuid);
+result:
+       if (record && ret)
+               sdp_pattern_add_uuid(record, &ret->val.uuid);
 
        return ret;
 }
 
-sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
+static sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd)
 {
        char *endptr;
        sdp_data_t *ret = NULL;
@@ -482,16 +187,12 @@ sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
        {
                uint8_t val = 0;
 
-               if (!strcmp("true", data)) {
+               if (!strcmp("true", data))
                        val = 1;
-               }
-
-               else if (!strcmp("false", data)) {
+               else if (!strcmp("false", data))
                        val = 0;
-               }
-               else {
+               else
                        return NULL;
-               }
 
                ret = sdp_data_alloc(dtd, &val);
                break;
@@ -618,7 +319,8 @@ sdp_data_t *sdp_xml_parse_int(const char * data, uint8_t dtd)
        return ret;
 }
 
-static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32_t *length)
+static char *sdp_xml_parse_string_decode(const char *data, char encoding,
+                                                       uint32_t *length)
 {
        int len = strlen(data);
        char *text;
@@ -652,7 +354,7 @@ static char *sdp_xml_parse_string_decode(const char *data, char encoding, uint32
        return text;
 }
 
-sdp_data_t *sdp_xml_parse_url(const char *data)
+static sdp_data_t *sdp_xml_parse_url(const char *data)
 {
        uint8_t dtd = SDP_URL_STR8;
        char *url;
@@ -672,7 +374,7 @@ sdp_data_t *sdp_xml_parse_url(const char *data)
        return ret;
 }
 
-sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
+static sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
 {
        uint8_t dtd = SDP_TEXT_STR8;
        char *text;
@@ -691,60 +393,14 @@ sdp_data_t *sdp_xml_parse_text(const char *data, char encoding)
        return ret;
 }
 
-sdp_data_t *sdp_xml_parse_nil(const char *data)
+static sdp_data_t *sdp_xml_parse_nil(const char *data)
 {
        return sdp_data_alloc(SDP_DATA_NIL, 0);
 }
 
-#define DEFAULT_XML_DATA_SIZE 1024
-
-struct sdp_xml_data *sdp_xml_data_alloc(void)
-{
-       struct sdp_xml_data *elem;
-
-       elem = malloc(sizeof(struct sdp_xml_data));
-       if (!elem)
-               return NULL;
-
-       memset(elem, 0, sizeof(struct sdp_xml_data));
-
-       /* Null terminate the text */
-       elem->size = DEFAULT_XML_DATA_SIZE;
-       elem->text = malloc(DEFAULT_XML_DATA_SIZE);
-       elem->text[0] = '\0';
-
-       return elem;
-}
-
-void sdp_xml_data_free(struct sdp_xml_data *elem)
-{
-       if (elem->data)
-               sdp_data_free(elem->data);
-
-       free(elem->name);
-       free(elem->text);
-       free(elem);
-}
-
-struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem)
-{
-       char *newbuf;
-
-       newbuf = malloc(elem->size * 2);
-       if (!newbuf)
-               return NULL;
-
-       memcpy(newbuf, elem->text, elem->size);
-       elem->size *= 2;
-       free(elem->text);
-
-       elem->text = newbuf;
-
-       return elem;
-}
-
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
-                                                       sdp_record_t *record)
+static sdp_data_t *sdp_xml_parse_datatype(const char *el,
+                                               struct sdp_xml_data *elem,
+                                               sdp_record_t *record)
 {
        const char *data = elem->text;
 
@@ -781,3 +437,560 @@ sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
 
        return NULL;
 }
+static void element_start(GMarkupParseContext *context,
+               const char *element_name, const char **attribute_names,
+               const char **attribute_values, gpointer user_data, GError **err)
+{
+       struct context_data *ctx_data = user_data;
+
+       if (!strcmp(element_name, "record"))
+               return;
+
+       if (!strcmp(element_name, "attribute")) {
+               int i;
+               for (i = 0; attribute_names[i]; i++) {
+                       if (!strcmp(attribute_names[i], "id")) {
+                               ctx_data->attr_id = strtol(attribute_values[i], 0, 0);
+                               break;
+                       }
+               }
+               DBG("New attribute 0x%04x", ctx_data->attr_id);
+               return;
+       }
+
+       if (ctx_data->stack_head) {
+               struct sdp_xml_data *newelem = sdp_xml_data_alloc();
+               newelem->next = ctx_data->stack_head;
+               ctx_data->stack_head = newelem;
+       } else {
+               ctx_data->stack_head = sdp_xml_data_alloc();
+               ctx_data->stack_head->next = NULL;
+       }
+
+       if (!strcmp(element_name, "sequence"))
+               ctx_data->stack_head->data = sdp_data_alloc(SDP_SEQ8, NULL);
+       else if (!strcmp(element_name, "alternate"))
+               ctx_data->stack_head->data = sdp_data_alloc(SDP_ALT8, NULL);
+       else {
+               int i;
+               /* Parse value, name, encoding */
+               for (i = 0; attribute_names[i]; i++) {
+                       if (!strcmp(attribute_names[i], "value")) {
+                               int curlen = strlen(ctx_data->stack_head->text);
+                               int attrlen = strlen(attribute_values[i]);
+
+                               /* Ensure we're big enough */
+                               while ((curlen + 1 + attrlen) > ctx_data->stack_head->size)
+                                       sdp_xml_data_expand(ctx_data->stack_head);
+
+                               memcpy(ctx_data->stack_head->text + curlen,
+                                               attribute_values[i], attrlen);
+                               ctx_data->stack_head->text[curlen + attrlen] = '\0';
+                       }
+
+                       if (!strcmp(attribute_names[i], "encoding")) {
+                               if (!strcmp(attribute_values[i], "hex"))
+                                       ctx_data->stack_head->type = 1;
+                       }
+
+                       if (!strcmp(attribute_names[i], "name"))
+                               ctx_data->stack_head->name = strdup(attribute_values[i]);
+               }
+
+               ctx_data->stack_head->data = sdp_xml_parse_datatype(element_name,
+                               ctx_data->stack_head, ctx_data->record);
+
+               if (ctx_data->stack_head->data == NULL)
+                       error("Can't parse element %s", element_name);
+       }
+}
+
+static void sdp_xml_data_free(struct sdp_xml_data *elem)
+{
+       if (elem->data)
+               sdp_data_free(elem->data);
+
+       free(elem->name);
+       free(elem->text);
+       free(elem);
+}
+
+static void element_end(GMarkupParseContext *context,
+               const char *element_name, gpointer user_data, GError **err)
+{
+       struct context_data *ctx_data = user_data;
+       struct sdp_xml_data *elem;
+
+       if (!strcmp(element_name, "record"))
+               return;
+
+       if (!strcmp(element_name, "attribute")) {
+               if (ctx_data->stack_head && ctx_data->stack_head->data) {
+                       int ret = sdp_attr_add(ctx_data->record, ctx_data->attr_id,
+                                                       ctx_data->stack_head->data);
+                       if (ret == -1)
+                               DBG("Could not add attribute 0x%04x",
+                                                       ctx_data->attr_id);
+
+                       ctx_data->stack_head->data = NULL;
+                       sdp_xml_data_free(ctx_data->stack_head);
+                       ctx_data->stack_head = NULL;
+               } else {
+                       DBG("No data for attribute 0x%04x", ctx_data->attr_id);
+               }
+               return;
+       }
+
+       if (!ctx_data->stack_head || !ctx_data->stack_head->data) {
+               DBG("No data for %s", element_name);
+               return;
+       }
+
+       if (!strcmp(element_name, "sequence")) {
+               ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+
+               if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+                       ctx_data->stack_head->data->dtd = SDP_SEQ32;
+               } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+                       ctx_data->stack_head->data->dtd = SDP_SEQ16;
+               } else {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
+               }
+       } else if (!strcmp(element_name, "alternate")) {
+               ctx_data->stack_head->data->unitSize = compute_seq_size(ctx_data->stack_head->data);
+
+               if (ctx_data->stack_head->data->unitSize > USHRT_MAX) {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint32_t);
+                       ctx_data->stack_head->data->dtd = SDP_ALT32;
+               } else if (ctx_data->stack_head->data->unitSize > UCHAR_MAX) {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint16_t);
+                       ctx_data->stack_head->data->dtd = SDP_ALT16;
+               } else {
+                       ctx_data->stack_head->data->unitSize += sizeof(uint8_t);
+               }
+       }
+
+       if (ctx_data->stack_head->next && ctx_data->stack_head->data &&
+                                       ctx_data->stack_head->next->data) {
+               switch (ctx_data->stack_head->next->data->dtd) {
+               case SDP_SEQ8:
+               case SDP_SEQ16:
+               case SDP_SEQ32:
+               case SDP_ALT8:
+               case SDP_ALT16:
+               case SDP_ALT32:
+                       ctx_data->stack_head->next->data->val.dataseq =
+                               sdp_seq_append(ctx_data->stack_head->next->data->val.dataseq,
+                                                               ctx_data->stack_head->data);
+                       ctx_data->stack_head->data = NULL;
+                       break;
+               }
+
+               elem = ctx_data->stack_head;
+               ctx_data->stack_head = ctx_data->stack_head->next;
+
+               sdp_xml_data_free(elem);
+       }
+}
+
+static GMarkupParser parser = {
+       element_start, element_end, NULL, NULL, NULL
+};
+
+sdp_record_t *sdp_xml_parse_record(const char *data, int size)
+{
+       GMarkupParseContext *ctx;
+       struct context_data *ctx_data;
+       sdp_record_t *record;
+
+       ctx_data = malloc(sizeof(*ctx_data));
+       if (!ctx_data)
+               return NULL;
+
+       record = sdp_record_alloc();
+       if (!record) {
+               free(ctx_data);
+               return NULL;
+       }
+
+       memset(ctx_data, 0, sizeof(*ctx_data));
+       ctx_data->record = record;
+
+       ctx = g_markup_parse_context_new(&parser, 0, ctx_data, NULL);
+
+       if (g_markup_parse_context_parse(ctx, data, size, NULL) == FALSE) {
+               error("XML parsing error");
+               g_markup_parse_context_free(ctx);
+               sdp_record_free(record);
+               free(ctx_data);
+               return NULL;
+       }
+
+       g_markup_parse_context_free(ctx);
+
+       free(ctx_data);
+
+       return record;
+}
+
+
+static void convert_raw_data_to_xml(sdp_data_t *value, int indent_level,
+               void *data, void (*appender)(void *, const char *))
+{
+       int i, hex;
+       char buf[STRBUFSIZE];
+       char indent[MAXINDENT];
+
+       if (!value)
+               return;
+
+       if (indent_level >= MAXINDENT)
+               indent_level = MAXINDENT - 2;
+
+       for (i = 0; i < indent_level; i++)
+               indent[i] = '\t';
+
+       indent[i] = '\0';
+       buf[STRBUFSIZE - 1] = '\0';
+
+       switch (value->dtd) {
+       case SDP_DATA_NIL:
+               appender(data, indent);
+               appender(data, "<nil/>\n");
+               break;
+
+       case SDP_BOOL:
+               appender(data, indent);
+               appender(data, "<boolean value=\"");
+               appender(data, value->val.uint8 ? "true" : "false");
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UINT8:
+               appender(data, indent);
+               appender(data, "<uint8 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%02x", value->val.uint8);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UINT16:
+               appender(data, indent);
+               appender(data, "<uint16 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uint16);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UINT32:
+               appender(data, indent);
+               appender(data, "<uint32 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uint32);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UINT64:
+               appender(data, indent);
+               appender(data, "<uint64 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%016jx", value->val.uint64);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UINT128:
+               appender(data, indent);
+               appender(data, "<uint128 value=\"");
+
+               for (i = 0; i < 16; i++) {
+                       sprintf(&buf[i * 2], "%02x",
+                               (unsigned char) value->val.uint128.data[i]);
+               }
+
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_INT8:
+               appender(data, indent);
+               appender(data, "<int8 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int8);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_INT16:
+               appender(data, indent);
+               appender(data, "<int16 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int16);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_INT32:
+               appender(data, indent);
+               appender(data, "<int32 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "%d", value->val.int32);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_INT64:
+               appender(data, indent);
+               appender(data, "<int64 value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "%jd", value->val.int64);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_INT128:
+               appender(data, indent);
+               appender(data, "<int128 value=\"");
+
+               for (i = 0; i < 16; i++) {
+                       sprintf(&buf[i * 2], "%02x",
+                               (unsigned char) value->val.int128.data[i]);
+               }
+               appender(data, buf);
+
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UUID16:
+               appender(data, indent);
+               appender(data, "<uuid value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%04x", value->val.uuid.value.uuid16);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UUID32:
+               appender(data, indent);
+               appender(data, "<uuid value=\"");
+               snprintf(buf, STRBUFSIZE - 1, "0x%08x", value->val.uuid.value.uuid32);
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_UUID128:
+               appender(data, indent);
+               appender(data, "<uuid value=\"");
+
+               snprintf(buf, STRBUFSIZE - 1,
+                        "%02x%02x%02x%02x-%02x%02x-%02x%02x-%02x%02x-%02x%02x%02x%02x%02x%02x",
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[0],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[1],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[2],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[3],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[4],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[5],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[6],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[7],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[8],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[9],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[10],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[11],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[12],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[13],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[14],
+                        (unsigned char) value->val.uuid.value.
+                        uuid128.data[15]);
+
+               appender(data, buf);
+               appender(data, "\" />\n");
+               break;
+
+       case SDP_TEXT_STR8:
+       case SDP_TEXT_STR16:
+       case SDP_TEXT_STR32:
+       {
+               int num_chars_to_escape = 0;
+               int length = value->unitSize - 1;
+               char *strBuf = 0;
+
+               hex = 0;
+
+               for (i = 0; i < length; i++) {
+                       if (!isprint(value->val.str[i]) &&
+                                       value->val.str[i] != '\0') {
+                               hex = 1;
+                               break;
+                       }
+
+                       /* XML is evil, must do this... */
+                       if ((value->val.str[i] == '<') ||
+                                       (value->val.str[i] == '>') ||
+                                       (value->val.str[i] == '"') ||
+                                       (value->val.str[i] == '&'))
+                               num_chars_to_escape++;
+               }
+
+               appender(data, indent);
+
+               appender(data, "<text ");
+
+               if (hex) {
+                       appender(data, "encoding=\"hex\" ");
+                       strBuf = malloc(sizeof(char)
+                                                * ((value->unitSize-1) * 2 + 1));
+
+                       /* Unit Size seems to include the size for dtd
+                          It is thus off by 1
+                          This is safe for Normal strings, but not
+                          hex encoded data */
+                       for (i = 0; i < (value->unitSize-1); i++)
+                               sprintf(&strBuf[i*sizeof(char)*2],
+                                       "%02x",
+                                       (unsigned char) value->val.str[i]);
+
+                       strBuf[(value->unitSize-1) * 2] = '\0';
+               } else {
+                       int j;
+                       /* escape the XML disallowed chars */
+                       strBuf = malloc(sizeof(char) *
+                                       (value->unitSize + 1 + num_chars_to_escape * 4));
+                       for (i = 0, j = 0; i < length; i++) {
+                               if (value->val.str[i] == '&') {
+                                       strBuf[j++] = '&';
+                                       strBuf[j++] = 'a';
+                                       strBuf[j++] = 'm';
+                                       strBuf[j++] = 'p';
+                               } else if (value->val.str[i] == '<') {
+                                       strBuf[j++] = '&';
+                                       strBuf[j++] = 'l';
+                                       strBuf[j++] = 't';
+                               } else if (value->val.str[i] == '>') {
+                                       strBuf[j++] = '&';
+                                       strBuf[j++] = 'g';
+                                       strBuf[j++] = 't';
+                               } else if (value->val.str[i] == '"') {
+                                       strBuf[j++] = '&';
+                                       strBuf[j++] = 'q';
+                                       strBuf[j++] = 'u';
+                                       strBuf[j++] = 'o';
+                                       strBuf[j++] = 't';
+                               } else if (value->val.str[i] == '\0') {
+                                       strBuf[j++] = ' ';
+                               } else {
+                                       strBuf[j++] = value->val.str[i];
+                               }
+                       }
+
+                       strBuf[j] = '\0';
+               }
+
+               appender(data, "value=\"");
+               appender(data, strBuf);
+               appender(data, "\" />\n");
+               free(strBuf);
+               break;
+       }
+
+       case SDP_URL_STR8:
+       case SDP_URL_STR16:
+       case SDP_URL_STR32:
+       {
+               char *strBuf;
+
+               appender(data, indent);
+               appender(data, "<url value=\"");
+               strBuf = strndup(value->val.str, value->unitSize - 1);
+               appender(data, strBuf);
+               free(strBuf);
+               appender(data, "\" />\n");
+               break;
+       }
+
+       case SDP_SEQ8:
+       case SDP_SEQ16:
+       case SDP_SEQ32:
+               appender(data, indent);
+               appender(data, "<sequence>\n");
+
+               convert_raw_data_to_xml(value->val.dataseq,
+                                       indent_level + 1, data, appender);
+
+               appender(data, indent);
+               appender(data, "</sequence>\n");
+
+               break;
+
+       case SDP_ALT8:
+       case SDP_ALT16:
+       case SDP_ALT32:
+               appender(data, indent);
+
+               appender(data, "<alternate>\n");
+
+               convert_raw_data_to_xml(value->val.dataseq,
+                                       indent_level + 1, data, appender);
+               appender(data, indent);
+
+               appender(data, "</alternate>\n");
+
+               break;
+       }
+
+       convert_raw_data_to_xml(value->next, indent_level, data, appender);
+}
+
+struct conversion_data {
+       void *data;
+       void (*appender)(void *data, const char *);
+};
+
+static void convert_raw_attr_to_xml_func(void *val, void *data)
+{
+       struct conversion_data *cd = data;
+       sdp_data_t *value = val;
+       char buf[STRBUFSIZE];
+
+       buf[STRBUFSIZE - 1] = '\0';
+       snprintf(buf, STRBUFSIZE - 1, "\t<attribute id=\"0x%04x\">\n",
+                value->attrId);
+       cd->appender(cd->data, buf);
+
+       convert_raw_data_to_xml(value, 2, cd->data, cd->appender);
+
+       cd->appender(cd->data, "\t</attribute>\n");
+}
+
+/*
+ * Will convert the sdp record to XML.  The appender and data can be used
+ * to control where to output the record (e.g. file or a data buffer).  The
+ * appender will be called repeatedly with data and the character buffer
+ * (containing parts of the generated XML) to append.
+ */
+void convert_sdp_record_to_xml(sdp_record_t *rec,
+                       void *data, void (*appender)(void *, const char *))
+{
+       struct conversion_data cd;
+
+       cd.data = data;
+       cd.appender = appender;
+
+       if (rec && rec->attrlist) {
+               appender(data, "<?xml version=\"1.0\" encoding=\"UTF-8\" ?>\n\n");
+               appender(data, "<record>\n");
+               sdp_list_foreach(rec->attrlist,
+                                convert_raw_attr_to_xml_func, &cd);
+               appender(data, "</record>\n");
+       }
+}
index db7db30..d6a2f73 100644 (file)
 
 #include <bluetooth/sdp.h>
 
-#define SDP_XML_ENCODING_NORMAL        0
-#define SDP_XML_ENCODING_HEX   1
-
 void convert_sdp_record_to_xml(sdp_record_t *rec,
                void *user_data, void (*append_func) (void *, const char *));
 
-sdp_data_t *sdp_xml_parse_nil(const char *data);
-sdp_data_t *sdp_xml_parse_text(const char *data, char encoding);
-sdp_data_t *sdp_xml_parse_url(const char *data);
-sdp_data_t *sdp_xml_parse_int(const char *data, uint8_t dtd);
-sdp_data_t *sdp_xml_parse_uuid(const char *data, sdp_record_t *record);
-
-struct sdp_xml_data {
-       char *text;                     /* Pointer to the current buffer */
-       int size;                       /* Size of the current buffer */
-       sdp_data_t *data;               /* The current item being built */
-       struct sdp_xml_data *next;      /* Next item on the stack */
-       char type;                      /* 0 = Text or Hexadecimal */
-       char *name;                     /* Name, optional in the dtd */
-       /* TODO: What is it used for? */
-};
-
-struct sdp_xml_data *sdp_xml_data_alloc(void);
-void sdp_xml_data_free(struct sdp_xml_data *elem);
-struct sdp_xml_data *sdp_xml_data_expand(struct sdp_xml_data *elem);
-
-sdp_data_t *sdp_xml_parse_datatype(const char *el, struct sdp_xml_data *elem,
-                                                       sdp_record_t *record);
+sdp_record_t *sdp_xml_parse_record(const char *data, int size);
 
 #endif /* __SDP_XML_H */
index dd492bf..f65a526 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
-#include <errno.h>
 #include <stdlib.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
-#include <bluetooth/l2cap.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
 #include "sdpd.h"
 #include "log.h"
-#include "adapter.h"
-#include "manager.h"
 
 static sdp_list_t *service_db;
 static sdp_list_t *access_db;
@@ -93,7 +87,10 @@ static void access_free(void *p)
 void sdp_svcdb_reset(void)
 {
        sdp_list_free(service_db, (sdp_free_func_t) sdp_record_free);
+       service_db = NULL;
+
        sdp_list_free(access_db, access_free);
+       access_db = NULL;
 }
 
 typedef struct _indexed {
@@ -170,7 +167,6 @@ void sdp_svcdb_set_collectable(sdp_record_t *record, int sock)
  */
 void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)
 {
-       struct btd_adapter *adapter;
        sdp_access_t *dev;
 
        SDPDBG("Adding rec : 0x%lx", (long) rec);
@@ -186,15 +182,6 @@ void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec)
        dev->handle = rec->handle;
 
        access_db = sdp_list_insert_sorted(access_db, dev, access_sort);
-
-       if (bacmp(device, BDADDR_ANY) == 0) {
-               manager_foreach_adapter(adapter_service_insert, rec);
-               return;
-       }
-
-       adapter = manager_find_adapter(device);
-       if (adapter)
-               adapter_service_insert(adapter, rec);
 }
 
 static sdp_list_t *record_locate(uint32_t handle)
@@ -266,13 +253,6 @@ int sdp_record_remove(uint32_t handle)
 
        a = p->data;
 
-       if (bacmp(&a->device, BDADDR_ANY) != 0) {
-               struct btd_adapter *adapter = manager_find_adapter(&a->device);
-               if (adapter)
-                       adapter_service_remove(adapter, r);
-       } else
-               manager_foreach_adapter(adapter_service_remove, r);
-
        access_db = sdp_list_remove(access_db, a);
        access_free(a);
 
@@ -287,11 +267,6 @@ sdp_list_t *sdp_get_record_list(void)
        return service_db;
 }
 
-sdp_list_t *sdp_get_access_list(void)
-{
-       return access_db;
-}
-
 int sdp_check_access(uint32_t handle, bdaddr_t *device)
 {
        sdp_list_t *p = access_locate(handle);
@@ -321,26 +296,3 @@ uint32_t sdp_next_handle(void)
 
        return handle;
 }
-
-void sdp_init_services_list(bdaddr_t *device)
-{
-       sdp_list_t *p;
-
-       DBG("");
-
-       for (p = access_db; p != NULL; p = p->next) {
-               sdp_access_t *access = p->data;
-               sdp_record_t *rec;
-
-               if (bacmp(BDADDR_ANY, &access->device))
-                       continue;
-
-               rec = sdp_record_find(access->handle);
-               if (rec == NULL)
-                       continue;
-
-               SDPDBG("adding record with handle %x", access->handle);
-
-               manager_foreach_adapter(adapter_service_insert, rec);
-       }
-}
index 6a903c6..fbeb488 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
-#include <string.h>
 #include <limits.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include <netinet/in.h>
-
 #include "sdpd.h"
 #include "log.h"
 
@@ -139,6 +134,7 @@ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *p
        for (;;) {
                char *pElem = NULL;
                int localSeqLength = 0;
+               uuid_t *puuid;
 
                if (bufsize < sizeof(uint8_t)) {
                        SDPDBG("->Unexpected end of buffer");
@@ -178,11 +174,15 @@ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *p
                                struct attrid *aid;
                                aid = malloc(sizeof(struct attrid));
                                aid->dtd = dataType;
-                               bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)&aid->uint16);
+                               aid->uint16 = bt_get_be16(p);
                                pElem = (char *) aid;
                        } else {
+                               uint16_t tmp;
+
+                               memcpy(&tmp, p, sizeof(tmp));
+
                                pElem = malloc(sizeof(uint16_t));
-                               bt_put_unaligned(ntohs(bt_get_unaligned((uint16_t *)p)), (uint16_t *)pElem);
+                               bt_put_be16(tmp, pElem);
                        }
                        p += sizeof(uint16_t);
                        seqlen += sizeof(uint16_t);
@@ -201,11 +201,16 @@ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *p
                                struct attrid *aid;
                                aid = malloc(sizeof(struct attrid));
                                aid->dtd = dataType;
-                               bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)&aid->uint32);
+                               aid->uint32 = bt_get_be32(p);
+
                                pElem = (char *) aid;
                        } else {
+                               uint32_t tmp;
+
+                               memcpy(&tmp, p, sizeof(tmp));
+
                                pElem = malloc(sizeof(uint32_t));
-                               bt_put_unaligned(ntohl(bt_get_unaligned((uint32_t *)p)), (uint32_t *)pElem);
+                               bt_put_be32(tmp, pElem);
                        }
                        p += sizeof(uint32_t);
                        seqlen += sizeof(uint32_t);
@@ -214,12 +219,14 @@ static int extract_des(uint8_t *buf, int len, sdp_list_t **svcReqSeq, uint8_t *p
                case SDP_UUID16:
                case SDP_UUID32:
                case SDP_UUID128:
-                       pElem = malloc(sizeof(uuid_t));
-                       status = sdp_uuid_extract(p, bufsize, (uuid_t *) pElem, &localSeqLength);
+                       puuid = malloc(sizeof(uuid_t));
+                       status = sdp_uuid_extract(p, bufsize, puuid, &localSeqLength);
                        if (status < 0) {
-                               free(pElem);
+                               free(puuid);
                                goto failed;
                        }
+
+                       pElem = (char *) puuid;
                        seqlen += localSeqLength;
                        p += localSeqLength;
                        bufsize -= localSeqLength;
@@ -359,7 +366,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
        uint8_t *pCacheBuffer = NULL;
        int handleSize = 0;
        uint32_t cStateId = 0;
-       short *pTotalRecordCount, *pCurrentRecordCount;
+       uint8_t *pTotalRecordCount, *pCurrentRecordCount;
        uint8_t *pdata = req->buf + sizeof(sdp_pdu_hdr_t);
        size_t data_left = req->len - sizeof(sdp_pdu_hdr_t);
 
@@ -385,7 +392,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                goto done;
        }
 
-       expected = ntohs(bt_get_unaligned((uint16_t *)pdata));
+       expected = bt_get_be16(pdata);
 
        SDPDBG("Expected count: %d", expected);
        SDPDBG("Bytes scanned : %d", scanned);
@@ -409,14 +416,14 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
        pdata = buf->data;
 
        /* total service record count = 0 */
-       pTotalRecordCount = (short *)pdata;
-       bt_put_unaligned(0, (uint16_t *)pdata);
+       pTotalRecordCount = pdata;
+       bt_put_be16(0, pdata);
        pdata += sizeof(uint16_t);
        buf->data_size += sizeof(uint16_t);
 
        /* current service record count = 0 */
-       pCurrentRecordCount = (short *)pdata;
-       bt_put_unaligned(0, (uint16_t *)pdata);
+       pCurrentRecordCount = pdata;
+       bt_put_be16(0, pdata);
        pdata += sizeof(uint16_t);
        buf->data_size += sizeof(uint16_t);
 
@@ -433,7 +440,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                        if (sdp_match_uuid(pattern, rec->pattern) > 0 &&
                                        sdp_check_access(rec->handle, &req->device)) {
                                rsp_count++;
-                               bt_put_unaligned(htonl(rec->handle), (uint32_t *)pdata);
+                               bt_put_be32(rec->handle, pdata);
                                pdata += sizeof(uint32_t);
                                handleSize += sizeof(uint32_t);
                        }
@@ -442,8 +449,8 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                SDPDBG("Match count: %d", rsp_count);
 
                buf->data_size += handleSize;
-               bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
-               bt_put_unaligned(htons(rsp_count), (uint16_t *)pCurrentRecordCount);
+               bt_put_be16(rsp_count, pTotalRecordCount);
+               bt_put_be16(rsp_count, pCurrentRecordCount);
 
                if (rsp_count > actual) {
                        /* cache the rsp and generate a continuation state */
@@ -472,7 +479,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                        if (pCache) {
                                pCacheBuffer = pCache->data;
                                /* get the rsp_count from the cached buffer */
-                               rsp_count = ntohs(bt_get_unaligned((uint16_t *)pCacheBuffer));
+                               rsp_count = bt_get_be16(pCacheBuffer);
 
                                /* get index of the last sdp_record_t sent */
                                lastIndex = cstate->cStateValue.lastIndexSent;
@@ -490,7 +497,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                 * current record count and increment the cached
                 * buffer pointer to beyond the counters
                 */
-               pdata = (uint8_t *) pCurrentRecordCount + sizeof(uint16_t);
+               pdata = pCurrentRecordCount + sizeof(uint16_t);
 
                /* increment beyond the totalCount and the currentCount */
                pCacheBuffer += 2 * sizeof(uint16_t);
@@ -498,7 +505,7 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                if (cstate) {
                        handleSize = 0;
                        for (i = lastIndex; (i - lastIndex) < actual && i < rsp_count; i++) {
-                               bt_put_unaligned(bt_get_unaligned((uint32_t *)(pCacheBuffer + i * sizeof(uint32_t))), (uint32_t *)pdata);
+                               memcpy(pdata, pCacheBuffer + i * sizeof(uint32_t), sizeof(uint32_t));
                                pdata += sizeof(uint32_t);
                                handleSize += sizeof(uint32_t);
                        }
@@ -508,8 +515,8 @@ static int service_search_req(sdp_req_t *req, sdp_buf_t *buf)
                }
 
                buf->data_size += handleSize;
-               bt_put_unaligned(htons(rsp_count), (uint16_t *)pTotalRecordCount);
-               bt_put_unaligned(htons(i - lastIndex), (uint16_t *)pCurrentRecordCount);
+               bt_put_be16(rsp_count, pTotalRecordCount);
+               bt_put_be16(i - lastIndex, pCurrentRecordCount);
 
                if (i == rsp_count) {
                        /* set "null" continuationState */
@@ -571,12 +578,12 @@ static int extract_attrs(sdp_record_t *rec, sdp_list_t *seq, sdp_buf_t *buf)
                SDPDBG("AttrDataType : %d", aid->dtd);
 
                if (aid->dtd == SDP_UINT16) {
-                       uint16_t attr = bt_get_unaligned((uint16_t *)&aid->uint16);
+                       uint16_t attr = aid->uint16;
                        sdp_data_t *a = sdp_data_get(rec, attr);
                        if (a)
                                sdp_append_to_pdu(buf, a);
                } else if (aid->dtd == SDP_UINT32) {
-                       uint32_t range = bt_get_unaligned((uint32_t *)&aid->uint32);
+                       uint32_t range = aid->uint32;
                        uint16_t attr;
                        uint16_t low = (0xffff0000 & range) >> 16;
                        uint16_t high = 0x0000ffff & range;
@@ -639,7 +646,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                goto done;
        }
 
-       handle = ntohl(bt_get_unaligned((uint32_t *)pdata));
+       handle = bt_get_be32(pdata);
 
        pdata += sizeof(uint32_t);
        data_left -= sizeof(uint32_t);
@@ -649,7 +656,7 @@ static int service_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                goto done;
        }
 
-       max_rsp_size = ntohs(bt_get_unaligned((uint16_t *)pdata));
+       max_rsp_size = bt_get_be16(pdata);
 
        pdata += sizeof(uint16_t);
        data_left -= sizeof(uint16_t);
@@ -765,7 +772,7 @@ done:
                return status;
 
        /* set attribute list byte count */
-       bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
+       bt_put_be16(buf->data_size - cstate_size, buf->data);
        buf->data_size += sizeof(uint16_t);
        return 0;
 }
@@ -806,7 +813,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
                goto done;
        }
 
-       max = ntohs(bt_get_unaligned((uint16_t *)pdata));
+       max = bt_get_be16(pdata);
 
        pdata += sizeof(uint16_t);
        data_left -= sizeof(uint16_t);
@@ -936,7 +943,7 @@ static int service_search_attr_req(sdp_req_t *req, sdp_buf_t *buf)
 
        if (!status) {
                /* set attribute list byte count */
-               bt_put_unaligned(htons(buf->data_size - cstate_size), (uint16_t *)buf->data);
+               bt_put_be16(buf->data_size - cstate_size, buf->data);
                buf->data_size += sizeof(uint16_t);
        }
 
@@ -1020,7 +1027,7 @@ static void process_request(sdp_req_t *req)
 send_rsp:
        if (status) {
                rsphdr->pdu_id = SDP_ERROR_RSP;
-               bt_put_unaligned(htons(status), (uint16_t *)rsp.data);
+               bt_put_be16(status, rsp.data);
                rsp.data_size = sizeof(uint16_t);
        }
 
@@ -1043,6 +1050,22 @@ send_rsp:
        free(req->buf);
 }
 
+void handle_internal_request(int sk, int mtu, void *data, int len)
+{
+       sdp_req_t req;
+
+       bacpy(&req.device, BDADDR_ANY);
+       bacpy(&req.bdaddr, BDADDR_LOCAL);
+       req.local = 0;
+       req.sock = sk;
+       req.mtu = mtu;
+       req.flags = 0;
+       req.buf = data;
+       req.len = len;
+
+       process_request(&req);
+}
+
 void handle_request(int sk, uint8_t *data, int len)
 {
        struct sockaddr_l2 sa;
index 1d9509e..b411abe 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <errno.h>
 #include <unistd.h>
 #include <stdlib.h>
 #include <sys/stat.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/l2cap.h>
 #include <bluetooth/sdp_lib.h>
 
 #include <sys/un.h>
-#include <netinet/in.h>
 
 #include <glib.h>
 
-#include "hcid.h"
 #include "log.h"
 #include "sdpd.h"
 
@@ -147,7 +143,7 @@ static int init_server(uint16_t mtu, int master, int compat)
                return -1;
        }
 
-       chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
+       chmod(SDP_UNIX_PATH, S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP);
 
        return 0;
 }
@@ -169,7 +165,7 @@ static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer d
        }
 
        len = recv(sk, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
-       if (len <= 0) {
+       if (len != sizeof(sdp_pdu_hdr_t)) {
                sdp_svcdb_collect_all(sk);
                return FALSE;
        }
@@ -180,7 +176,7 @@ static gboolean io_session_event(GIOChannel *chan, GIOCondition cond, gpointer d
                return TRUE;
 
        len = recv(sk, buf, size, 0);
-       if (len <= 0) {
+       if (len != size) {
                sdp_svcdb_collect_all(sk);
                free(buf);
                return FALSE;
@@ -241,9 +237,6 @@ int start_sdp_server(uint16_t mtu, uint32_t flags)
                return -1;
        }
 
-       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 39e05ab..38bf808 100644 (file)
 #include <config.h>
 #endif
 
-#include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <assert.h>
 #include <sys/time.h>
-#include <sys/socket.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
 
-#include <netinet/in.h>
-
 #include <glib.h>
-#include <dbus/dbus.h>
 
-#include "hcid.h"
 #include "sdpd.h"
 #include "log.h"
-#include "adapter.h"
-#include "manager.h"
 
 static sdp_record_t *server = NULL;
+static uint32_t fixed_dbts = 0;
 
 /*
  * List of version numbers supported by the SDP server.
@@ -89,9 +82,19 @@ uint32_t sdp_get_time(void)
  */
 static void update_db_timestamp(void)
 {
-       uint32_t dbts = sdp_get_time();
-       sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
-       sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
+       if (fixed_dbts) {
+               sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &fixed_dbts);
+               sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
+       } else {
+               uint32_t dbts = sdp_get_time();
+               sdp_data_t *d = sdp_data_alloc(SDP_UINT32, &dbts);
+               sdp_attr_replace(server, SDP_ATTR_SVCDB_STATE, d);
+       }
+}
+
+void set_fixed_db_timestamp(uint32_t dbts)
+{
+       fixed_dbts = dbts;
 }
 
 void register_public_browse_group(void)
@@ -173,7 +176,8 @@ void register_server_service(void)
        update_db_timestamp();
 }
 
-void register_device_id(void)
+void register_device_id(uint16_t source, uint16_t vendor,
+                                       uint16_t product, uint16_t version)
 {
        const uint16_t spec = 0x0103;
        const uint8_t primary = 1;
@@ -184,9 +188,8 @@ void register_device_id(void)
        sdp_profile_desc_t profile;
        sdp_record_t *record = sdp_record_alloc();
 
-       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);
+       DBG("Adding device id record for %04x:%04x:%04x:%04x",
+                                       source, vendor, product, version);
 
        record->handle = sdp_next_handle();
 
@@ -213,19 +216,19 @@ void register_device_id(void)
        spec_data = sdp_data_alloc(SDP_UINT16, &spec);
        sdp_attr_add(record, 0x0200, spec_data);
 
-       vendor_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_vendor);
+       vendor_data = sdp_data_alloc(SDP_UINT16, &vendor);
        sdp_attr_add(record, 0x0201, vendor_data);
 
-       product_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_product);
+       product_data = sdp_data_alloc(SDP_UINT16, &product);
        sdp_attr_add(record, 0x0202, product_data);
 
-       version_data = sdp_data_alloc(SDP_UINT16, &main_opts.did_version);
+       version_data = sdp_data_alloc(SDP_UINT16, &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, &main_opts.did_source);
+       source_data = sdp_data_alloc(SDP_UINT16, &source);
        sdp_attr_add(record, 0x0205, source_data);
 
        update_db_timestamp();
@@ -317,7 +320,7 @@ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
                return NULL;
        }
 
-       lookAheadAttrId = ntohs(bt_get_unaligned((uint16_t *) (p + sizeof(uint8_t))));
+       lookAheadAttrId = bt_get_be16(p + sizeof(uint8_t));
 
        SDPDBG("Look ahead attr id : %d", lookAheadAttrId);
 
@@ -327,9 +330,8 @@ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
                        SDPDBG("Unexpected end of packet");
                        return NULL;
                }
-               handle = ntohl(bt_get_unaligned((uint32_t *) (p +
-                               sizeof(uint8_t) + sizeof(uint16_t) +
-                               sizeof(uint8_t))));
+               handle = bt_get_be32(p + sizeof(uint8_t) + sizeof(uint16_t) +
+                                                       sizeof(uint8_t));
                SDPDBG("SvcRecHandle : 0x%x", handle);
                rec = sdp_record_find(handle);
        } else if (handleExpected != 0xffffffff)
@@ -363,7 +365,7 @@ static sdp_record_t *extract_pdu_server(bdaddr_t *device, uint8_t *p,
                                                        seqlen, localExtractedLength);
                dtd = *(uint8_t *) p;
 
-               attrId = ntohs(bt_get_unaligned((uint16_t *) (p + attrSize)));
+               attrId = bt_get_be16(p + attrSize);
                attrSize += sizeof(uint16_t);
 
                SDPDBG("DTD of attrId : %d Attr id : 0x%x", dtd, attrId);
@@ -454,13 +456,13 @@ success:
        update_db_timestamp();
 
        /* Build a rsp buffer */
-       bt_put_unaligned(htonl(rec->handle), (uint32_t *) rsp->data);
+       bt_put_be32(rec->handle, rsp->data);
        rsp->data_size = sizeof(uint32_t);
 
        return 0;
 
 invalid:
-       bt_put_unaligned(htons(SDP_INVALID_SYNTAX), (uint16_t *) rsp->data);
+       bt_put_be16(SDP_INVALID_SYNTAX, rsp->data);
        rsp->data_size = sizeof(uint16_t);
 
        return -1;
@@ -475,7 +477,7 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
        int status = 0, scanned = 0;
        uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
        int bufsize = req->len - sizeof(sdp_pdu_hdr_t);
-       uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
+       uint32_t handle = bt_get_be32(p);
 
        SDPDBG("Svc Rec Handle: 0x%x", handle);
 
@@ -503,7 +505,7 @@ int service_update_req(sdp_req_t *req, sdp_buf_t *rsp)
 
 done:
        p = rsp->data;
-       bt_put_unaligned(htons(status), (uint16_t *) p);
+       bt_put_be16(status, p);
        rsp->data_size = sizeof(uint16_t);
        return status;
 }
@@ -514,7 +516,7 @@ done:
 int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
 {
        uint8_t *p = req->buf + sizeof(sdp_pdu_hdr_t);
-       uint32_t handle = ntohl(bt_get_unaligned((uint32_t *) p));
+       uint32_t handle = bt_get_be32(p);
        sdp_record_t *rec;
        int status = 0;
 
@@ -533,7 +535,7 @@ int service_remove_req(sdp_req_t *req, sdp_buf_t *rsp)
        }
 
        p = rsp->data;
-       bt_put_unaligned(htons(status), (uint16_t *) p);
+       bt_put_be16(status, p);
        rsp->data_size = sizeof(uint16_t);
 
        return status;
index 83d2b03..6de0af7 100644 (file)
@@ -45,15 +45,19 @@ typedef struct request {
        int      len;
 } sdp_req_t;
 
+void handle_internal_request(int sk, int mtu, void *data, int len);
 void handle_request(int sk, uint8_t *data, int len);
 
+void set_fixed_db_timestamp(uint32_t dbts);
+
 int service_register_req(sdp_req_t *req, sdp_buf_t *rsp);
 int service_update_req(sdp_req_t *req, sdp_buf_t *rsp);
 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(void);
+void register_device_id(uint16_t source, uint16_t vendor,
+                                       uint16_t product, uint16_t version);
 
 int record_sort(const void *r1, const void *r2);
 void sdp_svcdb_reset(void);
@@ -64,7 +68,6 @@ sdp_record_t *sdp_record_find(uint32_t handle);
 void sdp_record_add(const bdaddr_t *device, sdp_record_t *rec);
 int sdp_record_remove(uint32_t handle);
 sdp_list_t *sdp_get_record_list(void);
-sdp_list_t *sdp_get_access_list(void);
 int sdp_check_access(uint32_t handle, bdaddr_t *device);
 uint32_t sdp_next_handle(void);
 
@@ -78,5 +81,3 @@ void stop_sdp_server(void);
 
 int add_record_to_server(const bdaddr_t *src, sdp_record_t *rec);
 int remove_record_from_server(uint32_t handle);
-
-void sdp_init_services_list(bdaddr_t *device);
diff --git a/src/service.c b/src/service.c
new file mode 100644 (file)
index 0000000..52a8291
--- /dev/null
@@ -0,0 +1,341 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012-2013  BMW Car IT GmbH. 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 <assert.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <stdbool.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <errno.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include <glib.h>
+
+#include "log.h"
+
+#include "adapter.h"
+#include "device.h"
+#include "profile.h"
+#include "service.h"
+
+struct btd_service {
+       int                     ref;
+       struct btd_device       *device;
+       struct btd_profile      *profile;
+       void                    *user_data;
+       btd_service_state_t     state;
+       int                     err;
+};
+
+struct service_state_callback {
+       btd_service_state_cb    cb;
+       void                    *user_data;
+       unsigned int            id;
+};
+
+static GSList *state_callbacks = NULL;
+
+static const char *state2str(btd_service_state_t state)
+{
+       switch (state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+               return "unavailable";
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               return "disconnected";
+       case BTD_SERVICE_STATE_CONNECTING:
+               return "connecting";
+       case BTD_SERVICE_STATE_CONNECTED:
+               return "connected";
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               return "disconnecting";
+       }
+
+       return NULL;
+}
+
+static void change_state(struct btd_service *service, btd_service_state_t state,
+                                                                       int err)
+{
+       btd_service_state_t old = service->state;
+       char addr[18];
+       GSList *l;
+
+       if (state == old)
+               return;
+
+       assert(service->device != NULL);
+       assert(service->profile != NULL);
+
+       service->state = state;
+       service->err = err;
+
+       ba2str(device_get_address(service->device), addr);
+       DBG("%p: device %s profile %s state changed: %s -> %s (%d)", service,
+                                       addr, service->profile->name,
+                                       state2str(old), state2str(state), err);
+
+       for (l = state_callbacks; l != NULL; l = g_slist_next(l)) {
+               struct service_state_callback *cb = l->data;
+
+               cb->cb(service, old, state, cb->user_data);
+       }
+}
+
+struct btd_service *btd_service_ref(struct btd_service *service)
+{
+       service->ref++;
+
+       DBG("%p: ref=%d", service, service->ref);
+
+       return service;
+}
+
+void btd_service_unref(struct btd_service *service)
+{
+       service->ref--;
+
+       DBG("%p: ref=%d", service, service->ref);
+
+       if (service->ref > 0)
+               return;
+
+       g_free(service);
+}
+
+struct btd_service *service_create(struct btd_device *device,
+                                               struct btd_profile *profile)
+{
+       struct btd_service *service;
+
+       service = g_try_new0(struct btd_service, 1);
+       if (!service) {
+               error("service_create: failed to alloc memory");
+               return NULL;
+       }
+
+       service->ref = 1;
+       service->device = device; /* Weak ref */
+       service->profile = profile;
+       service->state = BTD_SERVICE_STATE_UNAVAILABLE;
+
+       return service;
+}
+
+int service_probe(struct btd_service *service)
+{
+       char addr[18];
+       int err;
+
+       assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+
+       err = service->profile->device_probe(service);
+       if (err == 0) {
+               change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
+               return 0;
+       }
+
+       ba2str(device_get_address(service->device), addr);
+       error("%s profile probe failed for %s", service->profile->name, addr);
+
+       return err;
+}
+
+void service_remove(struct btd_service *service)
+{
+       change_state(service, BTD_SERVICE_STATE_UNAVAILABLE, 0);
+       service->profile->device_remove(service);
+       service->device = NULL;
+       service->profile = NULL;
+       btd_service_unref(service);
+}
+
+int btd_service_connect(struct btd_service *service)
+{
+       struct btd_profile *profile = service->profile;
+       char addr[18];
+       int err;
+
+       if (!profile->connect)
+               return -ENOTSUP;
+
+       switch (service->state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+               return -EINVAL;
+       case BTD_SERVICE_STATE_DISCONNECTED:
+               break;
+       case BTD_SERVICE_STATE_CONNECTING:
+       case BTD_SERVICE_STATE_CONNECTED:
+               return -EALREADY;
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               return -EBUSY;
+       }
+
+       change_state(service, BTD_SERVICE_STATE_CONNECTING, 0);
+
+       err = profile->connect(service);
+       if (err == 0)
+               return 0;
+
+       ba2str(device_get_address(service->device), addr);
+       error("%s profile connect failed for %s: %s", profile->name, addr,
+                                                               strerror(-err));
+
+       btd_service_connecting_complete(service, err);
+
+       return err;
+}
+
+int btd_service_disconnect(struct btd_service *service)
+{
+       struct btd_profile *profile = service->profile;
+       char addr[18];
+       int err;
+
+       if (!profile->disconnect)
+               return -ENOTSUP;
+
+       switch (service->state) {
+       case BTD_SERVICE_STATE_UNAVAILABLE:
+               return -EINVAL;
+       case BTD_SERVICE_STATE_DISCONNECTED:
+       case BTD_SERVICE_STATE_DISCONNECTING:
+               return -EALREADY;
+       case BTD_SERVICE_STATE_CONNECTING:
+       case BTD_SERVICE_STATE_CONNECTED:
+               break;
+       }
+
+       change_state(service, BTD_SERVICE_STATE_DISCONNECTING, 0);
+
+       err = profile->disconnect(service);
+       if (err == 0)
+               return 0;
+
+       if (err == -ENOTCONN) {
+               btd_service_disconnecting_complete(service, 0);
+               return 0;
+       }
+
+       ba2str(device_get_address(service->device), addr);
+       error("%s profile disconnect failed for %s: %s", profile->name, addr,
+                                                               strerror(-err));
+
+       btd_service_disconnecting_complete(service, err);
+
+       return err;
+}
+
+struct btd_device *btd_service_get_device(const struct btd_service *service)
+{
+       return service->device;
+}
+
+struct btd_profile *btd_service_get_profile(const struct btd_service *service)
+{
+       return service->profile;
+}
+
+void btd_service_set_user_data(struct btd_service *service, void *user_data)
+{
+       assert(service->state == BTD_SERVICE_STATE_UNAVAILABLE);
+       service->user_data = user_data;
+}
+
+void *btd_service_get_user_data(const struct btd_service *service)
+{
+       return service->user_data;
+}
+
+btd_service_state_t btd_service_get_state(const struct btd_service *service)
+{
+       return service->state;
+}
+
+int btd_service_get_error(const struct btd_service *service)
+{
+       return service->err;
+}
+
+unsigned int btd_service_add_state_cb(btd_service_state_cb cb, void *user_data)
+{
+       struct service_state_callback *state_cb;
+       static unsigned int id = 0;
+
+       state_cb = g_new0(struct service_state_callback, 1);
+       state_cb->cb = cb;
+       state_cb->user_data = user_data;
+       state_cb->id = ++id;
+
+       state_callbacks = g_slist_append(state_callbacks, state_cb);
+
+       return state_cb->id;
+}
+
+bool btd_service_remove_state_cb(unsigned int id)
+{
+       GSList *l;
+
+       for (l = state_callbacks; l != NULL; l = g_slist_next(l)) {
+               struct service_state_callback *cb = l->data;
+
+               if (cb && cb->id == id) {
+                       state_callbacks = g_slist_remove(state_callbacks, cb);
+                       g_free(cb);
+                       return true;
+               }
+       }
+
+       return false;
+}
+
+void btd_service_connecting_complete(struct btd_service *service, int err)
+{
+       if (service->state != BTD_SERVICE_STATE_DISCONNECTED &&
+                               service->state != BTD_SERVICE_STATE_CONNECTING)
+               return;
+
+       if (err == 0)
+               change_state(service, BTD_SERVICE_STATE_CONNECTED, 0);
+       else
+               change_state(service, BTD_SERVICE_STATE_DISCONNECTED, err);
+}
+
+void btd_service_disconnecting_complete(struct btd_service *service, int err)
+{
+       if (service->state != BTD_SERVICE_STATE_CONNECTED &&
+                       service->state != BTD_SERVICE_STATE_DISCONNECTING)
+               return;
+
+       if (err == 0)
+               change_state(service, BTD_SERVICE_STATE_DISCONNECTED, 0);
+       else /* If disconnect fails, we assume it remains connected */
+               change_state(service, BTD_SERVICE_STATE_CONNECTED, err);
+}
diff --git a/src/service.h b/src/service.h
new file mode 100644 (file)
index 0000000..5230115
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012-2013  BMW Car IT GmbH. 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
+ *
+ */
+
+typedef enum {
+       BTD_SERVICE_STATE_UNAVAILABLE, /* Not probed */
+       BTD_SERVICE_STATE_DISCONNECTED,
+       BTD_SERVICE_STATE_CONNECTING,
+       BTD_SERVICE_STATE_CONNECTED,
+       BTD_SERVICE_STATE_DISCONNECTING,
+} btd_service_state_t;
+
+struct btd_service;
+struct btd_device;
+struct btd_profile;
+
+typedef void (*btd_service_state_cb) (struct btd_service *service,
+                                               btd_service_state_t old_state,
+                                               btd_service_state_t new_state,
+                                               void *user_data);
+
+struct btd_service *btd_service_ref(struct btd_service *service);
+void btd_service_unref(struct btd_service *service);
+
+/* Service management functions used by the core */
+struct btd_service *service_create(struct btd_device *device,
+                                               struct btd_profile *profile);
+
+int service_probe(struct btd_service *service);
+void service_remove(struct btd_service *service);
+
+/* Connection control API */
+int btd_service_connect(struct btd_service *service);
+int btd_service_disconnect(struct btd_service *service);
+
+/* Public member access */
+struct btd_device *btd_service_get_device(const struct btd_service *service);
+struct btd_profile *btd_service_get_profile(const struct btd_service *service);
+btd_service_state_t btd_service_get_state(const struct btd_service *service);
+int btd_service_get_error(const struct btd_service *service);
+
+unsigned int btd_service_add_state_cb(btd_service_state_cb cb,
+                                                       void *user_data);
+bool btd_service_remove_state_cb(unsigned int id);
+
+/* Functions used by profile implementation */
+void btd_service_connecting_complete(struct btd_service *service, int err);
+void btd_service_disconnecting_complete(struct btd_service *service, int err);
+void btd_service_set_user_data(struct btd_service *service, void *user_data);
+void *btd_service_get_user_data(const struct btd_service *service);
diff --git a/src/shared/btsnoop.c b/src/shared/btsnoop.c
new file mode 100644 (file)
index 0000000..58c9f1d
--- /dev/null
@@ -0,0 +1,228 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.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;
+
+struct btsnoop {
+       int ref_count;
+       int fd;
+       uint32_t type;
+};
+
+struct btsnoop *btsnoop_open(const char *path)
+{
+       struct btsnoop *btsnoop;
+       struct btsnoop_hdr hdr;
+       ssize_t len;
+
+       btsnoop = calloc(1, sizeof(*btsnoop));
+       if (!btsnoop)
+               return NULL;
+
+       btsnoop->fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (btsnoop->fd < 0) {
+               free(btsnoop);
+               return NULL;
+       }
+
+       len = read(btsnoop->fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (len < 0 || len != BTSNOOP_HDR_SIZE)
+               goto failed;
+
+       if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id)))
+               goto failed;
+
+       if (ntohl(hdr.version) != btsnoop_version)
+               goto failed;
+
+       btsnoop->type = ntohl(hdr.type);
+
+       return btsnoop_ref(btsnoop);
+
+failed:
+       close(btsnoop->fd);
+       free(btsnoop);
+
+       return NULL;
+}
+
+struct btsnoop *btsnoop_create(const char *path, uint32_t type)
+{
+       struct btsnoop *btsnoop;
+       struct btsnoop_hdr hdr;
+       ssize_t written;
+
+       btsnoop = calloc(1, sizeof(*btsnoop));
+       if (!btsnoop)
+               return NULL;
+
+       btsnoop->fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+                                       S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       if (btsnoop->fd < 0) {
+               free(btsnoop);
+               return NULL;
+       }
+
+       btsnoop->type = type;
+
+       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) {
+               close(btsnoop->fd);
+               free(btsnoop);
+               return NULL;
+       }
+
+       return btsnoop_ref(btsnoop);
+}
+
+struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop)
+{
+       if (!btsnoop)
+               return NULL;
+
+       __sync_fetch_and_add(&btsnoop->ref_count, 1);
+
+       return btsnoop;
+}
+
+void btsnoop_unref(struct btsnoop *btsnoop)
+{
+       if (!btsnoop)
+               return;
+
+       if (__sync_sub_and_fetch(&btsnoop->ref_count, 1))
+               return;
+
+       if (btsnoop->fd >= 0)
+               close(btsnoop->fd);
+
+       free(btsnoop);
+}
+
+uint32_t btsnoop_get_type(struct btsnoop *btsnoop)
+{
+       if (!btsnoop)
+               return BTSNOOP_TYPE_INVALID;
+
+       return btsnoop->type;
+}
+
+bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
+                       uint32_t flags, const void *data, uint16_t size)
+{
+       struct btsnoop_pkt pkt;
+       uint64_t ts;
+       ssize_t written;
+
+       if (!btsnoop || !tv)
+               return false;
+
+       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 false;
+
+       if (data && size > 0) {
+               written = write(btsnoop->fd, data, size);
+               if (written < 0)
+                       return false;
+       }
+
+       return true;
+}
+
+bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
+                       uint16_t frequency, const void *data, uint16_t size)
+{
+       uint32_t flags;
+
+       if (!btsnoop)
+               return false;
+
+       switch (btsnoop->type) {
+       case BTSNOOP_TYPE_SIMULATOR:
+               flags = (1 << 16) | frequency;
+               break;
+
+       default:
+               return false;
+       }
+
+       return btsnoop_write(btsnoop, tv, flags, data, size);
+}
diff --git a/src/shared/btsnoop.h b/src/shared/btsnoop.h
new file mode 100644 (file)
index 0000000..24580d4
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
+
+#define BTSNOOP_TYPE_INVALID           0
+#define BTSNOOP_TYPE_HCI               1001
+#define BTSNOOP_TYPE_UART              1002
+#define BTSNOOP_TYPE_BCSP              1003
+#define BTSNOOP_TYPE_3WIRE             1004
+#define BTSNOOP_TYPE_MONITOR           2001
+#define BTSNOOP_TYPE_SIMULATOR         2002
+
+#define BTSNOOP_OPCODE_NEW_INDEX       0
+#define BTSNOOP_OPCODE_DEL_INDEX       1
+#define BTSNOOP_OPCODE_COMMAND_PKT     2
+#define BTSNOOP_OPCODE_EVENT_PKT       3
+#define BTSNOOP_OPCODE_ACL_TX_PKT      4
+#define BTSNOOP_OPCODE_ACL_RX_PKT      5
+#define BTSNOOP_OPCODE_SCO_TX_PKT      6
+#define BTSNOOP_OPCODE_SCO_RX_PKT      7
+
+struct btsnoop;
+
+struct btsnoop *btsnoop_open(const char *path);
+struct btsnoop *btsnoop_create(const char *path, uint32_t type);
+
+struct btsnoop *btsnoop_ref(struct btsnoop *btsnoop);
+void btsnoop_unref(struct btsnoop *btsnoop);
+
+uint32_t btsnoop_get_type(struct btsnoop *btsnoop);
+
+bool btsnoop_write(struct btsnoop *btsnoop, struct timeval *tv,
+                       uint32_t flags, const void *data, uint16_t size);
+bool btsnoop_write_phy(struct btsnoop *btsnoop, struct timeval *tv,
+                       uint16_t frequency, const void *data, uint16_t size);
diff --git a/src/shared/hciemu.c b/src/shared/hciemu.c
new file mode 100644 (file)
index 0000000..0ea191f
--- /dev/null
@@ -0,0 +1,477 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/bt.h"
+#include "emulator/btdev.h"
+#include "emulator/bthost.h"
+
+#include "hciemu.h"
+
+struct hciemu {
+       int ref_count;
+       enum btdev_type btdev_type;
+       struct bthost *host_stack;
+       struct btdev *master_dev;
+       struct btdev *client_dev;
+       guint host_source;
+       guint master_source;
+       guint client_source;
+       GList *post_command_hooks;
+       char bdaddr_str[18];
+};
+
+struct hciemu_command_hook {
+       hciemu_command_func_t function;
+       void *user_data;
+};
+
+static void destroy_command_hook(gpointer data, gpointer user_data)
+{
+       struct hciemu_command_hook *hook = data;
+
+       g_free(hook);
+}
+
+static void master_command_callback(uint16_t opcode,
+                               const void *data, uint8_t len,
+                               btdev_callback callback, void *user_data)
+{
+       struct hciemu *hciemu = user_data;
+       GList *list;
+
+       btdev_command_default(callback);
+
+       for (list = g_list_first(hciemu->post_command_hooks); list;
+                                               list = g_list_next(list)) {
+               struct hciemu_command_hook *hook = list->data;
+
+               if (hook->function)
+                       hook->function(opcode, data, len, hook->user_data);
+       }
+}
+
+static void client_command_callback(uint16_t opcode,
+                               const void *data, uint8_t len,
+                               btdev_callback callback, void *user_data)
+{
+       btdev_command_default(callback);
+}
+
+static void write_callback(const void *data, uint16_t len, void *user_data)
+{
+       GIOChannel *channel = user_data;
+       ssize_t written;
+       int fd;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       written = write(fd, data, len);
+       if (written < 0)
+               return;
+}
+
+static gboolean receive_bthost(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       struct bthost *bthost = user_data;
+       unsigned char buf[4096];
+       ssize_t len;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0)
+               return FALSE;
+
+       bthost_receive_h4(bthost, buf, len);
+
+       return TRUE;
+}
+
+static guint create_source_bthost(int fd, struct bthost *bthost)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       bthost_set_send_handler(bthost, write_callback, channel);
+
+       source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               receive_bthost, bthost, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean receive_btdev(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       struct btdev *btdev = user_data;
+       unsigned char buf[4096];
+       ssize_t len;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 1)
+               return FALSE;
+
+       switch (buf[0]) {
+       case BT_H4_CMD_PKT:
+       case BT_H4_ACL_PKT:
+       case BT_H4_SCO_PKT:
+               btdev_receive_h4(btdev, buf, len);
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint create_source_btdev(int fd, struct btdev *btdev)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       btdev_set_send_handler(btdev, write_callback, channel);
+
+       source = g_io_add_watch_full(channel, G_PRIORITY_DEFAULT,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               receive_btdev, btdev, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static bool create_vhci(struct hciemu *hciemu)
+{
+       struct btdev *btdev;
+       uint8_t create_req[2];
+       ssize_t written;
+       int fd;
+
+       btdev = btdev_create(hciemu->btdev_type, 0x00);
+       if (!btdev)
+               return false;
+
+       btdev_set_command_handler(btdev, master_command_callback, hciemu);
+
+       fd = open("/dev/vhci", O_RDWR | O_NONBLOCK | O_CLOEXEC);
+       if (fd < 0) {
+               btdev_destroy(btdev);
+               return false;
+       }
+
+       create_req[0] = HCI_VENDOR_PKT;
+       create_req[1] = HCI_BREDR;
+       written = write(fd, create_req, sizeof(create_req));
+       if (written < 0) {
+               close(fd);
+               btdev_destroy(btdev);
+               return false;
+       }
+
+       hciemu->master_dev = btdev;
+
+       hciemu->master_source = create_source_btdev(fd, btdev);
+
+       return true;
+}
+
+struct bthost *hciemu_client_get_host(struct hciemu *hciemu)
+{
+       if (!hciemu)
+               return NULL;
+
+       return hciemu->host_stack;
+}
+
+static bool create_stack(struct hciemu *hciemu)
+{
+       struct btdev *btdev;
+       struct bthost *bthost;
+       int sv[2];
+
+       btdev = btdev_create(hciemu->btdev_type, 0x00);
+       if (!btdev)
+               return false;
+
+       bthost = bthost_create();
+       if (!bthost) {
+               btdev_destroy(btdev);
+               return false;
+       }
+
+       btdev_set_command_handler(btdev, client_command_callback, hciemu);
+
+       if (socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_NONBLOCK | SOCK_CLOEXEC,
+                                                               0, sv) < 0) {
+               bthost_destroy(bthost);
+               btdev_destroy(btdev);
+               return false;
+       }
+
+       hciemu->client_dev = btdev;
+       hciemu->host_stack = bthost;
+
+       hciemu->client_source = create_source_btdev(sv[0], btdev);
+       hciemu->host_source = create_source_bthost(sv[1], bthost);
+
+       return true;
+}
+
+static gboolean start_stack(gpointer user_data)
+{
+       struct hciemu *hciemu = user_data;
+
+       bthost_start(hciemu->host_stack);
+
+       return FALSE;
+}
+
+struct hciemu *hciemu_new(enum hciemu_type type)
+{
+       struct hciemu *hciemu;
+
+       hciemu = g_try_new0(struct hciemu, 1);
+       if (!hciemu)
+               return NULL;
+
+       switch (type) {
+       case HCIEMU_TYPE_BREDRLE:
+               hciemu->btdev_type = BTDEV_TYPE_BREDRLE;
+               break;
+       case HCIEMU_TYPE_BREDR:
+               hciemu->btdev_type = BTDEV_TYPE_BREDR;
+               break;
+       case HCIEMU_TYPE_LE:
+               hciemu->btdev_type = BTDEV_TYPE_LE;
+               break;
+       default:
+               return NULL;
+       }
+
+       if (!create_vhci(hciemu)) {
+               g_free(hciemu);
+               return NULL;
+       }
+
+       if (!create_stack(hciemu)) {
+               g_source_remove(hciemu->master_source);
+               btdev_destroy(hciemu->master_dev);
+               g_free(hciemu);
+               return NULL;
+       }
+
+       g_idle_add(start_stack, hciemu);
+
+       return hciemu_ref(hciemu);
+}
+
+struct hciemu *hciemu_ref(struct hciemu *hciemu)
+{
+       if (!hciemu)
+               return NULL;
+
+       __sync_fetch_and_add(&hciemu->ref_count, 1);
+
+       return hciemu;
+}
+
+void hciemu_unref(struct hciemu *hciemu)
+{
+       if (!hciemu)
+               return;
+
+       if (__sync_sub_and_fetch(&hciemu->ref_count, 1) > 0)
+               return;
+
+       g_list_foreach(hciemu->post_command_hooks, destroy_command_hook, NULL);
+       g_list_free(hciemu->post_command_hooks);
+
+       bthost_stop(hciemu->host_stack);
+
+       g_source_remove(hciemu->host_source);
+       g_source_remove(hciemu->client_source);
+       g_source_remove(hciemu->master_source);
+
+       bthost_destroy(hciemu->host_stack);
+       btdev_destroy(hciemu->client_dev);
+       btdev_destroy(hciemu->master_dev);
+
+       g_free(hciemu);
+}
+
+const char *hciemu_get_address(struct hciemu *hciemu)
+{
+       const uint8_t *addr;
+
+       if (!hciemu || !hciemu->master_dev)
+               return NULL;
+
+       addr = btdev_get_bdaddr(hciemu->master_dev);
+       sprintf(hciemu->bdaddr_str, "%2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X",
+                       addr[5], addr[4], addr[3], addr[2], addr[1], addr[0]);
+       return hciemu->bdaddr_str;
+}
+
+uint8_t *hciemu_get_features(struct hciemu *hciemu)
+{
+       if (!hciemu || !hciemu->master_dev)
+               return NULL;
+
+       return btdev_get_features(hciemu->master_dev);
+}
+
+const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu)
+{
+       if (!hciemu || !hciemu->master_dev)
+               return NULL;
+
+       return btdev_get_bdaddr(hciemu->master_dev);
+}
+
+const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu)
+{
+       if (!hciemu || !hciemu->client_dev)
+               return NULL;
+
+       return btdev_get_bdaddr(hciemu->client_dev);
+}
+
+bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
+                       hciemu_command_func_t function, void *user_data)
+{
+       struct hciemu_command_hook *hook;
+
+       if (!hciemu)
+               return false;
+
+       hook = g_try_new0(struct hciemu_command_hook, 1);
+       if (!hook)
+               return false;
+
+       hook->function = function;
+       hook->user_data = user_data;
+
+       hciemu->post_command_hooks = g_list_append(hciemu->post_command_hooks,
+                                                                       hook);
+
+       return true;
+}
+
+int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+                               uint16_t opcode, hciemu_hook_func_t function,
+                               void *user_data)
+{
+       enum btdev_hook_type hook_type;
+
+       if (!hciemu)
+               return -1;
+
+       switch (type) {
+       case HCIEMU_HOOK_PRE_CMD:
+               hook_type = BTDEV_HOOK_PRE_CMD;
+               break;
+       case HCIEMU_HOOK_POST_CMD:
+               hook_type = BTDEV_HOOK_POST_CMD;
+               break;
+       case HCIEMU_HOOK_PRE_EVT:
+               hook_type = BTDEV_HOOK_PRE_EVT;
+               break;
+       case HCIEMU_HOOK_POST_EVT:
+               hook_type = BTDEV_HOOK_POST_EVT;
+               break;
+       default:
+               return -1;
+       }
+
+       return btdev_add_hook(hciemu->master_dev, hook_type, opcode, function,
+                                                               user_data);
+}
+
+bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+                                                               uint16_t opcode)
+{
+       enum btdev_hook_type hook_type;
+
+       if (!hciemu)
+               return false;
+
+       switch (type) {
+       case HCIEMU_HOOK_PRE_CMD:
+               hook_type = BTDEV_HOOK_PRE_CMD;
+               break;
+       case HCIEMU_HOOK_POST_CMD:
+               hook_type = BTDEV_HOOK_POST_CMD;
+               break;
+       case HCIEMU_HOOK_PRE_EVT:
+               hook_type = BTDEV_HOOK_PRE_EVT;
+               break;
+       case HCIEMU_HOOK_POST_EVT:
+               hook_type = BTDEV_HOOK_POST_EVT;
+               break;
+       default:
+               return false;
+       }
+
+       return btdev_del_hook(hciemu->master_dev, hook_type, opcode);
+}
diff --git a/src/shared/hciemu.h b/src/shared/hciemu.h
new file mode 100644 (file)
index 0000000..d17eaf7
--- /dev/null
@@ -0,0 +1,69 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+struct hciemu;
+
+enum hciemu_type {
+       HCIEMU_TYPE_BREDRLE,
+       HCIEMU_TYPE_BREDR,
+       HCIEMU_TYPE_LE,
+};
+
+enum hciemu_hook_type {
+       HCIEMU_HOOK_PRE_CMD,
+       HCIEMU_HOOK_POST_CMD,
+       HCIEMU_HOOK_PRE_EVT,
+       HCIEMU_HOOK_POST_EVT,
+};
+
+struct hciemu *hciemu_new(enum hciemu_type type);
+
+struct hciemu *hciemu_ref(struct hciemu *hciemu);
+void hciemu_unref(struct hciemu *hciemu);
+
+struct bthost *hciemu_client_get_host(struct hciemu *hciemu);
+
+const char *hciemu_get_address(struct hciemu *hciemu);
+uint8_t *hciemu_get_features(struct hciemu *hciemu);
+
+const uint8_t *hciemu_get_master_bdaddr(struct hciemu *hciemu);
+const uint8_t *hciemu_get_client_bdaddr(struct hciemu *hciemu);
+
+typedef void (*hciemu_command_func_t)(uint16_t opcode, const void *data,
+                                               uint8_t len, void *user_data);
+
+typedef bool (*hciemu_hook_func_t)(const void *data, uint16_t len,
+                                                       void *user_data);
+
+bool hciemu_add_master_post_command_hook(struct hciemu *hciemu,
+                       hciemu_command_func_t function, void *user_data);
+
+int hciemu_add_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+                               uint16_t opcode, hciemu_hook_func_t function,
+                               void *user_data);
+
+bool hciemu_del_hook(struct hciemu *hciemu, enum hciemu_hook_type type,
+                                                       uint16_t opcode);
diff --git a/src/shared/mgmt.c b/src/shared/mgmt.c
new file mode 100644 (file)
index 0000000..2c79886
--- /dev/null
@@ -0,0 +1,815 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+#include "lib/hci.h"
+
+#include "src/shared/util.h"
+#include "src/shared/mgmt.h"
+
+struct mgmt {
+       int ref_count;
+       int fd;
+       bool close_on_unref;
+       GIOChannel *io;
+       guint read_watch;
+       guint write_watch;
+       GQueue *request_queue;
+       GQueue *reply_queue;
+       GList *pending_list;
+       GList *notify_list;
+       GList *notify_destroyed;
+       unsigned int next_request_id;
+       unsigned int next_notify_id;
+       bool in_notify;
+       bool destroyed;
+       void *buf;
+       uint16_t len;
+       mgmt_debug_func_t debug_callback;
+       mgmt_destroy_func_t debug_destroy;
+       void *debug_data;
+};
+
+struct mgmt_request {
+       unsigned int id;
+       uint16_t opcode;
+       uint16_t index;
+       void *buf;
+       uint16_t len;
+       mgmt_request_func_t callback;
+       mgmt_destroy_func_t destroy;
+       void *user_data;
+};
+
+struct mgmt_notify {
+       unsigned int id;
+       uint16_t event;
+       uint16_t index;
+       bool destroyed;
+       mgmt_notify_func_t callback;
+       mgmt_destroy_func_t destroy;
+       void *user_data;
+};
+
+static void destroy_request(gpointer data, gpointer user_data)
+{
+       struct mgmt_request *request = data;
+
+       if (request->destroy)
+               request->destroy(request->user_data);
+
+       g_free(request->buf);
+       g_free(request);
+}
+
+static int compare_request_id(gconstpointer a, gconstpointer b)
+{
+       const struct mgmt_request *request = a;
+       unsigned int id = GPOINTER_TO_UINT(b);
+
+       return request->id - id;
+}
+
+static void destroy_notify(gpointer data, gpointer user_data)
+{
+       struct mgmt_notify *notify = data;
+
+       if (notify->destroy)
+               notify->destroy(notify->user_data);
+
+       g_free(notify);
+}
+
+static int compare_notify_id(gconstpointer a, gconstpointer b)
+{
+       const struct mgmt_notify *notify = a;
+       unsigned int id = GPOINTER_TO_UINT(b);
+
+       return notify->id - id;
+}
+
+static void write_watch_destroy(gpointer user_data)
+{
+       struct mgmt *mgmt = user_data;
+
+       mgmt->write_watch = 0;
+}
+
+static gboolean can_write_data(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct mgmt *mgmt = user_data;
+       struct mgmt_request *request;
+       ssize_t bytes_written;
+
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+               return FALSE;
+
+       request = g_queue_pop_head(mgmt->reply_queue);
+       if (!request) {
+               /* only reply commands can jump the queue */
+               if (mgmt->pending_list)
+                       return FALSE;
+
+               request = g_queue_pop_head(mgmt->request_queue);
+               if (!request)
+                       return FALSE;
+       }
+
+       bytes_written = write(mgmt->fd, request->buf, request->len);
+       if (bytes_written < 0) {
+               util_debug(mgmt->debug_callback, mgmt->debug_data,
+                               "write failed: %s", strerror(errno));
+               if (request->callback)
+                       request->callback(MGMT_STATUS_FAILED, 0, NULL,
+                                                       request->user_data);
+               destroy_request(request, NULL);
+               return TRUE;
+       }
+
+       util_debug(mgmt->debug_callback, mgmt->debug_data,
+                               "[0x%04x] command 0x%04x",
+                               request->index, request->opcode);
+
+       util_hexdump('<', request->buf, bytes_written,
+                               mgmt->debug_callback, mgmt->debug_data);
+
+       mgmt->pending_list = g_list_append(mgmt->pending_list, request);
+
+       return FALSE;
+}
+
+static void wakeup_writer(struct mgmt *mgmt)
+{
+       if (mgmt->pending_list) {
+               /* only queued reply commands trigger wakeup */
+               if (g_queue_get_length(mgmt->reply_queue) == 0)
+                       return;
+       }
+
+       if (mgmt->write_watch > 0)
+               return;
+
+       mgmt->write_watch = g_io_add_watch_full(mgmt->io, G_PRIORITY_HIGH,
+                               G_IO_OUT | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               can_write_data, mgmt, write_watch_destroy);
+}
+
+static GList *lookup_pending(struct mgmt *mgmt, uint16_t opcode, uint16_t index)
+{
+       GList *list;
+
+       for (list = g_list_first(mgmt->pending_list); list;
+                                               list = g_list_next(list)) {
+               struct mgmt_request *request = list->data;
+
+               if (request->opcode == opcode && request->index == index)
+                       return list;
+       }
+
+       return NULL;
+}
+
+static void request_complete(struct mgmt *mgmt, uint8_t status,
+                                       uint16_t opcode, uint16_t index,
+                                       uint16_t length, const void *param)
+{
+       struct mgmt_request *request;
+       GList *list;
+
+       list = lookup_pending(mgmt, opcode, index);
+       if (!list)
+               return;
+
+       request = list->data;
+
+       mgmt->pending_list = g_list_delete_link(mgmt->pending_list, list);
+
+       if (request->callback)
+               request->callback(status, length, param, request->user_data);
+
+       destroy_request(request, NULL);
+
+       if (mgmt->destroyed)
+               return;
+
+       wakeup_writer(mgmt);
+}
+
+static void process_notify(struct mgmt *mgmt, uint16_t event, uint16_t index,
+                                       uint16_t length, const void *param)
+{
+       GList *list;
+
+       mgmt->in_notify = true;
+
+       for (list = g_list_first(mgmt->notify_list); list;
+                                               list = g_list_next(list)) {
+               struct mgmt_notify *notify = list->data;
+
+               if (notify->destroyed)
+                       continue;
+
+               if (notify->event != event)
+                       continue;
+
+               if (notify->index != index && notify->index != MGMT_INDEX_NONE)
+                       continue;
+
+               if (notify->callback)
+                       notify->callback(index, length, param,
+                                                       notify->user_data);
+
+               if (mgmt->destroyed)
+                       break;
+       }
+
+       mgmt->in_notify = false;
+
+       g_list_foreach(mgmt->notify_destroyed, destroy_notify, NULL);
+       g_list_free(mgmt->notify_destroyed);
+
+       mgmt->notify_destroyed = NULL;
+}
+
+static void read_watch_destroy(gpointer user_data)
+{
+       struct mgmt *mgmt = user_data;
+
+       if (mgmt->destroyed) {
+               g_free(mgmt);
+               return;
+       }
+
+       mgmt->read_watch = 0;
+}
+
+static gboolean received_data(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct mgmt *mgmt = user_data;
+       struct mgmt_hdr *hdr;
+       struct mgmt_ev_cmd_complete *cc;
+       struct mgmt_ev_cmd_status *cs;
+       ssize_t bytes_read;
+       uint16_t opcode, event, index, length;
+
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL))
+               return FALSE;
+
+       bytes_read = read(mgmt->fd, mgmt->buf, mgmt->len);
+       if (bytes_read < 0)
+               return TRUE;
+
+       util_hexdump('>', mgmt->buf, bytes_read,
+                               mgmt->debug_callback, mgmt->debug_data);
+
+       if (bytes_read < MGMT_HDR_SIZE)
+               return TRUE;
+
+       hdr = mgmt->buf;
+       event = btohs(hdr->opcode);
+       index = btohs(hdr->index);
+       length = btohs(hdr->len);
+
+       if (bytes_read < length + MGMT_HDR_SIZE)
+               return TRUE;
+
+       switch (event) {
+       case MGMT_EV_CMD_COMPLETE:
+               cc = mgmt->buf + MGMT_HDR_SIZE;
+               opcode = btohs(cc->opcode);
+
+               util_debug(mgmt->debug_callback, mgmt->debug_data,
+                               "[0x%04x] command 0x%04x complete: 0x%02x",
+                                               index, opcode, cc->status);
+
+               request_complete(mgmt, cc->status, opcode, index, length - 3,
+                                               mgmt->buf + MGMT_HDR_SIZE + 3);
+               break;
+       case MGMT_EV_CMD_STATUS:
+               cs = mgmt->buf + MGMT_HDR_SIZE;
+               opcode = btohs(cs->opcode);
+
+               util_debug(mgmt->debug_callback, mgmt->debug_data,
+                               "[0x%04x] command 0x%02x status: 0x%02x",
+                                               index, opcode, cs->status);
+
+               request_complete(mgmt, cs->status, opcode, index, 0, NULL);
+               break;
+       default:
+               util_debug(mgmt->debug_callback, mgmt->debug_data,
+                               "[0x%04x] event 0x%04x", index, event);
+
+               process_notify(mgmt, event, index, length,
+                                               mgmt->buf + MGMT_HDR_SIZE);
+               break;
+       }
+
+       if (mgmt->destroyed)
+               return FALSE;
+
+       return TRUE;
+}
+
+struct mgmt *mgmt_new(int fd)
+{
+       struct mgmt *mgmt;
+
+       if (fd < 0)
+               return NULL;
+
+       mgmt = g_try_new0(struct mgmt, 1);
+       if (!mgmt)
+               return NULL;
+
+       mgmt->fd = fd;
+       mgmt->close_on_unref = false;
+
+       mgmt->len = 512;
+       mgmt->buf = g_try_malloc(mgmt->len);
+       if (!mgmt->buf) {
+               g_free(mgmt);
+               return NULL;
+       }
+
+       mgmt->io = g_io_channel_unix_new(mgmt->fd);
+
+       g_io_channel_set_encoding(mgmt->io, NULL, NULL);
+       g_io_channel_set_buffered(mgmt->io, FALSE);
+
+       mgmt->request_queue = g_queue_new();
+       mgmt->reply_queue = g_queue_new();
+
+       mgmt->read_watch = g_io_add_watch_full(mgmt->io, G_PRIORITY_DEFAULT,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               received_data, mgmt, read_watch_destroy);
+
+       return mgmt_ref(mgmt);
+}
+
+struct mgmt *mgmt_new_default(void)
+{
+       struct mgmt *mgmt;
+       struct sockaddr_hci addr;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC | SOCK_NONBLOCK,
+                                                               BTPROTO_HCI);
+       if (fd < 0)
+               return NULL;
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = HCI_DEV_NONE;
+       addr.hci_channel = HCI_CHANNEL_CONTROL;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               close(fd);
+               return NULL;
+       }
+
+       mgmt = mgmt_new(fd);
+       if (!mgmt) {
+               close(fd);
+               return NULL;
+       }
+
+       mgmt->close_on_unref = true;
+
+       return mgmt;
+}
+
+struct mgmt *mgmt_ref(struct mgmt *mgmt)
+{
+       if (!mgmt)
+               return NULL;
+
+       __sync_fetch_and_add(&mgmt->ref_count, 1);
+
+       return mgmt;
+}
+
+void mgmt_unref(struct mgmt *mgmt)
+{
+       if (!mgmt)
+               return;
+
+       if (__sync_sub_and_fetch(&mgmt->ref_count, 1))
+               return;
+
+       mgmt_unregister_all(mgmt);
+       mgmt_cancel_all(mgmt);
+
+       g_queue_free(mgmt->reply_queue);
+       g_queue_free(mgmt->request_queue);
+
+       if (mgmt->write_watch > 0)
+               g_source_remove(mgmt->write_watch);
+
+       if (mgmt->read_watch > 0)
+               g_source_remove(mgmt->read_watch);
+
+       g_io_channel_unref(mgmt->io);
+       mgmt->io = NULL;
+
+       if (mgmt->close_on_unref)
+               close(mgmt->fd);
+
+       if (mgmt->debug_destroy)
+               mgmt->debug_destroy(mgmt->debug_data);
+
+       g_free(mgmt->buf);
+       mgmt->buf = NULL;
+
+       if (!mgmt->in_notify) {
+               g_free(mgmt);
+               return;
+       }
+
+       mgmt->destroyed = true;
+}
+
+bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy)
+{
+       if (!mgmt)
+               return false;
+
+       if (mgmt->debug_destroy)
+               mgmt->debug_destroy(mgmt->debug_data);
+
+       mgmt->debug_callback = callback;
+       mgmt->debug_destroy = destroy;
+       mgmt->debug_data = user_data;
+
+       return true;
+}
+
+bool mgmt_set_close_on_unref(struct mgmt *mgmt, bool do_close)
+{
+       if (!mgmt)
+               return false;
+
+       mgmt->close_on_unref = do_close;
+
+       return true;
+}
+
+static struct mgmt_request *create_request(uint16_t opcode, uint16_t index,
+                               uint16_t length, const void *param,
+                               mgmt_request_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy)
+{
+       struct mgmt_request *request;
+       struct mgmt_hdr *hdr;
+
+       if (!opcode)
+               return NULL;
+
+       if (length > 0 && !param)
+               return NULL;
+
+       request = g_try_new0(struct mgmt_request, 1);
+       if (!request)
+               return NULL;
+
+       request->len = length + MGMT_HDR_SIZE;
+       request->buf = g_try_malloc(request->len);
+       if (!request->buf) {
+               g_free(request);
+               return NULL;
+       }
+
+       if (length > 0)
+               memcpy(request->buf + MGMT_HDR_SIZE, param, length);
+
+       hdr = request->buf;
+       hdr->opcode = htobs(opcode);
+       hdr->index = htobs(index);
+       hdr->len = htobs(length);
+
+       request->opcode = opcode;
+       request->index = index;
+
+       request->callback = callback;
+       request->destroy = destroy;
+       request->user_data = user_data;
+
+       return request;
+}
+
+unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
+                               uint16_t length, const void *param,
+                               mgmt_request_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy)
+{
+       struct mgmt_request *request;
+
+       if (!mgmt)
+               return 0;
+
+       request = create_request(opcode, index, length, param,
+                                       callback, user_data, destroy);
+       if (!request)
+               return 0;
+
+       if (mgmt->next_request_id < 1)
+               mgmt->next_request_id = 1;
+
+       request->id = mgmt->next_request_id++;
+
+       g_queue_push_tail(mgmt->request_queue, request);
+
+       wakeup_writer(mgmt);
+
+       return request->id;
+}
+
+unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
+                               uint16_t length, const void *param,
+                               mgmt_request_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy)
+{
+       struct mgmt_request *request;
+
+       if (!mgmt)
+               return 0;
+
+       request = create_request(opcode, index, length, param,
+                                       callback, user_data, destroy);
+       if (!request)
+               return 0;
+
+       if (mgmt->next_request_id < 1)
+               mgmt->next_request_id = 1;
+
+       request->id = mgmt->next_request_id++;
+
+       g_queue_push_tail(mgmt->reply_queue, request);
+
+       wakeup_writer(mgmt);
+
+       return request->id;
+}
+
+bool mgmt_cancel(struct mgmt *mgmt, unsigned int id)
+{
+       struct mgmt_request *request;
+       GList *list;
+
+       if (!mgmt || !id)
+               return false;
+
+       list = g_queue_find_custom(mgmt->request_queue, GUINT_TO_POINTER(id),
+                                                       compare_request_id);
+       if (list) {
+               request = list->data;
+               g_queue_delete_link(mgmt->request_queue, list);
+               goto done;
+       }
+
+       list = g_queue_find_custom(mgmt->reply_queue, GUINT_TO_POINTER(id),
+                                                       compare_request_id);
+       if (list) {
+               request = list->data;
+               g_queue_delete_link(mgmt->reply_queue, list);
+               goto done;
+       }
+
+       list = g_list_find_custom(mgmt->pending_list, GUINT_TO_POINTER(id),
+                                                       compare_request_id);
+       if (!list)
+               return false;
+
+       request = list->data;
+
+       mgmt->pending_list = g_list_delete_link(mgmt->pending_list, list);
+
+done:
+       destroy_request(request, NULL);
+
+       wakeup_writer(mgmt);
+
+       return true;
+}
+
+bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index)
+{
+       GList *list, *next;
+
+       if (!mgmt)
+               return false;
+
+       for (list = g_queue_peek_head_link(mgmt->request_queue); list;
+                                                               list = next) {
+               struct mgmt_request *request = list->data;
+
+               next = g_list_next(list);
+
+               if (request->index != index)
+                       continue;
+
+               g_queue_delete_link(mgmt->request_queue, list);
+
+               destroy_request(request, NULL);
+       }
+
+       for (list = g_queue_peek_head_link(mgmt->reply_queue); list;
+                                                               list = next) {
+               struct mgmt_request *request = list->data;
+
+               next = g_list_next(list);
+
+               if (request->index != index)
+                       continue;
+
+               g_queue_delete_link(mgmt->reply_queue, list);
+
+               destroy_request(request, NULL);
+       }
+
+       for (list = g_list_first(mgmt->pending_list); list; list = next) {
+               struct mgmt_request *request = list->data;
+
+               next = g_list_next(list);
+
+               if (request->index != index)
+                       continue;
+
+               mgmt->pending_list = g_list_delete_link(mgmt->pending_list,
+                                                                       list);
+
+               destroy_request(request, NULL);
+       }
+
+       return true;
+}
+
+bool mgmt_cancel_all(struct mgmt *mgmt)
+{
+       if (!mgmt)
+               return false;
+
+       g_list_foreach(mgmt->pending_list, destroy_request, NULL);
+       g_list_free(mgmt->pending_list);
+       mgmt->pending_list = NULL;
+
+       g_queue_foreach(mgmt->reply_queue, destroy_request, NULL);
+       g_queue_clear(mgmt->reply_queue);
+
+       g_queue_foreach(mgmt->request_queue, destroy_request, NULL);
+       g_queue_clear(mgmt->request_queue);
+
+       return true;
+}
+
+unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
+                               mgmt_notify_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy)
+{
+       struct mgmt_notify *notify;
+
+       if (!mgmt || !event)
+               return 0;
+
+       notify = g_try_new0(struct mgmt_notify, 1);
+       if (!notify)
+               return 0;
+
+       notify->event = event;
+       notify->index = index;
+
+       notify->callback = callback;
+       notify->destroy = destroy;
+       notify->user_data = user_data;
+
+       if (mgmt->next_notify_id < 1)
+               mgmt->next_notify_id = 1;
+
+       notify->id = mgmt->next_notify_id++;
+
+       mgmt->notify_list = g_list_append(mgmt->notify_list, notify);
+
+       return notify->id;
+}
+
+bool mgmt_unregister(struct mgmt *mgmt, unsigned int id)
+{
+       struct mgmt_notify *notify;
+       GList *list;
+
+       if (!mgmt || !id)
+               return false;
+
+       list = g_list_find_custom(mgmt->notify_list,
+                               GUINT_TO_POINTER(id), compare_notify_id);
+       if (!list)
+               return false;
+
+       notify = list->data;
+
+       mgmt->notify_list = g_list_remove_link(mgmt->notify_list, list);
+
+       if (!mgmt->in_notify) {
+               g_list_free_1(list);
+               destroy_notify(notify, NULL);
+               return true;
+       }
+
+       notify->destroyed = true;
+
+       mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed, list);
+
+       return true;
+}
+
+bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index)
+{
+       GList *list, *next;
+
+       if (!mgmt)
+               return false;
+
+       for (list = g_list_first(mgmt->notify_list); list; list = next) {
+               struct mgmt_notify *notify = list->data;
+
+               next = g_list_next(list);
+
+               if (notify->index != index)
+                       continue;
+
+               mgmt->notify_list = g_list_remove_link(mgmt->notify_list, list);
+
+               if (!mgmt->in_notify) {
+                       g_list_free_1(list);
+                       destroy_notify(notify, NULL);
+                       continue;
+               }
+
+               notify->destroyed = true;
+
+               mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed,
+                                                                       list);
+       }
+
+       return true;
+}
+
+static void mark_notify(gpointer data, gpointer user_data)
+{
+       struct mgmt_notify *notify = data;
+
+       notify->destroyed = true;
+}
+
+bool mgmt_unregister_all(struct mgmt *mgmt)
+{
+       if (!mgmt)
+               return false;
+
+       if (!mgmt->in_notify) {
+               g_list_foreach(mgmt->notify_list, destroy_notify, NULL);
+               g_list_free(mgmt->notify_list);
+       } else {
+               g_list_foreach(mgmt->notify_list, mark_notify, NULL);
+               mgmt->notify_destroyed = g_list_concat(mgmt->notify_destroyed,
+                                                       mgmt->notify_list);
+       }
+
+       mgmt->notify_list = NULL;
+
+       return true;
+}
diff --git a/src/shared/mgmt.h b/src/shared/mgmt.h
new file mode 100644 (file)
index 0000000..60a2128
--- /dev/null
@@ -0,0 +1,67 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdbool.h>
+#include <stdint.h>
+
+typedef void (*mgmt_destroy_func_t)(void *user_data);
+
+struct mgmt;
+
+struct mgmt *mgmt_new(int fd);
+struct mgmt *mgmt_new_default(void);
+
+struct mgmt *mgmt_ref(struct mgmt *mgmt);
+void mgmt_unref(struct mgmt *mgmt);
+
+typedef void (*mgmt_debug_func_t)(const char *str, void *user_data);
+
+bool mgmt_set_debug(struct mgmt *mgmt, mgmt_debug_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy);
+
+bool mgmt_set_close_on_unref(struct mgmt *mgmt, bool do_close);
+
+typedef void (*mgmt_request_func_t)(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data);
+
+unsigned int mgmt_send(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
+                               uint16_t length, const void *param,
+                               mgmt_request_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy);
+unsigned int mgmt_reply(struct mgmt *mgmt, uint16_t opcode, uint16_t index,
+                               uint16_t length, const void *param,
+                               mgmt_request_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy);
+bool mgmt_cancel(struct mgmt *mgmt, unsigned int id);
+bool mgmt_cancel_index(struct mgmt *mgmt, uint16_t index);
+bool mgmt_cancel_all(struct mgmt *mgmt);
+
+typedef void (*mgmt_notify_func_t)(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data);
+
+unsigned int mgmt_register(struct mgmt *mgmt, uint16_t event, uint16_t index,
+                               mgmt_notify_func_t callback,
+                               void *user_data, mgmt_destroy_func_t destroy);
+bool mgmt_unregister(struct mgmt *mgmt, unsigned int id);
+bool mgmt_unregister_index(struct mgmt *mgmt, uint16_t index);
+bool mgmt_unregister_all(struct mgmt *mgmt);
diff --git a/src/shared/pcap.c b/src/shared/pcap.c
new file mode 100644 (file)
index 0000000..c722db2
--- /dev/null
@@ -0,0 +1,237 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+#include "pcap.h"
+
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+
+struct pcap_hdr {
+       uint32_t magic_number;  /* magic number */
+       uint16_t version_major; /* major version number */
+       uint16_t version_minor; /* minor version number */
+       int32_t  thiszone;      /* GMT to local correction */
+       uint32_t sigfigs;       /* accuracy of timestamps */
+       uint32_t snaplen;       /* max length of captured packets, in octets */
+       uint32_t network;       /* data link type */
+} __attribute__ ((packed));
+#define PCAP_HDR_SIZE (sizeof(struct pcap_hdr))
+
+struct pcap_pkt {
+       uint32_t ts_sec;        /* timestamp seconds */
+       uint32_t ts_usec;       /* timestamp microseconds */
+       uint32_t incl_len;      /* number of octets of packet saved in file */
+       uint32_t orig_len;      /* actual length of packet */
+} __attribute__ ((packed));
+#define PCAP_PKT_SIZE (sizeof(struct pcap_pkt))
+
+struct pcap_ppi {
+       uint8_t  version;       /* version, currently 0 */
+       uint8_t  flags;         /* flags */
+       uint16_t len;           /* length of entire message */
+       uint32_t dlt;           /* data link type */
+} __attribute__ ((packed));
+#define PCAP_PPI_SIZE (sizeof(struct pcap_ppi))
+
+struct pcap {
+       int ref_count;
+       int fd;
+       uint32_t type;
+       uint32_t snaplen;
+};
+
+struct pcap *pcap_open(const char *path)
+{
+       struct pcap *pcap;
+       struct pcap_hdr hdr;
+       ssize_t len;
+
+       pcap = calloc(1, sizeof(*pcap));
+       if (!pcap)
+               return NULL;
+
+       pcap->fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (pcap->fd < 0) {
+               free(pcap);
+               return NULL;
+       }
+
+       len = read(pcap->fd, &hdr, PCAP_HDR_SIZE);
+       if (len < 0 || len != PCAP_HDR_SIZE)
+               goto failed;
+
+       if (hdr.magic_number != 0xa1b2c3d4)
+               goto failed;
+
+       if (hdr.version_major != 2 || hdr.version_minor != 4)
+               goto failed;
+
+       pcap->snaplen = hdr.snaplen;
+       pcap->type = hdr.network;
+
+       return pcap_ref(pcap);
+
+failed:
+       close(pcap->fd);
+       free(pcap);
+
+       return NULL;
+}
+
+struct pcap *pcap_ref(struct pcap *pcap)
+{
+       if (!pcap)
+               return NULL;
+
+       __sync_fetch_and_add(&pcap->ref_count, 1);
+
+       return pcap;
+}
+
+void pcap_unref(struct pcap *pcap)
+{
+       if (!pcap)
+               return;
+
+       if (__sync_sub_and_fetch(&pcap->ref_count, 1))
+               return;
+
+       if (pcap->fd >= 0)
+               close(pcap->fd);
+
+       free(pcap);
+}
+
+uint32_t pcap_get_type(struct pcap *pcap)
+{
+       if (!pcap)
+               return PCAP_TYPE_INVALID;
+
+       return pcap->type;
+}
+
+uint32_t pcap_get_snaplen(struct pcap *pcap)
+{
+       if (!pcap)
+               return 0;
+
+       return pcap->snaplen;
+}
+
+bool pcap_read(struct pcap *pcap, struct timeval *tv,
+                               void *data, uint32_t size, uint32_t *len)
+{
+       struct pcap_pkt pkt;
+       uint32_t toread;
+       ssize_t bytes_read;
+
+       if (!pcap)
+               return false;
+
+       bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE);
+       if (bytes_read != PCAP_PKT_SIZE)
+               return false;
+
+       if (pkt.incl_len > size)
+               toread = size;
+       else
+               toread = pkt.incl_len;
+
+       bytes_read = read(pcap->fd, data, toread);
+       if (bytes_read < 0)
+               return false;
+
+       if (tv) {
+               tv->tv_sec = pkt.ts_sec;
+               tv->tv_usec = pkt.ts_usec;
+       }
+
+       if (len)
+               *len = toread;
+
+       return true;
+}
+
+bool pcap_read_ppi(struct pcap *pcap, struct timeval *tv, uint32_t *type,
+                                       void *data, uint32_t size,
+                                       uint32_t *offset, uint32_t *len)
+{
+       struct pcap_pkt pkt;
+       struct pcap_ppi ppi;
+       uint16_t pph_len;
+       uint32_t toread;
+       ssize_t bytes_read;
+
+       if (!pcap)
+               return false;
+
+       bytes_read = read(pcap->fd, &pkt, PCAP_PKT_SIZE);
+       if (bytes_read != PCAP_PKT_SIZE)
+               return false;
+
+       if (pkt.incl_len > size)
+               toread = size;
+       else
+               toread = pkt.incl_len;
+
+       bytes_read = read(pcap->fd, &ppi, PCAP_PPI_SIZE);
+       if (bytes_read != PCAP_PPI_SIZE)
+               return false;
+
+       if (ppi.flags)
+               return false;
+
+       pph_len = le16_to_cpu(ppi.len);
+       if (pph_len < PCAP_PPI_SIZE)
+               return false;
+
+       bytes_read = read(pcap->fd, data, toread - PCAP_PPI_SIZE);
+       if (bytes_read < 0)
+               return false;
+
+       if (tv) {
+               tv->tv_sec = pkt.ts_sec;
+               tv->tv_usec = pkt.ts_usec;
+       }
+
+       if (type)
+               *type = le32_to_cpu(ppi.dlt);
+
+       if (offset)
+               *offset = pph_len - PCAP_PPI_SIZE;
+
+       if (len)
+               *len = toread - pph_len;
+
+       return true;
+}
similarity index 50%
rename from sbc/sbc_primitives_iwmmxt.h
rename to src/shared/pcap.h
index b535e68..f333bfc 100644 (file)
@@ -1,12 +1,8 @@
 /*
  *
- *  Bluetooth low-complexity, subband codec (SBC) library
+ *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2010 Keith Mok <ek9852@gmail.com>
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This library is free software; you can redistribute it and/or
  *
  */
 
-#ifndef __SBC_PRIMITIVES_IWMMXT_H
-#define __SBC_PRIMITIVES_IWMMXT_H
+#include <stdint.h>
+#include <stdbool.h>
+#include <sys/time.h>
 
-#include "sbc_primitives.h"
+#define PCAP_TYPE_INVALID              0
+#define PCAP_TYPE_USER0                        147
+#define PCAP_TYPE_PPI                  192
+#define PCAP_TYPE_BLUETOOTH_LE_LL      251
 
-#if defined(__GNUC__) && defined(__IWMMXT__) && \
-               !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
+struct pcap;
 
-#define SBC_BUILD_WITH_IWMMXT_SUPPORT
+struct pcap *pcap_open(const char *path);
 
-void sbc_init_primitives_iwmmxt(struct sbc_encoder_state *encoder_state);
+struct pcap *pcap_ref(struct pcap *pcap);
+void pcap_unref(struct pcap *pcap);
 
-#endif
+uint32_t pcap_get_type(struct pcap *pcap);
+uint32_t pcap_get_snaplen(struct pcap *pcap);
 
-#endif
+bool pcap_read(struct pcap *pcap, struct timeval *tv,
+                               void *data, uint32_t size, uint32_t *len);
+bool pcap_read_ppi(struct pcap *pcap, struct timeval *tv, uint32_t *type,
+                                       void *data, uint32_t size,
+                                       uint32_t *offset, uint32_t *len);
diff --git a/src/shared/tester.c b/src/shared/tester.c
new file mode 100644 (file)
index 0000000..f3edd74
--- /dev/null
@@ -0,0 +1,795 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <glib.h>
+
+#include "src/shared/tester.h"
+
+#define COLOR_OFF      "\x1B[0m"
+#define COLOR_BLACK    "\x1B[0;30m"
+#define COLOR_RED      "\x1B[0;31m"
+#define COLOR_GREEN    "\x1B[0;32m"
+#define COLOR_YELLOW   "\x1B[0;33m"
+#define COLOR_BLUE     "\x1B[0;34m"
+#define COLOR_MAGENTA  "\x1B[0;35m"
+#define COLOR_CYAN     "\x1B[0;36m"
+#define COLOR_WHITE    "\x1B[0;37m"
+#define COLOR_HIGHLIGHT        "\x1B[1;39m"
+
+#define print_text(color, fmt, args...) \
+               printf(color fmt COLOR_OFF "\n", ## args)
+
+#define print_summary(label, color, value, fmt, args...) \
+                       printf("%-45s " color "%-10s" COLOR_OFF fmt "\n", \
+                                                       label, value, ## args)
+
+#define print_progress(name, color, fmt, args...) \
+               printf(COLOR_HIGHLIGHT "%s" COLOR_OFF " - " \
+                               color fmt COLOR_OFF "\n", name, ## args)
+
+enum test_result {
+       TEST_RESULT_NOT_RUN,
+       TEST_RESULT_PASSED,
+       TEST_RESULT_FAILED,
+       TEST_RESULT_TIMED_OUT,
+};
+
+enum test_stage {
+       TEST_STAGE_INVALID,
+       TEST_STAGE_PRE_SETUP,
+       TEST_STAGE_SETUP,
+       TEST_STAGE_RUN,
+       TEST_STAGE_TEARDOWN,
+       TEST_STAGE_POST_TEARDOWN,
+};
+
+struct test_case {
+       char *name;
+       enum test_result result;
+       enum test_stage stage;
+       const void *test_data;
+       tester_data_func_t pre_setup_func;
+       tester_data_func_t setup_func;
+       tester_data_func_t test_func;
+       tester_data_func_t teardown_func;
+       tester_data_func_t post_teardown_func;
+       gdouble start_time;
+       gdouble end_time;
+       unsigned int timeout;
+       unsigned int timeout_id;
+       tester_destroy_func_t destroy;
+       void *user_data;
+};
+
+static GMainLoop *main_loop;
+
+static GList *test_list;
+static GList *test_current;
+static GTimer *test_timer;
+
+static gboolean option_version = FALSE;
+static gboolean option_quiet = FALSE;
+static gboolean option_debug = FALSE;
+static gboolean option_list = FALSE;
+static const char *option_prefix = NULL;
+
+static void test_destroy(gpointer data)
+{
+       struct test_case *test = data;
+
+       if (test->timeout_id > 0)
+               g_source_remove(test->timeout_id);
+
+       if (test->destroy)
+               test->destroy(test->user_data);
+
+       g_free(test->name);
+       g_free(test);
+}
+
+void tester_print(const char *format, ...)
+{
+       va_list ap;
+
+       if (tester_use_quiet())
+               return;
+
+       printf("  %s", COLOR_WHITE);
+       va_start(ap, format);
+       vprintf(format, ap);
+       va_end(ap);
+       printf("%s\n", COLOR_OFF);
+}
+
+void tester_warn(const char *format, ...)
+{
+       va_list ap;
+
+       printf("  %s", COLOR_WHITE);
+       va_start(ap, format);
+       vprintf(format, ap);
+       va_end(ap);
+       printf("%s\n", COLOR_OFF);
+}
+
+static void default_pre_setup(const void *test_data)
+{
+       tester_pre_setup_complete();
+}
+
+static void default_setup(const void *test_data)
+{
+       tester_setup_complete();
+}
+
+static void default_teardown(const void *test_data)
+{
+       tester_teardown_complete();
+}
+
+static void default_post_teardown(const void *test_data)
+{
+       tester_post_teardown_complete();
+}
+
+void tester_add_full(const char *name, const void *test_data,
+                               tester_data_func_t pre_setup_func,
+                               tester_data_func_t setup_func,
+                               tester_data_func_t test_func,
+                               tester_data_func_t teardown_func,
+                               tester_data_func_t post_teardown_func,
+                               unsigned int timeout,
+                               void *user_data, tester_destroy_func_t destroy)
+{
+       struct test_case *test;
+
+       if (!test_func)
+               return;
+
+       if (option_prefix && !g_str_has_prefix(name, option_prefix)) {
+               if (destroy)
+                       destroy(user_data);
+               return;
+       }
+
+       if (option_list) {
+               printf("%s\n", name);
+               if (destroy)
+                       destroy(user_data);
+               return;
+       }
+
+       test = g_new0(struct test_case, 1);
+
+       test->name = g_strdup(name);
+       test->result = TEST_RESULT_NOT_RUN;
+       test->stage = TEST_STAGE_INVALID;
+
+       test->test_data = test_data;
+
+       if (pre_setup_func)
+               test->pre_setup_func = pre_setup_func;
+       else
+               test->pre_setup_func = default_pre_setup;
+
+       if (setup_func)
+               test->setup_func = setup_func;
+       else
+               test->setup_func = default_setup;
+
+       test->test_func = test_func;
+
+       if (teardown_func)
+               test->teardown_func = teardown_func;
+       else
+               test->teardown_func = default_teardown;
+
+       if (post_teardown_func)
+               test->post_teardown_func = post_teardown_func;
+       else
+               test->post_teardown_func = default_post_teardown;
+
+       test->timeout = timeout;
+
+       test->destroy = destroy;
+       test->user_data = user_data;
+
+       test_list = g_list_append(test_list, test);
+}
+
+void tester_add(const char *name, const void *test_data,
+                                       tester_data_func_t setup_func,
+                                       tester_data_func_t test_func,
+                                       tester_data_func_t teardown_func)
+{
+       tester_add_full(name, test_data, NULL, setup_func, test_func,
+                                       teardown_func, NULL, 0, NULL, NULL);
+}
+
+void *tester_get_data(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return NULL;
+
+       test = test_current->data;
+
+       return test->user_data;
+}
+
+static void tester_summarize(void)
+{
+       unsigned int not_run = 0, passed = 0, failed = 0;
+       gdouble execution_time;
+       GList *list;
+
+       printf("\n");
+       print_text(COLOR_HIGHLIGHT, "");
+       print_text(COLOR_HIGHLIGHT, "Test Summary");
+       print_text(COLOR_HIGHLIGHT, "------------");
+
+       for (list = g_list_first(test_list); list; list = g_list_next(list)) {
+               struct test_case *test = list->data;
+               gdouble exec_time;
+
+               exec_time = test->end_time - test->start_time;
+
+               switch (test->result) {
+               case TEST_RESULT_NOT_RUN:
+                       print_summary(test->name, COLOR_YELLOW, "Not Run", "");
+                       not_run++;
+                       break;
+               case TEST_RESULT_PASSED:
+                       print_summary(test->name, COLOR_GREEN, "Passed",
+                                               "%8.3f seconds", exec_time);
+                       passed++;
+                       break;
+               case TEST_RESULT_FAILED:
+                       print_summary(test->name, COLOR_RED, "Failed",
+                                               "%8.3f seconds", exec_time);
+                       failed++;
+                       break;
+               case TEST_RESULT_TIMED_OUT:
+                       print_summary(test->name, COLOR_RED, "Timed out",
+                                               "%8.3f seconds", exec_time);
+                       failed++;
+                       break;
+               }
+        }
+
+       printf("\nTotal: %d, "
+               COLOR_GREEN "Passed: %d (%.1f%%)" COLOR_OFF ", "
+               COLOR_RED "Failed: %d" COLOR_OFF ", "
+               COLOR_YELLOW "Not Run: %d" COLOR_OFF "\n",
+                       not_run + passed + failed, passed,
+                       (float) passed * 100 / (not_run + passed + failed),
+                       failed, not_run);
+
+       execution_time = g_timer_elapsed(test_timer, NULL);
+       printf("Overall execution time: %.3g seconds\n", execution_time);
+
+}
+
+static gboolean teardown_callback(gpointer user_data)
+{
+       struct test_case *test = user_data;
+
+       test->stage = TEST_STAGE_TEARDOWN;
+
+       print_progress(test->name, COLOR_MAGENTA, "teardown");
+       test->teardown_func(test->test_data);
+
+       return FALSE;
+}
+
+static gboolean test_timeout(gpointer user_data)
+{
+       struct test_case *test = user_data;
+
+       test->timeout_id = 0;
+
+       if (!test_current)
+               return FALSE;
+
+       test->result = TEST_RESULT_TIMED_OUT;
+       print_progress(test->name, COLOR_RED, "test timed out");
+
+       g_idle_add(teardown_callback, test);
+
+       return FALSE;
+}
+
+static void next_test_case(void)
+{
+       struct test_case *test;
+
+       if (test_current)
+               test_current = g_list_next(test_current);
+       else
+               test_current = test_list;
+
+       if (!test_current) {
+               g_timer_stop(test_timer);
+
+               g_main_loop_quit(main_loop);
+               return;
+       }
+
+       test = test_current->data;
+
+       printf("\n");
+       print_progress(test->name, COLOR_BLACK, "init");
+
+       test->start_time = g_timer_elapsed(test_timer, NULL);
+
+       if (test->timeout > 0)
+               test->timeout_id = g_timeout_add_seconds(test->timeout,
+                                                       test_timeout, test);
+
+       test->stage = TEST_STAGE_PRE_SETUP;
+
+       test->pre_setup_func(test->test_data);
+}
+
+static gboolean setup_callback(gpointer user_data)
+{
+       struct test_case *test = user_data;
+
+       test->stage = TEST_STAGE_SETUP;
+
+       print_progress(test->name, COLOR_BLUE, "setup");
+       test->setup_func(test->test_data);
+
+       return FALSE;
+}
+
+static gboolean run_callback(gpointer user_data)
+{
+       struct test_case *test = user_data;
+
+       test->stage = TEST_STAGE_RUN;
+
+       print_progress(test->name, COLOR_BLACK, "run");
+       test->test_func(test->test_data);
+
+       return FALSE;
+}
+
+static gboolean done_callback(gpointer user_data)
+{
+       struct test_case *test = user_data;
+
+       test->end_time = g_timer_elapsed(test_timer, NULL);
+
+       print_progress(test->name, COLOR_BLACK, "done");
+       next_test_case();
+
+       return FALSE;
+}
+
+void tester_pre_setup_complete(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_PRE_SETUP)
+               return;
+
+       g_idle_add(setup_callback, test);
+}
+
+void tester_pre_setup_failed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_PRE_SETUP)
+               return;
+
+       test->stage = TEST_STAGE_SETUP;
+
+       tester_setup_failed();
+}
+
+void tester_setup_complete(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_SETUP)
+               return;
+
+       print_progress(test->name, COLOR_BLUE, "setup complete");
+
+       g_idle_add(run_callback, test);
+}
+
+void tester_setup_failed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_SETUP)
+               return;
+
+       print_progress(test->name, COLOR_RED, "setup failed");
+
+       g_idle_add(done_callback, test);
+}
+
+void tester_test_passed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_RUN)
+               return;
+
+       if (test->timeout_id > 0) {
+               g_source_remove(test->timeout_id);
+               test->timeout_id = 0;
+       }
+
+       test->result = TEST_RESULT_PASSED;
+       print_progress(test->name, COLOR_GREEN, "test passed");
+
+       g_idle_add(teardown_callback, test);
+}
+
+void tester_test_failed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_RUN)
+               return;
+
+       if (test->timeout_id > 0) {
+               g_source_remove(test->timeout_id);
+               test->timeout_id = 0;
+       }
+
+       test->result = TEST_RESULT_FAILED;
+       print_progress(test->name, COLOR_RED, "test failed");
+
+       g_idle_add(teardown_callback, test);
+}
+
+void tester_teardown_complete(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_TEARDOWN)
+               return;
+
+       test->stage = TEST_STAGE_POST_TEARDOWN;
+
+       test->post_teardown_func(test->test_data);
+}
+
+void tester_teardown_failed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_TEARDOWN)
+               return;
+
+       test->stage = TEST_STAGE_POST_TEARDOWN;
+
+       tester_post_teardown_failed();
+}
+
+void tester_post_teardown_complete(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_POST_TEARDOWN)
+               return;
+
+       print_progress(test->name, COLOR_MAGENTA, "teardown complete");
+
+       g_idle_add(done_callback, test);
+}
+
+void tester_post_teardown_failed(void)
+{
+       struct test_case *test;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       if (test->stage != TEST_STAGE_POST_TEARDOWN)
+               return;
+
+       print_progress(test->name, COLOR_RED, "teardown failed");
+
+       g_idle_add(done_callback, test);
+}
+
+static gboolean start_tester(gpointer user_data)
+{
+       test_timer = g_timer_new();
+
+       next_test_case();
+
+       return FALSE;
+}
+
+struct wait_data {
+       unsigned int seconds;
+       struct test_case *test;
+       tester_wait_func_t func;
+       void *user_data;
+};
+
+static gboolean wait_callback(gpointer user_data)
+{
+       struct wait_data *wait = user_data;
+       struct test_case *test = wait->test;
+
+       wait->seconds--;
+
+       if (wait->seconds > 0) {
+               print_progress(test->name, COLOR_BLACK, "%u seconds left",
+                                                               wait->seconds);
+               return TRUE;
+       }
+
+       print_progress(test->name, COLOR_BLACK, "waiting done");
+
+       wait->func(wait->user_data);
+
+       g_free(wait);
+
+       return FALSE;
+}
+
+void tester_wait(unsigned int seconds, tester_wait_func_t func,
+                                                       void *user_data)
+{
+       struct test_case *test;
+       struct wait_data *wait;
+
+       if (!func || seconds < 1)
+               return;
+
+       if (!test_current)
+               return;
+
+       test = test_current->data;
+
+       print_progress(test->name, COLOR_BLACK, "waiting %u seconds", seconds);
+
+       wait = g_new0(struct wait_data, 1);
+
+       wait->seconds = seconds;
+       wait->test = test;
+       wait->func = func;
+       wait->user_data = user_data;
+
+       g_timeout_add(1000, wait_callback, wait);
+}
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+       case SIGTERM:
+               if (__terminated == 0)
+                       g_main_loop_quit(main_loop);
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+bool tester_use_quiet(void)
+{
+       return option_quiet == TRUE ? true : false;
+}
+
+bool tester_use_debug(void)
+{
+       return option_debug == TRUE ? true : false;
+}
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { "quiet", 'q', 0, G_OPTION_ARG_NONE, &option_quiet,
+                               "Run tests without logging" },
+       { "debug", 'd', 0, G_OPTION_ARG_NONE, &option_debug,
+                               "Run tests with debug output" },
+       { "list", 'l', 0, G_OPTION_ARG_NONE, &option_list,
+                               "Only list the tests to be run" },
+       { "prefix", 'p', 0, G_OPTION_ARG_STRING, &option_prefix,
+                               "Run tests matching provided prefix" },
+       { NULL },
+};
+
+void tester_init(int *argc, char ***argv)
+{
+       GOptionContext *context;
+       GError *error = NULL;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, argc, argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               g_print("%s\n", VERSION);
+               exit(EXIT_SUCCESS);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       test_list = NULL;
+       test_current = NULL;
+}
+
+int tester_run(void)
+{
+       guint signal;
+
+       if (!main_loop)
+               return EXIT_FAILURE;
+
+       if (option_list) {
+               g_main_loop_unref(main_loop);
+               return EXIT_SUCCESS;
+       }
+
+       signal = setup_signalfd();
+
+       g_idle_add(start_tester, NULL);
+       g_main_loop_run(main_loop);
+
+       g_source_remove(signal);
+
+       g_main_loop_unref(main_loop);
+
+       tester_summarize();
+
+       g_list_free_full(test_list, test_destroy);
+
+       return EXIT_SUCCESS;
+}
diff --git a/src/shared/tester.h b/src/shared/tester.h
new file mode 100644 (file)
index 0000000..775ed1e
--- /dev/null
@@ -0,0 +1,74 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#include <stdbool.h>
+
+void tester_init(int *argc, char ***argv);
+int tester_run(void);
+
+bool tester_use_quiet(void);
+bool tester_use_debug(void);
+
+void tester_print(const char *format, ...)
+                               __attribute__((format(printf, 1, 2)));
+void tester_warn(const char *format, ...)
+                               __attribute__((format(printf, 1, 2)));
+
+typedef void (*tester_destroy_func_t)(void *user_data);
+typedef void (*tester_data_func_t)(const void *test_data);
+
+void tester_add_full(const char *name, const void *test_data,
+                               tester_data_func_t pre_setup_func,
+                               tester_data_func_t setup_func,
+                               tester_data_func_t test_func,
+                               tester_data_func_t teardown_func,
+                               tester_data_func_t post_teardown_func,
+                               unsigned int timeout,
+                               void *user_data, tester_destroy_func_t destroy);
+
+void tester_add(const char *name, const void *test_data,
+                                       tester_data_func_t setup_func,
+                                       tester_data_func_t test_func,
+                                       tester_data_func_t teardown_func);
+
+void *tester_get_data(void);
+
+void tester_pre_setup_complete(void);
+void tester_pre_setup_failed(void);
+
+void tester_setup_complete(void);
+void tester_setup_failed(void);
+
+void tester_test_passed(void);
+void tester_test_failed(void);
+
+void tester_teardown_complete(void);
+void tester_teardown_failed(void);
+
+void tester_post_teardown_complete(void);
+void tester_post_teardown_failed(void);
+
+typedef void (*tester_wait_func_t)(void *user_data);
+
+void tester_wait(unsigned int seconds, tester_wait_func_t func,
+                                                       void *user_data);
diff --git a/src/shared/util.c b/src/shared/util.c
new file mode 100644 (file)
index 0000000..5aee69d
--- /dev/null
@@ -0,0 +1,90 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This library is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU Lesser General Public
+ *  License as published by the Free Software Foundation; either
+ *  version 2.1 of the License, or (at your option) any later version.
+ *
+ *  This library is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ *  Lesser General Public License for more details.
+ *
+ *  You should have received a copy of the GNU Lesser General Public
+ *  License along with this library; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <ctype.h>
+#include <stdarg.h>
+
+#include "src/shared/util.h"
+
+void util_debug(util_debug_func_t function, void *user_data,
+                                               const char *format, ...)
+{
+       char str[78];
+       va_list ap;
+
+       if (!function || !format)
+               return;
+
+       va_start(ap, format);
+       vsnprintf(str, sizeof(str), format, ap);
+       va_end(ap);
+
+       function(str, user_data);
+}
+
+void util_hexdump(const char dir, const unsigned char *buf, size_t len,
+                               util_debug_func_t function, void *user_data)
+{
+       static const char hexdigits[] = "0123456789abcdef";
+       char str[68];
+       size_t i;
+
+       if (!function || !len)
+               return;
+
+       str[0] = dir;
+
+       for (i = 0; i < len; i++) {
+               str[((i % 16) * 3) + 1] = ' ';
+               str[((i % 16) * 3) + 2] = hexdigits[buf[i] >> 4];
+               str[((i % 16) * 3) + 3] = hexdigits[buf[i] & 0xf];
+               str[(i % 16) + 51] = isprint(buf[i]) ? buf[i] : '.';
+
+               if ((i + 1) % 16 == 0) {
+                       str[49] = ' ';
+                       str[50] = ' ';
+                       str[67] = '\0';
+                       function(str, user_data);
+                       str[0] = ' ';
+               }
+       }
+
+       if (i % 16 > 0) {
+               size_t j;
+               for (j = (i % 16); j < 16; j++) {
+                       str[(j * 3) + 1] = ' ';
+                       str[(j * 3) + 2] = ' ';
+                       str[(j * 3) + 3] = ' ';
+                       str[j + 51] = ' ';
+               }
+               str[49] = ' ';
+               str[50] = ' ';
+               str[67] = '\0';
+               function(str, user_data);
+       }
+}
similarity index 54%
rename from sbc/sbc_primitives_mmx.h
rename to src/shared/util.h
index e0e728b..88e8954 100644 (file)
@@ -1,11 +1,8 @@
 /*
  *
- *  Bluetooth low-complexity, subband codec (SBC) library
+ *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2008-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2004-2005  Henryk Ploetz <henryk@ploetzli.ch>
- *  Copyright (C) 2005-2006  Brad Midgley <bmidgley@xmission.com>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This library is free software; you can redistribute it and/or
  *
  */
 
-#ifndef __SBC_PRIMITIVES_MMX_H
-#define __SBC_PRIMITIVES_MMX_H
+typedef void (*util_debug_func_t)(const char *str, void *user_data);
 
-#include "sbc_primitives.h"
+void util_debug(util_debug_func_t function, void *user_data,
+                                               const char *format, ...)
+                                       __attribute__((format(printf, 3, 4)));
 
-#if defined(__GNUC__) && (defined(__i386__) || defined(__amd64__)) && \
-               !defined(SBC_HIGH_PRECISION) && (SCALE_OUT_BITS == 15)
-
-#define SBC_BUILD_WITH_MMX_SUPPORT
-
-void sbc_init_primitives_mmx(struct sbc_encoder_state *encoder_state);
-
-#endif
-
-#endif
+void util_hexdump(const char dir, const unsigned char *buf, size_t len,
+                               util_debug_func_t function, void *user_data);
index 17e8001..f7e4db6 100644 (file)
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/uuid.h>
 
+#include "lib/uuid.h"
 #include "textfile.h"
 #include "glib-helper.h"
 #include "storage.h"
 
+/* When all services should trust a remote device */
+#define GLOBAL_TRUST "[all]"
+
 struct match {
        GSList *keys;
        char *pattern;
@@ -62,48 +65,6 @@ static inline int create_filename(char *buf, size_t size,
        return create_name(buf, size, STORAGEDIR, addr, name);
 }
 
-int read_device_alias(const char *src, const char *dst, char *alias, size_t size)
-{
-       char filename[PATH_MAX + 1], *tmp;
-       int err;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases");
-
-       tmp = textfile_get(filename, dst);
-       if (!tmp)
-               return -ENXIO;
-
-       err = snprintf(alias, size, "%s", tmp);
-
-       free(tmp);
-
-       return err < 0 ? -EIO : 0;
-}
-
-int write_device_alias(const char *src, const char *dst, const char *alias)
-{
-       char filename[PATH_MAX + 1];
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "aliases");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, dst, alias);
-}
-
-int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout)
-{
-       char filename[PATH_MAX + 1], str[32];
-
-       snprintf(str, sizeof(str), "%d", timeout);
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "discovto", str);
-}
-
 int read_discoverable_timeout(const char *src, int *timeout)
 {
        char filename[PATH_MAX + 1], *str;
@@ -124,19 +85,6 @@ int read_discoverable_timeout(const char *src, int *timeout)
        return 0;
 }
 
-int write_pairable_timeout(bdaddr_t *bdaddr, int timeout)
-{
-       char filename[PATH_MAX + 1], str[32];
-
-       snprintf(str, sizeof(str), "%d", timeout);
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "pairto", str);
-}
-
 int read_pairable_timeout(const char *src, int *timeout)
 {
        char filename[PATH_MAX + 1], *str;
@@ -157,38 +105,6 @@ int read_pairable_timeout(const char *src, int *timeout)
        return 0;
 }
 
-int write_device_mode(bdaddr_t *bdaddr, const char *mode)
-{
-       char filename[PATH_MAX + 1];
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       if (strcmp(mode, "off") != 0)
-               textfile_put(filename, "onmode", mode);
-
-       return textfile_put(filename, "mode", mode);
-}
-
-int read_device_mode(const char *src, char *mode, int length)
-{
-       char filename[PATH_MAX + 1], *str;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "config");
-
-       str = textfile_get(filename, "mode");
-       if (!str)
-               return -ENOENT;
-
-       strncpy(mode, str, length);
-       mode[length - 1] = '\0';
-
-       free(str);
-
-       return 0;
-}
-
 int read_on_mode(const char *src, char *mode, int length)
 {
        char filename[PATH_MAX + 1], *str;
@@ -207,26 +123,7 @@ int read_on_mode(const char *src, char *mode, int length)
        return 0;
 }
 
-int write_local_name(bdaddr_t *bdaddr, const char *name)
-{
-       char filename[PATH_MAX + 1], str[249];
-       int i;
-
-       memset(str, 0, sizeof(str));
-       for (i = 0; i < 248 && name[i]; i++)
-               if ((unsigned char) name[i] < 32 || name[i] == 127)
-                       str[i] = '.';
-               else
-                       str[i] = name[i];
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "name", str);
-}
-
-int read_local_name(bdaddr_t *bdaddr, char *name)
+int read_local_name(const bdaddr_t *bdaddr, char *name)
 {
        char filename[PATH_MAX + 1], *str;
        int len;
@@ -247,1150 +144,55 @@ int read_local_name(bdaddr_t *bdaddr, char *name)
        return 0;
 }
 
-int write_local_class(bdaddr_t *bdaddr, uint8_t *class)
-{
-       char filename[PATH_MAX + 1], str[9];
-
-       sprintf(str, "0x%2.2x%2.2x%2.2x", class[2], class[1], class[0]);
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "class", str);
-}
-
-int read_local_class(bdaddr_t *bdaddr, uint8_t *class)
-{
-       char filename[PATH_MAX + 1], tmp[3], *str;
-       int i;
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       str = textfile_get(filename, "class");
-       if (!str)
-               return -ENOENT;
-
-       memset(tmp, 0, sizeof(tmp));
-       for (i = 0; i < 3; i++) {
-               memcpy(tmp, str + (i * 2) + 2, 2);
-               class[2 - i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
-
-       free(str);
-
-       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];
-
-       create_filename(filename, PATH_MAX, local, "classes");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(peer, addr);
-       sprintf(str, "0x%6.6x", class);
-
-       return textfile_put(filename, addr, str);
-}
-
-int read_remote_class(bdaddr_t *local, bdaddr_t *peer, uint32_t *class)
-{
-       char filename[PATH_MAX + 1], addr[18], *str;
-
-       create_filename(filename, PATH_MAX, local, "classes");
-
-       ba2str(peer, addr);
-
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
-
-       if (sscanf(str, "%x", class) != 1) {
-               free(str);
-               return -ENOENT;
-       }
-
-       free(str);
-
-       return 0;
-}
-
-int write_device_name(bdaddr_t *local, bdaddr_t *peer, char *name)
-{
-       char filename[PATH_MAX + 1], addr[18], str[HCI_MAX_NAME_LENGTH + 1];
-       int i;
-
-       memset(str, 0, sizeof(str));
-       for (i = 0; i < HCI_MAX_NAME_LENGTH && name[i]; i++)
-               if ((unsigned char) name[i] < 32 || name[i] == 127)
-                       str[i] = '.';
-               else
-                       str[i] = name[i];
-
-       create_filename(filename, PATH_MAX, local, "names");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(peer, addr);
-       return textfile_put(filename, addr, str);
-}
-
-int read_device_name(const char *src, const char *dst, char *name)
-{
-       char filename[PATH_MAX + 1], *str;
-       int len;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "names");
-
-       str = textfile_get(filename, dst);
-       if (!str)
-               return -ENOENT;
-
-       len = strlen(str);
-       if (len > HCI_MAX_NAME_LENGTH)
-               str[HCI_MAX_NAME_LENGTH] = '\0';
-       strcpy(name, str);
-
-       free(str);
-
-       return 0;
-}
-
-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 < data_len; i++)
-               sprintf(str + (i * 2), "%2.2X", data[i]);
-
-       create_filename(filename, PATH_MAX, local, "eir");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(peer, addr);
-       return textfile_put(filename, addr, str);
-}
-
-int read_remote_eir(bdaddr_t *local, bdaddr_t *peer, uint8_t *data)
+sdp_record_t *record_from_string(const char *str)
 {
-       char filename[PATH_MAX + 1], addr[18], *str;
-       int i;
-
-       create_filename(filename, PATH_MAX, local, "eir");
-
-       ba2str(peer, addr);
-
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
+       sdp_record_t *rec;
+       int size, i, len;
+       uint8_t *pdata;
+       char tmp[3];
 
-       if (!data) {
-               free(str);
-               return 0;
-       }
+       size = strlen(str)/2;
+       pdata = g_malloc0(size);
 
-       if (strlen(str) < 480) {
-               free(str);
-               return -EIO;
+       tmp[2] = 0;
+       for (i = 0; i < size; i++) {
+               memcpy(tmp, str + (i * 2), 2);
+               pdata[i] = (uint8_t) strtol(tmp, NULL, 16);
        }
 
-       for (i = 0; i < HCI_MAX_EIR_LENGTH; i++)
-               sscanf(str + (i * 2), "%02hhX", &data[i]);
-
-       free(str);
-
-       return 0;
-}
-
-int write_version_info(bdaddr_t *local, bdaddr_t *peer, uint16_t manufacturer,
-                                       uint8_t lmp_ver, uint16_t lmp_subver)
-{
-       char filename[PATH_MAX + 1], addr[18], str[16];
-
-       memset(str, 0, sizeof(str));
-       sprintf(str, "%d %d %d", manufacturer, lmp_ver, lmp_subver);
-
-       create_filename(filename, PATH_MAX, local, "manufacturers");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       rec = sdp_extract_pdu(pdata, size, &len);
+       g_free(pdata);
 
-       ba2str(peer, addr);
-       return textfile_put(filename, addr, str);
+       return rec;
 }
 
-int write_features_info(bdaddr_t *local, bdaddr_t *peer,
-                               unsigned char *page1, unsigned char *page2)
+sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid)
 {
-       char filename[PATH_MAX + 1], addr[18];
-       char str[] = "0000000000000000 0000000000000000";
-       char *old_value;
-       int i;
-
-       ba2str(peer, addr);
-
-       create_filename(filename, PATH_MAX, local, "features");
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       old_value = textfile_get(filename, addr);
-
-       if (page1)
-               for (i = 0; i < 8; i++)
-                       sprintf(str + (i * 2), "%2.2X", page1[i]);
-       else if (old_value && strlen(old_value) >= 16)
-               strncpy(str, old_value, 16);
+       sdp_list_t *seq;
 
-       if (page2)
-               for (i = 0; i < 8; i++)
-                       sprintf(str + 17 + (i * 2), "%2.2X", page2[i]);
-       else if (old_value && strlen(old_value) >= 33)
-               strncpy(str + 17, old_value + 17, 16);
+       for (seq = recs; seq; seq = seq->next) {
+               sdp_record_t *rec = (sdp_record_t *) seq->data;
+               sdp_list_t *svcclass = NULL;
+               char *uuid_str;
 
-       free(old_value);
+               if (sdp_get_service_classes(rec, &svcclass) < 0)
+                       continue;
 
-       return textfile_put(filename, addr, str);
-}
+               /* Extract the uuid */
+               uuid_str = bt_uuid2string(svcclass->data);
+               if (!uuid_str) {
+                       sdp_list_free(svcclass, free);
+                       continue;
+               }
 
-static int decode_bytes(const char *str, unsigned char *bytes, size_t len)
-{
-       unsigned int i;
+               if (!strcasecmp(uuid_str, uuid)) {
+                       sdp_list_free(svcclass, free);
+                       free(uuid_str);
+                       return rec;
+               }
 
-       for (i = 0; i < len; i++) {
-               if (sscanf(str + (i * 2), "%02hhX", &bytes[i]) != 1)
-                       return -EINVAL;
-       }
-
-       return 0;
-}
-
-int read_remote_features(bdaddr_t *local, bdaddr_t *peer,
-                               unsigned char *page1, unsigned char *page2)
-{
-       char filename[PATH_MAX + 1], addr[18], *str;
-       size_t len;
-       int err;
-
-       if (page1 == NULL && page2 == NULL)
-               return -EINVAL;
-
-       create_filename(filename, PATH_MAX, local, "features");
-
-       ba2str(peer, addr);
-
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
-
-       len = strlen(str);
-
-       err = -ENOENT;
-
-       if (page1 && len >= 16)
-               err = decode_bytes(str, page1, 8);
-
-       if (page2 && len >= 33)
-               err = decode_bytes(str + 17, page2, 8);
-
-       free(str);
-
-       return err;
-}
-
-int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
-{
-       char filename[PATH_MAX + 1], addr[18], str[24];
-
-       memset(str, 0, sizeof(str));
-       strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
-
-       create_filename(filename, PATH_MAX, local, "lastseen");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(peer, addr);
-       return textfile_put(filename, addr, str);
-}
-
-int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm)
-{
-       char filename[PATH_MAX + 1], addr[18], str[24];
-
-       memset(str, 0, sizeof(str));
-       strftime(str, sizeof(str), "%Y-%m-%d %H:%M:%S %Z", tm);
-
-       create_filename(filename, PATH_MAX, local, "lastused");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(peer, addr);
-       return textfile_put(filename, addr, str);
-}
-
-int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length)
-{
-       char filename[PATH_MAX + 1], addr[18], str[38];
-       int i;
-
-       memset(str, 0, sizeof(str));
-       for (i = 0; i < 16; i++)
-               sprintf(str + (i * 2), "%2.2X", key[i]);
-       sprintf(str + 32, " %d %d", type, length);
-
-       create_filename(filename, PATH_MAX, local, "linkkeys");
-
-       create_file(filename, S_IRUSR | S_IWUSR);
-
-       ba2str(peer, addr);
-
-       if (length < 0) {
-               char *tmp = textfile_get(filename, addr);
-               if (tmp) {
-                       if (strlen(tmp) > 34)
-                               memcpy(str + 34, tmp + 34, 3);
-                       free(tmp);
-               }
-       }
-
-       return textfile_put(filename, addr, str);
-}
-
-int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type)
-{
-       char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
-       int i;
-
-       create_filename(filename, PATH_MAX, local, "linkkeys");
-
-       ba2str(peer, addr);
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
-
-       if (!key) {
-               free(str);
-               return 0;
-       }
-
-       memset(tmp, 0, sizeof(tmp));
-       for (i = 0; i < 16; i++) {
-               memcpy(tmp, str + (i * 2), 2);
-               key[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
-
-       if (type) {
-               memcpy(tmp, str + 33, 2);
-               *type = (uint8_t) strtol(tmp, NULL, 10);
-       }
-
-       free(str);
-
-       return 0;
-}
-
-ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin)
-{
-       char filename[PATH_MAX + 1], addr[18], *str;
-       ssize_t len;
-
-       create_filename(filename, PATH_MAX, local, "pincodes");
-
-       ba2str(peer, addr);
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -ENOENT;
-
-       strncpy(pin, str, 16);
-       len = strlen(pin);
-
-       free(str);
-
-       return len;
-}
-
-static GSList *service_string_to_list(char *services)
-{
-       GSList *l = NULL;
-       char *start = services;
-       int i, finished = 0;
-
-       for (i = 0; !finished; i++) {
-               if (services[i] == '\0')
-                       finished = 1;
-
-               if (services[i] == ' ' || services[i] == '\0') {
-                       services[i] = '\0';
-                       l = g_slist_append(l, start);
-                       start = services + i + 1;
-               }
-       }
-
-       return l;
-}
-
-static char *service_list_to_string(GSList *services)
-{
-       char str[1024];
-       int len = 0;
-
-       if (!services)
-               return g_strdup("");
-
-       memset(str, 0, sizeof(str));
-
-       while (services) {
-               int ret;
-               char *ident = services->data;
-
-               ret = snprintf(str + len, sizeof(str) - len - 1, "%s%s",
-                               ident, services->next ? " " : "");
-
-               if (ret > 0)
-                       len += ret;
-
-               services = services->next;
-       }
-
-       return g_strdup(str);
-}
-
-int write_trust(const char *src, const char *addr, const char *service,
-               gboolean trust)
-{
-       char filename[PATH_MAX + 1], *str;
-       GSList *services = NULL, *match;
-       gboolean trusted;
-       int ret;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "trusts");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       str = textfile_caseget(filename, addr);
-       if (str)
-               services = service_string_to_list(str);
-
-       match = g_slist_find_custom(services, service, (GCompareFunc) strcmp);
-       trusted = match ? TRUE : FALSE;
-
-       /* If the old setting is the same as the requested one, we're done */
-       if (trusted == trust) {
-               g_slist_free(services);
-               free(str);
-               return 0;
-       }
-
-       if (trust)
-               services = g_slist_append(services, (void *) service);
-       else
-               services = g_slist_remove(services, match->data);
-
-       /* Remove the entry if the last trusted service was removed */
-       if (!trust && !services)
-               ret = textfile_casedel(filename, addr);
-       else {
-               char *new_str = service_list_to_string(services);
-               ret = textfile_caseput(filename, addr, new_str);
-               g_free(new_str);
-       }
-
-       g_slist_free(services);
-
-       free(str);
-
-       return ret;
-}
-
-gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service)
-{
-       char filename[PATH_MAX + 1], *str;
-       GSList *services;
-       gboolean ret;
-
-       create_filename(filename, PATH_MAX, local, "trusts");
-
-       str = textfile_caseget(filename, addr);
-       if (!str)
-               return FALSE;
-
-       services = service_string_to_list(str);
-
-       if (g_slist_find_custom(services, service, (GCompareFunc) strcmp))
-               ret = TRUE;
-       else
-               ret = FALSE;
-
-       g_slist_free(services);
-       free(str);
-
-       return ret;
-}
-
-int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles)
-{
-       char filename[PATH_MAX + 1], addr[18];
-
-       if (!profiles)
-               return -EINVAL;
-
-       create_filename(filename, PATH_MAX, src, "profiles");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(dst, addr);
-       return textfile_put(filename, addr, profiles);
-}
-
-int delete_entry(bdaddr_t *src, const char *storage, const char *key)
-{
-       char filename[PATH_MAX + 1];
-
-       create_filename(filename, PATH_MAX, src, storage);
-
-       return textfile_del(filename, key);
-}
-
-int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec)
-{
-       char filename[PATH_MAX + 1], key[28];
-       sdp_buf_t buf;
-       int err, size, i;
-       char *str;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       snprintf(key, sizeof(key), "%17s#%08X", dst, rec->handle);
-
-       if (sdp_gen_record_pdu(rec, &buf) < 0)
-               return -1;
-
-       size = buf.data_size;
-
-       str = g_malloc0(size*2+1);
-
-       for (i = 0; i < size; i++)
-               sprintf(str + (i * 2), "%02X", buf.data[i]);
-
-       err = textfile_put(filename, key, str);
-
-       free(buf.data);
-       g_free(str);
-
-       return err;
-}
-
-sdp_record_t *record_from_string(const gchar *str)
-{
-       sdp_record_t *rec;
-       int size, i, len;
-       uint8_t *pdata;
-       char tmp[3];
-
-       size = strlen(str)/2;
-       pdata = g_malloc0(size);
-
-       tmp[2] = 0;
-       for (i = 0; i < size; i++) {
-               memcpy(tmp, str + (i * 2), 2);
-               pdata[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
-
-       rec = sdp_extract_pdu(pdata, size, &len);
-       g_free(pdata);
-
-       return rec;
-}
-
-
-sdp_record_t *fetch_record(const gchar *src, const gchar *dst,
-                                               const uint32_t handle)
-{
-       char filename[PATH_MAX + 1], key[28], *str;
-       sdp_record_t *rec;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
-
-       snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
-
-       str = textfile_get(filename, key);
-       if (!str)
-               return NULL;
-
-       rec = record_from_string(str);
-       free(str);
-
-       return rec;
-}
-
-int delete_record(const gchar *src, const gchar *dst, const uint32_t handle)
-{
-       char filename[PATH_MAX + 1], key[28];
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "sdp");
-
-       snprintf(key, sizeof(key), "%17s#%08X", dst, handle);
-
-       return textfile_del(filename, key);
-}
-
-struct record_list {
-       sdp_list_t *recs;
-       const gchar *addr;
-};
-
-static void create_stored_records_from_keys(char *key, char *value,
-                                                       void *user_data)
-{
-       struct record_list *rec_list = user_data;
-       const gchar *addr = rec_list->addr;
-       sdp_record_t *rec;
-
-       if (strncmp(key, addr, 17))
-               return;
-
-       rec = record_from_string(value);
-
-       rec_list->recs = sdp_list_append(rec_list->recs, rec);
-}
-
-void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       sdp_list_t *records, *seq;
-       char srcaddr[18], dstaddr[18];
-
-       ba2str(src, srcaddr);
-       ba2str(dst, dstaddr);
-
-       records = read_records(src, dst);
-
-       for (seq = records; seq; seq = seq->next) {
-               sdp_record_t *rec = seq->data;
-               delete_record(srcaddr, dstaddr, rec->handle);
-       }
-
-       if (records)
-               sdp_list_free(records, (sdp_free_func_t) sdp_record_free);
-}
-
-sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst)
-{
-       char filename[PATH_MAX + 1];
-       struct record_list rec_list;
-       char srcaddr[18], dstaddr[18];
-
-       ba2str(src, srcaddr);
-       ba2str(dst, dstaddr);
-
-       rec_list.addr = dstaddr;
-       rec_list.recs = NULL;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, srcaddr, "sdp");
-       textfile_foreach(filename, create_stored_records_from_keys, &rec_list);
-
-       return rec_list.recs;
-}
-
-sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid)
-{
-       sdp_list_t *seq;
-
-       for (seq = recs; seq; seq = seq->next) {
-               sdp_record_t *rec = (sdp_record_t *) seq->data;
-               sdp_list_t *svcclass = NULL;
-               char *uuid_str;
-
-               if (sdp_get_service_classes(rec, &svcclass) < 0)
-                       continue;
-
-               /* Extract the uuid */
-               uuid_str = bt_uuid2string(svcclass->data);
-               if (!uuid_str)
-                       continue;
-
-               if (!strcasecmp(uuid_str, uuid)) {
-                       sdp_list_free(svcclass, free);
-                       free(uuid_str);
-                       return rec;
-               }
-
-               sdp_list_free(svcclass, free);
-               free(uuid_str);
+               sdp_list_free(svcclass, free);
+               free(uuid_str);
        }
        return NULL;
 }
-
-int store_device_id(const gchar *src, const gchar *dst,
-                               const uint16_t source, const uint16_t vendor,
-                               const uint16_t product, const uint16_t version)
-{
-       char filename[PATH_MAX + 1], str[20];
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       snprintf(str, sizeof(str), "%04X %04X %04X %04X", source,
-                                               vendor, product, version);
-
-       return textfile_put(filename, dst, str);
-}
-
-static int read_device_id_from_did(const gchar *src, const gchar *dst,
-                                       uint16_t *source, uint16_t *vendor,
-                                       uint16_t *product, uint16_t *version)
-{
-       char filename[PATH_MAX + 1];
-       char *str, *vendor_str, *product_str, *version_str;
-
-       create_name(filename, PATH_MAX, STORAGEDIR, src, "did");
-
-       str = textfile_get(filename, dst);
-       if (!str)
-               return -ENOENT;
-
-       vendor_str = strchr(str, ' ');
-       if (!vendor_str) {
-               free(str);
-               return -ENOENT;
-       }
-       *(vendor_str++) = 0;
-
-       product_str = strchr(vendor_str, ' ');
-       if (!product_str) {
-               free(str);
-               return -ENOENT;
-       }
-       *(product_str++) = 0;
-
-       version_str = strchr(product_str, ' ');
-       if (!version_str) {
-               free(str);
-               return -ENOENT;
-       }
-       *(version_str++) = 0;
-
-       if (source)
-               *source = (uint16_t) strtol(str, NULL, 16);
-       if (vendor)
-               *vendor = (uint16_t) strtol(vendor_str, NULL, 16);
-       if (product)
-               *product = (uint16_t) strtol(product_str, NULL, 16);
-       if (version)
-               *version = (uint16_t) strtol(version_str, NULL, 16);
-
-       free(str);
-
-       return 0;
-}
-
-int read_device_id(const gchar *srcaddr, const gchar *dstaddr,
-                                       uint16_t *source, uint16_t *vendor,
-                                       uint16_t *product, uint16_t *version)
-{
-       uint16_t lsource, lvendor, lproduct, lversion;
-       sdp_list_t *recs;
-       sdp_record_t *rec;
-       bdaddr_t src, dst;
-       int err;
-
-       err = read_device_id_from_did(srcaddr, dstaddr, &lsource,
-                                               vendor, product, version);
-       if (!err) {
-               if (lsource == 0xffff)
-                       err = -ENOENT;
-
-               return err;
-       }
-
-       str2ba(srcaddr, &src);
-       str2ba(dstaddr, &dst);
-
-       recs = read_records(&src, &dst);
-       rec = find_record_in_list(recs, PNP_UUID);
-
-       if (rec) {
-               sdp_data_t *pdlist;
-
-               pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID_SOURCE);
-               lsource = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               pdlist = sdp_data_get(rec, SDP_ATTR_VENDOR_ID);
-               lvendor = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               pdlist = sdp_data_get(rec, SDP_ATTR_PRODUCT_ID);
-               lproduct = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               pdlist = sdp_data_get(rec, SDP_ATTR_VERSION);
-               lversion = pdlist ? pdlist->val.uint16 : 0x0000;
-
-               err = 0;
-       }
-
-       sdp_list_free(recs, (sdp_free_func_t)sdp_record_free);
-
-       if (err) {
-               /* FIXME: We should try EIR data if we have it, too */
-
-               /* If we don't have the data, we don't want to go through the
-                * above search every time. */
-               lsource = 0xffff;
-               lvendor = 0x0000;
-               lproduct = 0x0000;
-               lversion = 0x0000;
-       }
-
-       store_device_id(srcaddr, dstaddr, lsource, lvendor, lproduct, lversion);
-
-       if (err)
-               return err;
-
-       if (source)
-               *source = lsource;
-       if (vendor)
-               *vendor = lvendor;
-       if (product)
-               *product = lproduct;
-       if (version)
-               *version = lversion;
-
-       return 0;
-}
-
-int write_device_pairable(bdaddr_t *bdaddr, gboolean mode)
-{
-       char filename[PATH_MAX + 1];
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       return textfile_put(filename, "pairable", mode ? "yes" : "no");
-}
-
-int read_device_pairable(bdaddr_t *bdaddr, gboolean *mode)
-{
-       char filename[PATH_MAX + 1], *str;
-
-       create_filename(filename, PATH_MAX, bdaddr, "config");
-
-       str = textfile_get(filename, "pairable");
-       if (!str)
-               return -ENOENT;
-
-       *mode = strcmp(str, "yes") == 0 ? TRUE : FALSE;
-
-       free(str);
-
-       return 0;
-}
-
-gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote)
-{
-       char filename[PATH_MAX + 1], *str, addr[18];
-
-       create_filename(filename, PATH_MAX, local, "blocked");
-
-       ba2str(remote, addr);
-
-       str = textfile_caseget(filename, addr);
-       if (!str)
-               return FALSE;
-
-       free(str);
-
-       return TRUE;
-}
-
-int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
-                                                       gboolean blocked)
-{
-       char filename[PATH_MAX + 1], addr[18];
-
-       create_filename(filename, PATH_MAX, local, "blocked");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(remote, addr);
-
-       if (blocked == FALSE)
-               return textfile_casedel(filename, addr);
-
-       return textfile_caseput(filename, addr, "");
-}
-
-int write_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
-                         uint8_t bdaddr_type, const char *services)
-{
-       char filename[PATH_MAX + 1], key[20];
-
-       create_filename(filename, PATH_MAX, sba, "primaries");
-
-       create_file(filename, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-
-       ba2str(dba, key);
-       sprintf(&key[17], "#%hhu", bdaddr_type);
-
-       return textfile_put(filename, key, services);
-}
-
-static void filter_keys(char *key, char *value, void *data)
-{
-       struct match *match = data;
-
-       if (strncasecmp(key, match->pattern, strlen(match->pattern)) == 0)
-               match->keys = g_slist_append(match->keys, g_strdup(key));
-}
-
-static void delete_by_pattern(const char *filename, char *pattern)
-{
-       struct match match;
-       GSList *l;
-       int err;
-
-       memset(&match, 0, sizeof(match));
-       match.pattern = pattern;
-
-       err = textfile_foreach(filename, filter_keys, &match);
-       if (err < 0)
-               goto done;
-
-       for (l = match.keys; l; l = l->next) {
-               const char *key = l->data;
-               textfile_del(filename, key);
-       }
-
-done:
-       g_slist_free_full(match.keys, g_free);
-}
-
-int delete_device_service(const bdaddr_t *sba, const bdaddr_t *dba,
-                                               uint8_t bdaddr_type)
-{
-       char filename[PATH_MAX + 1], key[20];
-
-       memset(key, 0, sizeof(key));
-
-       ba2str(dba, key);
-       sprintf(&key[17], "#%hhu", bdaddr_type);
-
-       /* 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 key */
-       create_filename(filename, PATH_MAX, sba, "attributes");
-       delete_by_pattern(filename, key);
-
-       /* Deleting all CCC values of a given key */
-       create_filename(filename, PATH_MAX, sba, "ccc");
-       delete_by_pattern(filename, key);
-
-       create_filename(filename, PATH_MAX, sba, "primaries");
-
-       return textfile_del(filename, key);
-}
-
-char *read_device_services(const bdaddr_t *sba, const bdaddr_t *dba,
-                                                       uint8_t bdaddr_type)
-{
-       char filename[PATH_MAX + 1], key[20];
-
-       create_filename(filename, PATH_MAX, sba, "primaries");
-
-       ba2str(dba, key);
-       sprintf(&key[17], "#%hhu", bdaddr_type);
-
-       return textfile_caseget(filename, key);
-}
-
-int write_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint8_t bdaddr_type, uint16_t handle,
-                                                             const char *chars)
-{
-       char filename[PATH_MAX + 1], addr[18], key[25];
-
-       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#%hhu#%04X", addr, bdaddr_type, handle);
-
-       return textfile_put(filename, key, chars);
-}
-
-char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint8_t bdaddr_type, uint16_t handle)
-{
-       char filename[PATH_MAX + 1], addr[18], key[25];
-
-       create_filename(filename, PATH_MAX, sba, "characteristics");
-
-       ba2str(dba, addr);
-       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,
-                               uint8_t bdaddr_type, uint16_t handle,
-                                                       const char *chars)
-{
-       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#%hhu#%04X", addr, bdaddr_type, handle);
-
-       return textfile_put(filename, key, chars);
-}
-
-int read_device_attributes(const bdaddr_t *sba, textfile_cb func, void *data)
-{
-       char filename[PATH_MAX + 1];
-
-       create_filename(filename, PATH_MAX, sba, "attributes");
-
-       return textfile_foreach(filename, func, data);
-}
-
-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[25];
-       char *str;
-       unsigned int config;
-       int err = 0;
-
-       create_filename(filename, PATH_MAX, local, "ccc");
-
-       ba2str(peer, addr);
-       snprintf(key, sizeof(key), "%17s#%hhu#%04X", addr, bdaddr_type, handle);
-
-       str = textfile_caseget(filename, key);
-       if (str == NULL)
-               return -ENOENT;
-
-       if (sscanf(str, "%04X", &config) != 1)
-               err = -ENOENT;
-       else
-               *value = config;
-
-       free(str);
-
-       return err;
-}
-
-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[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(config, sizeof(config), "%04X", value);
-
-       return textfile_put(filename, key, config);
-}
-
-void delete_device_ccc(bdaddr_t *local, bdaddr_t *peer)
-{
-       char filename[PATH_MAX + 1], addr[18];
-
-       ba2str(peer, addr);
-
-       /* Deleting all CCC values of a given address */
-       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 cc00e97..4c5ab50 100644 (file)
 
 #include "textfile.h"
 
-int read_device_alias(const char *src, const char *dst, char *alias, size_t size);
-int write_device_alias(const char *src, const char *dst, const char *alias);
-int write_discoverable_timeout(bdaddr_t *bdaddr, int timeout);
 int read_discoverable_timeout(const char *src, int *timeout);
-int write_pairable_timeout(bdaddr_t *bdaddr, int timeout);
 int read_pairable_timeout(const char *src, int *timeout);
-int write_device_mode(bdaddr_t *bdaddr, const char *mode);
-int read_device_mode(const char *src, char *mode, int length);
 int read_on_mode(const char *src, char *mode, int length);
-int write_local_name(bdaddr_t *bdaddr, 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,
-                                                       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);
-int read_remote_features(bdaddr_t *local, bdaddr_t *peer, unsigned char *page1, unsigned char *page2);
-int write_lastseen_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
-int write_lastused_info(bdaddr_t *local, bdaddr_t *peer, struct tm *tm);
-int write_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t type, int length);
-int read_link_key(bdaddr_t *local, bdaddr_t *peer, unsigned char *key, uint8_t *type);
-ssize_t read_pin_code(bdaddr_t *local, bdaddr_t *peer, char *pin);
-gboolean read_trust(const bdaddr_t *local, const char *addr, const char *service);
-int write_trust(const char *src, const char *addr, const char *service, gboolean trust);
-int write_device_profiles(bdaddr_t *src, bdaddr_t *dst, const char *profiles);
-int delete_entry(bdaddr_t *src, const char *storage, const char *key);
-int store_record(const gchar *src, const gchar *dst, sdp_record_t *rec);
-sdp_record_t *record_from_string(const gchar *str);
-sdp_record_t *fetch_record(const gchar *src, const gchar *dst, const uint32_t handle);
-int delete_record(const gchar *src, const gchar *dst, const uint32_t handle);
-void delete_all_records(const bdaddr_t *src, const bdaddr_t *dst);
-sdp_list_t *read_records(const bdaddr_t *src, const bdaddr_t *dst);
+int read_local_name(const bdaddr_t *bdaddr, char *name);
+sdp_record_t *record_from_string(const char *str);
 sdp_record_t *find_record_in_list(sdp_list_t *recs, const char *uuid);
-int store_device_id(const gchar *src, const gchar *dst,
-                               const uint16_t source, const uint16_t vendor,
-                               const uint16_t product, const uint16_t version);
-int read_device_id(const gchar *src, const gchar *dst,
-                                       uint16_t *source, uint16_t *vendor,
-                                       uint16_t *product, uint16_t *version);
-int write_device_pairable(bdaddr_t *local, gboolean mode);
-int read_device_pairable(bdaddr_t *local, gboolean *mode);
-gboolean read_blocked(const bdaddr_t *local, const bdaddr_t *remote);
-int write_blocked(const bdaddr_t *local, const bdaddr_t *remote,
-                                                       gboolean blocked);
-int write_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,
-                                       uint8_t bdaddr_type, uint16_t handle,
-                                                            const char *chars);
-char *read_device_characteristics(const bdaddr_t *sba, const bdaddr_t *dba,
-                                       uint8_t bdaddr_type, uint16_t handle);
-int write_device_attribute(const bdaddr_t *sba, const bdaddr_t *dba,
-                               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, 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);
-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);
diff --git a/src/systemd.c b/src/systemd.c
new file mode 100644 (file)
index 0000000..f0985d1
--- /dev/null
@@ -0,0 +1,106 @@
+/*
+ *
+ *  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 <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stddef.h>
+#include <sys/socket.h>
+#include <sys/un.h>
+
+#include "systemd.h"
+
+int sd_listen_fds(int unset_environment)
+{
+       return 0;
+}
+
+int sd_notify(int unset_environment, const char *state)
+{
+       const char *sock;
+       struct sockaddr_un addr;
+       struct msghdr msghdr;
+       struct iovec iovec;
+       int fd, err;
+
+       if (!state) {
+               err = -EINVAL;
+               goto done;
+       }
+
+       sock = getenv("NOTIFY_SOCKET");
+       if (!sock)
+               return 0;
+
+       /* check for abstract socket or absolute path */
+       if (sock[0] != '@' && sock[0] != '/') {
+               err = -EINVAL;
+               goto done;
+       }
+
+       fd = socket(AF_UNIX, SOCK_DGRAM | SOCK_CLOEXEC, 0);
+       if (fd < 0) {
+               err = -errno;
+               goto done;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sun_family = AF_UNIX;
+       strncpy(addr.sun_path, sock, sizeof(addr.sun_path));
+
+       if (addr.sun_path[0] == '@')
+               addr.sun_path[0] = '\0';
+
+       memset(&iovec, 0, sizeof(iovec));
+       iovec.iov_base = (char *) state;
+       iovec.iov_len = strlen(state);
+
+       memset(&msghdr, 0, sizeof(msghdr));
+       msghdr.msg_name = &addr;
+       msghdr.msg_namelen = offsetof(struct sockaddr_un, sun_path) +
+                                                               strlen(sock);
+
+       if (msghdr.msg_namelen > sizeof(struct sockaddr_un))
+               msghdr.msg_namelen = sizeof(struct sockaddr_un);
+
+       msghdr.msg_iov = &iovec;
+       msghdr.msg_iovlen = 1;
+
+       if (sendmsg(fd, &msghdr, MSG_NOSIGNAL) < 0)
+               err = -errno;
+       else
+               err = 1;
+
+       close(fd);
+
+done:
+       if (unset_environment)
+               unsetenv("NOTIFY_SOCKET");
+
+       return err;
+}
similarity index 80%
rename from alert/server.h
rename to src/systemd.h
index e59bdb1..0ef7c82 100644 (file)
@@ -2,8 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2012  Intel Corporation. All rights reserved.
  *
  *
  *  This program is free software; you can redistribute it and/or modify
@@ -22,5 +21,8 @@
  *
  */
 
-int alert_server_init(void);
-void alert_server_exit(void);
+#define SD_LISTEN_FDS_START 3
+
+int sd_listen_fds(int unset_environment);
+
+int sd_notify(int unset_environment, const char *state);
index 9d88fbc..7267f3a 100644 (file)
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <ctype.h>
@@ -40,7 +39,7 @@
 
 #include "textfile.h"
 
-int create_dirs(const char *filename, const mode_t mode)
+static int create_dirs(const char *filename, const mode_t mode)
 {
        struct stat st;
        char dir[PATH_MAX + 1], *prev, *next;
@@ -78,9 +77,7 @@ int create_file(const char *filename, const mode_t mode)
 {
        int fd;
 
-       umask(S_IWGRP | S_IWOTH);
-       create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR |
-                                       S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+       create_dirs(filename, S_IRUSR | S_IWUSR | S_IXUSR);
 
        fd = open(filename, O_RDWR | O_CREAT, mode);
        if (fd < 0)
@@ -104,7 +101,7 @@ static inline char *find_key(char *map, size_t size, const char *key, size_t len
        while (ptrlen > len + 1) {
                int cmp = (icase) ? strncasecmp(ptr, key, len) : strncmp(ptr, key, len);
                if (cmp == 0) {
-                       if (ptr == map)
+                       if (ptr == map && *(ptr + len) == ' ')
                                return ptr;
 
                        if ((*(ptr - 1) == '\r' || *(ptr - 1) == '\n') &&
@@ -338,7 +335,7 @@ static char *read_key(const char *pathname, const char *key, int icase)
                goto unmap;
        }
 
-       end = strnpbrk(off, size - (map - off), "\r\n");
+       end = strnpbrk(off, size - (off - map), "\r\n");
        if (!end) {
                err = -EILSEQ;
                goto unmap;
@@ -371,31 +368,16 @@ int textfile_put(const char *pathname, const char *key, const char *value)
        return write_key(pathname, key, value, 0);
 }
 
-int textfile_caseput(const char *pathname, const char *key, const char *value)
-{
-       return write_key(pathname, key, value, 1);
-}
-
 int textfile_del(const char *pathname, const char *key)
 {
        return write_key(pathname, key, NULL, 0);
 }
 
-int textfile_casedel(const char *pathname, const char *key)
-{
-       return write_key(pathname, key, NULL, 1);
-}
-
 char *textfile_get(const char *pathname, const char *key)
 {
        return read_key(pathname, key, 0);
 }
 
-char *textfile_caseget(const char *pathname, const char *key)
-{
-       return read_key(pathname, key, 1);
-}
-
 int textfile_foreach(const char *pathname, textfile_cb func, void *data)
 {
        struct stat st;
index dc5fc2b..b779bd2 100644 (file)
 #ifndef __TEXTFILE_H
 #define __TEXTFILE_H
 
-int create_dirs(const char *filename, const mode_t mode);
 int create_file(const char *filename, const mode_t mode);
 int create_name(char *buf, size_t size, const char *path,
                                const char *address, const char *name);
 
 int textfile_put(const char *pathname, const char *key, const char *value);
-int textfile_caseput(const char *pathname, const char *key, const char *value);
 int textfile_del(const char *pathname, const char *key);
-int textfile_casedel(const char *pathname, const char *key);
 char *textfile_get(const char *pathname, const char *key);
-char *textfile_caseget(const char *pathname, const char *key);
 
 typedef void (*textfile_cb) (char *key, char *value, void *data);
 
diff --git a/test/agent.c b/test/agent.c
deleted file mode 100644 (file)
index 5cdeeb4..0000000
+++ /dev/null
@@ -1,717 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <getopt.h>
-#include <string.h>
-
-#include <dbus/dbus.h>
-
-static char *passkey_value = NULL;
-static int passkey_delay = 0;
-static int do_reject = 0;
-
-static volatile sig_atomic_t __io_canceled = 0;
-static volatile sig_atomic_t __io_terminated = 0;
-static volatile sig_atomic_t exit_on_release = 1;
-
-static void sig_term(int sig)
-{
-       __io_canceled = 1;
-}
-
-static DBusHandlerResult agent_filter(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *name, *old, *new;
-
-       if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
-                                               "NameOwnerChanged"))
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_STRING, &old,
-                                       DBUS_TYPE_STRING, &new,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (!strcmp(name, "org.bluez") && *new == '\0') {
-               fprintf(stderr, "Agent has been terminated\n");
-               __io_terminated = 1;
-       }
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult request_pincode_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       const char *path;
-
-       if (!passkey_value)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for RequestPinCode method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (do_reject) {
-               reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
-               goto send;
-       }
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       printf("Pincode request for device %s\n", path);
-
-       if (passkey_delay) {
-               printf("Waiting for %d seconds\n", passkey_delay);
-               sleep(passkey_delay);
-       }
-
-       dbus_message_append_args(reply, DBUS_TYPE_STRING, &passkey_value,
-                                                       DBUS_TYPE_INVALID);
-
-send:
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult request_passkey_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       const char *path;
-       unsigned int passkey;
-
-       if (!passkey_value)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for RequestPasskey method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (do_reject) {
-               reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
-               goto send;
-       }
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       printf("Passkey request for device %s\n", path);
-
-       if (passkey_delay) {
-               printf("Waiting for %d seconds\n", passkey_delay);
-               sleep(passkey_delay);
-       }
-
-       passkey = strtoul(passkey_value, NULL, 10);
-
-       dbus_message_append_args(reply, DBUS_TYPE_UINT32, &passkey,
-                                                       DBUS_TYPE_INVALID);
-
-send:
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult request_confirmation_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       const char *path;
-       unsigned int passkey;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_UINT32, &passkey,
-                                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for RequestPasskey method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (do_reject) {
-               reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
-               goto send;
-       }
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       printf("Confirmation request of %u for device %s\n", passkey, path);
-
-       if (passkey_delay) {
-               printf("Waiting for %d seconds\n", passkey_delay);
-               sleep(passkey_delay);
-       }
-
-send:
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult authorize_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-       const char *path, *uuid;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_STRING, &uuid,
-                                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for Authorize method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (do_reject) {
-               reply = dbus_message_new_error(msg, "org.bluez.Error.Rejected", "");
-               goto send;
-       }
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       printf("Authorizing request for %s\n", path);
-
-send:
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult cancel_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for passkey Confirm method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       printf("Request canceled\n");
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult release_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       DBusMessage *reply;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for Release method");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (!__io_canceled)
-               fprintf(stderr, "Agent has been released\n");
-
-       if (exit_on_release)
-               __io_terminated = 1;
-
-       reply = dbus_message_new_method_return(msg);
-       if (!reply) {
-               fprintf(stderr, "Can't create reply message\n");
-               return DBUS_HANDLER_RESULT_NEED_MEMORY;
-       }
-
-       dbus_connection_send(conn, reply, NULL);
-
-       dbus_connection_flush(conn);
-
-       dbus_message_unref(reply);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult agent_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent",
-                                                       "RequestPinCode"))
-               return request_pincode_message(conn, msg, data);
-
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent",
-                                                       "RequestPasskey"))
-               return request_passkey_message(conn, msg, data);
-
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent",
-                                                       "RequestConfirmation"))
-               return request_confirmation_message(conn, msg, data);
-
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Authorize"))
-               return authorize_message(conn, msg, data);
-
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Cancel"))
-               return cancel_message(conn, msg, data);
-
-       if (dbus_message_is_method_call(msg, "org.bluez.Agent", "Release"))
-               return release_message(conn, msg, data);
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static const DBusObjectPathVTable agent_table = {
-       .message_function = agent_message,
-};
-
-static int register_agent(DBusConnection *conn, const char *adapter_path,
-                                               const char *agent_path,
-                                               const char *capabilities)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-
-       msg = dbus_message_new_method_call("org.bluez", adapter_path,
-                                       "org.bluez.Adapter", "RegisterAgent");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return -1;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capabilities,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't register agent\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return -1;
-       }
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return 0;
-}
-
-static int unregister_agent(DBusConnection *conn, const char *adapter_path,
-                                                       const char *agent_path)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-
-       msg = dbus_message_new_method_call("org.bluez", adapter_path,
-                                       "org.bluez.Adapter", "UnregisterAgent");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return -1;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't unregister agent\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return -1;
-       }
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       dbus_connection_unregister_object_path(conn, agent_path);
-
-       return 0;
-}
-
-static void create_paired_device_reply(DBusPendingCall *pending,
-                                                       void *user_data)
-{
-       __io_terminated = 1;
-       return;
-}
-
-static int create_paired_device(DBusConnection *conn, const char *adapter_path,
-                                               const char *agent_path,
-                                               const char *capabilities,
-                                               const char *device)
-{
-       dbus_bool_t success;
-       DBusMessage *msg;
-       DBusPendingCall *pending;
-
-       msg = dbus_message_new_method_call("org.bluez", adapter_path,
-                                               "org.bluez.Adapter",
-                                               "CreatePairedDevice");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return -1;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &device,
-                                       DBUS_TYPE_OBJECT_PATH, &agent_path,
-                                       DBUS_TYPE_STRING, &capabilities,
-                                       DBUS_TYPE_INVALID);
-
-       exit_on_release = 0;
-       success = dbus_connection_send_with_reply(conn, msg, &pending, -1);
-       if (pending)
-               dbus_pending_call_set_notify(pending,
-                                               create_paired_device_reply,
-                                               NULL, NULL);
-
-       dbus_message_unref(msg);
-
-       if (!success) {
-               fprintf(stderr, "Not enough memory for message send\n");
-               return -1;
-       }
-
-       dbus_connection_flush(conn);
-
-       return 0;
-}
-
-static char *get_default_adapter_path(DBusConnection *conn)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *reply_path;
-       char *path;
-
-       msg = dbus_message_new_method_call("org.bluez", "/",
-                                       "org.bluez.Manager", "DefaultAdapter");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr,
-                       "Can't get default adapter\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr,
-                       "Can't get reply arguments\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       path = strdup(reply_path);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return path;
-}
-
-static char *get_adapter_path(DBusConnection *conn, const char *adapter)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *reply_path;
-       char *path;
-
-       if (!adapter)
-               return get_default_adapter_path(conn);
-
-       msg = dbus_message_new_method_call("org.bluez", "/",
-                                       "org.bluez.Manager", "FindAdapter");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr,
-                       "Can't find adapter %s\n", adapter);
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr,
-                       "Can't get reply arguments\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       path = strdup(reply_path);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return path;
-}
-
-static void usage(void)
-{
-       printf("Bluetooth agent ver %s\n\n", VERSION);
-
-       printf("Usage:\n"
-               "\tagent [--adapter adapter-path] [--path agent-path] <passkey> [<device>]\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "adapter",    1, 0, 'a' },
-       { "path",       1, 0, 'p' },
-       { "capabilites",1, 0, 'c' },
-       { "delay",      1, 0, 'd' },
-       { "reject",     0, 0, 'r' },
-       { "help",       0, 0, 'h' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       const char *capabilities = "DisplayYesNo";
-       struct sigaction sa;
-       DBusConnection *conn;
-       char match_string[128], default_path[128], *adapter_id = NULL;
-       char *adapter_path = NULL, *agent_path = NULL, *device = NULL;
-       int opt;
-
-       snprintf(default_path, sizeof(default_path),
-                                       "/org/bluez/agent_%d", getpid());
-
-       while ((opt = getopt_long(argc, argv, "+a:p:c:d:rh", main_options, NULL)) != EOF) {
-               switch(opt) {
-               case 'a':
-                       adapter_id = optarg;
-                       break;
-               case 'p':
-                       if (optarg[0] != '/') {
-                               fprintf(stderr, "Invalid path\n");
-                               exit(1);
-                       }
-                       agent_path = strdup(optarg);
-                       break;
-               case 'c':
-                       capabilities = optarg;
-                       break;
-               case 'd':
-                       passkey_delay = atoi(optarg);
-                       break;
-               case 'r':
-                       do_reject = 1;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       exit(1);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       passkey_value = strdup(argv[0]);
-
-       if (argc > 1)
-               device = strdup(argv[1]);
-
-       if (!agent_path)
-               agent_path = strdup(default_path);
-
-       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (!conn) {
-               fprintf(stderr, "Can't get on system bus");
-               exit(1);
-       }
-
-       adapter_path = get_adapter_path(conn, adapter_id);
-       if (!adapter_path)
-               exit(1);
-
-       if (!dbus_connection_register_object_path(conn, agent_path,
-                                                       &agent_table, NULL)) {
-               fprintf(stderr, "Can't register object path for agent\n");
-               exit(1);
-       }
-
-       if (device) {
-               if (create_paired_device(conn, adapter_path, agent_path,
-                                               capabilities, device) < 0) {
-                       dbus_connection_unref(conn);
-                       exit(1);
-               }
-       } else {
-               if (register_agent(conn, adapter_path, agent_path,
-                                                       capabilities) < 0) {
-                       dbus_connection_unref(conn);
-                       exit(1);
-               }
-       }
-
-       if (!dbus_connection_add_filter(conn, agent_filter, NULL, NULL))
-               fprintf(stderr, "Can't add signal filter");
-
-       snprintf(match_string, sizeof(match_string),
-                       "interface=%s,member=NameOwnerChanged,arg0=%s",
-                       DBUS_INTERFACE_DBUS, "org.bluez");
-
-       dbus_bus_add_match(conn, match_string, NULL);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       while (!__io_canceled && !__io_terminated) {
-               if (dbus_connection_read_write_dispatch(conn, 500) != TRUE)
-                       break;
-       }
-
-       if (!__io_terminated && !device)
-               unregister_agent(conn, adapter_path, agent_path);
-
-       free(adapter_path);
-       free(agent_path);
-
-       free(passkey_value);
-
-       dbus_connection_unref(conn);
-
-       return 0;
-}
diff --git a/test/attest.c b/test/attest.c
deleted file mode 100644 (file)
index 12ba682..0000000
+++ /dev/null
@@ -1,183 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2001-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 <termios.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-static int at_command(int fd, char *cmd, int to)
-{
-       fd_set rfds;
-       struct timeval timeout;
-       char buf[1024];
-       int sel, len, i, n;
-
-       len = write(fd, cmd, strlen(cmd));
-
-       for (i = 0; i < 100; i++) {
-
-               FD_ZERO(&rfds);
-               FD_SET(fd, &rfds);
-
-               timeout.tv_sec = 0;
-               timeout.tv_usec = to;
-
-               if ((sel = select(fd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
-
-                       if (FD_ISSET(fd, &rfds)) {
-                               memset(buf, 0, sizeof(buf));
-                               len = read(fd, buf, sizeof(buf));
-                               for (n = 0; n < len; n++)
-                                       printf("%c", buf[n]);
-                               if (strstr(buf, "\r\nOK") != NULL)
-                                       break;
-                               if (strstr(buf, "\r\nERROR") != NULL)
-                                       break;
-                               if (strstr(buf, "\r\nCONNECT") != NULL)
-                                       break;
-                       }
-
-               }
-
-       }
-
-       return 0;
-}
-
-static int open_device(char *device)
-{
-       struct termios ti;
-       int fd;
-
-       fd = open(device, O_RDWR | O_NOCTTY | O_NONBLOCK);
-       if (fd < 0) {
-               fprintf(stderr, "Can't open serial port: %s (%d)\n",
-                                                       strerror(errno), errno);
-               return -1;
-       }
-
-       tcflush(fd, TCIOFLUSH);
-
-       /* Switch tty to RAW mode */
-       cfmakeraw(&ti);
-       tcsetattr(fd, TCSANOW, &ti);
-
-       return fd;
-}
-
-static int open_socket(bdaddr_t *bdaddr, uint8_t channel)
-{
-       struct sockaddr_rc addr;
-       int sk;
-
-       sk = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
-       if (sk < 0) {
-               fprintf(stderr, "Can't create socket: %s (%d)\n",
-                                                       strerror(errno), errno);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, BDADDR_ANY);
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "Can't bind socket: %s (%d)\n",
-                                                       strerror(errno), errno);
-               close(sk);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, bdaddr);
-       addr.rc_channel = channel;
-
-       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "Can't connect: %s (%d)\n",
-                                                       strerror(errno), errno);
-               close(sk);
-               return -1;
-       }
-
-       return sk;
-}
-
-static void usage(void)
-{
-       printf("Usage:\n\tattest <device> | <bdaddr> [channel]\n");
-}
-
-int main(int argc, char *argv[])
-{
-       int fd;
-
-       bdaddr_t bdaddr;
-       uint8_t channel;
-
-       switch (argc) {
-       case 2:
-               str2ba(argv[1], &bdaddr);
-               channel = 1;
-               break;
-       case 3:
-               str2ba(argv[1], &bdaddr);
-               channel = atoi(argv[2]);
-               break;
-       default:
-               usage();
-               exit(-1);
-       }
-
-       if (bacmp(BDADDR_ANY, &bdaddr)) {
-               printf("Connecting to %s on channel %d\n", argv[1], channel);
-               fd = open_socket(&bdaddr, channel);
-       } else {
-               printf("Opening device %s\n", argv[1]);
-               fd = open_device(argv[1]);
-       }
-
-       if (fd < 0)
-               exit(-2);
-
-       at_command(fd, "ATZ\r\n", 10000);
-       at_command(fd, "AT+CPBS=\"ME\"\r\n", 10000);
-       at_command(fd, "AT+CPBR=1,100\r\n", 100000);
-
-       close(fd);
-
-       return 0;
-}
diff --git a/test/bdaddr.8 b/test/bdaddr.8
deleted file mode 100644 (file)
index 88345f8..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-.TH BDADDR 8 "Sep 27 2005" BlueZ "Linux System Administration"
-.SH NAME
-bdaddr \- Utility for changing the Bluetooth device address
-.SH SYNOPSIS
-.B bdaddr
-.br
-.B bdaddr -h
-.br
-.B bdaddr [-i <dev>] [-r] [-t] [new bdaddr]
-
-.SH DESCRIPTION
-.LP
-.B
-bdaddr
-is used to query or set the local Bluetooth device address (BD_ADDR). If run
-with no arguments,
-.B
-bdaddr
-prints the chip manufacturer's name, and the current BD_ADDR. If the IEEE OUI
-index file "oui.txt" is installed on the system, the BD_ADDR owner will be
-displayed. If the optional [new bdaddr] argument is given, the device will be
-reprogrammed with that address. This can either be permanent or temporary, as
-specified by the -t flag. In both cases, the device must be reset before the
-new address will become active. This can be done with a 'soft' reset by
-specifying the -r flag, or a 'hard' reset by removing and replugging the
-device. A 'hard' reset will cause the address to revert to the current
-non-volatile value.
-.PP
-.B
-bdaddr
-uses manufacturer specific commands to set the address, and is therefore
-device specific. For this reason, not all devices are supported, and not all
-options are supported on all devices.
-Current supported manufacturers are:
-.B Ericsson, Cambridge Silicon Radio (CSR), Texas Instruments (TI), Zeevo
-and
-.B ST Microelectronics (ST)
-
-.SH OPTIONS
-.TP
-.BI -h
-Gives a list of possible commands.
-.TP
-.BI -i\ <dev>
-Specify a particular device to operate on. If not specified, default is the
-first available device.
-.TP
-.BI -r
-Reset device and make new BD_ADDR active.
-.B
-CSR
-devices only.
-.TP
-.BI -t
-Temporary change. Do not write to non-volatile memory.
-.B
-CSR
-devices only.
-.SH FILES
-.TP
-.I
-/usr/share/misc/oui.txt
-IEEE Organizationally Unique Identifier master file.
-Manually update from: http://standards.ieee.org/regauth/oui/oui.txt
-.SH AUTHORS
-Written by Marcel Holtmann <marcel@holtmann.org>,
-man page by Adam Laurie <adam@algroup.co.uk>
-.PP
diff --git a/test/bluezutils.py b/test/bluezutils.py
new file mode 100644 (file)
index 0000000..de08cbd
--- /dev/null
@@ -0,0 +1,47 @@
+import dbus
+
+SERVICE_NAME = "org.bluez"
+ADAPTER_INTERFACE = SERVICE_NAME + ".Adapter1"
+DEVICE_INTERFACE = SERVICE_NAME + ".Device1"
+
+def get_managed_objects():
+       bus = dbus.SystemBus()
+       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
+                               "org.freedesktop.DBus.ObjectManager")
+       return manager.GetManagedObjects()
+
+def find_adapter(pattern=None):
+       return find_adapter_in_objects(get_managed_objects(), pattern)
+
+def find_adapter_in_objects(objects, pattern=None):
+       bus = dbus.SystemBus()
+       for path, ifaces in objects.iteritems():
+               adapter = ifaces.get(ADAPTER_INTERFACE)
+               if adapter is None:
+                       continue
+               if not pattern or pattern == adapter["Address"] or \
+                                                       path.endswith(pattern):
+                       obj = bus.get_object(SERVICE_NAME, path)
+                       return dbus.Interface(obj, ADAPTER_INTERFACE)
+       raise Exception("Bluetooth adapter not found")
+
+def find_device(device_address, adapter_pattern=None):
+       return find_device_in_objects(get_managed_objects(), device_address,
+                                                               adapter_pattern)
+
+def find_device_in_objects(objects, device_address, adapter_pattern=None):
+       bus = dbus.SystemBus()
+       path_prefix = ""
+       if adapter_pattern:
+               adapter = find_adapter_in_objects(objects, adapter_pattern)
+               path_prefix = adapter.object_path
+       for path, ifaces in objects.iteritems():
+               device = ifaces.get(DEVICE_INTERFACE)
+               if device is None:
+                       continue
+               if (device["Address"] == device_address and
+                                               path.startswith(path_prefix)):
+                       obj = bus.get_object(SERVICE_NAME, path)
+                       return dbus.Interface(obj, DEVICE_INTERFACE)
+
+       raise Exception("Bluetooth device not found")
index 5af6153..f1cd35a 100644 (file)
@@ -1,4 +1,5 @@
 import dbus
+import bluezutils
 
 bus = dbus.SystemBus()
 
@@ -8,9 +9,7 @@ dummy = dbus.Interface(bus.get_object('org.bluez', '/'), 'org.freedesktop.DBus.I
 #print dummy.Introspect()
 
 
-manager = dbus.Interface(bus.get_object('org.bluez', '/'), 'org.bluez.Manager')
-
 try:
-       adapter = dbus.Interface(bus.get_object('org.bluez', manager.DefaultAdapter()), 'org.bluez.Adapter')
+       adapter = bluezutils.find_adapter()
 except:
        pass
diff --git a/test/gaptest.c b/test/gaptest.c
deleted file mode 100644 (file)
index 3e9f534..0000000
+++ /dev/null
@@ -1,335 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2007-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <dbus/dbus.h>
-
-#define BLUEZ_SERVICE  "org.bluez"
-
-#define MANAGER_PATH   "/"
-#define MANAGER_INTF   BLUEZ_SERVICE ".Manager"
-#define ADAPTER_INTF   BLUEZ_SERVICE ".Adapter"
-
-static char *get_adapter(DBusConnection *conn)
-{
-       DBusMessage *message, *reply;
-       DBusError error;
-       const char *path;
-       char *result = NULL;
-
-       message = dbus_message_new_method_call(BLUEZ_SERVICE, MANAGER_PATH,
-                                       MANAGER_INTF, "DefaultAdapter");
-       if (!message)
-               return NULL;
-
-       dbus_error_init(&error);
-
-       reply = dbus_connection_send_with_reply_and_block(conn,
-                                                       message, -1, &error);
-
-       dbus_message_unref(message);
-
-       if (!reply) {
-               if (dbus_error_is_set(&error) == TRUE) {
-                       fprintf(stderr, "%s\n", error.message);
-                       dbus_error_free(&error);
-               } else
-                       fprintf(stderr, "Failed to set property\n");
-               return NULL;
-       }
-
-       if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               goto done;
-
-       printf("Using default adapter %s\n", path);
-
-       result = strdup(path);
-
-done:
-       dbus_message_unref(reply);
-
-       return result;
-}
-
-static char *find_device(DBusConnection *conn, const char *adapter,
-                                                       const char *address)
-{
-       DBusMessage *message, *reply;
-       DBusError error;
-       const char *path;
-       char *result = NULL;
-
-       message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
-                                       ADAPTER_INTF, "FindDevice");
-       if (!message)
-               return NULL;
-
-       dbus_message_append_args(message, DBUS_TYPE_STRING, &address,
-                                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&error);
-
-       reply = dbus_connection_send_with_reply_and_block(conn,
-                                                       message, -1, &error);
-
-       dbus_message_unref(message);
-
-       if (!reply) {
-               if (dbus_error_is_set(&error) == TRUE) {
-                       fprintf(stderr, "%s\n", error.message);
-                       dbus_error_free(&error);
-               } else
-                       fprintf(stderr, "Failed to set property\n");
-               return NULL;
-       }
-
-       if (dbus_message_get_args(reply, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                               DBUS_TYPE_INVALID) == FALSE)
-               goto done;
-
-       printf("Using device %s for address %s\n", path, address);
-
-       result = strdup(path);
-
-done:
-       dbus_message_unref(reply);
-
-       return result;
-}
-
-static int remove_device(DBusConnection *conn, const char *adapter,
-                                                       const char *device)
-{
-       DBusMessage *message, *reply;
-       DBusError error;
-
-       message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
-                                       ADAPTER_INTF, "RemoveDevice");
-       if (!message)
-               return -ENOMEM;
-
-       dbus_message_append_args(message, DBUS_TYPE_OBJECT_PATH, &device,
-                                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&error);
-
-       reply = dbus_connection_send_with_reply_and_block(conn,
-                                                       message, -1, &error);
-
-       dbus_message_unref(message);
-
-       if (!reply) {
-               if (dbus_error_is_set(&error) == TRUE) {
-                       fprintf(stderr, "%s\n", error.message);
-                       dbus_error_free(&error);
-               } else
-                       fprintf(stderr, "Failed to set property\n");
-               return -EIO;
-       }
-
-       dbus_message_unref(reply);
-
-       printf("Removed device %s\n", device);
-
-       return 0;
-}
-
-static int set_property(DBusConnection *conn, const char *adapter,
-                                       const char *key, int type, void *val)
-{
-       DBusMessage *message, *reply;
-       DBusMessageIter array, value;
-       DBusError error;
-       const char *signature;
-
-       message = dbus_message_new_method_call(BLUEZ_SERVICE, adapter,
-                                               ADAPTER_INTF, "SetProperty");
-       if (!message)
-               return -ENOMEM;
-
-       switch (type) {
-       case DBUS_TYPE_BOOLEAN:
-               signature = DBUS_TYPE_BOOLEAN_AS_STRING;
-               break;
-       case DBUS_TYPE_UINT32:
-               signature = DBUS_TYPE_UINT32_AS_STRING;
-               break;
-       default:
-               return -EILSEQ;
-       }
-
-       dbus_message_iter_init_append(message, &array);
-
-       dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &key);
-
-       dbus_message_iter_open_container(&array, DBUS_TYPE_VARIANT,
-                                                       signature, &value);
-       dbus_message_iter_append_basic(&value, type, val);
-       dbus_message_iter_close_container(&array, &value);
-
-       dbus_error_init(&error);
-
-       reply = dbus_connection_send_with_reply_and_block(conn,
-                                                       message, -1, &error);
-
-       dbus_message_unref(message);
-
-       if (!reply) {
-               if (dbus_error_is_set(&error) == TRUE) {
-                       fprintf(stderr, "%s\n", error.message);
-                       dbus_error_free(&error);
-               } else
-                       fprintf(stderr, "Failed to set property\n");
-               return -EIO;
-       }
-
-       dbus_message_unref(reply);
-
-       printf("Set property %s for %s\n", key, adapter);
-
-       return 0;
-}
-
-static void usage(void)
-{
-       printf("gaptest - GAP testing\n"
-               "Usage:\n");
-       printf("\tgaptest [options]\n");
-       printf("Options:\n"
-               "\t-T <timeout>        Set timeout\n"
-               "\t-P <powered>        Set powered\n"
-               "\t-D <discoverable>   Set discoverable\n"
-               "\t-B <pairable>       Set pairable\n"
-               "\t-C <address>        Create device\n"
-               "\t-R <address>        Remove device\n");
-}
-
-int main(int argc, char *argv[])
-{
-       DBusConnection *conn;
-       char *adapter, *device;
-       const char *create = NULL, *remove = NULL;
-       int opt, timeout = -1, powered = -1, discoverable = -1, pairable = -1;
-
-       while ((opt = getopt(argc, argv, "T:P:D:B:C:R:h")) != EOF) {
-               switch (opt) {
-               case 'T':
-                       timeout = atoi(optarg);
-                       break;
-               case 'P':
-                       powered = atoi(optarg);
-                       break;
-               case 'D':
-                       discoverable = atoi(optarg);
-                       break;
-               case 'B':
-                       pairable = atoi(optarg);
-                       break;
-               case 'C':
-                       create = optarg;
-                       break;
-               case 'R':
-                       remove = optarg;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       usage();
-                       exit(1);
-               }
-       }
-
-       conn = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (!conn) {
-               fprintf(stderr, "Can't get on system bus\n");
-               exit(1);
-       }
-
-       adapter = get_adapter(conn);
-       if (!adapter) {
-               fprintf(stderr, "Can't get default adapter\n");
-               exit(1);
-       }
-
-       if (powered >= 0) {
-               set_property(conn, adapter, "Powered",
-                                       DBUS_TYPE_BOOLEAN, &powered);
-       }
-
-       if (discoverable >= 0) {
-               set_property(conn, adapter, "Discoverable",
-                                       DBUS_TYPE_BOOLEAN, &discoverable);
-
-               if (timeout >= 0)
-                       set_property(conn, adapter, "DiscoverableTimeout",
-                                               DBUS_TYPE_UINT32, &timeout);
-       }
-
-       if (pairable >= 0) {
-               set_property(conn, adapter, "Pairable",
-                                       DBUS_TYPE_BOOLEAN, &pairable);
-
-               if (timeout >= 0)
-                       set_property(conn, adapter, "PairableTimeout",
-                                               DBUS_TYPE_UINT32, &timeout);
-       }
-
-       if (create) {
-               device = find_device(conn, adapter, create);
-               if (!device) {
-                       fprintf(stderr, "Can't find device\n");
-                       exit(1);
-               }
-
-               free(device);
-       }
-
-       if (remove) {
-               device = find_device(conn, adapter, remove);
-               if (!device) {
-                       fprintf(stderr, "Can't find device\n");
-                       exit(1);
-               }
-
-               remove_device(conn, adapter, device);
-
-               free(device);
-       }
-
-       free(adapter);
-
-       dbus_connection_unref(conn);
-
-       return 0;
-}
diff --git a/test/hciemu.1 b/test/hciemu.1
deleted file mode 100644 (file)
index cecaeb7..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-.TH HCIEMU 1 "Jul 6 2009" BlueZ ""
-.SH NAME
-hciemu \- HCI emulator
-.SH SYNOPSIS
-.B hciemu
-[\fIoptions\fR] \fIlocal_address\fR
-
-.SH DESCRIPTION
-.LP
-.B
-hciemu
-is used to emulate an HCI via \fBhci_vhci\fR kernel module
-
-.SH OPTIONS
-.TP
-.BI -d\  device
-use specified \fIdevice\fR
-.TP
-.BI -b\  bdaddr
-emulate \fIbdaddr\fR
-.TP
-.BI -s\  file
-create snoop file \fIfile\fR
-.TP
-.B -n
-do not detach
-
-.SH AUTHORS
-Written by Marcel Holtmann <marcel@holtmann.org> and Maxim Krasnyansky
-<maxk@qualcomm.com>, man page by Filippo Giunchedi <filippo@debian.org>
-.PP
diff --git a/test/hciemu.c b/test/hciemu.c
deleted file mode 100644 (file)
index 4c62223..0000000
+++ /dev/null
@@ -1,1292 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
- *  Copyright (C) 2003-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 <stdint.h>
-#include <string.h>
-#include <signal.h>
-#include <getopt.h>
-#include <syslog.h>
-#include <sys/time.h>
-#include <sys/epoll.h>
-#include <sys/socket.h>
-#include <sys/resource.h>
-#include <sys/stat.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/l2cap.h>
-
-#define VHCI_DEV               "/dev/vhci"
-
-#define VHCI_MAX_CONN          12
-
-#define VHCI_ACL_MTU           192
-#define VHCI_ACL_MAX_PKT       8
-
-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;
-       int             scan_fd;
-       int             dd;
-};
-
-struct vhci_conn {
-       bdaddr_t        dest;
-       uint16_t        handle;
-       int             fd;
-};
-
-struct vhci_link_info {
-       bdaddr_t        bdaddr;
-       uint8_t         dev_class[3];
-       uint8_t         link_type;
-       uint8_t         role;
-} __attribute__ ((packed));
-
-static struct vhci_device vdev;
-static struct vhci_conn *vconn[VHCI_MAX_CONN];
-
-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 uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
-
-#define MAX_EPOLL_EVENTS 10
-
-static int epoll_fd;
-
-static volatile sig_atomic_t __io_canceled = 0;
-
-static void sig_term(int sig)
-{
-       __io_canceled = 1;
-}
-
-static inline int read_n(int fd, void *buf, int len)
-{
-       register int w, t = 0;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = read(fd, buf, len)) < 0 ){
-                       if( errno == EINTR || errno == EAGAIN )
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w; buf += w; t += w;
-       }
-       return t;
-}
-
-/* Write exactly len bytes (Signal safe)*/
-static inline int write_n(int fd, void *buf, int len)
-{
-       register int w, t = 0;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = write(fd, buf, len)) < 0 ){
-                       if( errno == EINTR || errno == EAGAIN )
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w; buf += w; t += w;
-       }
-       return t;
-}
-
-static int create_snoop(char *file)
-{
-       struct btsnoop_hdr hdr;
-       int fd, len;
-
-       fd = open(file, O_WRONLY | O_CREAT, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-       if (fd < 0)
-               return fd;
-
-       memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
-       hdr.version = htonl(1);
-       hdr.type = htonl(1002);
-
-       len = write(fd, &hdr, BTSNOOP_HDR_SIZE);
-       if (len < 0) {
-               close(fd);
-               return -EIO;
-       }
-
-       if (len != BTSNOOP_HDR_SIZE) {
-               close(fd);
-               return -1;
-       }
-
-       return fd;
-}
-
-static int write_snoop(int fd, int type, int incoming,
-                               unsigned char *buf, int len)
-{
-       struct btsnoop_pkt pkt;
-       struct timeval tv;
-       uint32_t size = len;
-       uint64_t ts;
-
-       if (fd < 0)
-               return -1;
-
-       memset(&tv, 0, sizeof(tv));
-       gettimeofday(&tv, NULL);
-       ts = (tv.tv_sec - 946684800ll) * 1000000ll + tv.tv_usec;
-
-       pkt.size = htonl(size);
-       pkt.len  = pkt.size;
-       pkt.flags = ntohl(incoming & 0x01);
-       pkt.drops = htonl(0);
-       pkt.ts = hton64(ts + 0x00E03AB44A676000ll);
-
-       if (type == HCI_COMMAND_PKT || type == HCI_EVENT_PKT)
-               pkt.flags |= ntohl(0x02);
-
-       if (write(fd, &pkt, BTSNOOP_PKT_SIZE) < 0)
-               return -errno;
-
-       if (write(fd, buf, size) < 0)
-               return -errno;
-
-       return 0;
-}
-
-static struct vhci_conn *conn_get_by_bdaddr(bdaddr_t *ba)
-{
-       register int i;
-
-       for (i = 0; i < VHCI_MAX_CONN; i++)
-               if (!bacmp(&vconn[i]->dest, ba))
-                       return vconn[i];
-
-       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;
-       evt_cmd_status *cs;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_CMD_STATUS;
-       he->plen = EVT_CMD_STATUS_SIZE;
-
-       cs = (void *) ptr; ptr += EVT_CMD_STATUS_SIZE;
-
-       cs->status = status;
-       cs->ncmd   = 1;
-       cs->opcode = htobs(cmd_opcode_pack(ogf, ocf));
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s(%d)",
-                                               strerror(errno), errno);
-}
-
-static void command_complete(uint16_t ogf, uint16_t ocf, int plen, void *data)
-{
-       uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
-       evt_cmd_complete *cc;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_CMD_COMPLETE;
-       he->plen = EVT_CMD_COMPLETE_SIZE + plen;
-
-       cc = (void *) ptr; ptr += EVT_CMD_COMPLETE_SIZE;
-
-       cc->ncmd = 1;
-       cc->opcode = htobs(cmd_opcode_pack(ogf, ocf));
-
-       if (plen) {
-               memcpy(ptr, data, plen);
-               ptr += plen;
-       }
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s(%d)",
-                                               strerror(errno), errno);
-}
-
-static void connect_request(struct vhci_conn *conn)
-{
-       uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
-       evt_conn_request *cr;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_CONN_REQUEST;
-       he->plen = EVT_CONN_REQUEST_SIZE;
-
-       cr = (void *) ptr; ptr += EVT_CONN_REQUEST_SIZE;
-
-       bacpy(&cr->bdaddr, &conn->dest);
-       memset(&cr->dev_class, 0, sizeof(cr->dev_class));
-       cr->link_type = ACL_LINK;
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s (%d)",
-                                               strerror(errno), errno);
-}
-
-static void connect_complete(struct vhci_conn *conn)
-{
-       uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
-       evt_conn_complete *cc;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_CONN_COMPLETE;
-       he->plen = EVT_CONN_COMPLETE_SIZE;
-
-       cc = (void *) ptr; ptr += EVT_CONN_COMPLETE_SIZE;
-
-       bacpy(&cc->bdaddr, &conn->dest);
-       cc->status = 0x00;
-       cc->handle = htobs(conn->handle);
-       cc->link_type = ACL_LINK;
-       cc->encr_mode = 0x00;
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s (%d)",
-                                               strerror(errno), errno);
-
-       /* TODO: Add io_acl_data() handling */
-}
-
-static void disconn_complete(struct vhci_conn *conn)
-{
-       uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
-       evt_disconn_complete *dc;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_DISCONN_COMPLETE;
-       he->plen = EVT_DISCONN_COMPLETE_SIZE;
-
-       dc = (void *) ptr; ptr += EVT_DISCONN_COMPLETE_SIZE;
-
-       dc->status = 0x00;
-       dc->handle = htobs(conn->handle);
-       dc->reason = 0x00;
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s (%d)",
-                                               strerror(errno), errno);
-
-       vdev.acl_cnt = 0;
-}
-
-static void num_completed_pkts(struct vhci_conn *conn)
-{
-       uint8_t buf[HCI_MAX_FRAME_SIZE], *ptr = buf;
-       evt_num_comp_pkts *np;
-       hci_event_hdr *he;
-
-       /* Packet type */
-       *ptr++ = HCI_EVENT_PKT;
-
-       /* Event header */
-       he = (void *) ptr; ptr += HCI_EVENT_HDR_SIZE;
-
-       he->evt  = EVT_NUM_COMP_PKTS;
-       he->plen = EVT_NUM_COMP_PKTS_SIZE;
-
-       np = (void *) ptr; ptr += EVT_NUM_COMP_PKTS_SIZE;
-       np->num_hndl = 1;
-
-       *((uint16_t *) ptr) = htobs(conn->handle); ptr += 2;
-       *((uint16_t *) ptr) = htobs(vdev.acl_cnt); ptr += 2;
-
-       write_snoop(vdev.dd, HCI_EVENT_PKT, 1, buf, ptr - buf);
-
-       if (write(vdev.dev_fd, buf, ptr - buf) < 0)
-               syslog(LOG_ERR, "Can't send event: %s (%d)",
-                                               strerror(errno), errno);
-}
-
-static uint8_t scan_enable(uint8_t *data)
-{
-#if 0
-       struct epoll_event scan_event;
-       struct sockaddr_in sa;
-       bdaddr_t ba;
-       int sk, opt;
-
-       if (!(*data & SCAN_PAGE)) {
-               if (vdev.scan_fd >= 0) {
-                       close(vdev.scan_fd);
-                       vdev.scan_fd = -1;
-               }
-               return 0;
-       }
-
-       if (vdev.scan_fd >= 0)
-               return 0;
-
-       if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               syslog(LOG_ERR, "Can't create socket: %s (%d)",
-                                               strerror(errno), errno);
-               return 1;
-       }
-
-       opt = 1;
-       setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-       baswap(&ba, &vdev.bdaddr);
-       sa.sin_family = AF_INET;
-       memcpy(&sa.sin_addr.s_addr, &ba, sizeof(sa.sin_addr.s_addr));
-       memcpy(&sa.sin_port, &ba.b[4], sizeof(sa.sin_port));
-       if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
-               syslog(LOG_ERR, "Can't bind socket: %s (%d)",
-                                               strerror(errno), errno);
-               goto failed;
-       }
-
-       if (listen(sk, 10)) {
-               syslog(LOG_ERR, "Can't listen on socket: %s (%d)",
-                                               strerror(errno), errno);
-               goto failed;
-       }
-
-       memset(&scan_event, 0, sizeof(scan_event));
-       scan_event.events = EPOLLIN;
-       scan_event.data.fd = sk;
-
-       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, sk, &scan_event) < 0) {
-               syslog(LOG_ERR, "Failed to setup scan event watch");
-               goto failed;
-       }
-
-       vdev.scan_fd = sk;
-       return 0;
-
-failed:
-       close(sk);
-       return 1;
-#endif
-
-       return data[0];
-}
-
-static void accept_connection(uint8_t *data)
-{
-       accept_conn_req_cp *cp = (void *) data;
-       struct vhci_conn *conn;
-
-       if (!(conn = conn_get_by_bdaddr(&cp->bdaddr)))
-               return;
-
-       connect_complete(conn);
-}
-
-static void close_connection(struct vhci_conn *conn)
-{
-       char addr[18];
-
-       ba2str(&conn->dest, addr);
-       syslog(LOG_INFO, "Closing connection %s handle %d",
-                                       addr, conn->handle);
-
-       close(conn->fd);
-
-       vconn[conn->handle - 1] = NULL;
-       disconn_complete(conn);
-       free(conn);
-}
-
-static void disconnect(uint8_t *data)
-{
-       disconnect_cp *cp = (void *) data;
-       struct vhci_conn *conn;
-       uint16_t handle;
-
-       handle = btohs(cp->handle);
-
-       if (handle > VHCI_MAX_CONN)
-               return;
-
-       if (!(conn = vconn[handle-1]))
-               return;
-
-       close_connection(conn);
-}
-
-static void create_connection(uint8_t *data)
-{
-       create_conn_cp *cp = (void *) data;
-       struct vhci_link_info info;
-       struct vhci_conn *conn;
-       struct sockaddr_in sa;
-       int h, sk, opt;
-       bdaddr_t ba;
-
-       for (h = 0; h < VHCI_MAX_CONN; h++)
-               if (!vconn[h])
-                       goto do_connect;
-
-       syslog(LOG_ERR, "Too many connections");
-       return;
-
-do_connect:
-       if ((sk = socket(AF_INET, SOCK_STREAM, 0)) < 0) {
-               syslog(LOG_ERR, "Can't create socket: %s (%d)",
-                                               strerror(errno), errno);
-               return;
-       }
-
-       opt = 1;
-       setsockopt(sk, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt));
-
-       baswap(&ba, &vdev.bdaddr);
-       sa.sin_family = AF_INET;
-       sa.sin_addr.s_addr = INADDR_ANY;        // *(uint32_t *) &ba;
-       sa.sin_port = 0;                        // *(uint16_t *) &ba.b[4];
-       if (bind(sk, (struct sockaddr *) &sa, sizeof(sa))) {
-               syslog(LOG_ERR, "Can't bind socket: %s (%d)",
-                                               strerror(errno), errno);
-               close(sk);
-               return;
-       }
-
-       baswap(&ba, &cp->bdaddr);
-       sa.sin_family = AF_INET;
-       memcpy(&sa.sin_addr.s_addr, &ba, sizeof(sa.sin_addr.s_addr));
-       memcpy(&sa.sin_port, &ba.b[4], sizeof(sa.sin_port));
-       if (connect(sk, (struct sockaddr *) &sa, sizeof(sa)) < 0) {
-               syslog(LOG_ERR, "Can't connect: %s (%d)",
-                                               strerror(errno), errno);
-               close(sk);
-               return;
-       }
-
-       /* Send info */
-       memset(&info, 0, sizeof(info));
-       bacpy(&info.bdaddr, &vdev.bdaddr);
-       info.link_type = ACL_LINK;
-       info.role = 1;
-       write_n(sk, (void *) &info, sizeof(info));
-
-       if (!(conn = malloc(sizeof(*conn)))) {
-               syslog(LOG_ERR, "Can't alloc new connection: %s (%d)",
-                                               strerror(errno), errno);
-               close(sk);
-               return;
-       }
-
-       memcpy((uint8_t *) &ba, (uint8_t *) &sa.sin_addr, 4);
-       memcpy((uint8_t *) &ba.b[4], (uint8_t *) &sa.sin_port, 2);
-       baswap(&conn->dest, &ba);
-
-       vconn[h] = conn;
-       conn->handle = h + 1;
-       conn->fd = sk;
-
-       connect_complete(conn);
-}
-
-static void hci_link_control(uint16_t ocf, int plen, uint8_t *data)
-{
-       const uint16_t ogf = OGF_LINK_CTL;
-
-       switch (ocf) {
-       case OCF_CREATE_CONN:
-               command_status(ogf, ocf, 0x00);
-               create_connection(data);
-               break;
-
-       case OCF_ACCEPT_CONN_REQ:
-               command_status(ogf, ocf, 0x00);
-               accept_connection(data);
-               break;
-
-       case OCF_DISCONNECT:
-               command_status(ogf, ocf, 0x00);
-               disconnect(data);
-               break;
-
-       default:
-               command_status(ogf, ocf, 0x01);
-               break;
-       }
-}
-
-static void hci_link_policy(uint16_t ocf, int plen, uint8_t *data)
-{
-       const uint16_t ogf = OGF_INFO_PARAM;
-
-       switch (ocf) {
-       default:
-               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;
-
-       switch (ocf) {
-       case OCF_RESET:
-               status = 0x00;
-               reset_vdev();
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_SET_EVENT_FLT:
-               status = 0x00;
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_CHANGE_LOCAL_NAME:
-               status = 0x00;
-               memcpy(vdev.name, data, sizeof(vdev.name));
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_READ_LOCAL_NAME:
-               ln.status = 0x00;
-               memcpy(ln.name, vdev.name, sizeof(ln.name));
-               command_complete(ogf, ocf, sizeof(ln), &ln);
-               break;
-
-       case OCF_WRITE_CONN_ACCEPT_TIMEOUT:
-       case OCF_WRITE_PAGE_TIMEOUT:
-               status = 0x00;
-               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 = 0x00;
-               vdev.scan_enable = scan_enable(data);
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_WRITE_AUTH_ENABLE:
-               status = 0x00;
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_WRITE_ENCRYPT_MODE:
-               status = 0x00;
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_READ_CLASS_OF_DEV:
-               cd.status = 0x00;
-               memcpy(cd.dev_class, vdev.dev_class, 3);
-               command_complete(ogf, ocf, sizeof(cd), &cd);
-               break;
-
-       case OCF_WRITE_CLASS_OF_DEV:
-               status = 0x00;
-               memcpy(vdev.dev_class, data, 3);
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_READ_INQUIRY_MODE:
-               im.status = 0x00;
-               im.mode = vdev.inq_mode;
-               command_complete(ogf, ocf, sizeof(im), &im);
-               break;
-
-       case OCF_WRITE_INQUIRY_MODE:
-               status = 0x00;
-               vdev.inq_mode = data[0];
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       case OCF_READ_EXT_INQUIRY_RESPONSE:
-               ir.status = 0x00;
-               ir.fec = vdev.eir_fec;
-               memcpy(ir.data, vdev.eir_data, HCI_MAX_EIR_LENGTH);
-               command_complete(ogf, ocf, sizeof(ir), &ir);
-               break;
-
-       case OCF_WRITE_EXT_INQUIRY_RESPONSE:
-               status = 0x00;
-               vdev.eir_fec = data[0];
-               memcpy(vdev.eir_data, data + 1, HCI_MAX_EIR_LENGTH);
-               command_complete(ogf, ocf, 1, &status);
-               break;
-
-       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;
-       }
-}
-
-static void hci_info_param(uint16_t ocf, int plen, uint8_t *data)
-{
-       read_local_version_rp lv;
-       read_local_features_rp lf;
-       read_local_ext_features_rp ef;
-       read_buffer_size_rp bs;
-       read_bd_addr_rp ba;
-
-       const uint16_t ogf = OGF_INFO_PARAM;
-
-       switch (ocf) {
-       case OCF_READ_LOCAL_VERSION:
-               lv.status = 0x00;
-               lv.hci_ver = 0x06;
-               lv.hci_rev = htobs(0x0000);
-               lv.lmp_ver = 0x06;
-               lv.manufacturer = htobs(63);
-               lv.lmp_subver = htobs(0x0000);
-               command_complete(ogf, ocf, sizeof(lv), &lv);
-               break;
-
-       case OCF_READ_LOCAL_FEATURES:
-               lf.status = 0x00;
-               memcpy(lf.features, vdev.features, 8);
-               command_complete(ogf, ocf, sizeof(lf), &lf);
-               break;
-
-       case OCF_READ_LOCAL_EXT_FEATURES:
-               ef.status = 0x00;
-               if (*data == 0) {
-                       ef.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;
-                       memset(ef.features, 0, 8);
-               }
-               command_complete(ogf, ocf, sizeof(ef), &ef);
-               break;
-
-       case OCF_READ_BUFFER_SIZE:
-               bs.status = 0x00;
-               bs.acl_mtu = htobs(VHCI_ACL_MTU);
-               bs.sco_mtu = 0;
-               bs.acl_max_pkt = htobs(VHCI_ACL_MAX_PKT);
-               bs.sco_max_pkt = htobs(0);
-               command_complete(ogf, ocf, sizeof(bs), &bs);
-               break;
-
-       case OCF_READ_BD_ADDR:
-               ba.status = 0x00;
-               bacpy(&ba.bdaddr, &vdev.bdaddr);
-               command_complete(ogf, ocf, sizeof(ba), &ba);
-               break;
-
-       default:
-               command_status(ogf, ocf, 0x01);
-               break;
-       }
-}
-
-static void hci_status_param(uint16_t ocf, int plen, uint8_t *data)
-{
-       read_local_amp_info_rp ai;
-
-       const uint16_t ogf = OGF_STATUS_PARAM;
-
-       switch (ocf) {
-       case OCF_READ_LOCAL_AMP_INFO:
-               memset(&ai, 0, sizeof(ai));
-
-               /* BT only */
-               ai.amp_status = 0x01;
-               ai.max_pdu_size = htobl(L2CAP_DEFAULT_MTU);
-               ai.controller_type = HCI_AMP;
-               ai.max_amp_assoc_length = htobl(HCI_MAX_ACL_SIZE);
-               /* No flushing at all */
-               ai.max_flush_timeout = 0xFFFFFFFF;
-               ai.best_effort_flush_timeout = 0xFFFFFFFF;
-
-               command_complete(ogf, ocf, sizeof(ai), &ai);
-               break;
-
-       default:
-               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;
-       }
-}
-
-static void hci_command(uint8_t *data)
-{
-       hci_command_hdr *ch;
-       uint8_t *ptr = data;
-       uint16_t ogf, ocf;
-
-       ch = (hci_command_hdr *) ptr;
-       ptr += HCI_COMMAND_HDR_SIZE;
-
-       ch->opcode = btohs(ch->opcode);
-       ogf = cmd_opcode_ogf(ch->opcode);
-       ocf = cmd_opcode_ocf(ch->opcode);
-
-       switch (ogf) {
-       case OGF_LINK_CTL:
-               hci_link_control(ocf, ch->plen, ptr);
-               break;
-
-       case OGF_LINK_POLICY:
-               hci_link_policy(ocf, ch->plen, ptr);
-               break;
-
-       case OGF_HOST_CTL:
-               hci_host_control(ocf, ch->plen, ptr);
-               break;
-
-       case OGF_INFO_PARAM:
-               hci_info_param(ocf, ch->plen, ptr);
-               break;
-
-       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;
-       }
-}
-
-static void hci_acl_data(uint8_t *data)
-{
-       hci_acl_hdr *ah = (void *) data;
-       struct vhci_conn *conn;
-       uint16_t handle;
-
-       handle = acl_handle(btohs(ah->handle));
-
-       if (handle > VHCI_MAX_CONN || !(conn = vconn[handle - 1])) {
-               syslog(LOG_ERR, "Bad connection handle %d", handle);
-               return;
-       }
-
-       if (write_n(conn->fd, data, btohs(ah->dlen) + HCI_ACL_HDR_SIZE) < 0) {
-               close_connection(conn);
-               return;
-       }
-
-       if (++vdev.acl_cnt > VHCI_ACL_MAX_PKT - 1) {
-               /* Send num of complete packets event */
-               num_completed_pkts(conn);
-               vdev.acl_cnt = 0;
-       }
-}
-
-#if 0
-static void io_acl_data(void *data)
-{
-       struct vhci_conn *conn = data;
-       unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
-       hci_acl_hdr *ah;
-       uint16_t flags;
-       int len;
-
-       ptr = buf + 1;
-       if (read_n(conn->fd, ptr, HCI_ACL_HDR_SIZE) <= 0) {
-               close_connection(conn);
-               return;
-       }
-
-       ah = (void *) ptr;
-       ptr += HCI_ACL_HDR_SIZE;
-
-       len = btohs(ah->dlen);
-       if (read_n(conn->fd, ptr, len) <= 0) {
-               close_connection(conn);
-               return;
-       }
-
-       buf[0] = HCI_ACLDATA_PKT;
-
-       flags = acl_flags(btohs(ah->handle));
-       ah->handle = htobs(acl_handle_pack(conn->handle, flags));
-       len += HCI_ACL_HDR_SIZE + 1;
-
-       write_snoop(vdev.dd, HCI_ACLDATA_PKT, 1, buf, len);
-
-       if (write(vdev.dev_fd, buf, len) < 0)
-               syslog(LOG_ERR, "ACL data write error");
-}
-#endif
-
-static void io_conn_ind(void)
-{
-       struct vhci_link_info info;
-       struct vhci_conn *conn;
-       struct sockaddr_in sa;
-       socklen_t len;
-       int nsk, h;
-
-       len = sizeof(sa);
-       if ((nsk = accept(vdev.scan_fd, (struct sockaddr *) &sa, &len)) < 0)
-               return;
-
-       if (read_n(nsk, &info, sizeof(info)) < 0) {
-               syslog(LOG_ERR, "Can't read link info");
-               return;
-       }
-
-       if (!(conn = malloc(sizeof(*conn)))) {
-               syslog(LOG_ERR, "Can't alloc new connection");
-               close(nsk);
-               return;
-       }
-
-       bacpy(&conn->dest, &info.bdaddr);
-
-       for (h = 0; h < VHCI_MAX_CONN; h++)
-               if (!vconn[h])
-                       goto accepted;
-
-       syslog(LOG_ERR, "Too many connections");
-       free(conn);
-       close(nsk);
-       return;
-
-accepted:
-       vconn[h] = conn;
-       conn->handle = h + 1;
-       conn->fd = nsk;
-       connect_request(conn);
-}
-
-static void io_hci_data(void)
-{
-       unsigned char buf[HCI_MAX_FRAME_SIZE], *ptr;
-       int type;
-       ssize_t len;
-
-       ptr = buf;
-
-       len = read(vdev.dev_fd, buf, sizeof(buf));
-       if (len < 0) {
-               if (errno == EAGAIN)
-                       return;
-
-               syslog(LOG_ERR, "Read failed: %s (%d)", strerror(errno), errno);
-               __io_canceled = 1;
-               return;
-       }
-
-       type = *ptr++;
-
-       write_snoop(vdev.dd, type, 0, buf, len);
-
-       switch (type) {
-       case HCI_COMMAND_PKT:
-               hci_command(ptr);
-               break;
-
-       case HCI_ACLDATA_PKT:
-               hci_acl_data(ptr);
-               break;
-
-       default:
-               syslog(LOG_ERR, "Unknown packet type 0x%2.2x", type);
-               break;
-       }
-}
-
-static int getbdaddrbyname(char *str, bdaddr_t *ba)
-{
-       int i, n, len;
-
-       len = strlen(str);
-
-       /* Check address format */
-       for (i = 0, n = 0; i < len; i++)
-               if (str[i] == ':')
-                       n++;
-
-       if (n == 5) {
-               /* BD address */
-               str2ba(str, ba);
-               return 0;
-       }
-
-       if (n == 0) {
-               /* loopback port */
-               in_addr_t addr = INADDR_LOOPBACK;
-               uint16_t be16 = htons(atoi(str));
-               bdaddr_t b;
-
-               memcpy(&b, &addr, 4);
-               memcpy(&b.b[4], &be16, sizeof(be16));
-               baswap(ba, &b);
-
-               return 0;
-       }
-
-       fprintf(stderr, "Invalid address format\n");
-
-       return -1;
-}
-
-static void usage(void)
-{
-       printf("hciemu - HCI emulator ver %s\n", VERSION);
-       printf("Usage: \n");
-       printf("\thciemu [options] port_number\n"
-               "Options:\n"
-               "\t[-d device] use specified device node\n"
-               "\t[-s file] create snoop file\n"
-               "\t[-n] do not detach\n"
-               "\t[-h] help, you are looking at it\n");
-}
-
-static const struct option options[] = {
-       { "device",     1, 0, 'd' },
-       { "bdaddr",     1, 0, 'b' },
-       { "snoop",      1, 0, 's' },
-       { "nodetach",   0, 0, 'n' },
-       { "help",       0, 0, 'h' },
-       { }
-};
-
-int main(int argc, char *argv[])
-{
-       int exitcode = EXIT_FAILURE;
-       struct sigaction sa;
-       char *device = NULL, *snoop = NULL;
-       int device_fd;
-       struct epoll_event device_event;
-       int dd, opt, detach = 1;
-
-       while ((opt=getopt_long(argc, argv, "d:s:nh", options, NULL)) != EOF) {
-               switch(opt) {
-               case 'd':
-                       device = strdup(optarg);
-                       break;
-               case 's':
-                       snoop = strdup(optarg);
-                       break;
-               case 'n':
-                       detach = 0;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       usage();
-                       exit(1);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       if (getbdaddrbyname(argv[0], &vdev.bdaddr) < 0)
-               exit(1);
-
-       if (detach) {
-               if (daemon(0, 0)) {
-                       perror("Can't start daemon");
-                       exit(1);
-               }
-       }
-
-       /* Start logging to syslog and stderr */
-       openlog("hciemu", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-       syslog(LOG_INFO, "HCI emulation daemon ver %s started", VERSION);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       if (!device)
-               device = strdup(VHCI_DEV);
-
-       /* Open and create virtual HCI device */
-       device_fd = open(device, O_RDWR);
-       if (device_fd < 0) {
-               syslog(LOG_ERR, "Can't open device %s: %s (%d)",
-                                       device, strerror(errno), errno);
-               free(device);
-               return exitcode;
-       }
-
-       free(device);
-
-       /* Create snoop file */
-       if (snoop) {
-               dd = create_snoop(snoop);
-               if (dd < 0)
-                       syslog(LOG_ERR, "Can't create snoop file %s: %s (%d)",
-                                               snoop, strerror(errno), errno);
-               free(snoop);
-       } else
-               dd = -1;
-
-       /* Create event loop */
-       epoll_fd = epoll_create1(EPOLL_CLOEXEC);
-       if (epoll_fd < 0) {
-               perror("Failed to create epoll descriptor");
-               goto close_device;
-       }
-
-       reset_vdev();
-
-       vdev.dev_fd = device_fd;
-       vdev.dd = dd;
-
-       memset(&device_event, 0, sizeof(device_event));
-       device_event.events = EPOLLIN;
-       device_event.data.fd = device_fd;
-
-       if (epoll_ctl(epoll_fd, EPOLL_CTL_ADD, device_fd, &device_event) < 0) {
-               perror("Failed to setup device event watch");
-               goto close_device;
-       }
-
-       setpriority(PRIO_PROCESS, 0, -19);
-
-       /* Start event processor */
-       for (;;) {
-               struct epoll_event events[MAX_EPOLL_EVENTS];
-               int n, nfds;
-
-               if (__io_canceled)
-                       break;
-
-               nfds = epoll_wait(epoll_fd, events, MAX_EPOLL_EVENTS, -1);
-               if (nfds < 0)
-                       continue;
-
-               for (n = 0; n < nfds; n++) {
-                       if (events[n].data.fd == vdev.dev_fd)
-                               io_hci_data();
-                       else if (events[n].data.fd == vdev.scan_fd)
-                               io_conn_ind();
-               }
-       }
-
-       exitcode = EXIT_SUCCESS;
-
-       epoll_ctl(epoll_fd, EPOLL_CTL_DEL, device_fd, NULL);
-
-close_device:
-       close(device_fd);
-
-       if (dd >= 0)
-               close(dd);
-
-       close(epoll_fd);
-
-       syslog(LOG_INFO, "Exit");
-
-       return exitcode;
-}
diff --git a/test/hsmicro b/test/hsmicro
deleted file mode 100755 (executable)
index c254226..0000000
+++ /dev/null
@@ -1,20 +0,0 @@
-#!/bin/sh
-
-SOX=`which sox`
-HSTEST=`which hstest`
-
-if [ -z "$HSTEST" ]
-then
-       HSTEST="./hstest"
-fi
-
-if [ -z "$1" ]
-then
-       echo -e "Usage:\n\thsmicro <bdaddr> [channel]"
-       exit
-fi
-
-BDADDR=$1
-CHANNEL=$2
-
-$HSTEST record - $BDADDR $CHANNEL | $SOX -t raw -r 8000 -c 1 -s -w - -t ossdsp -r 44100 -c 2 -s -w /dev/dsp polyphase vol 5.0 2> /dev/null
diff --git a/test/hsplay b/test/hsplay
deleted file mode 100755 (executable)
index 8cecbff..0000000
+++ /dev/null
@@ -1,22 +0,0 @@
-#!/bin/sh
-
-MPG123=`which mpg123`
-SOX=`which sox`
-HSTEST=`which hstest`
-
-if [ -z "$HSTEST" ]
-then
-       HSTEST="./hstest"
-fi
-
-if [ -z "$1" ] || [ -z "$2" ]
-then
-       echo -e "Usage:\n\thsplay <file> <bdaddr> [channel]"
-       exit
-fi
-
-FILE=$1
-BDADDR=$2
-CHANNEL=$3
-
-$MPG123 -q -s "$FILE" | $SOX -t raw -r 44100 -c 2 -s -w - -t raw -r 8000 -c 1 -s -w - | $HSTEST play - $BDADDR $CHANNEL
diff --git a/test/hstest.c b/test/hstest.c
deleted file mode 100644 (file)
index ac68059..0000000
+++ /dev/null
@@ -1,310 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <termios.h>
-#include <sys/wait.h>
-#include <sys/time.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sco.h>
-#include <bluetooth/rfcomm.h>
-
-static volatile int terminate = 0;
-
-static void sig_term(int sig) {
-       terminate = 1;
-}
-
-static int rfcomm_connect(bdaddr_t *src, bdaddr_t *dst, uint8_t channel)
-{
-       struct sockaddr_rc addr;
-       int s;
-
-       if ((s = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0) {
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, src);
-       addr.rc_channel = 0;
-       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-               close(s);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, dst);
-       addr.rc_channel = channel;
-       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
-               close(s);
-               return -1;
-       }
-
-       return s;
-}
-
-static int sco_connect(bdaddr_t *src, bdaddr_t *dst, uint16_t *handle, uint16_t *mtu)
-{
-       struct sockaddr_sco addr;
-       struct sco_conninfo conn;
-       struct sco_options opts;
-       socklen_t size;
-       int s;
-
-       if ((s = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)) < 0) {
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sco_family = AF_BLUETOOTH;
-       bacpy(&addr.sco_bdaddr, src);
-
-       if (bind(s, (struct sockaddr *)&addr, sizeof(addr)) < 0) {
-               close(s);
-               return -1;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.sco_family = AF_BLUETOOTH;
-       bacpy(&addr.sco_bdaddr, dst);
-
-       if (connect(s, (struct sockaddr *)&addr, sizeof(addr)) < 0 ){
-               close(s);
-               return -1;
-       }
-
-       memset(&conn, 0, sizeof(conn));
-       size = sizeof(conn);
-
-       if (getsockopt(s, SOL_SCO, SCO_CONNINFO, &conn, &size) < 0) {
-               close(s);
-               return -1;
-       }
-
-       memset(&opts, 0, sizeof(opts));
-       size = sizeof(opts);
-
-       if (getsockopt(s, SOL_SCO, SCO_OPTIONS, &opts, &size) < 0) {
-               close(s);
-               return -1;
-       }
-
-       if (handle)
-               *handle = conn.hci_handle;
-
-       if (mtu)
-               *mtu = opts.mtu;
-
-       return s;
-}
-
-static void usage(void)
-{
-       printf("Usage:\n"
-               "\thstest play   <file> <bdaddr> [channel]\n"
-               "\thstest record <file> <bdaddr> [channel]\n");
-}
-
-#define PLAY   1
-#define RECORD 2
-
-int main(int argc, char *argv[])
-{
-       struct sigaction sa;
-
-       fd_set rfds;
-       struct timeval timeout;
-       unsigned char buf[2048], *p;
-       int maxfd, sel, rlen, wlen;
-
-       bdaddr_t local;
-       bdaddr_t bdaddr;
-       uint8_t channel;
-
-       char *filename;
-       mode_t filemode;
-       int mode = 0;
-       int dd, rd, sd, fd;
-       uint16_t sco_handle, sco_mtu, vs;
-
-       switch (argc) {
-       case 4:
-               str2ba(argv[3], &bdaddr);
-               channel = 6;
-               break;
-       case 5:
-               str2ba(argv[3], &bdaddr);
-               channel = atoi(argv[4]);
-               break;
-       default:
-               usage();
-               exit(-1);
-       }
-
-       if (strncmp(argv[1], "play", 4) == 0) {
-               mode = PLAY;
-               filemode = O_RDONLY;
-       } else if (strncmp(argv[1], "rec", 3) == 0) {
-               mode = RECORD;
-               filemode = O_WRONLY | O_CREAT | O_TRUNC;
-       } else {
-               usage();
-               exit(-1);
-       }
-
-       filename = argv[2];
-
-       hci_devba(0, &local);
-       dd = hci_open_dev(0);
-       hci_read_voice_setting(dd, &vs, 1000);
-       vs = htobs(vs);
-       fprintf(stderr, "Voice setting: 0x%04x\n", vs);
-       close(dd);
-       if (vs != 0x0060) {
-               fprintf(stderr, "The voice setting must be 0x0060\n");
-               return -1;
-       }
-
-       if (strcmp(filename, "-") == 0) {
-               switch (mode) {
-               case PLAY:
-                       fd = 0;
-                       break;
-               case RECORD:
-                       fd = 1;
-                       break;
-               default:
-                       return -1;
-               }
-       } else {
-               if ((fd = open(filename, filemode)) < 0) {
-                       perror("Can't open input/output file");
-                       return -1;
-               }
-       }
-
-       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_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       if ((rd = rfcomm_connect(&local, &bdaddr, channel)) < 0) {
-               perror("Can't connect RFCOMM channel");
-               return -1;
-       }
-
-       fprintf(stderr, "RFCOMM channel connected\n");
-
-       if ((sd = sco_connect(&local, &bdaddr, &sco_handle, &sco_mtu)) < 0) {
-               perror("Can't connect SCO audio channel");
-               close(rd);
-               return -1;
-       }
-
-       fprintf(stderr, "SCO audio channel connected (handle %d, mtu %d)\n", sco_handle, sco_mtu);
-
-       if (mode == RECORD) {
-               if (write(rd, "RING\r\n", 6) < 0)
-                       return -errno;
-       }
-
-       maxfd = (rd > sd) ? rd : sd;
-
-       while (!terminate) {
-
-               FD_ZERO(&rfds);
-               FD_SET(rd, &rfds);
-               FD_SET(sd, &rfds);
-
-               timeout.tv_sec = 0;
-               timeout.tv_usec = 10000;
-
-               if ((sel = select(maxfd + 1, &rfds, NULL, NULL, &timeout)) > 0) {
-
-                       if (FD_ISSET(rd, &rfds)) {
-                               memset(buf, 0, sizeof(buf));
-                               rlen = read(rd, buf, sizeof(buf));
-                               if (rlen > 0) {
-                                       fprintf(stderr, "%s\n", buf);
-                                       wlen = write(rd, "OK\r\n", 4);
-                               }
-                       }
-
-                       if (FD_ISSET(sd, &rfds)) {
-                               memset(buf, 0, sizeof(buf));
-                               rlen = read(sd, buf, sizeof(buf));
-                               if (rlen > 0)
-                                       switch (mode) {
-                                       case PLAY:
-                                               rlen = read(fd, buf, rlen);
-
-                                               wlen = 0;
-                                               p = buf;
-                                               while (rlen > sco_mtu) {
-                                                       wlen += write(sd, p, sco_mtu);
-                                                       rlen -= sco_mtu;
-                                                       p += sco_mtu;
-                                               }
-                                               wlen += write(sd, p, rlen);
-                                               break;
-                                       case RECORD:
-                                               wlen = write(fd, buf, rlen);
-                                               break;
-                                       default:
-                                               break;
-                                       }
-                       }
-
-               }
-
-       }
-
-       close(sd);
-       sleep(5);
-       close(rd);
-
-       close(fd);
-
-       return 0;
-}
diff --git a/test/ipctest.c b/test/ipctest.c
deleted file mode 100644 (file)
index cbfd78d..0000000
+++ /dev/null
@@ -1,1133 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2006-2010  Nokia Corporation
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *  Copyright (C) 2009 Lennart Poettering
- *  Copyright (C) 2008 Joao Paulo Rechi Vita
- *
- *
- *  This library is free software; you can redistribute it and/or
- *  modify it under the terms of the GNU Lesser General Public
- *  License as published by the Free Software Foundation; either
- *  version 2.1 of the License, or (at your option) any later version.
- *
- *  This library is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
- *  Lesser General Public License for more details.
- *
- *  You should have received a copy of the GNU Lesser General Public
- *  License along with this library; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdlib.h>
-#include <stdio.h>
-#include <errno.h>
-#include <string.h>
-#include <assert.h>
-#include <libgen.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <signal.h>
-
-#include <glib.h>
-
-#include "ipc.h"
-#include "sbc.h"
-
-#define DBG(fmt, arg...)                               \
-       printf("debug %s: " fmt "\n" , __FUNCTION__ , ## arg)
-#define ERR(fmt, arg...)                               \
-       fprintf(stderr, "ERROR %s: " fmt "\n" , __FUNCTION__ , ## arg)
-
-#define ARRAY_SIZE(arr) (sizeof(arr) / sizeof((arr)[0]))
-
-#ifndef MIN
-# define MIN(x, y) ((x) < (y) ? (x) : (y))
-#endif
-
-#ifndef MAX
-# define MAX(x, y) ((x) > (y) ? (x) : (y))
-#endif
-
-#ifndef TRUE
-# define TRUE (1)
-#endif
-
-#ifndef FALSE
-# define FALSE (0)
-#endif
-
-#define YES_NO(t) ((t) ? "yes" : "no")
-
-#define BUFFER_SIZE 2048
-#define MAX_BITPOOL 64
-#define MIN_BITPOOL 2
-
-struct a2dp_info {
-       sbc_capabilities_t sbc_capabilities;
-       sbc_t sbc; /* Codec data */
-       int sbc_initialized; /* Keep track if the encoder is initialized */
-       size_t codesize; /* SBC codesize */
-
-       void* buffer; /* Codec transfer buffer */
-       size_t buffer_size; /* Size of the buffer */
-
-       uint16_t seq_num; /* Cumulative packet sequence */
-};
-
-struct hsp_info {
-       pcm_capabilities_t pcm_capabilities;
-};
-
-struct userdata {
-       int service_fd;
-       int stream_fd;
-       GIOChannel *stream_channel;
-       guint stream_watch;
-       GIOChannel *gin; /* dude, I am thirsty now */
-       guint gin_watch;
-       int transport;
-       uint32_t rate;
-       int channels;
-       char *address;
-       struct a2dp_info a2dp;
-       struct hsp_info hsp;
-       size_t link_mtu;
-       size_t block_size;
-       gboolean debug_stream_read : 1;
-       gboolean debug_stream_write : 1;
-};
-
-static struct userdata data = {
-       .service_fd = -1,
-       .stream_fd = -1,
-       .transport = BT_CAPABILITIES_TRANSPORT_A2DP,
-       .rate = 48000,
-       .channels = 2,
-       .address = NULL
-};
-
-static int start_stream(struct userdata *u);
-static int stop_stream(struct userdata *u);
-static gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data);
-
-static GMainLoop *main_loop;
-
-static int service_send(struct userdata *u, const bt_audio_msg_header_t *msg)
-{
-       int err;
-       uint16_t length;
-
-       assert(u);
-
-       length = msg->length ? msg->length : BT_SUGGESTED_BUFFER_SIZE;
-
-       DBG("sending %s:%s", bt_audio_strtype(msg->type),
-               bt_audio_strname(msg->name));
-
-       if (send(u->service_fd, msg, length, 0) > 0)
-               err = 0;
-       else {
-               err = -errno;
-               ERR("Error sending data to audio service: %s(%d)",
-                       strerror(-err), -err);
-       }
-
-       return err;
-}
-
-static int service_recv(struct userdata *u, bt_audio_msg_header_t *rsp)
-{
-       int err;
-       const char *type, *name;
-       uint16_t length;
-
-       assert(u);
-
-       length = rsp->length ? : BT_SUGGESTED_BUFFER_SIZE;
-
-       DBG("trying to receive msg from audio service...");
-       if (recv(u->service_fd, rsp, length, 0) > 0) {
-               type = bt_audio_strtype(rsp->type);
-               name = bt_audio_strname(rsp->name);
-               if (type && name) {
-                       DBG("Received %s - %s", type, name);
-                       err = 0;
-               } else {
-                       err = -EINVAL;
-                       ERR("Bogus message type %d - name %d"
-                               "received from audio service",
-                               rsp->type, rsp->name);
-               }
-       } else {
-               err = -errno;
-               ERR("Error receiving data from audio service: %s(%d)",
-                       strerror(-err), -err);
-       }
-
-       return err;
-}
-
-static ssize_t service_expect(struct userdata *u, bt_audio_msg_header_t *rsp,
-                               uint8_t expected_name)
-{
-       int r;
-
-       assert(u);
-       assert(u->service_fd >= 0);
-       assert(rsp);
-
-       if ((r = service_recv(u, rsp)) < 0)
-               return r;
-
-       if ((rsp->type != BT_INDICATION && rsp->type != BT_RESPONSE) ||
-                       (rsp->name != expected_name)) {
-               if (rsp->type == BT_ERROR && rsp->length == sizeof(bt_audio_error_t))
-                       ERR("Received error condition: %s",
-                               strerror(((bt_audio_error_t*) rsp)->posix_errno));
-               else
-                       ERR("Bogus message %s received while %s was expected",
-                               bt_audio_strname(rsp->name),
-                               bt_audio_strname(expected_name));
-               return -1;
-       }
-
-       return 0;
-}
-
-static int init_bt(struct userdata *u)
-{
-       assert(u);
-
-       if (u->service_fd != -1)
-               return 0;
-
-       DBG("bt_audio_service_open");
-
-       u->service_fd = bt_audio_service_open();
-       if (u->service_fd < 0) {
-               int err = -errno;
-
-               ERR("bt_audio_service_open() failed: %s (%d)", strerror(-err),
-                                                                       -err);
-
-               return err;
-       }
-
-       return 0;
-}
-
-static int parse_caps(struct userdata *u, const struct bt_get_capabilities_rsp *rsp)
-{
-       unsigned char *ptr;
-       uint16_t bytes_left;
-       codec_capabilities_t codec;
-
-       assert(u);
-       assert(rsp);
-
-       bytes_left = rsp->h.length - sizeof(*rsp);
-
-       if (bytes_left < sizeof(codec_capabilities_t)) {
-               ERR("Packet too small to store codec information.");
-               return -1;
-       }
-
-       ptr = ((void *) rsp) + sizeof(*rsp);
-
-       memcpy(&codec, ptr, sizeof(codec)); /** ALIGNMENT? **/
-
-       DBG("Payload size is %lu %lu",
-               (unsigned long) bytes_left, (unsigned long) sizeof(codec));
-
-       if (u->transport != codec.transport) {
-               ERR("Got capabilities for wrong codec.");
-               return -1;
-       }
-
-       if (u->transport == BT_CAPABILITIES_TRANSPORT_SCO) {
-
-               if (bytes_left <= 0 ||
-                               codec.length != sizeof(u->hsp.pcm_capabilities))
-                       return -1;
-
-               assert(codec.type == BT_HFP_CODEC_PCM);
-
-               memcpy(&u->hsp.pcm_capabilities,
-                               &codec, sizeof(u->hsp.pcm_capabilities));
-
-               DBG("Has NREC: %s",
-                       YES_NO(u->hsp.pcm_capabilities.flags & BT_PCM_FLAG_NREC));
-
-       } else if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-
-               while (bytes_left > 0) {
-                       if (codec.type == BT_A2DP_SBC_SINK &&
-                                       !(codec.lock & BT_WRITE_LOCK))
-                               break;
-
-                       bytes_left -= codec.length;
-                       ptr += codec.length;
-                       memcpy(&codec, ptr, sizeof(codec));
-               }
-
-               DBG("bytes_left = %d, codec.length = %d",
-                                               bytes_left, codec.length);
-
-               if (bytes_left <= 0 ||
-                               codec.length != sizeof(u->a2dp.sbc_capabilities))
-                       return -1;
-
-               assert(codec.type == BT_A2DP_SBC_SINK);
-
-               memcpy(&u->a2dp.sbc_capabilities, &codec,
-                                       sizeof(u->a2dp.sbc_capabilities));
-       } else {
-               assert(0);
-       }
-
-       return 0;
-}
-
-static int get_caps(struct userdata *u)
-{
-       union {
-               struct bt_get_capabilities_req getcaps_req;
-               struct bt_get_capabilities_rsp getcaps_rsp;
-               bt_audio_error_t error;
-               uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
-       } msg;
-
-       assert(u);
-
-       memset(&msg, 0, sizeof(msg));
-       msg.getcaps_req.h.type = BT_REQUEST;
-       msg.getcaps_req.h.name = BT_GET_CAPABILITIES;
-       msg.getcaps_req.h.length = sizeof(msg.getcaps_req);
-
-       strncpy(msg.getcaps_req.destination, u->address,
-                       sizeof(msg.getcaps_req.destination));
-       msg.getcaps_req.transport = u->transport;
-       msg.getcaps_req.flags = BT_FLAG_AUTOCONNECT;
-
-       if (service_send(u, &msg.getcaps_req.h) < 0)
-               return -1;
-
-       msg.getcaps_rsp.h.length = 0;
-       if (service_expect(u, &msg.getcaps_rsp.h, BT_GET_CAPABILITIES) < 0)
-               return -1;
-
-       return parse_caps(u, &msg.getcaps_rsp);
-}
-
-static uint8_t a2dp_default_bitpool(uint8_t freq, uint8_t mode)
-{
-       switch (freq) {
-       case BT_SBC_SAMPLING_FREQ_16000:
-       case BT_SBC_SAMPLING_FREQ_32000:
-               return 53;
-
-       case BT_SBC_SAMPLING_FREQ_44100:
-
-               switch (mode) {
-               case BT_A2DP_CHANNEL_MODE_MONO:
-               case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 31;
-
-               case BT_A2DP_CHANNEL_MODE_STEREO:
-               case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
-                       return 53;
-
-               default:
-                       DBG("Invalid channel mode %u", mode);
-                       return 53;
-               }
-
-       case BT_SBC_SAMPLING_FREQ_48000:
-
-               switch (mode) {
-               case BT_A2DP_CHANNEL_MODE_MONO:
-               case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
-                       return 29;
-
-               case BT_A2DP_CHANNEL_MODE_STEREO:
-               case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
-                       return 51;
-
-               default:
-                       DBG("Invalid channel mode %u", mode);
-                       return 51;
-               }
-
-       default:
-               DBG("Invalid sampling freq %u", freq);
-               return 53;
-       }
-}
-
-static int setup_a2dp(struct userdata *u)
-{
-       sbc_capabilities_t *cap;
-       int i;
-
-       static const struct {
-               uint32_t rate;
-               uint8_t cap;
-       } freq_table[] = {
-               { 16000U, BT_SBC_SAMPLING_FREQ_16000 },
-               { 32000U, BT_SBC_SAMPLING_FREQ_32000 },
-               { 44100U, BT_SBC_SAMPLING_FREQ_44100 },
-               { 48000U, BT_SBC_SAMPLING_FREQ_48000 }
-       };
-
-       assert(u);
-       assert(u->transport == BT_CAPABILITIES_TRANSPORT_A2DP);
-
-       cap = &u->a2dp.sbc_capabilities;
-
-       /* Find the lowest freq that is at least as high as the requested
-        * sampling rate */
-       for (i = 0; (unsigned) i < ARRAY_SIZE(freq_table); i++)
-               if (freq_table[i].rate >= u->rate &&
-                       (cap->frequency & freq_table[i].cap)) {
-                       u->rate = freq_table[i].rate;
-                       cap->frequency = freq_table[i].cap;
-                       break;
-               }
-
-       if ((unsigned) i >= ARRAY_SIZE(freq_table)) {
-               for (; i >= 0; i--) {
-                       if (cap->frequency & freq_table[i].cap) {
-                               u->rate = freq_table[i].rate;
-                               cap->frequency = freq_table[i].cap;
-                               break;
-                       }
-               }
-
-               if (i < 0) {
-                       DBG("Not suitable sample rate");
-                       return -1;
-               }
-       }
-
-       if (u->channels <= 1) {
-               if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
-                       u->channels = 1;
-               } else
-                       u->channels = 2;
-       }
-
-       if (u->channels >= 2) {
-               u->channels = 2;
-
-               if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_JOINT_STEREO)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_JOINT_STEREO;
-               else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_STEREO)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_STEREO;
-               else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL)
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL;
-               else if (cap->channel_mode & BT_A2DP_CHANNEL_MODE_MONO) {
-                       cap->channel_mode = BT_A2DP_CHANNEL_MODE_MONO;
-                       u->channels = 1;
-               } else {
-                       DBG("No supported channel modes");
-                       return -1;
-               }
-       }
-
-       if (cap->block_length & BT_A2DP_BLOCK_LENGTH_16)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_16;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_12)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_12;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_8)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_8;
-       else if (cap->block_length & BT_A2DP_BLOCK_LENGTH_4)
-               cap->block_length = BT_A2DP_BLOCK_LENGTH_4;
-       else {
-               DBG("No supported block lengths");
-               return -1;
-       }
-
-       if (cap->subbands & BT_A2DP_SUBBANDS_8)
-               cap->subbands = BT_A2DP_SUBBANDS_8;
-       else if (cap->subbands & BT_A2DP_SUBBANDS_4)
-               cap->subbands = BT_A2DP_SUBBANDS_4;
-       else {
-               DBG("No supported subbands");
-               return -1;
-       }
-
-       if (cap->allocation_method & BT_A2DP_ALLOCATION_LOUDNESS)
-               cap->allocation_method = BT_A2DP_ALLOCATION_LOUDNESS;
-       else if (cap->allocation_method & BT_A2DP_ALLOCATION_SNR)
-               cap->allocation_method = BT_A2DP_ALLOCATION_SNR;
-
-       cap->min_bitpool = (uint8_t) MAX(MIN_BITPOOL, cap->min_bitpool);
-       cap->max_bitpool = (uint8_t) MIN(
-               a2dp_default_bitpool(cap->frequency, cap->channel_mode),
-               cap->max_bitpool);
-
-       return 0;
-}
-
-static void setup_sbc(struct a2dp_info *a2dp)
-{
-       sbc_capabilities_t *active_capabilities;
-
-       assert(a2dp);
-
-       active_capabilities = &a2dp->sbc_capabilities;
-
-       if (a2dp->sbc_initialized)
-               sbc_reinit(&a2dp->sbc, 0);
-       else
-               sbc_init(&a2dp->sbc, 0);
-       a2dp->sbc_initialized = TRUE;
-
-       switch (active_capabilities->frequency) {
-       case BT_SBC_SAMPLING_FREQ_16000:
-               a2dp->sbc.frequency = SBC_FREQ_16000;
-               break;
-       case BT_SBC_SAMPLING_FREQ_32000:
-               a2dp->sbc.frequency = SBC_FREQ_32000;
-               break;
-       case BT_SBC_SAMPLING_FREQ_44100:
-               a2dp->sbc.frequency = SBC_FREQ_44100;
-               break;
-       case BT_SBC_SAMPLING_FREQ_48000:
-               a2dp->sbc.frequency = SBC_FREQ_48000;
-               break;
-       default:
-               assert(0);
-       }
-
-       switch (active_capabilities->channel_mode) {
-       case BT_A2DP_CHANNEL_MODE_MONO:
-               a2dp->sbc.mode = SBC_MODE_MONO;
-               break;
-       case BT_A2DP_CHANNEL_MODE_DUAL_CHANNEL:
-               a2dp->sbc.mode = SBC_MODE_DUAL_CHANNEL;
-               break;
-       case BT_A2DP_CHANNEL_MODE_STEREO:
-               a2dp->sbc.mode = SBC_MODE_STEREO;
-               break;
-       case BT_A2DP_CHANNEL_MODE_JOINT_STEREO:
-               a2dp->sbc.mode = SBC_MODE_JOINT_STEREO;
-               break;
-       default:
-               assert(0);
-       }
-
-       switch (active_capabilities->allocation_method) {
-       case BT_A2DP_ALLOCATION_SNR:
-               a2dp->sbc.allocation = SBC_AM_SNR;
-               break;
-       case BT_A2DP_ALLOCATION_LOUDNESS:
-               a2dp->sbc.allocation = SBC_AM_LOUDNESS;
-               break;
-       default:
-               assert(0);
-       }
-
-       switch (active_capabilities->subbands) {
-       case BT_A2DP_SUBBANDS_4:
-               a2dp->sbc.subbands = SBC_SB_4;
-               break;
-       case BT_A2DP_SUBBANDS_8:
-               a2dp->sbc.subbands = SBC_SB_8;
-               break;
-       default:
-               assert(0);
-       }
-
-       switch (active_capabilities->block_length) {
-       case BT_A2DP_BLOCK_LENGTH_4:
-               a2dp->sbc.blocks = SBC_BLK_4;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_8:
-               a2dp->sbc.blocks = SBC_BLK_8;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_12:
-               a2dp->sbc.blocks = SBC_BLK_12;
-               break;
-       case BT_A2DP_BLOCK_LENGTH_16:
-               a2dp->sbc.blocks = SBC_BLK_16;
-               break;
-       default:
-               assert(0);
-       }
-
-       a2dp->sbc.bitpool = active_capabilities->max_bitpool;
-       a2dp->codesize = (uint16_t) sbc_get_codesize(&a2dp->sbc);
-}
-
-static int bt_open(struct userdata *u)
-{
-       union {
-               struct bt_open_req open_req;
-               struct bt_open_rsp open_rsp;
-               bt_audio_error_t error;
-               uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
-       } msg;
-
-       memset(&msg, 0, sizeof(msg));
-       msg.open_req.h.type = BT_REQUEST;
-       msg.open_req.h.name = BT_OPEN;
-       msg.open_req.h.length = sizeof(msg.open_req);
-
-       strncpy(msg.open_req.destination, u->address,
-                       sizeof(msg.open_req.destination));
-       msg.open_req.seid = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
-                               u->a2dp.sbc_capabilities.capability.seid :
-                               BT_A2DP_SEID_RANGE + 1;
-       msg.open_req.lock = u->transport == BT_CAPABILITIES_TRANSPORT_A2DP ?
-                               BT_WRITE_LOCK : BT_READ_LOCK | BT_WRITE_LOCK;
-
-       if (service_send(u, &msg.open_req.h) < 0)
-               return -1;
-
-       msg.open_rsp.h.length = sizeof(msg.open_rsp);
-       if (service_expect(u, &msg.open_rsp.h, BT_OPEN) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int set_conf(struct userdata *u)
-{
-       union {
-               struct bt_set_configuration_req setconf_req;
-               struct bt_set_configuration_rsp setconf_rsp;
-               bt_audio_error_t error;
-               uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
-       } msg;
-
-       if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               if (setup_a2dp(u) < 0)
-                       return -1;
-       }
-
-       memset(&msg, 0, sizeof(msg));
-       msg.setconf_req.h.type = BT_REQUEST;
-       msg.setconf_req.h.name = BT_SET_CONFIGURATION;
-       msg.setconf_req.h.length = sizeof(msg.setconf_req);
-
-       if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               memcpy(&msg.setconf_req.codec, &u->a2dp.sbc_capabilities,
-                       sizeof(u->a2dp.sbc_capabilities));
-               msg.setconf_req.h.length += msg.setconf_req.codec.length -
-                       sizeof(msg.setconf_req.codec);
-       } else {
-               msg.setconf_req.codec.transport = BT_CAPABILITIES_TRANSPORT_SCO;
-               msg.setconf_req.codec.seid = BT_A2DP_SEID_RANGE + 1;
-               msg.setconf_req.codec.length = sizeof(pcm_capabilities_t);
-       }
-
-       if (service_send(u, &msg.setconf_req.h) < 0)
-               return -1;
-
-       msg.setconf_rsp.h.length = sizeof(msg.setconf_rsp);
-       if (service_expect(u, &msg.setconf_rsp.h, BT_SET_CONFIGURATION) < 0)
-               return -1;
-
-       u->link_mtu = msg.setconf_rsp.link_mtu;
-
-       /* setup SBC encoder now we agree on parameters */
-       if (u->transport == BT_CAPABILITIES_TRANSPORT_A2DP) {
-               setup_sbc(&u->a2dp);
-               u->block_size = u->a2dp.codesize;
-               DBG("SBC parameters:\n\tallocation=%u\n"
-                       "\tsubbands=%u\n\tblocks=%u\n\tbitpool=%u\n",
-                       u->a2dp.sbc.allocation, u->a2dp.sbc.subbands,
-                       u->a2dp.sbc.blocks, u->a2dp.sbc.bitpool);
-       } else
-               u->block_size = u->link_mtu;
-
-       return 0;
-}
-
-static int setup_bt(struct userdata *u)
-{
-       assert(u);
-
-       if (get_caps(u) < 0)
-               return -1;
-
-       DBG("Got device caps");
-
-       if (bt_open(u) < 0)
-               return -1;
-
-       if (set_conf(u) < 0)
-               return -1;
-
-       return 0;
-}
-
-static int init_profile(struct userdata *u)
-{
-       assert(u);
-
-       return setup_bt(u);
-}
-
-static void shutdown_bt(struct userdata *u)
-{
-       assert(u);
-
-       if (u->stream_fd != -1) {
-               stop_stream(u);
-               DBG("close(stream_fd)");
-               close(u->stream_fd);
-               u->stream_fd = -1;
-       }
-
-       if (u->service_fd != -1) {
-               DBG("bt_audio_service_close");
-               bt_audio_service_close(u->service_fd);
-               u->service_fd = -1;
-       }
-}
-
-static void make_fd_nonblock(int fd)
-{
-       int v;
-
-       assert(fd >= 0);
-       assert((v = fcntl(fd, F_GETFL)) >= 0);
-
-       if (!(v & O_NONBLOCK))
-               assert(fcntl(fd, F_SETFL, v|O_NONBLOCK) >= 0);
-}
-
-static void make_socket_low_delay(int fd)
-{
-/* FIXME: is this widely supported? */
-#ifdef SO_PRIORITY
-       int priority;
-       assert(fd >= 0);
-
-       priority = 6;
-       if (setsockopt(fd, SOL_SOCKET, SO_PRIORITY, (void*)&priority,
-                       sizeof(priority)) < 0)
-               ERR("SO_PRIORITY failed: %s", strerror(errno));
-#endif
-}
-
-static int read_stream(struct userdata *u)
-{
-       int ret = 0;
-       ssize_t l;
-       char *buf;
-
-       assert(u);
-       assert(u->stream_fd >= 0);
-
-       buf = alloca(u->link_mtu);
-
-       for (;;) {
-               l = read(u->stream_fd, buf, u->link_mtu);
-               if (u->debug_stream_read)
-                       DBG("read from socket: %lli bytes", (long long) l);
-               if (l <= 0) {
-                       if (l < 0 && errno == EINTR)
-                               continue;
-                       else {
-                               ERR("Failed to read date from stream_fd: %s",
-                                       ret < 0 ? strerror(errno) : "EOF");
-                               return -1;
-                       }
-               } else {
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-/* It's what PulseAudio is doing, not sure it's necessary for this
- * test */
-static ssize_t pa_write(int fd, const void *buf, size_t count)
-{
-       ssize_t r;
-
-       if ((r = send(fd, buf, count, MSG_NOSIGNAL)) >= 0)
-               return r;
-
-       if (errno != ENOTSOCK)
-               return r;
-
-       return write(fd, buf, count);
-}
-
-static int write_stream(struct userdata *u)
-{
-       int ret = 0;
-       ssize_t l;
-       char *buf;
-
-       assert(u);
-       assert(u->stream_fd >= 0);
-       buf = alloca(u->link_mtu);
-
-       for (;;) {
-               l = pa_write(u->stream_fd, buf, u->link_mtu);
-               if (u->debug_stream_write)
-                       DBG("written to socket: %lli bytes", (long long) l);
-               assert(l != 0);
-               if (l < 0) {
-                       if (errno == EINTR)
-                               continue;
-                       else {
-                               ERR("Failed to write data: %s", strerror(errno));
-                               ret = -1;
-                               break;
-                       }
-               } else {
-                       assert((size_t)l <= u->link_mtu);
-                       break;
-               }
-       }
-
-       return ret;
-}
-
-static gboolean stream_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
-{
-       struct userdata *u;
-
-       assert(u = data);
-
-       if (condition & G_IO_IN) {
-               if (read_stream(u) < 0)
-                       goto fail;
-       } else if (condition & G_IO_OUT) {
-               if (write_stream(u) < 0)
-                       goto fail;
-       } else {
-               DBG("Got %d", condition);
-               g_main_loop_quit(main_loop);
-               return FALSE;
-       }
-
-       return TRUE;
-
-fail:
-       stop_stream(u);
-       return FALSE;
-}
-
-static int start_stream(struct userdata *u)
-{
-       union {
-               bt_audio_msg_header_t rsp;
-               struct bt_start_stream_req start_req;
-               struct bt_start_stream_rsp start_rsp;
-               struct bt_new_stream_ind streamfd_ind;
-               bt_audio_error_t error;
-               uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
-       } msg;
-
-       assert(u);
-
-       if (u->stream_fd >= 0)
-               return 0;
-       if (u->stream_watch != 0) {
-               g_source_remove(u->stream_watch);
-               u->stream_watch = 0;
-       }
-       if (u->stream_channel != 0) {
-               g_io_channel_unref(u->stream_channel);
-               u->stream_channel = NULL;
-       }
-
-       memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
-       msg.start_req.h.type = BT_REQUEST;
-       msg.start_req.h.name = BT_START_STREAM;
-       msg.start_req.h.length = sizeof(msg.start_req);
-
-       if (service_send(u, &msg.start_req.h) < 0)
-               return -1;
-
-       msg.rsp.length = sizeof(msg.start_rsp);
-       if (service_expect(u, &msg.rsp, BT_START_STREAM) < 0)
-               return -1;
-
-       msg.rsp.length = sizeof(msg.streamfd_ind);
-       if (service_expect(u, &msg.rsp, BT_NEW_STREAM) < 0)
-               return -1;
-
-       if ((u->stream_fd = bt_audio_service_get_data_fd(u->service_fd)) < 0) {
-               DBG("Failed to get stream fd from audio service.");
-               return -1;
-       }
-
-       make_fd_nonblock(u->stream_fd);
-       make_socket_low_delay(u->stream_fd);
-
-       assert(u->stream_channel = g_io_channel_unix_new(u->stream_fd));
-
-       u->stream_watch = g_io_add_watch(u->stream_channel,
-                                       G_IO_IN|G_IO_OUT|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
-                                       stream_cb, u);
-
-       return 0;
-}
-
-static int stop_stream(struct userdata *u)
-{
-       union {
-               bt_audio_msg_header_t rsp;
-               struct bt_stop_stream_req stop_req;
-               struct bt_stop_stream_rsp stop_rsp;
-               bt_audio_error_t error;
-               uint8_t buf[BT_SUGGESTED_BUFFER_SIZE];
-       } msg;
-       int r = 0;
-
-       if (u->stream_fd < 0)
-               return 0;
-
-       assert(u);
-       assert(u->stream_channel);
-
-       g_source_remove(u->stream_watch);
-       u->stream_watch = 0;
-       g_io_channel_unref(u->stream_channel);
-       u->stream_channel = NULL;
-
-       memset(msg.buf, 0, BT_SUGGESTED_BUFFER_SIZE);
-       msg.stop_req.h.type = BT_REQUEST;
-       msg.stop_req.h.name = BT_STOP_STREAM;
-       msg.stop_req.h.length = sizeof(msg.stop_req);
-
-       if (service_send(u, &msg.stop_req.h) < 0) {
-               r = -1;
-               goto done;
-       }
-
-       msg.rsp.length = sizeof(msg.stop_rsp);
-       if (service_expect(u, &msg.rsp, BT_STOP_STREAM) < 0)
-               r = -1;
-
-done:
-       close(u->stream_fd);
-       u->stream_fd = -1;
-
-       return r;
-}
-
-static gboolean sleep_cb(gpointer data)
-{
-       struct userdata *u;
-
-       assert(u = data);
-
-       u->gin_watch = g_io_add_watch(u->gin,
-               G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, data);
-
-       printf(">>> ");
-       fflush(stdout);
-
-       return FALSE;
-}
-
-static gboolean input_cb(GIOChannel *gin, GIOCondition condition, gpointer data)
-{
-       char *line, *tmp;
-       gsize term_pos;
-       GError *error = NULL;
-       struct userdata *u;
-       int success;
-
-       assert(u = data);
-       if (!(condition & G_IO_IN)) {
-               DBG("Got %d", condition);
-               g_main_loop_quit(main_loop);
-               return FALSE;
-       }
-
-       if (g_io_channel_read_line(gin, &line, NULL, &term_pos, &error) !=
-               G_IO_STATUS_NORMAL)
-               return FALSE;
-
-       line[term_pos] = '\0';
-       g_strstrip(line);
-       if ((tmp = strchr(line, '#')))
-               *tmp = '\0';
-       success = FALSE;
-
-#define IF_CMD(cmd) \
-       if (!success && (success = (strncmp(line, #cmd, strlen(#cmd)) == 0)))
-
-       IF_CMD(quit) {
-               g_main_loop_quit(main_loop);
-               return FALSE;
-       }
-
-       IF_CMD(sleep) {
-               unsigned int seconds;
-               if (sscanf(line, "%*s %d", &seconds) != 1)
-                       DBG("sleep SECONDS");
-               else {
-                       g_source_remove(u->gin_watch);
-                       g_timeout_add_seconds(seconds, sleep_cb, u);
-                       return FALSE;
-               }
-       }
-
-       IF_CMD(debug) {
-               char *what = NULL;
-               int enable;
-
-               if (sscanf(line, "%*s %as %d", &what, &enable) != 1)
-                       DBG("debug [stream_read|stream_write] [0|1]");
-               if (strncmp(what, "stream_read", 12) == 0) {
-                       u->debug_stream_read = enable;
-               } else if (strncmp(what, "stream_write", 13) == 0) {
-                       u->debug_stream_write = enable;
-               } else {
-                       DBG("debug [stream_read|stream_write] [0|1]");
-               }
-       }
-
-       IF_CMD(init_bt) {
-               DBG("%d", init_bt(u));
-       }
-
-       IF_CMD(init_profile) {
-               DBG("%d", init_profile(u));
-       }
-
-       IF_CMD(start_stream) {
-               DBG("%d", start_stream(u));
-       }
-
-       IF_CMD(stop_stream) {
-               DBG("%d", stop_stream(u));
-       }
-
-       IF_CMD(shutdown_bt) {
-               shutdown_bt(u);
-       }
-
-       IF_CMD(rate) {
-               if (sscanf(line, "%*s %d", &u->rate) != 1)
-                       DBG("set with rate RATE");
-               DBG("rate %d", u->rate);
-       }
-
-       IF_CMD(bdaddr) {
-               char *address;
-
-               if (sscanf(line, "%*s %as", &address) != 1)
-                       DBG("set with bdaddr BDADDR");
-
-               free(u->address);
-
-               u->address = address;
-               DBG("bdaddr %s", u->address);
-       }
-
-       IF_CMD(profile) {
-               char *profile = NULL;
-
-               if (sscanf(line, "%*s %as", &profile) != 1)
-                       DBG("set with profile [hsp|a2dp]");
-               if (strncmp(profile, "hsp", 4) == 0) {
-                       u->transport = BT_CAPABILITIES_TRANSPORT_SCO;
-               } else if (strncmp(profile, "a2dp", 5) == 0) {
-                       u->transport = BT_CAPABILITIES_TRANSPORT_A2DP;
-               } else {
-                       DBG("set with profile [hsp|a2dp]");
-               }
-
-               free(profile);
-               DBG("profile %s", u->transport == BT_CAPABILITIES_TRANSPORT_SCO ?
-                       "hsp" : "a2dp");
-       }
-
-       if (!success && strlen(line) != 0) {
-               DBG("%s, unknown command", line);
-       }
-
-       printf(">>> ");
-       fflush(stdout);
-       return TRUE;
-}
-
-
-static void show_usage(char* prgname)
-{
-       printf("%s: ipctest [--interactive] BDADDR\n", basename(prgname));
-}
-
-static void sig_term(int sig)
-{
-       g_main_loop_quit(main_loop);
-}
-
-int main(int argc, char *argv[])
-{
-       if (argc < 2) {
-               show_usage(argv[0]);
-               exit(EXIT_FAILURE);
-       }
-
-       assert(main_loop = g_main_loop_new(NULL, FALSE));
-
-       if (strncmp("--interactive", argv[1], 14) == 0) {
-               if (argc < 3) {
-                       show_usage(argv[0]);
-                       exit(EXIT_FAILURE);
-               }
-
-               data.address = strdup(argv[2]);
-
-               signal(SIGTERM, sig_term);
-               signal(SIGINT, sig_term);
-
-               assert(data.gin = g_io_channel_unix_new(fileno(stdin)));
-
-               data.gin_watch = g_io_add_watch(data.gin,
-                       G_IO_IN|G_IO_ERR|G_IO_HUP|G_IO_NVAL, input_cb, &data);
-
-               printf(">>> ");
-               fflush(stdout);
-
-               g_main_loop_run(main_loop);
-
-       } else {
-               data.address = strdup(argv[1]);
-
-               assert(init_bt(&data) == 0);
-
-               assert(init_profile(&data) == 0);
-
-               assert(start_stream(&data) == 0);
-
-               g_main_loop_run(main_loop);
-
-               assert(stop_stream(&data) == 0);
-
-               shutdown_bt(&data);
-       }
-
-       g_main_loop_unref(main_loop);
-
-       printf("\nExiting\n");
-
-       exit(EXIT_SUCCESS);
-
-       return 0;
-}
index 7ef6511..0aac217 100755 (executable)
@@ -7,7 +7,7 @@ import dbus
 bus = dbus.SystemBus()
 
 manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
+                                       "org.freedesktop.DBus.ObjectManager")
 
 def extract_objects(object_list):
        list = ""
@@ -29,42 +29,37 @@ def extract_uuids(uuid_list):
                list = list + val + " "
        return list
 
-adapter_list = manager.ListAdapters()
+objects = manager.GetManagedObjects()
 
-for i in adapter_list:
-       adapter = dbus.Interface(bus.get_object("org.bluez", i),
-                                                       "org.bluez.Adapter")
-       print("[ " + i + " ]")
+all_devices = (str(path) for path, interfaces in objects.iteritems() if
+                                       "org.bluez.Device1" in interfaces.keys())
 
-       properties  = adapter.GetProperties()
+for path, interfaces in objects.iteritems():
+       if "org.bluez.Adapter1" not in interfaces.keys():
+               continue
+
+       print("[ " + path + " ]")
+
+       properties = interfaces["org.bluez.Adapter1"]
        for key in properties.keys():
                value = properties[key]
-               if (key == "Devices"):
-                       list = extract_objects(value)
-                       print("    %s = %s" % (key, list))
-               elif (key == "UUIDs"):
+               if (key == "UUIDs"):
                        list = extract_uuids(value)
                        print("    %s = %s" % (key, list))
                else:
                        print("    %s = %s" % (key, value))
 
-       try:
-               device_list = properties["Devices"]
-       except:
-               device_list = []
+       device_list = [d for d in all_devices if d.startswith(path + "/")]
+
+       for dev_path in device_list:
+               print("    [ " + dev_path + " ]")
 
-       for n in device_list:
-               device = dbus.Interface(bus.get_object("org.bluez", n),
-                                                       "org.bluez.Device")
-               print("    [ " + n + " ]")
+               dev = objects[dev_path]
+               properties = dev["org.bluez.Device1"]
 
-               properties = device.GetProperties()
                for key in properties.keys():
                        value = properties[key]
-                       if (key == "Nodes"):
-                               list = extract_objects(value)
-                               print("        %s = %s" % (key, list))
-                       elif (key == "UUIDs"):
+                       if (key == "UUIDs"):
                                list = extract_uuids(value)
                                print("        %s = %s" % (key, list))
                        elif (key == "Class"):
@@ -78,18 +73,4 @@ for i in adapter_list:
                        else:
                                print("        %s = %s" % (key, value))
 
-               try:
-                       node_list = properties["Nodes"]
-               except:
-                       node_list = []
-
-               for x in node_list:
-                       node = dbus.Interface(bus.get_object("org.bluez", x),
-                                                       "org.bluez.Node")
-                       print("        [ " + x + " ]")
-
-                       properties = node.GetProperties()
-                       for key in properties.keys():
-                               print("            %s = %s" % (key, properties[key]))
-
        print("")
diff --git a/test/lmptest.c b/test/lmptest.c
deleted file mode 100644 (file)
index 549ae12..0000000
+++ /dev/null
@@ -1,175 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-
-#if 0
-#define OCF_ERICSSON_SEND_LMP          0x0021
-typedef struct {
-       uint16_t handle;
-       uint8_t  length;
-       uint8_t  data[17];
-} __attribute__ ((packed)) ericsson_send_lmp_cp;
-#define ERICSSON_SEND_LMP_CP_SIZE 20
-
-static int ericsson_send_lmp(int dd, uint16_t handle, uint8_t length, uint8_t *data)
-{
-       struct hci_request rq;
-       ericsson_send_lmp_cp cp;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.handle = htobs(handle);
-       cp.length = length;
-       memcpy(cp.data, data, length);
-
-       memset(&rq, 0, sizeof(rq));
-       rq.ogf    = OGF_VENDOR_CMD;
-       rq.ocf    = OCF_ERICSSON_SEND_LMP;
-       rq.cparam = &cp;
-       rq.clen   = ERICSSON_SEND_LMP_CP_SIZE;
-       rq.rparam = NULL;
-       rq.rlen   = 0;
-
-       if (hci_send_req(dd, &rq, 1000) < 0)
-               return -1;
-
-       return 0;
-}
-#endif
-
-#define OCF_ERICSSON_WRITE_EVENTS      0x0043
-typedef struct {
-       uint8_t mask;
-       uint8_t opcode;
-       uint8_t opcode_ext;
-} __attribute__ ((packed)) ericsson_write_events_cp;
-#define ERICSSON_WRITE_EVENTS_CP_SIZE 3
-
-static int ericsson_write_events(int dd, uint8_t mask)
-{
-       struct hci_request rq;
-       ericsson_write_events_cp cp;
-
-       memset(&cp, 0, sizeof(cp));
-       cp.mask = mask;
-       cp.opcode = 0x00;
-       cp.opcode_ext = 0x00;
-
-       memset(&rq, 0, sizeof(rq));
-       rq.ogf    = OGF_VENDOR_CMD;
-       rq.ocf    = OCF_ERICSSON_WRITE_EVENTS;
-       rq.cparam = &cp;
-       rq.clen   = ERICSSON_WRITE_EVENTS_CP_SIZE;
-       rq.rparam = NULL;
-       rq.rlen   = 0;
-
-       if (hci_send_req(dd, &rq, 1000) < 0)
-               return -1;
-
-       return 0;
-}
-
-static void usage(void)
-{
-       printf("lmptest - Utility for testing special LMP functions\n\n");
-       printf("Usage:\n"
-               "\tlmptest [-i <dev>]\n");
-}
-
-static struct option main_options[] = {
-       { "device",     1, 0, 'i' },
-       { "help",       0, 0, 'h' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       struct hci_version ver;
-       int dd, opt, dev = 0;
-
-       while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
-               switch (opt) {
-               case 'i':
-                       dev = hci_devid(optarg);
-                       if (dev < 0) {
-                               perror("Invalid device");
-                               exit(1);
-                       }
-                       break;
-
-               case 'h':
-               default:
-                       usage();
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       dd = hci_open_dev(dev);
-       if (dd < 0) {
-               fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
-                                               dev, strerror(errno), errno);
-               exit(1);
-       }
-
-       if (hci_read_local_version(dd, &ver, 1000) < 0) {
-               fprintf(stderr, "Can't read version for hci%d: %s (%d)\n",
-                                               dev, strerror(errno), errno);
-               hci_close_dev(dd);
-               exit(1);
-       }
-
-       if (ver.manufacturer != 37 && ver.manufacturer != 48) {
-               fprintf(stderr, "Can't find supported device hci%d: %s (%d)\n",
-                                               dev, strerror(ENOSYS), ENOSYS);
-               hci_close_dev(dd);
-               exit(1);
-       }
-
-       if (ericsson_write_events(dd, 0x03) < 0) {
-               fprintf(stderr, "Can't activate events for hci%d: %s (%d)\n",
-                                               dev, strerror(errno), errno);
-               hci_close_dev(dd);
-               exit(1);
-       }
-
-       hci_close_dev(dd);
-
-       return 0;
-}
index 4a598e1..bc5ddaf 100755 (executable)
@@ -7,15 +7,28 @@ import gobject
 import dbus
 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))
+relevant_ifaces = [ "org.bluez.Adapter1", "org.bluez.Device1" ]
 
-def object_signal(value, path, interface, member):
+def property_changed(interface, changed, invalidated, path):
        iface = interface[interface.rfind(".") + 1:]
-       val = str(value)
-       print("{%s.%s} [%s] Path = %s" % (iface, member, path, val))
+       for name, value in changed.iteritems():
+               val = str(value)
+               print("{%s.PropertyChanged} [%s] %s = %s" % (iface, path, name,
+                                                                       val))
+
+def interfaces_added(path, interfaces):
+       for iface, props in interfaces.iteritems():
+               if not(iface in relevant_ifaces):
+                       continue
+               print("{Added %s} [%s]" % (iface, path))
+               for name, value in props.iteritems():
+                       print("      %s = %s" % (name, value))
+
+def interfaces_removed(path, interfaces):
+       for iface in interfaces:
+               if not(iface in relevant_ifaces):
+                       continue
+               print("{Removed %s} [%s]" % (iface, path))
 
 if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
@@ -23,36 +36,17 @@ if __name__ == '__main__':
        bus = dbus.SystemBus()
 
        bus.add_signal_receiver(property_changed, bus_name="org.bluez",
-                                       signal_name = "PropertyChanged",
-                                               path_keyword="path",
-                                               interface_keyword="interface")
-
-       bus.add_signal_receiver(object_signal, bus_name="org.bluez",
-                                       signal_name = "AdapterAdded",
-                                               path_keyword="path",
-                                               member_keyword="member",
-                                               interface_keyword="interface")
-       bus.add_signal_receiver(object_signal, bus_name="org.bluez",
-                                       signal_name = "AdapterRemoved",
-                                               path_keyword="path",
-                                               member_keyword="member",
-                                               interface_keyword="interface")
-       bus.add_signal_receiver(object_signal, bus_name="org.bluez",
-                                       signal_name = "DefaultAdapterChanged",
-                                               path_keyword="path",
-                                               member_keyword="member",
-                                               interface_keyword="interface")
-
-       bus.add_signal_receiver(object_signal, bus_name="org.bluez",
-                                       signal_name = "DeviceCreated",
-                                               path_keyword="path",
-                                               member_keyword="member",
-                                               interface_keyword="interface")
-       bus.add_signal_receiver(object_signal, bus_name="org.bluez",
-                                       signal_name = "DeviceRemoved",
-                                               path_keyword="path",
-                                               member_keyword="member",
-                                               interface_keyword="interface")
+                       dbus_interface="org.freedesktop.DBus.Properties",
+                       signal_name="PropertiesChanged",
+                       path_keyword="path")
+
+       bus.add_signal_receiver(interfaces_added, bus_name="org.bluez",
+                       dbus_interface="org.freedesktop.DBus.ObjectManager",
+                       signal_name="InterfacesAdded")
+
+       bus.add_signal_receiver(interfaces_removed, bus_name="org.bluez",
+                       dbus_interface="org.freedesktop.DBus.ObjectManager",
+                       signal_name="InterfacesRemoved")
 
        mainloop = gobject.MainLoop()
        mainloop.run()
diff --git a/test/mpris-player.c b/test/mpris-player.c
deleted file mode 100644 (file)
index a2c4cc6..0000000
+++ /dev/null
@@ -1,993 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <getopt.h>
-#include <string.h>
-
-#include <dbus/dbus.h>
-#include <glib.h>
-
-static volatile sig_atomic_t __io_canceled = 0;
-static volatile sig_atomic_t __io_terminated = 0;
-static char *adapter = NULL;
-static DBusConnection *sys = NULL;
-static DBusConnection *session = NULL;
-
-static void sig_term(int sig)
-{
-       __io_canceled = 1;
-}
-
-static DBusMessage *get_all(DBusConnection *conn, const char *name)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *iface = "org.mpris.MediaPlayer2.Player";
-
-       msg = dbus_message_new_method_call(name, "/org/mpris/MediaPlayer2",
-                                       DBUS_INTERFACE_PROPERTIES, "GetAll");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't get default adapter\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       return reply;
-}
-
-static void append_variant(DBusMessageIter *iter, int type, void *val)
-{
-       DBusMessageIter value;
-       char sig[2] = { type, '\0' };
-
-       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
-
-       dbus_message_iter_append_basic(&value, type, val);
-
-       dbus_message_iter_close_container(iter, &value);
-}
-
-static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
-                                                               void *val)
-{
-       DBusMessageIter entry;
-
-       if (type == DBUS_TYPE_STRING) {
-               const char *str = *((const char **) val);
-               if (str == NULL)
-                       return;
-       }
-
-       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
-                                                       NULL, &entry);
-
-       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
-
-       append_variant(&entry, type, val);
-
-       dbus_message_iter_close_container(dict, &entry);
-}
-
-static dbus_bool_t emit_property_changed(DBusConnection *conn,
-                                       const char *path,
-                                       const char *interface,
-                                       const char *name,
-                                       int type, void *value)
-{
-       DBusMessage *signal;
-       DBusMessageIter iter;
-       dbus_bool_t result;
-
-       signal = dbus_message_new_signal(path, interface, "PropertyChanged");
-
-       if (!signal) {
-               fprintf(stderr, "Unable to allocate new %s.PropertyChanged"
-                                                       " signal", interface);
-               return FALSE;
-       }
-
-       dbus_message_iter_init_append(signal, &iter);
-
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_STRING, &name);
-
-       append_variant(&iter, type, value);
-
-       result = dbus_connection_send(conn, signal, NULL);
-       dbus_message_unref(signal);
-
-       return result;
-}
-
-static int parse_property(DBusConnection *conn, const char *path,
-                                               const char *key,
-                                               DBusMessageIter *entry,
-                                               DBusMessageIter *properties)
-{
-       DBusMessageIter var;
-
-       printf("property %s found\n", key);
-
-       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(entry, &var);
-
-       if (strcasecmp(key, "PlaybackStatus") == 0) {
-               const char *value;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &value);
-
-               if (properties)
-                       dict_append_entry(properties, "Status",
-                                               DBUS_TYPE_STRING, &value);
-               else
-                       emit_property_changed(sys, path,
-                                       "org.bluez.MediaPlayer", "Status",
-                                       DBUS_TYPE_STRING, &value);
-       } else if (strcasecmp(key, "Position") == 0) {
-               int64_t usec, msec;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_INT64)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &usec);
-               msec = usec / 1000;
-
-               if (properties)
-                       dict_append_entry(properties, "Position",
-                                               DBUS_TYPE_UINT32, &msec);
-               else
-                       emit_property_changed(sys, path,
-                                       "org.bluez.MediaPlayer", "Position",
-                                       DBUS_TYPE_UINT32, &msec);
-       } else if (strcasecmp(key, "Shuffle") == 0) {
-               dbus_bool_t value;
-               const char *str;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_BOOLEAN)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &value);
-
-               str = value ? "on" : "off";
-               if (properties)
-                       dict_append_entry(properties, "Shuffle",
-                                               DBUS_TYPE_STRING, &str);
-               else
-                       emit_property_changed(sys, path,
-                                       "org.bluez.MediaPlayer", "Shuffle",
-                                       DBUS_TYPE_UINT32, &str);
-       }
-
-       return 0;
-}
-
-static int parse_properties(DBusConnection *conn, const char *path,
-                                               DBusMessageIter *args,
-                                               DBusMessageIter *properties)
-{
-       DBusMessageIter dict;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(args, &dict);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
-                                                       DBUS_TYPE_INVALID) {
-               DBusMessageIter entry;
-               const char *key;
-
-               if (ctype != DBUS_TYPE_DICT_ENTRY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&dict, &entry);
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&entry, &key);
-               dbus_message_iter_next(&entry);
-
-               if (parse_property(conn, path, key, &entry, properties) < 0)
-                       return -EINVAL;
-
-               dbus_message_iter_next(&dict);
-       }
-
-       return 0;
-}
-
-static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
-                                               DBusMessageIter *metadata)
-{
-       DBusMessageIter var;
-
-       printf("metadata %s found\n", key);
-
-       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(entry, &var);
-
-       if (strcasecmp(key, "xesam:title") == 0) {
-               const char *value;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &value);
-               dict_append_entry(metadata, "Title", DBUS_TYPE_STRING,
-                                                               &value);
-       } else if (strcasecmp(key, "xesam:artist") == 0) {
-               const char *value;
-               DBusMessageIter array;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_ARRAY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&var, &array);
-
-               if (dbus_message_iter_get_arg_type(&array) !=
-                                                       DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&array, &value);
-               dict_append_entry(metadata, "Artist", DBUS_TYPE_STRING,
-                                                               &value);
-       } else if (strcasecmp(key, "xesam:album") == 0) {
-               const char *value;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &value);
-               dict_append_entry(metadata, "Album", DBUS_TYPE_STRING,
-                                                               &value);
-       } else if (strcasecmp(key, "xesam:genre") == 0) {
-               const char *value;
-               DBusMessageIter array;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_ARRAY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&var, &array);
-
-               if (dbus_message_iter_get_arg_type(&array) !=
-                                                       DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&array, &value);
-               dict_append_entry(metadata, "Genre", DBUS_TYPE_STRING,
-                                                               &value);
-       } else if (strcasecmp(key, "mpris:length") == 0) {
-               int64_t usec, msec;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_INT64)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &usec);
-               msec = usec / 1000;
-
-               dict_append_entry(metadata, "Duration", DBUS_TYPE_UINT32,
-                                                               &msec);
-       } else if (strcasecmp(key, "xesam:trackNumber") == 0) {
-               int32_t value;
-
-               if (dbus_message_iter_get_arg_type(&var) !=
-                                                       DBUS_TYPE_INT32)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&var, &value);
-
-               dict_append_entry(metadata, "Number", DBUS_TYPE_UINT32,
-                                                               &value);
-       }
-
-       return 0;
-}
-
-static int parse_track(DBusMessageIter *args, DBusMessageIter *metadata)
-{
-       DBusMessageIter var, dict;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_VARIANT)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(args, &var);
-
-       ctype = dbus_message_iter_get_arg_type(&var);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(&var, &dict);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
-                                                       DBUS_TYPE_INVALID) {
-               DBusMessageIter entry;
-               const char *key;
-
-               if (ctype != DBUS_TYPE_DICT_ENTRY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&dict, &entry);
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&entry, &key);
-               dbus_message_iter_next(&entry);
-
-               if (parse_metadata_entry(&entry, key, metadata) < 0)
-                       return -EINVAL;
-
-               dbus_message_iter_next(&dict);
-       }
-
-       return 0;
-}
-
-static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata)
-{
-       DBusMessageIter dict;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return -EINVAL;
-
-       dbus_message_iter_recurse(args, &dict);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
-                                                       DBUS_TYPE_INVALID) {
-               DBusMessageIter entry;
-               const char *key;
-
-               if (ctype != DBUS_TYPE_DICT_ENTRY)
-                       return -EINVAL;
-
-               dbus_message_iter_recurse(&dict, &entry);
-               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
-                       return -EINVAL;
-
-               dbus_message_iter_get_basic(&entry, &key);
-               dbus_message_iter_next(&entry);
-
-               if (strcasecmp(key, "Metadata") == 0)
-                       return parse_track(&entry, metadata);
-
-               dbus_message_iter_next(&dict);
-       }
-
-       return -EINVAL;
-}
-
-static char *sender2path(const char *sender)
-{
-       char *path;
-
-       path = g_strconcat("/", sender, NULL);
-       return g_strdelimit(path, ":.", '_');
-}
-
-static DBusHandlerResult player_message(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       if (dbus_message_is_method_call(msg, "org.bluez.MediaPlayer",
-                                                               "Release")) {
-               printf("Release\n");
-               exit(1);
-       }
-
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static const DBusObjectPathVTable player_table = {
-       .message_function = player_message,
-};
-
-static void add_player(DBusConnection *conn, const char *name,
-                                                       const char *sender)
-{
-       DBusMessage *reply = get_all(conn, name);
-       DBusMessage *msg;
-       DBusMessageIter iter, args, properties, metadata;
-       DBusError err;
-       char *path;
-
-       if (!reply)
-               return;
-
-       msg = dbus_message_new_method_call("org.bluez", adapter,
-                                       "org.bluez.Media",
-                                       "RegisterPlayer");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return;
-       }
-
-       dbus_message_iter_init_append(msg, &iter);
-
-       path = sender2path(sender);
-       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &properties);
-
-       dbus_message_iter_init(reply, &args);
-
-       if (parse_properties(conn, path, &args, &properties) < 0)
-               goto done;
-
-       dbus_message_iter_close_container(&iter, &properties);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
-
-       dbus_message_iter_init(reply, &args);
-
-       if (parse_metadata(&args, &metadata) < 0)
-               goto done;
-
-       dbus_message_iter_close_container(&iter, &metadata);
-
-       dbus_message_unref(reply);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err);
-       if (!reply) {
-               fprintf(stderr, "Can't register player\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               goto done;
-       }
-
-       if (!dbus_connection_register_object_path(sys, path, &player_table,
-                                                               NULL))
-               fprintf(stderr, "Can't register object path for agent\n");
-
-done:
-       if (reply)
-               dbus_message_unref(reply);
-       dbus_message_unref(msg);
-       g_free(path);
-}
-
-static void remove_player(DBusConnection *conn, const char *sender)
-{
-       DBusMessage *msg;
-       char *path;
-
-       msg = dbus_message_new_method_call("org.bluez", adapter,
-                                       "org.bluez.Media",
-                                       "UnregisterPlayer");
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return;
-       }
-
-       path = sender2path(sender);
-       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_connection_send(sys, msg, NULL);
-
-       dbus_message_unref(msg);
-       g_free(path);
-}
-
-static DBusHandlerResult properties_changed(DBusConnection *conn,
-                                                       DBusMessage *msg)
-{
-       DBusMessage *signal;
-       DBusMessageIter iter, entry, metadata;
-       const char *iface;
-       char *path;
-
-       dbus_message_iter_init(msg, &iter);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       dbus_message_iter_get_basic(&iter, &iface);
-
-       printf("PropertiesChanged interface %s\n", iface);
-
-       dbus_message_iter_next(&iter);
-
-       path = sender2path(dbus_message_get_sender(msg));
-       parse_properties(conn, path, &iter, NULL);
-
-       signal = dbus_message_new_signal(path, "org.bluez.MediaPlayer",
-                                                       "TrackChanged");
-       if (!signal) {
-               fprintf(stderr, "Unable to allocate new PropertyChanged"
-                                                       " signal\n");
-               goto err;
-       }
-
-       dbus_message_iter_init_append(signal, &entry);
-
-       dbus_message_iter_open_container(&entry, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
-
-       dbus_message_iter_init(msg, &iter);
-       dbus_message_iter_next(&iter);
-
-       if (parse_metadata(&iter, &metadata) < 0)
-               goto err;
-
-       dbus_message_iter_close_container(&entry, &metadata);
-
-       dbus_connection_send(sys, signal, NULL);
-       dbus_message_unref(signal);
-       g_free(path);
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-
-err:
-       if (signal)
-               dbus_message_unref(signal);
-       g_free(path);
-       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-}
-
-static DBusHandlerResult session_filter(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *name, *old, *new;
-
-       if (dbus_message_is_signal(msg, DBUS_INTERFACE_PROPERTIES,
-                                               "PropertiesChanged"))
-               return properties_changed(conn, msg);
-
-       if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
-                                               "NameOwnerChanged"))
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_STRING, &old,
-                                       DBUS_TYPE_STRING, &new,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (!g_str_has_prefix(name, "org.mpris"))
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (*new == '\0') {
-               printf("player %s at %s disappear\n", name, old);
-               remove_player(conn, old);
-       } else {
-               printf("player %s at %s found\n", name, new);
-               add_player(conn, name, new);
-       }
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static DBusHandlerResult system_filter(DBusConnection *conn,
-                                               DBusMessage *msg, void *data)
-{
-       const char *name, *old, *new;
-
-       if (!dbus_message_is_signal(msg, DBUS_INTERFACE_DBUS,
-                                               "NameOwnerChanged"))
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-
-       if (!dbus_message_get_args(msg, NULL,
-                                       DBUS_TYPE_STRING, &name,
-                                       DBUS_TYPE_STRING, &old,
-                                       DBUS_TYPE_STRING, &new,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
-               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
-       }
-
-       if (!strcmp(name, "org.bluez") && *new == '\0') {
-               fprintf(stderr, "bluetoothd disconnected\n");
-               __io_terminated = 1;
-       }
-
-       return DBUS_HANDLER_RESULT_HANDLED;
-}
-
-static char *get_default_adapter(DBusConnection *conn)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *reply_path;
-       char *path;
-
-       msg = dbus_message_new_method_call("org.bluez", "/",
-                                       "org.bluez.Manager", "DefaultAdapter");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't get default adapter\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Can't get reply arguments\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       path = strdup(reply_path);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return path;
-}
-
-static char *get_adapter(DBusConnection *conn, const char *adapter)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       const char *reply_path;
-       char *path;
-
-       if (!adapter)
-               return get_default_adapter(conn);
-
-       msg = dbus_message_new_method_call("org.bluez", "/",
-                                       "org.bluez.Manager", "FindAdapter");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &adapter,
-                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't find adapter %s\n", adapter);
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, &err,
-                                       DBUS_TYPE_OBJECT_PATH, &reply_path,
-                                       DBUS_TYPE_INVALID)) {
-               fprintf(stderr, "Can't get reply arguments\n");
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       path = strdup(reply_path);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return path;
-}
-
-static char *get_name_owner(DBusConnection *conn, const char *name)
-{
-       DBusMessage *msg, *reply;
-       DBusError err;
-       char *owner;
-
-       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                                       DBUS_INTERFACE_DBUS, "GetNameOwner");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return NULL;
-       }
-
-       dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
-                                                       DBUS_TYPE_INVALID);
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't find adapter %s\n", adapter);
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return NULL;
-       }
-
-       if (!dbus_message_get_args(reply, NULL,
-                                       DBUS_TYPE_STRING, &owner,
-                                       DBUS_TYPE_INVALID)) {
-               dbus_message_unref(reply);
-               return NULL;
-       }
-
-       owner = g_strdup(owner);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-
-       return owner;
-}
-
-static void parse_list_names(DBusConnection *conn, DBusMessageIter *args)
-{
-       DBusMessageIter array;
-       int ctype;
-
-       ctype = dbus_message_iter_get_arg_type(args);
-       if (ctype != DBUS_TYPE_ARRAY)
-               return;
-
-       dbus_message_iter_recurse(args, &array);
-
-       while ((ctype = dbus_message_iter_get_arg_type(&array)) !=
-                                                       DBUS_TYPE_INVALID) {
-               const char *name;
-               char *owner;
-
-               if (ctype != DBUS_TYPE_STRING)
-                       goto next;
-
-               dbus_message_iter_get_basic(&array, &name);
-
-               if (!g_str_has_prefix(name, "org.mpris"))
-                       goto next;
-
-               owner = get_name_owner(conn, name);
-
-               if (owner == NULL)
-                       goto next;
-
-               add_player(conn, name, owner);
-
-               g_free(owner);
-next:
-               dbus_message_iter_next(&array);
-       }
-}
-
-static void list_names(DBusConnection *conn)
-{
-       DBusMessage *msg, *reply;
-       DBusMessageIter iter;
-       DBusError err;
-
-       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
-                                       DBUS_INTERFACE_DBUS, "ListNames");
-
-       if (!msg) {
-               fprintf(stderr, "Can't allocate new method call\n");
-               return;
-       }
-
-       dbus_error_init(&err);
-
-       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
-
-       dbus_message_unref(msg);
-
-       if (!reply) {
-               fprintf(stderr, "Can't find adapter %s\n", adapter);
-               if (dbus_error_is_set(&err)) {
-                       fprintf(stderr, "%s\n", err.message);
-                       dbus_error_free(&err);
-               }
-               return;
-       }
-
-       dbus_message_iter_init(reply, &iter);
-
-       parse_list_names(conn, &iter);
-
-       dbus_message_unref(reply);
-
-       dbus_connection_flush(conn);
-}
-
-static void usage(void)
-{
-       printf("Bluetooth player ver %s\n\n", VERSION);
-
-       printf("Usage:\n"
-               "\tplayer [--adapter adapter id]\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "adapter",    1, 0, 'a' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       struct sigaction sa;
-       char *adapter_id = NULL;
-       char match[128];
-       int opt;
-
-       while ((opt = getopt_long(argc, argv, "+a,h", main_options, NULL)) != EOF) {
-               switch(opt) {
-               case '1':
-                       adapter_id = optarg;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       exit(1);
-               }
-       }
-
-       sys = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (!sys) {
-               fprintf(stderr, "Can't get on system bus");
-               exit(1);
-       }
-
-       adapter = get_adapter(sys, adapter_id);
-       if (!adapter)
-               exit(1);
-
-       if (!dbus_connection_add_filter(sys, system_filter, NULL, NULL)) {
-               fprintf(stderr, "Can't add signal filter");
-               exit(1);
-       }
-
-       snprintf(match, sizeof(match),
-                       "interface=%s,member=NameOwnerChanged,arg0=%s",
-                       DBUS_INTERFACE_DBUS, "org.bluez");
-
-       dbus_bus_add_match(sys, match, NULL);
-
-       session = dbus_bus_get(DBUS_BUS_SESSION, NULL);
-       if (!session) {
-               fprintf(stderr, "Can't get on session bus");
-               exit(1);
-       }
-
-       if (!dbus_connection_add_filter(session, session_filter, NULL, NULL)) {
-               fprintf(stderr, "Can't add signal filter");
-               exit(1);
-       }
-
-       snprintf(match, sizeof(match),
-                       "interface=%s,member=NameOwnerChanged",
-                       DBUS_INTERFACE_DBUS);
-
-       dbus_bus_add_match(session, match, NULL);
-
-       snprintf(match, sizeof(match),
-                       "interface=%s,member=PropertiesChanged,arg0=%s",
-                       DBUS_INTERFACE_PROPERTIES,
-                       "org.mpris.MediaPlayer2.Player");
-
-       list_names(session);
-
-       dbus_bus_add_match(session, match, NULL);
-
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       while (!__io_canceled && !__io_terminated) {
-               if (dbus_connection_read_write_dispatch(sys, 500) != TRUE)
-                       break;
-               if (dbus_connection_read_write_dispatch(session, 500) != TRUE)
-                       break;
-       }
-
-       dbus_connection_unref(sys);
-
-       return 0;
-}
similarity index 100%
rename from test/sap-client
rename to test/sap_client.py
diff --git a/test/sdptest.c b/test/sdptest.c
deleted file mode 100644 (file)
index 480a468..0000000
+++ /dev/null
@@ -1,146 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2005-2010  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdio.h>
-#include <errno.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <signal.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/hci.h>
-#include <bluetooth/hci_lib.h>
-#include <bluetooth/sdp.h>
-#include <bluetooth/sdp_lib.h>
-
-static volatile sig_atomic_t __io_finished = 0;
-
-static void callback(uint8_t type, uint16_t status,
-                               uint8_t *rsp, size_t size, void *udata)
-{
-       unsigned int i;
-
-       for (i = 0; i < size; i++) {
-               printf("%02x ", rsp[i]);
-               if ((i + 1) % 8 == 0)
-                       printf(" ");
-               if ((i + 1) % 16 == 0)
-                       printf("\n");
-       }
-       printf("\n");
-
-       __io_finished = 1;
-}
-
-static void cmd_search(bdaddr_t *src, bdaddr_t *dst)
-{
-       sdp_session_t *session;
-       sdp_list_t *search, *attrids;
-       uint32_t range = 0x0000ffff;
-       uuid_t uuid;
-
-       session = sdp_connect(src, dst, 0);
-       if (!session) {
-               perror("Can't connect to SDP service");
-               exit(1);
-       }
-
-       sdp_set_notify(session, callback, NULL);
-
-       sdp_uuid16_create(&uuid, PUBLIC_BROWSE_GROUP);
-
-       search = sdp_list_append(NULL, &uuid);
-
-       attrids = sdp_list_append(NULL, &range);
-
-       //sdp_service_search_attr_async(session, search,
-       //                              SDP_ATTR_REQ_RANGE, attrids);
-
-       sdp_service_search_async(session, search, 0xffff);
-
-       sdp_list_free(attrids, NULL);
-
-       sdp_list_free(search, NULL);
-
-       while (!__io_finished)
-               sdp_process(session);
-
-       sdp_close(session);
-}
-
-static void usage(void)
-{
-       printf("sdptest - Utility for SDP testing\n\n");
-       printf("Usage:\n"
-               "\tsdptest [-i <dev>] <bdaddr>\n");
-}
-
-static struct option main_options[] = {
-       { "device",     1, 0, 'i' },
-       { "help",       0, 0, 'h' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       bdaddr_t src, dst;
-       int opt;
-
-       bacpy(&src, BDADDR_ANY);
-
-       while ((opt=getopt_long(argc, argv, "+i:h", main_options, NULL)) != -1) {
-               switch (opt) {
-               case 'i':
-                       if (!strncasecmp(optarg, "hci", 3))
-                               hci_devba(atoi(optarg + 3), &src);
-                       else
-                               str2ba(optarg, &dst);
-                       break;
-
-               case 'h':
-               default:
-                       usage();
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       str2ba(argv[0], &dst);
-
-       cmd_search(&src, &dst);
-
-       return 0;
-}
index a25eaf0..854e1af 100755 (executable)
@@ -9,6 +9,15 @@ import dbus
 import dbus.service
 import dbus.mainloop.glib
 from optparse import OptionParser
+import bluezutils
+
+BUS_NAME = 'org.bluez'
+AGENT_INTERFACE = 'org.bluez.Agent1'
+AGENT_PATH = "/test/agent"
+
+bus = None
+device_obj = None
+dev_path = None
 
 def ask(prompt):
        try:
@@ -16,6 +25,16 @@ def ask(prompt):
        except:
                return input(prompt)
 
+def set_trusted(path):
+       props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
+       props.Set("org.bluez.Device1", "Trusted", True)
+
+def dev_connect(path):
+       dev = dbus.Interface(bus.get_object("org.bluez", path),
+                                                       "org.bluez.Device1")
+       dev.Connect()
+
 class Rejected(dbus.DBusException):
        _dbus_error_name = "org.bluez.Error.Rejected"
 
@@ -25,118 +44,136 @@ class Agent(dbus.service.Object):
        def set_exit_on_release(self, exit_on_release):
                self.exit_on_release = exit_on_release
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="", out_signature="")
        def Release(self):
                print("Release")
                if self.exit_on_release:
                        mainloop.quit()
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="os", out_signature="")
-       def Authorize(self, device, uuid):
-               print("Authorize (%s, %s)" % (device, uuid))
+       def AuthorizeService(self, device, uuid):
+               print("AuthorizeService (%s, %s)" % (device, uuid))
                authorize = ask("Authorize connection (yes/no): ")
                if (authorize == "yes"):
                        return
                raise Rejected("Connection rejected by user")
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="o", out_signature="s")
        def RequestPinCode(self, device):
                print("RequestPinCode (%s)" % (device))
+               set_trusted(device)
                return ask("Enter PIN Code: ")
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="o", out_signature="u")
        def RequestPasskey(self, device):
                print("RequestPasskey (%s)" % (device))
+               set_trusted(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, %06d)" % (device, passkey))
+       @dbus.service.method(AGENT_INTERFACE,
+                                       in_signature="ouq", out_signature="")
+       def DisplayPasskey(self, device, passkey, entered):
+               print("DisplayPasskey (%s, %06u entered %u)" %
+                                               (device, passkey, entered))
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="os", out_signature="")
        def DisplayPinCode(self, device, pincode):
                print("DisplayPinCode (%s, %s)" % (device, pincode))
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="ou", out_signature="")
        def RequestConfirmation(self, device, passkey):
                print("RequestConfirmation (%s, %06d)" % (device, passkey))
                confirm = ask("Confirm passkey (yes/no): ")
                if (confirm == "yes"):
+                       set_trusted(device)
                        return
                raise Rejected("Passkey doesn't match")
 
-       @dbus.service.method("org.bluez.Agent",
-                                       in_signature="s", out_signature="")
-       def ConfirmModeChange(self, mode):
-               print("ConfirmModeChange (%s)" % (mode))
-               authorize = ask("Authorize mode change (yes/no): ")
-               if (authorize == "yes"):
+       @dbus.service.method(AGENT_INTERFACE,
+                                       in_signature="o", out_signature="")
+       def RequestAuthorization(self, device):
+               print("RequestAuthorization (%s)" % (device))
+               auth = ask("Authorize? (yes/no): ")
+               if (auth == "yes"):
                        return
-               raise Rejected("Mode change by user")
+               raise Rejected("Pairing rejected")
 
-       @dbus.service.method("org.bluez.Agent",
+       @dbus.service.method(AGENT_INTERFACE,
                                        in_signature="", out_signature="")
        def Cancel(self):
                print("Cancel")
 
-def create_device_reply(device):
-       print("New device (%s)" % (device))
+def pair_reply():
+       print("Device paired")
+       set_trusted(dev_path)
+       dev_connect(dev_path)
        mainloop.quit()
 
-def create_device_error(error):
-       print("Creating device failed: %s" % (error))
+def pair_error(error):
+       err_name = error.get_dbus_name()
+       if err_name == "org.freedesktop.DBus.Error.NoReply" and device_obj:
+               print("Timed out. Cancelling pairing")
+               device_obj.CancelPairing()
+       else:
+               print("Creating device failed: %s" % (error))
+
+
        mainloop.quit()
 
 if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                                       "org.bluez.Manager")
 
        capability = "KeyboardDisplay"
 
        parser = OptionParser()
+       parser.add_option("-i", "--adapter", action="store",
+                                       type="string",
+                                       dest="adapter_pattern",
+                                       default=None)
        parser.add_option("-c", "--capability", action="store",
                                        type="string", dest="capability")
+       parser.add_option("-t", "--timeout", action="store",
+                                       type="int", dest="timeout",
+                                       default=60000)
        (options, args) = parser.parse_args()
        if options.capability:
                capability  = options.capability
 
-       if len(args) > 0:
-               path = manager.FindAdapter(args[0])
-       else:
-               path = manager.DefaultAdapter()
-
-       adapter = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Adapter")
-
        path = "/test/agent"
        agent = Agent(bus, path)
 
        mainloop = GObject.MainLoop()
 
-       if len(args) > 1:
-               if len(args) > 2:
-                       device = adapter.FindDevice(args[1])
-                       adapter.RemoveDevice(device)
+       obj = bus.get_object(BUS_NAME, "/org/bluez");
+       manager = dbus.Interface(obj, "org.bluez.AgentManager1")
+       manager.RegisterAgent(path, capability)
+
+       print("Agent registered")
 
+       # Fix-up old style invocation (BlueZ 4)
+       if len(args) > 0 and args[0].startswith("hci"):
+               options.adapter_pattern = args[0]
+               del args[:1]
+
+       if len(args) > 0:
+               device = bluezutils.find_device(args[0],
+                                               options.adapter_pattern)
+               dev_path = device.object_path
                agent.set_exit_on_release(False)
-               adapter.CreatePairedDevice(args[1], path, capability,
-                                       timeout=60000,
-                                       reply_handler=create_device_reply,
-                                       error_handler=create_device_error)
+               device.Pair(reply_handler=pair_reply, error_handler=pair_error,
+                                                               timeout=60000)
+               device_obj = device
        else:
-               adapter.RegisterAgent(path, capability)
-               print("Agent registered")
+               manager.RequestDefaultAgent(path)
 
        mainloop.run()
 
index 20c8159..590f83a 100755 (executable)
@@ -7,10 +7,12 @@ import dbus
 import dbus.service
 import dbus.mainloop.glib
 import gobject
+import bluezutils
 
 A2DP_SOURCE_UUID = "0000110A-0000-1000-8000-00805F9B34FB"
 A2DP_SINK_UUID = "0000110B-0000-1000-8000-00805F9B34FB"
 HFP_AG_UUID = "0000111F-0000-1000-8000-00805F9B34FB"
+HFP_HF_UUID = "0000111E-0000-1000-8000-00805F9B34FB"
 HSP_AG_UUID = "00001112-0000-1000-8000-00805F9B34FB"
 
 SBC_CODEC = dbus.Byte(0x00)
@@ -38,6 +40,8 @@ MP3_CONFIGURATION = dbus.Array([dbus.Byte(0x21), dbus.Byte(0x02), dbus.Byte(0x00
 PCM_CODEC = dbus.Byte(0x00)
 PCM_CONFIGURATION = dbus.Array([], signature="ay")
 
+CVSD_CODEC = dbus.Byte(0x01)
+
 class Rejected(dbus.DBusException):
        _dbus_error_name = "org.bluez.Error.Rejected"
 
@@ -51,25 +55,25 @@ class Endpoint(dbus.service.Object):
        def default_configuration(self, configuration):
                self.configuration = configuration
 
-       @dbus.service.method("org.bluez.MediaEndpoint",
+       @dbus.service.method("org.bluez.MediaEndpoint1",
                                        in_signature="", out_signature="")
        def Release(self):
                print("Release")
                if self.exit_on_release:
                        mainloop.quit()
 
-       @dbus.service.method("org.bluez.MediaEndpoint",
+       @dbus.service.method("org.bluez.MediaEndpoint1",
                                        in_signature="", out_signature="")
        def ClearConfiguration(self):
                print("ClearConfiguration")
 
-       @dbus.service.method("org.bluez.MediaEndpoint",
+       @dbus.service.method("org.bluez.MediaEndpoint1",
                                        in_signature="oay", out_signature="")
        def SetConfiguration(self, transport, config):
                print("SetConfiguration (%s, %s)" % (transport, config))
                return
 
-       @dbus.service.method("org.bluez.MediaEndpoint",
+       @dbus.service.method("org.bluez.MediaEndpoint1",
                                        in_signature="ay", out_signature="ay")
        def SelectConfiguration(self, caps):
                print("SelectConfiguration (%s)" % (caps))
@@ -79,16 +83,14 @@ if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
 
        if len(sys.argv) > 1:
-               path = manager.FindAdapter(sys.argv[1])
+               path = bluezutils.find_adapter(sys.argv[1]).object_path
        else:
-               path = manager.DefaultAdapter()
+               path = bluezutils.find_adapter().object_path
 
        media = dbus.Interface(bus.get_object("org.bluez", path),
-                                               "org.bluez.Media")
+                                               "org.bluez.Media1")
 
        path = "/test/endpoint"
        endpoint = Endpoint(bus, path)
@@ -120,6 +122,11 @@ if __name__ == '__main__':
                                                        "Codec" : PCM_CODEC,
                                                        "Capabilities" :  PCM_CONFIGURATION })
                        endpoint.default_configuration(dbus.Array([]))
+               if sys.argv[2] == "hfphf":
+                       properties = dbus.Dictionary({ "UUID" : HFP_HF_UUID,
+                                                       "Codec" : CVSD_CODEC,
+                                                       "Capabilities" :  PCM_CONFIGURATION })
+                       endpoint.default_configuration(dbus.Array([]))
 
        print(properties)
 
index 70701da..01bec06 100755 (executable)
@@ -7,45 +7,86 @@ import dbus
 import dbus.service
 import dbus.mainloop.glib
 import gobject
+import bluezutils
 
 class Player(dbus.service.Object):
-       @dbus.service.method("org.bluez.MediaPlayer",
-                                       in_signature="", out_signature="")
-       def Release(self):
-               print("Release")
-               mainloop.quit()
-
-       @dbus.service.method("org.bluez.MediaPlayer",
-                                       in_signature="sv", out_signature="")
-       def SetProperty(self, key, value):
-               print("SetProperty (%s, %s)" % (key, value), file=sys.stderr)
+       properties = None
+       metadata = None
+
+       def set_object(self, obj = None):
+               if obj != None:
+                       bus = dbus.SystemBus()
+                       mp = dbus.Interface(bus.get_object("org.bluez", obj),
+                                               "org.bluez.MediaPlayer1")
+                       prop = dbus.Interface(bus.get_object("org.bluez", obj),
+                                               "org.freedesktop.DBus.Properties")
+
+                       self.properties = prop.GetAll("org.bluez.MediaPlayer1")
+
+                       bus.add_signal_receiver(self.properties_changed,
+                               path = obj,
+                               dbus_interface = "org.freedesktop.DBus.Properties",
+                               signal_name = "PropertiesChanged")
+               else:
+                       track = dbus.Dictionary({
+                                       "xesam:title" : "Title",
+                                       "xesam:artist" : "Artist",
+                                       "xesam:album" : "Album",
+                                       "xesam:genre" : "Genre",
+                                       "xesam:trackNumber" : dbus.Int32(1),
+                                       "mpris:length" : dbus.Int64(10000) },
+                                       signature="sv")
+
+                       self.properties = dbus.Dictionary({
+                                       "PlaybackStatus" : "playing",
+                                       "LoopStatus" : "None",
+                                       "Rate" : dbus.Double(1.0),
+                                       "Shuffle" : dbus.Boolean(False),
+                                       "Metadata" : track,
+                                       "Volume" : dbus.Double(1.0),
+                                       "Position" : dbus.UInt32(0),
+                                       "MinimumRate" : dbus.Double(1.0),
+                                       "MaximumRate" : dbus.Double(1.0),
+                                       "CanGoNext" : dbus.Boolean(False),
+                                       "CanGoPrevious" : dbus.Boolean(False),
+                                       "CanPlay" : dbus.Boolean(False),
+                                       "CanSeek" : dbus.Boolean(False),
+                                       "CanControl" : dbus.Boolean(False),
+                                       },
+                                       signature="sv")
+
+                       handler = InputHandler(self)
+                       gobject.io_add_watch(sys.stdin, gobject.IO_IN,
+                                                       handler.handle)
+
+       @dbus.service.method("org.freedesktop.DBus.Properties",
+                                       in_signature="ssv", out_signature="")
+       def Set(self, interface, key, value):
+               print("Set (%s, %s)" % (key, value), file=sys.stderr)
                return
 
-       @dbus.service.signal("org.bluez.MediaPlayer", signature="sv")
-       def PropertyChanged(self, setting, value):
-               """PropertyChanged(setting, value)
+       @dbus.service.signal("org.freedesktop.DBus.Properties",
+                                                       signature="sa{sv}as")
+       def PropertiesChanged(self, interface, properties,
+                                               invalidated = dbus.Array()):
+               """PropertiesChanged(interface, properties, invalidated)
 
-               Send a PropertyChanged signal. 'setting' and 'value' are
-               string parameters as specified in doc/media-api.txt.
-               """
-               pass
-
-       @dbus.service.signal("org.bluez.MediaPlayer", signature="a{sv}")
-       def TrackChanged(self, metadata):
-               """TrackChanged(metadata)
-
-               Send a TrackChanged signal. 'metadata' parameter is a dictionary,
-               with values as defined in doc/media-api.txt.
+               Send a PropertiesChanged signal. 'properties' is a dictionary
+               containing string parameters as specified in doc/media-api.txt.
                """
                pass
 
        def help(self, func):
                help(self.__class__.__dict__[func])
 
+       def properties_changed(self, interface, properties, invalidated):
+               print("properties_changed(%s, %s)" % (properties, invalidated))
+
+               self.PropertiesChanged(interface, properties, invalidated)
+
 class InputHandler:
-       commands = { 'TrackChanged': '(metadata)',
-                                       'PropertyChanged': '(key, value)',
-                                       'help': '(cmd)' }
+       commands = { 'PropertiesChanged': '(interface, properties)',
+                       'help': '(cmd)' }
        def __init__(self, player):
                self.player = player
                print('\n\nAvailable commands:')
@@ -53,7 +94,8 @@ class InputHandler:
                        print('\t', cmd, self.commands[cmd], sep='')
 
                print("\nUse python syntax to pass arguments to available methods.\n" \
-                "E.g.: TrackChanged({'Title': 'My title', 'Album': 'my album' })")
+                "E.g.: PropertiesChanged({'Metadata' : {'Title': 'My title', \
+               'Album': 'my album' }})")
                self.prompt()
 
        def prompt(self):
@@ -79,47 +121,31 @@ class InputHandler:
                return True
 
 
-
 if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
 
        if len(sys.argv) > 1:
-               path = manager.FindAdapter(sys.argv[1])
+               path = bluezutils.find_adapter(sys.argv[1]).object_path
        else:
-               path = manager.DefaultAdapter()
+               path = bluezutils.find_adapter().object_path
 
        media = dbus.Interface(bus.get_object("org.bluez", path),
-                                               "org.bluez.Media")
+                                               "org.bluez.Media1")
 
        path = "/test/player"
        player = Player(bus, path)
        mainloop = gobject.MainLoop()
 
-       properties = dbus.Dictionary({ "Equalizer" : "off",
-                                       "Repeat" : "off",
-                                       "Shuffle" : "off",
-                                       "Scan" : "off",
-                                       "Status" : "playing",
-                                       "Position" : dbus.UInt32(0) }, signature="sv")
-
-       metadata = dbus.Dictionary({ "Title" : "Title",
-                                       "Artist" : "Artist",
-                                       "Album" : "Album",
-                                       "Genre" : "Genre",
-                                       "NumberOfTracks" : dbus.UInt32(10),
-                                       "Number" : dbus.UInt32(1),
-                                       "Duration" : dbus.UInt32(10000) }, signature="sv")
-
-       print('Register media player with:\n\tProperties: %s\n\tMetadata: %s' \
-                                               % (properties, metadata))
+       if len(sys.argv) > 2:
+               player.set_object(sys.argv[2])
+       else:
+               player.set_object()
 
-       handler = InputHandler(player)
-       gobject.io_add_watch(sys.stdin, gobject.IO_IN, handler.handle)
+       print('Register media player with:\n\tProperties: %s' \
+                                               % (player.properties))
 
-       media.RegisterPlayer(dbus.ObjectPath(path), properties, metadata)
+       media.RegisterPlayer(dbus.ObjectPath(path), player.properties)
 
        mainloop.run()
index ed27d0c..02d7648 100755 (executable)
@@ -5,6 +5,7 @@ from __future__ import absolute_import, print_function, unicode_literals
 import sys
 import time
 import dbus
+import bluezutils
 
 xml = ' \
 <?xml version="1.0" encoding="UTF-8" ?>        \
@@ -103,13 +104,11 @@ xml = ' \
 '
 
 bus = dbus.SystemBus()
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
 
 if len(sys.argv) > 1:
-       path = manager.FindAdapter(sys.argv[1])
+       path = bluezutils.find_adapter(sys.argv[1]).object_path
 else:
-       path = manager.DefaultAdapter()
+       path = bluezutils.find_adapter().object_path
 
 service = dbus.Interface(bus.get_object("org.bluez", path),
                                                "org.bluez.Service")
index 4e2f029..5deeda4 100755 (executable)
@@ -6,11 +6,10 @@ import sys
 import dbus
 import time
 from optparse import OptionParser, make_option
+import bluezutils
 
 bus = dbus.SystemBus()
 
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
 option_list = [
                make_option("-i", "--device", action="store",
                                type="string", dest="dev_id"),
@@ -19,20 +18,17 @@ parser = OptionParser(option_list=option_list)
 
 (options, args) = parser.parse_args()
 
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
+adapter_path = bluezutils.find_adapter(options.dev_id).object_path
 adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
+                                       "org.freedesktop.DBus.Properties")
 
 if (len(args) < 1):
        print("Usage: %s <command>" % (sys.argv[0]))
        print("")
        print("  address")
        print("  list")
-       print("  name [name]")
+       print("  name")
+       print("  alias [alias]")
        print("  powered [on/off]")
        print("  pairable [on/off]")
        print("  pairabletimeout [timeout]")
@@ -42,27 +38,37 @@ if (len(args) < 1):
        sys.exit(1)
 
 if (args[0] == "address"):
-       properties = adapter.GetProperties()
-       print(properties["Address"])
+       addr = adapter.Get("org.bluez.Adapter1", "Address")
+       print(addr)
        sys.exit(0)
 
 if (args[0] == "name"):
+       name = adapter.Get("org.bluez.Adapter1", "Name")
+       print(name)
+       sys.exit(0)
+
+if (args[0] == "alias"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["Name"])
+               alias = adapter.Get("org.bluez.Adapter1", "Alias")
+               print(alias)
        else:
-               adapter.SetProperty("Name", args[1])
+               adapter.Set("org.bluez.Adapter1", "Alias", args[1])
        sys.exit(0)
 
 if (args[0] == "list"):
        if (len(args) < 2):
-               properties = manager.GetProperties()
-               for adapter_path in properties["Adapters"]:
-                       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                               "org.bluez.Adapter")
-                       prop = adapter.GetProperties()
-                       print(" [ %s ]" % (adapter_path))
-                       for (key, value) in prop.items():
+               om = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                       "org.freedesktop.DBus.ObjectManager")
+               objects = om.GetManagedObjects()
+               for path, interfaces in objects.iteritems():
+                       if "org.bluez.Adapter1" not in interfaces:
+                               continue
+
+                       print(" [ %s ]" % (path))
+
+                       props = interfaces["org.bluez.Adapter1"]
+
+                       for (key, value) in props.items():
                                if (key == "Class"):
                                        print("    %s = 0x%06x" % (key, value))
                                else:
@@ -72,8 +78,8 @@ if (args[0] == "list"):
 
 if (args[0] == "powered"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["Powered"])
+               powered = adapter.Get("org.bluez.Adapter1", "Powered")
+               print(powered)
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -81,13 +87,13 @@ if (args[0] == "powered"):
                        value = dbus.Boolean(0)
                else:
                        value = dbus.Boolean(args[1])
-               adapter.SetProperty("Powered", value)
+               adapter.Set("org.bluez.Adapter1", "Powered", value)
        sys.exit(0)
 
 if (args[0] == "pairable"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["Pairable"])
+               pairable = adapter.Get("org.bluez.Adapter1", "Pairable")
+               print(pairable)
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -95,22 +101,22 @@ if (args[0] == "pairable"):
                        value = dbus.Boolean(0)
                else:
                        value = dbus.Boolean(args[1])
-               adapter.SetProperty("Pairable", value)
+               adapter.Set("org.bluez.Adapter1", "Pairable", value)
        sys.exit(0)
 
 if (args[0] == "pairabletimeout"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["PairableTimeout"])
+               pt = adapter.Get("org.bluez.Adapter1", "PairableTimeout")
+               print(pt)
        else:
                timeout = dbus.UInt32(args[1])
-               adapter.SetProperty("PairableTimeout", timeout)
+               adapter.Set("org.bluez.Adapter1", "PairableTimeout", timeout)
        sys.exit(0)
 
 if (args[0] == "discoverable"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["Discoverable"])
+               discoverable = adapter.Get("org.bluez.Adapter1", "Discoverable")
+               print(discoverable)
        else:
                if (args[1] == "on"):
                        value = dbus.Boolean(1)
@@ -118,21 +124,21 @@ if (args[0] == "discoverable"):
                        value = dbus.Boolean(0)
                else:
                        value = dbus.Boolean(args[1])
-               adapter.SetProperty("Discoverable", value)
+               adapter.Set("org.bluez.Adapter1", "Discoverable", value)
        sys.exit(0)
 
 if (args[0] == "discoverabletimeout"):
        if (len(args) < 2):
-               properties = adapter.GetProperties()
-               print(properties["DiscoverableTimeout"])
+               dt = adapter.Get("org.bluez.Adapter1", "DiscoverableTimeout")
+               print(dt)
        else:
-               timeout = dbus.UInt32(args[1])
-               adapter.SetProperty("DiscoverableTimeout", timeout)
+               to = dbus.UInt32(args[1])
+               adapter.Set("org.bluez.Adapter1", "DiscoverableTimeout", to)
        sys.exit(0)
 
 if (args[0] == "discovering"):
-       properties = adapter.GetProperties()
-       print(properties["Discovering"])
+       discovering = adapter.Get("org.bluez.Adapter1", "Discovering")
+       print(discovering)
        sys.exit(0)
 
 print("Unknown command")
diff --git a/test/test-alert b/test/test-alert
new file mode 100755 (executable)
index 0000000..066e537
--- /dev/null
@@ -0,0 +1,180 @@
+#!/usr/bin/python
+from __future__ import absolute_import, print_function, unicode_literals
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+import gobject
+import optparse
+import sys
+import os
+
+BUS_NAME = 'org.bluez'
+ALERT_INTERFACE = 'org.bluez.Alert1'
+ALERT_AGENT_INTERFACE = 'org.bluez.AlertAgent1'
+BLUEZ_OBJECT_PATH = '/org/bluez'
+TEST_OBJECT_PATH = '/org/bluez/test'
+
+class AlertAgent(dbus.service.Object):
+       def __init__(self, bus, object_path, alert, mainloop):
+               dbus.service.Object.__init__(self, bus, object_path)
+               self.alert = alert
+               self.mainloop = mainloop
+
+       @dbus.service.method(ALERT_AGENT_INTERFACE, in_signature='',
+                                                       out_signature='')
+       def MuteOnce(self):
+               print('method MuteOnce() was called')
+               self.alert.NewAlert('ringer', 1, 'not active')
+
+       @dbus.service.method(ALERT_AGENT_INTERFACE, in_signature='s',
+                                                       out_signature='')
+       def SetRinger(self, mode):
+               print('method SetRinger(%s) was called' % mode)
+               self.alert.NewAlert('ringer', 1, mode)
+
+       @dbus.service.method(ALERT_AGENT_INTERFACE, in_signature='',
+                                                       out_signature='')
+       def Release(self):
+               print('method Release() was called')
+               self.mainloop.quit()
+
+def print_command_line(options):
+       if not options.verbose:
+               return False
+
+       print('-w: ' + str(options.wait))
+
+       if options.times:
+               print('-t: ' + str(options.times))
+
+       if options.register:
+               print('-r: ' + options.register)
+       else:
+               print('-r: ' + str(None))
+
+       if options.new_alert:
+               print('-n:')
+               for i in options.new_alert:
+                       print('    ' + i[0] + ', ' + i[1] + ', ' + i[2])
+       else:
+               print('-n: ' + str(None))
+
+       if options.unread_alert:
+               print('-u:')
+               for i in options.unread_alert:
+                       print('    ' + i[0] + ', ' + i[1])
+       else:
+               print('-u: ' + str(None))
+
+       print()
+
+       return True
+
+def read_count(param):
+       try:
+               return int(param)
+       except ValueError:
+               print('<count> must be integer, not \"%s\"' % param)
+               sys.exit(1)
+
+def new_alert(alert, params):
+       if not params:
+               return False
+
+       for param in params:
+               category = param[0]
+               count = read_count(param[1])
+               description = param[2]
+
+               alert.NewAlert(category, count, description)
+
+def unread_alert(alert, params):
+       if not params:
+               return False
+
+       for param in params:
+               category = param[0]
+               count = read_count(param[1])
+
+               alert.UnreadAlert(category, count)
+
+option_list = [
+       optparse.make_option('-v', None,
+                       action = 'store_true',
+                       default = False,
+                       dest = 'verbose',
+                       help = 'verbose'),
+
+       optparse.make_option('-w', None,
+                       action = 'store_true',
+                       default = False,
+                       dest = 'wait',
+                       help = 'wait for dbus events'),
+
+       optparse.make_option('-t', None,
+                       action = 'store',
+                       default = 1,
+                       type = "int",
+                       dest = 'times',
+                       help = 'repeat UnreadAlert/NewAlert <times> times',
+                       metavar = '<times>'),
+
+       optparse.make_option('-r', None,
+                       action = 'store',
+                       dest = 'register',
+                       type = 'string',
+                       metavar = '<category>',
+                       help = 'register alert'),
+
+       optparse.make_option('-n', None,
+                       action = 'append',
+                       dest = 'new_alert',
+                       type = 'string',
+                       nargs = 3,
+                       metavar = '<category> <count> <description>',
+                       help = 'send new alert'),
+
+       optparse.make_option('-u', None,
+                       action = 'append',
+                       dest = 'unread_alert',
+                       type = 'string',
+                       nargs = 2,
+                       metavar = '<category> <count>',
+                       help = 'send unread alert'),
+]
+
+parser = optparse.OptionParser(option_list=option_list)
+parser.disable_interspersed_args()
+(options, args) = parser.parse_args()
+
+dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+bus = dbus.SystemBus()
+mainloop = gobject.MainLoop()
+alert = dbus.Interface(bus.get_object(BUS_NAME, BLUEZ_OBJECT_PATH),
+                                                               ALERT_INTERFACE)
+alert_agent = AlertAgent(bus, TEST_OBJECT_PATH, alert, mainloop)
+
+print_command_line(options)
+
+if not (options.register or options.new_alert or options.unread_alert or
+                                                               options.wait):
+       parser.print_usage()
+       sys.exit(1)
+
+if options.register:
+       alert.RegisterAlert(options.register, TEST_OBJECT_PATH)
+
+times = 0
+while times < options.times:
+       times += 1
+
+       new_alert(alert, options.new_alert)
+       unread_alert(alert, options.unread_alert)
+
+if not options.wait:
+       sys.exit(0)
+
+try:
+       mainloop.run()
+except:
+       pass
diff --git a/test/test-attrib b/test/test-attrib
deleted file mode 100755 (executable)
index 52b399c..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-# Script for testing the Attribute D-Bus API
-
-import sys
-from optparse import OptionParser, OptionValueError
-from binascii import hexlify, unhexlify
-
-import gobject
-
-import sys
-import dbus
-import dbus.mainloop.glib
-from optparse import OptionParser, make_option
-
-dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-bus = dbus.SystemBus()
-mainloop = gobject.MainLoop()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
-if (len(args) < 1):
-       print("Usage: %s <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"):
-       for path in adapter.ListDevices():
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               devprop = device.GetProperties()
-               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: ",)
-                       for char in srvprop["Characteristics"]:
-                               print("%s " % char,)
-                       print()
-                       print()
-               print()
-       sys.exit(0)
-
-if (args[0] == "services"):
-       if (len(args) < 2):
-               print("Need address parameter")
-       else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               properties = device.GetProperties()
-               for path in properties["Services"]:
-                       print(path)
-       sys.exit(0)
-
-if (args[0] == "discover"):
-       if (len(args) < 2):
-               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)
-       sys.exit(0)
-
-if (args[0] == "chars"):
-       if (len(args) < 2):
-               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))
-                       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()
-       sys.exit(0)
-
-print("Unknown command")
-sys.exit(1)
diff --git a/test/test-audio b/test/test-audio
deleted file mode 100755 (executable)
index 1ba2042..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import dbus
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
-if len(args) < 2:
-       print("""Usage: %s <command>
-
-       connect <bdaddr>
-       disconnect <bdaddr>
-       """ % sys.argv[0])
-       sys.exit(1)
-
-device = adapter.FindDevice(args[1])
-audio = dbus.Interface(bus.get_object("org.bluez", device),
-                               "org.bluez.Audio")
-
-if args[0] == "connect":
-       audio.Connect()
-elif args[0] == "disconnect":
-       audio.Disconnect()
-else:
-       print("Unknown command")
-       sys.exit(1)
diff --git a/test/test-cyclingspeed b/test/test-cyclingspeed
new file mode 100755 (executable)
index 0000000..75bd7d7
--- /dev/null
@@ -0,0 +1,194 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+'''
+Cycling Speed and Cadence test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+BUS_NAME = 'org.bluez'
+CYCLINGSPEED_MANAGER_INTERFACE = 'org.bluez.CyclingSpeedManager1'
+CYCLINGSPEED_WATCHER_INTERFACE = 'org.bluez.CyclingSpeedWatcher1'
+CYCLINGSPEED_INTERFACE = 'org.bluez.CyclingSpeed1'
+
+class MeasurementQ:
+       def __init__(self, wrap_v):
+               self._now = [None, None]
+               self._prev = [None, None]
+               self._wrap_v = wrap_v
+
+       def can_calc(self):
+               return ((self._now[0] is not None)
+                       and (self._now[1] is not None)
+                       and (self._prev[0] is not None)
+                       and (self._prev[1] is not None))
+
+       def delta_v(self):
+               delta = self._now[0] - self._prev[0]
+               if (delta < 0) and (self._wrap_v):
+                       delta = delta + 65536
+               return delta
+
+       def delta_t(self):
+               delta = self._now[1] - self._prev[1]
+               if delta < 0:
+                       delta = delta + 65536
+               return delta
+
+       def put(self, data):
+               self._prev = self._now
+               self._now = data
+
+class Watcher(dbus.service.Object):
+       _wheel = MeasurementQ(False)
+       _crank = MeasurementQ(True)
+       _circumference = None
+
+       def enable_calc(self, v):
+               self._circumference = v
+
+       @dbus.service.method(CYCLINGSPEED_WATCHER_INTERFACE,
+                                       in_signature="oa{sv}", out_signature="")
+       def MeasurementReceived(self, device, measure):
+               print("Measurement received from %s" % device)
+
+               rev = None
+               evt = None
+               if "WheelRevolutions" in measure:
+                       rev = measure["WheelRevolutions"]
+                       print("WheelRevolutions: ", measure["WheelRevolutions"])
+               if "LastWheelEventTime" in measure:
+                       evt = measure["LastWheelEventTime"]
+                       print("LastWheelEventTime: ", measure["LastWheelEventTime"])
+               self._wheel.put( [rev, evt] )
+
+               rev = None
+               evt = None
+               if "CrankRevolutions" in measure:
+                       rev = measure["CrankRevolutions"]
+                       print("CrankRevolutions: ", measure["CrankRevolutions"])
+               if "LastCrankEventTime" in measure:
+                       evt = measure["LastCrankEventTime"]
+                       print("LastCrankEventTime: ", measure["LastCrankEventTime"])
+               self._crank.put( [rev, evt] )
+
+               if self._circumference is None:
+                       return
+
+               if self._wheel.can_calc():
+                       delta_v = self._wheel.delta_v()
+                       delta_t = self._wheel.delta_t()
+
+                       if (delta_v >= 0) and (delta_t > 0):
+                               speed = delta_v * self._circumference * 1024 / delta_t # mm/s
+                               speed = speed * 0.0036 # mm/s -> km/h
+                               print("(calculated) Speed: %.2f km/h" % speed)
+
+               if self._crank.can_calc():
+                       delta_v = self._crank.delta_v()
+                       delta_t = self._crank.delta_t()
+
+                       if delta_t > 0:
+                               cadence = delta_v * 1024 / delta_t
+                               print("(calculated) Cadence: %d rpm" % cadence)
+
+def properties_changed(interface, changed, invalidated):
+       if "Location" in changed:
+               print("Sensor location: %s" % changed["Location"])
+
+if __name__ == "__main__":
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       option_list = [
+               make_option("-i", "--adapter", action="store",
+                       type="string", dest="adapter"),
+               make_option("-b", "--device", action="store",
+                       type="string", dest="address"),
+               make_option("-c", "--circumference", action="store",
+                       type="int", dest="circumference"),
+               ]
+
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       if not options.address:
+               print("Usage: %s [-i <adapter>] -b <bdaddr> [-c <value>] [cmd]" % (sys.argv[0]))
+               print("Possible commands:")
+               print("\tShowSupportedLocations")
+               print("\tSetLocation <location>")
+               print("\tSetCumulativeWheelRevolutions <value>")
+               sys.exit(1)
+
+       managed_objects = bluezutils.get_managed_objects()
+       adapter = bluezutils.find_adapter_in_objects(managed_objects,
+                                                               options.adapter)
+       adapter_path = adapter.object_path
+
+       device = bluezutils.find_device_in_objects(managed_objects,
+                                                               options.address,
+                                                               options.adapter)
+       device_path = device.object_path
+
+       cscmanager = dbus.Interface(bus.get_object(BUS_NAME, adapter_path),
+                                               CYCLINGSPEED_WATCHER_INTERFACE)
+
+       watcher_path = "/test/watcher"
+       watcher = Watcher(bus, watcher_path)
+       if options.circumference:
+               watcher.enable_calc(options.circumference)
+       cscmanager.RegisterWatcher(watcher_path)
+
+       csc = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                                       CYCLINGSPEED_INTERFACE)
+
+       bus.add_signal_receiver(properties_changed, bus_name=BUS_NAME,
+                               path=device_path,
+                               dbus_interface="org.freedesktop.DBus.Properties",
+                               signal_name="PropertiesChanged")
+
+       device_prop = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                       "org.freedesktop.DBus.Properties")
+
+       properties = device_prop.GetAll(CYCLINGSPEED_INTERFACE)
+
+       if "Location" in properties:
+               print("Sensor location: %s" % properties["Location"])
+       else:
+               print("Sensor location is not supported")
+
+       if len(args) > 0:
+               if args[0] == "ShowSupportedLocations":
+                       if properties["MultipleLocationsSupported"]:
+                               print("Supported locations: ", properties["SupportedLocations"])
+                       else:
+                               print("Multiple sensor locations not supported")
+
+               elif args[0] == "SetLocation":
+                       if properties["MultipleLocationsSupported"]:
+                               device_prop.Set(CYCLINGSPEED_INTERFACE, "Location", args[1])
+                       else:
+                               print("Multiple sensor locations not supported")
+
+               elif args[0] == "SetCumulativeWheelRevolutions":
+                       if properties["WheelRevolutionDataSupported"]:
+                               csc.SetCumulativeWheelRevolutions(dbus.UInt32(args[1]))
+                       else:
+                               print("Wheel revolution data not supported")
+
+               else:
+                       print("Unknown command")
+                       sys.exit(1)
+
+       mainloop = gobject.MainLoop()
+       mainloop.run()
index 81a44f8..3d7b852 100755 (executable)
@@ -9,13 +9,12 @@ import dbus
 import dbus.mainloop.glib
 import re
 from optparse import OptionParser, make_option
+import bluezutils
 
 dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 bus = dbus.SystemBus()
 mainloop = GObject.MainLoop()
 
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
 option_list = [
                make_option("-i", "--device", action="store",
                                type="string", dest="dev_id"),
@@ -24,23 +23,14 @@ parser = OptionParser(option_list=option_list)
 
 (options, args) = parser.parse_args()
 
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
 if (len(args) < 1):
        print("Usage: %s <command>" % (sys.argv[0]))
        print("")
        print("  list")
-       print("  services <address>")
        print("  create <address>")
        print("  remove <address|path>")
-       print("  disconnect <address>")
-       print("  discover <address> [pattern]")
+       print("  connect <address> [profile]")
+       print("  disconnect <address> [profile]")
        print("  class <address>")
        print("  name <address>")
        print("  alias <address> [alias]")
@@ -49,10 +39,19 @@ if (len(args) < 1):
        sys.exit(1)
 
 if (args[0] == "list"):
-       for path in adapter.ListDevices():
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               properties = device.GetProperties()
+       adapter = bluezutils.find_adapter(options.dev_id)
+       adapter_path = adapter.object_path
+
+       om = dbus.Interface(bus.get_object("org.bluez", "/"),
+                                       "org.freedesktop.DBus.ObjectManager")
+       objects = om.GetManagedObjects()
+
+       for path, interfaces in objects.iteritems():
+               if "org.bluez.Device1" not in interfaces:
+                       continue
+               properties = interfaces["org.bluez.Device1"]
+               if properties["Adapter"] != adapter_path:
+                       continue;
                print("%s %s" % (properties["Address"], properties["Alias"]))
 
        sys.exit(0)
@@ -71,6 +70,7 @@ if (args[0] == "create"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
+               adapter = bluezutils.find_adapter(options.dev_id)
                adapter.CreateDevice(args[1],
                                reply_handler=create_device_reply,
                                error_handler=create_device_error)
@@ -80,89 +80,91 @@ if (args[0] == "remove"):
        if (len(args) < 2):
                print("Need address or object path parameter")
        else:
+               managed_objects = bluezutils.get_managed_objects()
+               adapter = bluezutils.find_adapter_in_objects(managed_objects,
+                                                               options.dev_id)
                try:
-                       path = adapter.FindDevice(args[1])
+                       dev = bluezutils.find_device_in_objects(managed_objects,
+                                                               args[1],
+                                                               options.dev_id)
+                       path = dev.object_path
                except:
                        path = args[1]
                adapter.RemoveDevice(path)
        sys.exit(0)
 
-if (args[0] == "disconnect"):
+if (args[0] == "connect"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               device.Disconnect()
+               device = bluezutils.find_device(args[1], options.dev_id)
+               if (len(args) > 2):
+                       device.ConnectProfile(args[2])
+               else:
+                       device.Connect()
        sys.exit(0)
 
-if (args[0] == "discover"):
+if (args[0] == "disconnect"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               if (len(args) < 3):
-                       pattern = ""
+               device = bluezutils.find_device(args[1], options.dev_id)
+               if (len(args) > 2):
+                       device.DisconnectProfile(args[2])
                else:
-                       pattern = args[2]
-               services = device.DiscoverServices(pattern);
-               for key in services.keys():
-                       p = re.compile(">.*?<")
-                       xml = p.sub("><", services[key].replace("\n", ""))
-                       print("[ 0x%5x ]" % (key))
-                       print(xml)
-                       print()
+                       device.Disconnect()
        sys.exit(0)
 
 if (args[0] == "class"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               properties = device.GetProperties()
-               print("0x%06x" % (properties["Class"]))
+               device = bluezutils.find_device(args[1], options.dev_id)
+               path = device.object_path
+               props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
+               cls = props.Get("org.bluez.Device1", "Class")
+               print("0x%06x" % cls)
        sys.exit(0)
 
 if (args[0] == "name"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               properties = device.GetProperties()
-               print(properties["Name"])
+               device = bluezutils.find_device(args[1], options.dev_id)
+               path = device.object_path
+               props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
+               name = props.Get("org.bluez.Device1", "Name")
+               print(name)
        sys.exit(0)
 
 if (args[0] == "alias"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
+               device = bluezutils.find_device(args[1], options.dev_id)
+               path = device.object_path
+               props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
                if (len(args) < 3):
-                       properties = device.GetProperties()
-                       print(properties["Alias"])
+                       alias = props.Get("org.bluez.Device1", "Alias")
+                       print(alias)
                else:
-                       device.SetProperty("Alias", args[2])
+                       props.Set("org.bluez.Device1", "Alias", args[2])
        sys.exit(0)
 
 if (args[0] == "trusted"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
+               device = bluezutils.find_device(args[1], options.dev_id)
+               path = device.object_path
+               props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
                if (len(args) < 3):
-                       properties = device.GetProperties()
-                       print(properties["Trusted"])
+                       trusted = props.Get("org.bluez.Device1", "Trusted")
+                       print(trusted)
                else:
                        if (args[2] == "yes"):
                                value = dbus.Boolean(1)
@@ -170,19 +172,20 @@ if (args[0] == "trusted"):
                                value = dbus.Boolean(0)
                        else:
                                value = dbus.Boolean(args[2])
-                       device.SetProperty("Trusted", value)
+                       props.Set("org.bluez.Device1", "Trusted", value)
        sys.exit(0)
 
 if (args[0] == "blocked"):
        if (len(args) < 2):
                print("Need address parameter")
        else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
+               device = bluezutils.find_device(args[1], options.dev_id)
+               path = device.object_path
+               props = dbus.Interface(bus.get_object("org.bluez", path),
+                                       "org.freedesktop.DBus.Properties")
                if (len(args) < 3):
-                       properties = device.GetProperties()
-                       print(properties["Blocked"])
+                       blocked = props.Get("org.bluez.Device1", "Blocked")
+                       print(blocked)
                else:
                        if (args[2] == "yes"):
                                value = dbus.Boolean(1)
@@ -190,19 +193,7 @@ if (args[0] == "blocked"):
                                value = dbus.Boolean(0)
                        else:
                                value = dbus.Boolean(args[2])
-                       device.SetProperty("Blocked", value)
-       sys.exit(0)
-
-if (args[0] == "services"):
-       if (len(args) < 2):
-               print("Need address parameter")
-       else:
-               path = adapter.FindDevice(args[1])
-               device = dbus.Interface(bus.get_object("org.bluez", path),
-                                                       "org.bluez.Device")
-               properties = device.GetProperties()
-               for path in properties["Services"]:
-                       print(path)
+                       props.Set("org.bluez.Device1", "Blocked", value)
        sys.exit(0)
 
 print("Unknown command")
index 269c51c..c13bfac 100755 (executable)
@@ -7,8 +7,33 @@ from gi.repository import GObject
 import dbus
 import dbus.mainloop.glib
 from optparse import OptionParser, make_option
+import bluezutils
 
-def device_found(address, properties):
+compact = False
+devices = {}
+
+def print_compact(address, properties):
+       name = ""
+       address = "<unknown>"
+
+       for key, value in properties.iteritems():
+               if type(value) is dbus.String:
+                       value = unicode(value).encode('ascii', 'replace')
+               if (key == "Name"):
+                       name = value
+               elif (key == "Address"):
+                       address = value
+
+       if "Logged" in properties:
+               flag = "*"
+       else:
+               flag = " "
+
+       print("%s%s %s" % (flag, address, name))
+
+       properties["Logged"] = True
+
+def print_normal(address, properties):
        print("[ " + address + " ]")
 
        for key in properties.keys():
@@ -22,6 +47,64 @@ def device_found(address, properties):
 
        print()
 
+       properties["Logged"] = True
+
+def skip_dev(old_dev, new_dev):
+       if not "Logged" in old_dev:
+               return False
+       if "Name" in old_dev:
+               return True
+       if not "Name" in new_dev:
+               return True
+       return False
+
+def interfaces_added(path, interfaces):
+       properties = interfaces["org.bluez.Device1"]
+       if not properties:
+               return
+
+       if path in devices:
+               dev = devices[path]
+
+               if compact and skip_dev(dev, properties):
+                       return
+               devices[path] = dict(devices[path].items() + properties.items())
+       else:
+               devices[path] = properties
+
+       if "Address" in devices[path]:
+               address = properties["Address"]
+       else:
+               address = "<unknown>"
+
+       if compact:
+               print_compact(address, devices[path])
+       else:
+               print_normal(address, devices[path])
+
+def properties_changed(interface, changed, invalidated, path):
+       if interface != "org.bluez.Device1":
+               return
+
+       if path in devices:
+               dev = devices[path]
+
+               if compact and skip_dev(dev, changed):
+                       return
+               devices[path] = dict(devices[path].items() + changed.items())
+       else:
+               devices[path] = changed
+
+       if "Address" in devices[path]:
+               address = devices[path]["Address"]
+       else:
+               address = "<unknown>"
+
+       if compact:
+               print_compact(address, devices[path])
+       else:
+               print_normal(address, devices[path])
+
 def property_changed(name, value):
        if (name == "Discovering" and not value):
                mainloop.quit()
@@ -30,33 +113,43 @@ if __name__ == '__main__':
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                                       "org.bluez.Manager")
 
        option_list = [
                        make_option("-i", "--device", action="store",
                                        type="string", dest="dev_id"),
+                       make_option("-c", "--compact",
+                                       action="store_true", dest="compact"),
                        ]
        parser = OptionParser(option_list=option_list)
 
        (options, args) = parser.parse_args()
 
-       if options.dev_id:
-               adapter_path = manager.FindAdapter(options.dev_id)
-       else:
-               adapter_path = manager.DefaultAdapter()
+       adapter = bluezutils.find_adapter(options.dev_id)
+
+       if options.compact:
+               compact = True;
 
-       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
+       bus.add_signal_receiver(interfaces_added,
+                       dbus_interface = "org.freedesktop.DBus.ObjectManager",
+                       signal_name = "InterfacesAdded")
 
-       bus.add_signal_receiver(device_found,
-                       dbus_interface = "org.bluez.Adapter",
-                                       signal_name = "DeviceFound")
+       bus.add_signal_receiver(properties_changed,
+                       dbus_interface = "org.freedesktop.DBus.Properties",
+                       signal_name = "PropertiesChanged",
+                       arg0 = "org.bluez.Device1",
+                       path_keyword = "path")
 
        bus.add_signal_receiver(property_changed,
-                       dbus_interface = "org.bluez.Adapter",
+                                       dbus_interface = "org.bluez.Adapter1",
                                        signal_name = "PropertyChanged")
 
+       om = dbus.Interface(bus.get_object("org.bluez", "/"),
+                               "org.freedesktop.DBus.ObjectManager")
+       objects = om.GetManagedObjects()
+       for path, interfaces in objects.iteritems():
+               if "org.bluez.Device1" in interfaces:
+                       devices[path] = interfaces["org.bluez.Device1"]
+
        adapter.StartDiscovery()
 
        mainloop = GObject.MainLoop()
index f7d4241..052a602 100755 (executable)
@@ -9,6 +9,12 @@ import gobject
 from dbus.mainloop.glib import DBusGMainLoop
 import sys
 
+BUS_NAME = 'org.bluez'
+PATH = '/org/bluez'
+ADAPTER_INTERFACE = 'org.bluez.Adapter1'
+HEALTH_MANAGER_INTERFACE = 'org.bluez.HealthManager1'
+HEALTH_DEVICE_INTERFACE = 'org.bluez.HealthDevice1'
+
 DBusGMainLoop(set_as_default=True)
 loop = gobject.MainLoop()
 
@@ -33,8 +39,8 @@ def sig_received(*args, **kwargs):
 
 
 def enter_mainloop():
-       bus.add_signal_receiver(sig_received, bus_name="org.bluez",
-                               dbus_interface = "org.bluez.HealthDevice",
+       bus.add_signal_receiver(sig_received, bus_name=BUS_NAME,
+                               dbus_interface=HEALTH_DEVICE_INTERFACE,
                                path_keyword="path",
                                member_keyword="member",
                                interface_keyword="interface")
@@ -49,8 +55,8 @@ def enter_mainloop():
        finally:
                print("Exiting, bye")
 
-hdp_manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
-                                               "org.bluez.HealthManager")
+hdp_manager = dbus.Interface(bus.get_object(BUS_NAME, PATH),
+                                               HEALTH_MANAGER_INTERFACE)
 
 role = None
 while role == None:
@@ -58,9 +64,9 @@ while role == None:
        try:
                sel = int(sys.stdin.readline())
                if sel == 1:
-                       role = "Source"
+                       role = "source"
                elif sel == 2:
-                       role = "Sink"
+                       role = "sink"
                else:
                        raise ValueError
        except (TypeError, ValueError):
@@ -82,16 +88,16 @@ while dtype == None:
                sys.exit()
 
 pref = None
-if role == "Source":
+if role == "source":
        while pref == None:
                try:
                        print("Select a preferred data channel type 1.",)
                        print("reliable 2. streaming: ",)
                        sel = int(sys.stdin.readline())
                        if sel == 1:
-                               pref = "Reliable"
+                               pref = "reliable"
                        elif sel == 2:
-                               pref = "Streaming"
+                               pref = "streaming"
                        else:
                                raise ValueError
 
@@ -131,10 +137,15 @@ if not con:
        enter_mainloop()
        sys.exit()
 
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
+manager = dbus.Interface(bus.get_object(BUS_NAME, "/"),
+                                       "org.freedesktop.DBus.ObjectManager")
+
+objects = manager.GetManagedObjects()
+adapters = []
 
-adapters = manager.ListAdapters()
+for path, ifaces in objects.iteritems():
+       if ifaces.has_key(ADAPTER_INTERFACE):
+               adapters.append(path)
 
 i = 1
 for ad in adapters:
@@ -154,10 +165,9 @@ while select == None:
        except KeyboardInterrupt:
                sys.exit()
 
-adapter =  dbus.Interface(bus.get_object("org.bluez", select),
-                                               "org.bluez.Adapter")
+adapter = dbus.Interface(bus.get_object(BUS_NAME, select), ADAPTER_INTERFACE)
 
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
 
 if len(devices) == 0:
        print("No devices available")
@@ -181,8 +191,8 @@ while select == None:
        except KeyboardInterrupt:
                sys.exit()
 
-device = dbus.Interface(bus.get_object("org.bluez", select),
-                                       "org.bluez.HealthDevice")
+device = dbus.Interface(bus.get_object(BUS_NAME, select),
+                                       HEALTH_DEVICE_INTERFACE)
 
 echo = None
 while echo == None:
@@ -207,10 +217,10 @@ if echo:
 
 print("Connecting to device %s" % (select))
 
-if role == "Source":
-       chan = device.CreateChannel(app_path, "Reliable")
+if role == "source":
+       chan = device.CreateChannel(app_path, "reliable")
 else:
-       chan = device.CreateChannel(app_path, "Any")
+       chan = device.CreateChannel(app_path, "any")
 
 print(chan)
 
index ce7337a..32afd71 100755 (executable)
@@ -9,22 +9,33 @@ import gobject
 from dbus.mainloop.glib import DBusGMainLoop
 import sys
 
+BUS_NAME = 'org.bluez'
+PATH = '/org/bluez'
+ADAPTER_INTERFACE = 'org.bluez.Adapter1'
+HEALTH_MANAGER_INTERFACE = 'org.bluez.HealthManager1'
+HEALTH_DEVICE_INTERFACE = 'org.bluez.HealthDevice1'
+
 DBusGMainLoop(set_as_default=True)
 loop = gobject.MainLoop()
 
 bus = dbus.SystemBus()
 
-hdp_manager = dbus.Interface(bus.get_object("org.bluez", "/org/bluez"),
-                                               "org.bluez.HealthManager")
+hdp_manager = dbus.Interface(bus.get_object(BUS_NAME, PATH),
+                                               HEALTH_MANAGER_INTERFACE)
 app_path = hdp_manager.CreateApplication({"DataType": dbus.types.UInt16(4103),
                                        "Role": "sink"})
 
 print(app_path)
 
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
+manager = dbus.Interface(bus.get_object(BUS_NAME, "/"),
+                                       "org.freedesktop.DBus.ObjectManager")
+
+objects = manager.GetManagedObjects()
+adapters = []
 
-adapters = manager.ListAdapters()
+for path, ifaces in objects.iteritems():
+       if ifaces.has_key(ADAPTER_INTERFACE):
+               adapters.append(path)
 
 i = 1
 for ad in adapters:
@@ -44,10 +55,10 @@ while select == None:
        except KeyboardInterrupt:
                sys.exit()
 
-adapter =  dbus.Interface(bus.get_object("org.bluez", select),
-                                               "org.bluez.Adapter")
+adapter =  dbus.Interface(bus.get_object(BUS_NAME, select),
+                                               ADAPTER_INTERFACE)
 
-devices = adapter.ListDevices()
+devices = adapter.GetProperties()["Devices"]
 
 if len(devices) == 0:
        print("No devices available")
@@ -72,8 +83,8 @@ while select == None:
                sys.exit()
 
 print("Connecting to %s" % (select))
-device = dbus.Interface(bus.get_object("org.bluez", select),
-                                       "org.bluez.HealthDevice")
+device = dbus.Interface(bus.get_object(BUS_NAME, select),
+                                               HEALTH_DEVICE_INTERFACE)
 
 chan = device.CreateChannel(app_path, "Any")
 
diff --git a/test/test-heartrate b/test/test-heartrate
new file mode 100755 (executable)
index 0000000..f26b3db
--- /dev/null
@@ -0,0 +1,106 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+'''
+Heart Rate Monitor test script
+'''
+
+import gobject
+
+import sys
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+import bluezutils
+
+BUS_NAME = 'org.bluez'
+HEARTRATE_MANAGER_INTERFACE = 'org.bluez.HeartRateManager1'
+HEARTRATE_WATCHER_INTERFACE = 'org.bluez.HeartRateWatcher1'
+HEARTRATE_INTERFACE = 'org.bluez.HeartRate1'
+
+class Watcher(dbus.service.Object):
+       @dbus.service.method(HEARTRATE_WATCHER_INTERFACE,
+                                       in_signature="oa{sv}", out_signature="")
+       def MeasurementReceived(self, device, measure):
+               print("Measurement received from %s" % device)
+               print("Value: ", measure["Value"])
+
+               if "Energy" in measure:
+                       print("Energy: ", measure["Energy"])
+
+               if "Contact" in measure:
+                       print("Contact: ", measure["Contact"])
+
+               if "Interval" in measure:
+                       for i in measure["Interval"]:
+                               print("Interval: ", i)
+
+if __name__ == "__main__":
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       option_list = [
+               make_option("-i", "--adapter", action="store",
+                       type="string", dest="adapter"),
+               make_option("-b", "--device", action="store",
+                       type="string", dest="address"),
+               ]
+
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       if not options.address:
+               print("Usage: %s [-i <adapter>] -b <bdaddr> [cmd]" % (sys.argv[0]))
+               print("Possible commands:")
+               print("\tReset")
+               sys.exit(1)
+
+       managed_objects = bluezutils.get_managed_objects()
+       adapter = bluezutils.find_adapter_in_objects(managed_objects,
+                                                               options.adapter)
+       adapter_path = adapter.object_path
+
+       heartrateManager = dbus.Interface(bus.get_object(BUS_NAME,
+                               adapter_path), HEARTRATE_MANAGER_INTERFACE)
+
+       path = "/test/watcher"
+       heartrateManager.RegisterWatcher(path)
+
+       device = bluezutils.find_device_in_objects(managed_objects,
+                                                               options.address,
+                                                               options.adapter)
+       device_path = device.object_path
+
+       heartrate = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                                       HEARTRATE_INTERFACE)
+
+       watcher = Watcher(bus, path)
+
+       dev_prop = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                       "org.freedesktop.DBus.Properties")
+
+       properties = dev_prop.GetAll(HEARTRATE_INTERFACE)
+
+       if "Location" in properties:
+               print("Sensor location: %s" % properties["Location"])
+       else:
+               print("Sensor location is not supported")
+
+       if len(args) > 0:
+               if args[0] == "Reset":
+                       reset_sup = properties["ResetSupported"]
+                       if reset_sup:
+                               heartrate.Reset()
+                       else:
+                               print("Reset not supported")
+                               sys.exit(1)
+               else:
+                       print("unknown command")
+                       sys.exit(1)
+
+       mainloop = gobject.MainLoop()
+       mainloop.run()
diff --git a/test/test-hfp b/test/test-hfp
new file mode 100755 (executable)
index 0000000..873de0a
--- /dev/null
@@ -0,0 +1,246 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import os
+import sys
+import dbus
+import glib
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+from socket import SOCK_SEQPACKET, socket
+
+mainloop = None
+audio_supported = True
+
+try:
+       from socket import AF_BLUETOOTH, BTPROTO_SCO
+except:
+       print("WARNING: python compiled without Bluetooth support"
+                                       " - audio will not be available")
+       audio_supported = False
+
+BUF_SIZE = 1024
+
+BDADDR_ANY = '00:00:00:00:00:00'
+
+HF_NREC                        = 0x0001
+HF_3WAY                        = 0x0002
+HF_CLI                 = 0x0004
+HF_VOICE_RECOGNITION   = 0x0008
+HF_REMOTE_VOL          = 0x0010
+HF_ENHANCED_STATUS     = 0x0020
+HF_ENHANCED_CONTROL    = 0x0040
+HF_CODEC_NEGOTIATION   = 0x0080
+
+AG_3WAY                        = 0x0001
+AG_NREC                        = 0x0002
+AG_VOICE_RECOGNITION   = 0x0004
+AG_INBAND_RING         = 0x0008
+AG_VOICE_TAG           = 0x0010
+AG_REJECT_CALL         = 0x0020
+AG_ENHANCED_STATUS     = 0x0040
+AG_ENHANCED_CONTROL    = 0x0080
+AG_EXTENDED_RESULT     = 0x0100
+AG_CODEC_NEGOTIATION   = 0x0200
+
+HF_FEATURES = (HF_3WAY | HF_CLI | HF_VOICE_RECOGNITION |
+                       HF_REMOTE_VOL | HF_ENHANCED_STATUS |
+                       HF_ENHANCED_CONTROL | HF_CODEC_NEGOTIATION)
+
+AVAIL_CODECS = "1,2"
+
+class HfpConnection:
+       slc_complete = False
+       fd = None
+       io_id = 0
+       version = 0
+       features = 0
+       pending = None
+
+       def disconnect(self):
+               if (self.fd >= 0):
+                       os.close(self.fd)
+                       self.fd = -1
+                       glib.source_remove(self.io_id)
+                       self.io_id = 0
+
+       def slc_completed(self):
+               print("SLC establisment complete")
+               self.slc_complete = True
+
+       def slc_next_cmd(self, cmd):
+               if not cmd:
+                       self.send_cmd("AT+BRSF=%u" % (HF_FEATURES))
+               elif (cmd.startswith("AT+BRSF")):
+                       if (self.features & AG_CODEC_NEGOTIATION and
+                                       HF_FEATURES & HF_CODEC_NEGOTIATION):
+                               self.send_cmd("AT+BAC=%s" % (AVAIL_CODECS))
+                       else:
+                               self.send_cmd("AT+CIND=?")
+               elif (cmd.startswith("AT+BAC")):
+                       self.send_cmd("AT+CIND=?")
+               elif (cmd.startswith("AT+CIND=?")):
+                       self.send_cmd("AT+CIND?")
+               elif (cmd.startswith("AT+CIND?")):
+                       self.send_cmd("AT+CMER=3,0,0,1")
+               elif (cmd.startswith("AT+CMER=")):
+                       if (HF_FEATURES & HF_3WAY and self.features & AG_3WAY):
+                               self.send_cmd("AT+CHLD=?")
+                       else:
+                               self.slc_completed()
+               elif (cmd.startswith("AT+CHLD=?")):
+                       self.slc_completed()
+               else:
+                       print("Unknown SLC command completed: %s" % (cmd))
+
+       def io_cb(self, fd, cond):
+               buf = os.read(fd, BUF_SIZE)
+               buf = buf.strip()
+
+               print("Received: %s" % (buf))
+
+               if (buf == "OK" or buf == "ERROR"):
+                       cmd = self.pending
+                       self.pending = None
+
+                       if (not self.slc_complete):
+                               self.slc_next_cmd(cmd)
+
+                       return True
+
+               parts = buf.split(':')
+
+               if (parts[0] == "+BRSF"):
+                       self.features = int(parts[1])
+
+               return True
+
+       def send_cmd(self, cmd):
+               if (self.pending):
+                       print("ERROR: Another command is pending")
+                       return
+
+               print("Sending: %s" % (cmd))
+
+               os.write(self.fd, cmd + "\r\n")
+               self.pending = cmd
+
+       def __init__(self, fd, version, features):
+               self.fd = fd
+               self.version = version
+               self.features = features
+
+               print("Version 0x%04x Features 0x%04x" % (version, features))
+
+               self.io_id = glib.io_add_watch(fd, glib.IO_IN, self.io_cb)
+
+               self.slc_next_cmd(None)
+
+class HfpProfile(dbus.service.Object):
+       sco_socket = None
+       io_id = 0
+       conns = {}
+
+       def sco_cb(self, sock, cond):
+               (sco, peer) = sock.accept()
+               print("New SCO connection from %s" % (peer))
+
+       def init_sco(self, sock):
+               self.sco_socket = sock
+               self.io_id = glib.io_add_watch(sock, glib.IO_IN, self.sco_cb)
+
+       def __init__(self, bus, path, sco):
+               dbus.service.Object.__init__(self, bus, path)
+
+               if sco:
+                       self.init_sco(sco)
+
+       @dbus.service.method("org.bluez.Profile1",
+                                       in_signature="", out_signature="")
+       def Release(self):
+               print("Release")
+               mainloop.quit()
+
+       @dbus.service.method("org.bluez.Profile1",
+                                       in_signature="", out_signature="")
+       def Cancel(self):
+               print("Cancel")
+
+       @dbus.service.method("org.bluez.Profile1",
+                               in_signature="o", out_signature="")
+       def RequestDisconnection(self, path):
+               conn = self.conns.pop(path)
+               conn.disconnect()
+
+       @dbus.service.method("org.bluez.Profile1",
+                               in_signature="oha{sv}", out_signature="")
+       def NewConnection(self, path, fd, properties):
+               fd = fd.take()
+               version = 0x0105
+               features = 0
+               print("NewConnection(%s, %d)" % (path, fd))
+               for key in properties.keys():
+                       if key == "Version":
+                               version = properties[key]
+                       elif key == "Features":
+                               features = properties[key]
+
+               conn = HfpConnection(fd, version, features)
+
+               self.conns[path] = conn
+
+if __name__ == '__main__':
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       manager = dbus.Interface(bus.get_object("org.bluez",
+                               "/org/bluez"), "org.bluez.ProfileManager1")
+
+       option_list = [
+                       make_option("-p", "--path", action="store",
+                                       type="string", dest="path",
+                                       default="/bluez/test/hfp"),
+                       make_option("-n", "--name", action="store",
+                                       type="string", dest="name",
+                                       default=None),
+                       make_option("-C", "--channel", action="store",
+                                       type="int", dest="channel",
+                                       default=None),
+                       ]
+
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       mainloop = GObject.MainLoop()
+
+       opts = {
+                       "Version" : dbus.UInt16(0x0106),
+                       "Features" : dbus.UInt16(HF_FEATURES),
+               }
+
+       if (options.name):
+               opts["Name"] = options.name
+
+       if (options.channel is not None):
+               opts["Channel"] = dbus.UInt16(options.channel)
+
+       if audio_supported:
+               sco = socket(AF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO)
+               sco.bind(BDADDR_ANY)
+               sco.listen(1)
+       else:
+               sco = None
+
+       profile = HfpProfile(bus, options.path, sco)
+
+       manager.RegisterProfile(options.path, "hfp-hf", opts)
+
+       print("Profile registered - waiting for connections")
+
+       mainloop.run()
diff --git a/test/test-input b/test/test-input
deleted file mode 100755 (executable)
index 110cbef..0000000
+++ /dev/null
@@ -1,47 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import dbus
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
-if len(args) < 2:
-       print("""Usage: %s <command>
-
-       connect <bdaddr>
-       disconnect <bdaddr>
-       """ % sys.argv[0])
-       sys.exit(1)
-
-device = adapter.FindDevice(args[1])
-input = dbus.Interface(bus.get_object("org.bluez", device),
-                               "org.bluez.Input")
-
-if args[0] == "connect":
-       input.Connect()
-elif args[0] == "disconnect":
-       input.Disconnect()
-else:
-       print("Unknown command")
-       sys.exit(1)
index 8a7e2f6..1e3882f 100755 (executable)
@@ -6,35 +6,34 @@ from gi.repository import GObject
 
 import dbus
 import dbus.mainloop.glib
+import bluezutils
 
-def adapter_added(path):
-       print("Adapter with path %s added" % (path))
+def interfaces_added(path, interfaces):
+       if interfaces.get("org.bluez.Adapter1") != None:
+               print("Adapter with path %s added" % (path))
 
-def adapter_removed(path):
-       print("Adapter with path %s removed" % (path))
-
-def default_changed(path):
-       print("Default adapter is now at path %s" % (path))
+def interfaces_removed(path, interfaces):
+       if "org.bluez.Adapter1" in interfaces:
+               print("Adapter with path %s removed" % (path))
 
 if __name__ == "__main__":
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
 
-       manager = dbus.Interface(bus.get_object('org.bluez', '/'),
-                                                       'org.bluez.Manager')
-
-       manager.connect_to_signal("AdapterAdded", adapter_added)
-
-       manager.connect_to_signal("AdapterRemoved", adapter_removed)
+       bus.add_signal_receiver(interfaces_added, bus_name="org.bluez",
+                       dbus_interface="org.freedesktop.DBus.ObjectManager",
+                       signal_name="InterfacesAdded")
 
-       manager.connect_to_signal("DefaultAdapterChanged", default_changed)
+       bus.add_signal_receiver(interfaces_removed, bus_name="org.bluez",
+                       dbus_interface="org.freedesktop.DBus.ObjectManager",
+                       signal_name="InterfacesRemoved")
 
        try:
-               path = manager.DefaultAdapter()
-               default_changed(path)
+               path = bluezutils.find_adapter().object_path
+               print("Adapter found at path %s" % (path))
        except:
-               pass
+               print("No adapter found")
 
        mainloop = GObject.MainLoop()
        mainloop.run()
index dc779ad..197e3c2 100755 (executable)
@@ -6,12 +6,10 @@ import sys
 import time
 import dbus
 from optparse import OptionParser, make_option
+import bluezutils
 
 bus = dbus.SystemBus()
 
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
-
 option_list = [
                make_option("-i", "--device", action="store",
                                type="string", dest="dev_id"),
@@ -20,13 +18,9 @@ parser = OptionParser(option_list=option_list)
 
 (options, args) = parser.parse_args()
 
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
+adapter_path = bluezutils.find_adapter(options.dev_id).object_path
 server = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                               "org.bluez.NetworkServer")
+                                               "org.bluez.NetworkServer1")
 
 service = "nap"
 
index 2ade584..3e8713f 100755 (executable)
@@ -6,6 +6,7 @@ import sys
 import time
 import dbus
 from optparse import OptionParser, make_option
+import bluezutils
 
 bus = dbus.SystemBus()
 
@@ -20,33 +21,27 @@ parser = OptionParser(option_list=option_list)
 
 (options, args) = parser.parse_args()
 
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
 if (len(args) < 1):
        print("Usage: %s <address> [service]" % (sys.argv[0]))
        sys.exit(1)
 
-address = args[0]
+# Fix-up in case of "connect" invocation that other scripts use
+if args[0] == "connect":
+       del args[:1]
 
 if (len(args) < 2):
        service = "panu"
 else:
        service = args[1]
 
-device = adapter.FindDevice(address)
+device = bluezutils.find_device(args[0], options.dev_id)
 
-network = dbus.Interface(bus.get_object("org.bluez", device),
-                                               "org.bluez.Network")
+network = dbus.Interface(bus.get_object("org.bluez", device.object_path),
+                                               "org.bluez.Network1")
 
 iface = network.Connect(service)
 
-print("Connected %s to %s" % (device, address))
+print("Connected to %s service %s, interface %s" % (args[0], service, iface))
 
 print("Press CTRL-C to disconnect")
 
diff --git a/test/test-oob b/test/test-oob
deleted file mode 100755 (executable)
index bec9de5..0000000
+++ /dev/null
@@ -1,82 +0,0 @@
-#!/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!")
-       mainloop.quit()
-
-def create_device_error(error):
-       print("Pairing failed.")
-       mainloop.quit()
-
-if __name__ == '__main__':
-       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
-
-       mainloop = gobject.MainLoop()
-
-       bus = dbus.SystemBus()
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                                       "org.bluez.Manager")
-
-       adapter0_path = manager.FindAdapter("hci0")
-       adapter1_path = manager.FindAdapter("hci1")
-
-       adapter0 = dbus.Interface(bus.get_object("org.bluez", adapter0_path),
-                                                       "org.bluez.Adapter")
-       adapter1 = dbus.Interface(bus.get_object("org.bluez", adapter1_path),
-                                                       "org.bluez.Adapter")
-
-       adapter0_address = adapter0.GetProperties()["Address"]
-       adapter1_address = adapter1.GetProperties()["Address"]
-       print("Adapters:")
-       print("    hci0: " + adapter0_address)
-       print("    hci1: " + adapter1_address)
-       print()
-
-       print("Removing any existing bond...")
-
-       try:
-               device = adapter0.FindDevice(adapter1_address)
-               adapter0.RemoveDevice(device)
-       except:
-               pass
-
-       try:
-               device = adapter1.FindDevice(adapter0_address)
-               adapter1.RemoveDevice(device)
-       except:
-               pass
-
-       print("Done.")
-       print()
-       print("Reading local Out of Band data...")
-
-       oob_adapter0 = dbus.Interface(bus.get_object("org.bluez",
-                                       adapter0_path), "org.bluez.OutOfBand")
-       oob_adapter1 = dbus.Interface(bus.get_object("org.bluez",
-                                       adapter1_path), "org.bluez.OutOfBand")
-
-       oob0 = oob_adapter0.ReadLocalData()
-       oob1 = oob_adapter1.ReadLocalData()
-
-       print("Done.")
-       print()
-       print("Exchanging Out of Band data...")
-
-       oob_adapter0.AddRemoteData(adapter1_address, oob1[0], oob1[1])
-       oob_adapter1.AddRemoteData(adapter0_address, oob0[0], oob0[1])
-
-       print("Done.")
-       print()
-       print("Starting to pair.")
-       adapter1.CreatePairedDevice(adapter0_address, "/test/agent_oob",
-                                       "DisplayYesNo",
-                                       reply_handler=create_device_reply,
-                                       error_handler=create_device_error)
-
-       mainloop.run()
diff --git a/test/test-profile b/test/test-profile
new file mode 100755 (executable)
index 0000000..b78d00c
--- /dev/null
@@ -0,0 +1,125 @@
+#!/usr/bin/python
+
+from __future__ import absolute_import, print_function, unicode_literals
+
+from gi.repository import GObject
+
+import os
+import sys
+import uuid
+import dbus
+import dbus.service
+import dbus.mainloop.glib
+from optparse import OptionParser, make_option
+
+class Profile(dbus.service.Object):
+       fd = -1
+
+       @dbus.service.method("org.bluez.Profile1",
+                                       in_signature="", out_signature="")
+       def Release(self):
+               print("Release")
+               mainloop.quit()
+
+       @dbus.service.method("org.bluez.Profile1",
+                                       in_signature="", out_signature="")
+       def Cancel(self):
+               print("Cancel")
+
+       @dbus.service.method("org.bluez.Profile1",
+                               in_signature="oha{sv}", out_signature="")
+       def NewConnection(self, path, fd, properties):
+               self.fd = fd.take()
+               print("NewConnection(%s, %d)" % (path, self.fd))
+               for key in properties.keys():
+                       if key == "Version" or key == "Features":
+                               print("  %s = 0x%04x" % (key, properties[key]))
+                       else:
+                               print("  %s = %s" % (key, properties[key]))
+
+       @dbus.service.method("org.bluez.Profile1",
+                               in_signature="o", out_signature="")
+       def RequestDisconnection(self, path):
+               print("RequestDisconnection(%s)" % (path))
+
+               if (self.fd > 0):
+                       os.close(self.fd)
+                       self.fd = -1
+
+if __name__ == '__main__':
+       dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
+
+       bus = dbus.SystemBus()
+
+       manager = dbus.Interface(bus.get_object("org.bluez",
+                               "/org/bluez"), "org.bluez.ProfileManager1")
+
+       option_list = [
+                       make_option("-u", "--uuid", action="store",
+                                       type="string", dest="uuid",
+                                       default=None),
+                       make_option("-p", "--path", action="store",
+                                       type="string", dest="path",
+                                       default="/foo/bar/profile"),
+                       make_option("-n", "--name", action="store",
+                                       type="string", dest="name",
+                                       default=None),
+                       make_option("-s", "--server",
+                                       action="store_const",
+                                       const="server", dest="role"),
+                       make_option("-c", "--client",
+                                       action="store_const",
+                                       const="client", dest="role"),
+                       make_option("-a", "--auto-connect",
+                                       action="store_true",
+                                       dest="auto_connect", default=False),
+                       make_option("-P", "--PSM", action="store",
+                                       type="int", dest="psm",
+                                       default=None),
+                       make_option("-C", "--channel", action="store",
+                                       type="int", dest="channel",
+                                       default=None),
+                       make_option("-r", "--record", action="store",
+                                       type="string", dest="record",
+                                       default=None),
+                       make_option("-S", "--service", action="store",
+                                       type="string", dest="service",
+                                       default=None),
+                       ]
+
+       parser = OptionParser(option_list=option_list)
+
+       (options, args) = parser.parse_args()
+
+       profile = Profile(bus, options.path)
+
+       mainloop = GObject.MainLoop()
+
+       opts = {
+                       "AutoConnect" : options.auto_connect,
+               }
+
+       if (options.name):
+               opts["Name"] = options.name
+
+       if (options.role):
+               opts["Role"] = options.role
+
+       if (options.psm is not None):
+               opts["PSM"] = dbus.UInt16(options.psm)
+
+       if (options.channel is not None):
+               opts["Channel"] = dbus.UInt16(options.channel)
+
+       if (options.record):
+               opts["ServiceRecord"] = options.record
+
+       if (options.service):
+               opts["Service"] = options.service
+
+       if not options.uuid:
+               options.uuid = str(uuid.uuid4())
+
+       manager.RegisterProfile(options.path, options.uuid, opts)
+
+       mainloop.run()
index b08a62a..2f47824 100755 (executable)
@@ -12,20 +12,23 @@ import sys
 import dbus
 import dbus.mainloop.glib
 from optparse import OptionParser, make_option
+import bluezutils
 
-def property_changed(name, value):
+BUS_NAME = 'org.bluez'
+PROXIMITY_MONITOR_INTERFACE = 'org.bluez.ProximityMonitor1'
 
-       print("PropertyChanged('%s', '%s')" % (name, value))
-       mainloop.quit()
+def properties_changed(interface, changed, invalidated):
+       if interface != PROXIMITY_MONITOR_INTERFACE:
+               return
+
+       for name, value in changed.iteritems():
+               print("Property %s changed:  %s" % (name, str(value)))
 
 if __name__ == "__main__":
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
 
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                       "org.bluez.Manager")
-
        option_list = [
                make_option("-i", "--adapter", action="store",
                        type="string", dest="dev_id"),
@@ -37,14 +40,6 @@ if __name__ == "__main__":
 
        (options, args) = parser.parse_args()
 
-       if options.dev_id:
-               adapter_path = manager.FindAdapter(options.dev_id)
-       else:
-               adapter_path = manager.DefaultAdapter()
-
-       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
        if (len(args) < 1):
                print("Usage: %s <command>" % (sys.argv[0]))
                print("")
@@ -52,17 +47,22 @@ if __name__ == "__main__":
                print("  -b MAC ImmediateAlertLevel <none|mild|high>")
                sys.exit(1)
 
-       device_path = adapter.FindDevice(options.address)
+       device = bluezutils.find_device(options.address, options.dev_id)
+       device_path = device.object_path
+
+       bus.add_signal_receiver(properties_changed, bus_name=BUS_NAME,
+                       path=device_path,
+                       dbus_interface="org.freedesktop.DBus.Properties",
+                       signal_name="PropertiesChanged")
 
-       bus.add_signal_receiver(property_changed, bus_name="org.bluez",
-                               dbus_interface="org.bluez.ProximityMonitor",
-                               signal_name="PropertyChanged")
+       proximity = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                               PROXIMITY_MONITOR_INTERFACE)
 
-       proximity = dbus.Interface(bus.get_object("org.bluez",
-                                       device_path), "org.bluez.ProximityMonitor")
+       device_prop = dbus.Interface(bus.get_object(BUS_NAME, device_path),
+                                       "org.freedesktop.DBus.Properties")
 
        print("Proximity SetProperty('%s', '%s')" % (args[0], args[1]))
-       proximity.SetProperty(args[0], args[1])
+       device_prop.Set(PROXIMITY_MONITOR_INTERFACE, args[0], args[1])
 
        mainloop = gobject.MainLoop()
        mainloop.run()
index df838f6..ff178af 100755 (executable)
@@ -2,8 +2,9 @@
 
 from __future__ import absolute_import, print_function, unicode_literals
 
-from sap import *
+from sap_client import *
 import time
+import sys
 
 def connect_disconnect_by_client(sap):
 
@@ -124,13 +125,23 @@ def power_sim_off_on(sap):
 
 if __name__ == "__main__":
 
-    host = "00:00:00:00:00:0"  # server bd_addr
+    host = None  # server bd_addr
     port = 8  # sap server port
 
+    if (len(sys.argv) < 2):
+        print("Usage: %s <address> [port]" % (sys.argv[0]))
+        sys.exit(1)
+
+    host = sys.argv[1]
+
+    if (len(sys.argv) == 3):
+        port = sys.argv[2]
+
     try:
         s = SAPClient(host, port)
     except BluetoothError as e:
-        print("Error " + str(e))
+        print("Error: " + str(e))
+        sys.exit(1)
 
     connect_disconnect_by_client(s)
     connect_disconnect_by_server_gracefully(s)
diff --git a/test/test-serial b/test/test-serial
deleted file mode 100755 (executable)
index 8858dbd..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import time
-import dbus
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-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]))
-       sys.exit(1)
-
-address = args[0]
-
-if (len(args) < 2):
-       service = "spp"
-else:
-       service = args[1]
-
-path = adapter.FindDevice(address)
-
-serial = dbus.Interface(bus.get_object("org.bluez", path),
-                                               "org.bluez.Serial")
-
-node = serial.Connect(service)
-
-print("Connected %s to %s" % (node, address))
-
-print("Press CTRL-C to disconnect")
-
-try:
-       time.sleep(1000)
-       print("Terminating connection")
-except:
-       pass
-
-serial.Disconnect(node)
diff --git a/test/test-serial-proxy b/test/test-serial-proxy
deleted file mode 100755 (executable)
index 7963f23..0000000
+++ /dev/null
@@ -1,66 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import time
-import dbus
-import socket
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                               "org.bluez.Manager")
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
-if (len(args) < 1):
-       print("Usage: %s <socket_name> [service]" % (sys.argv[0]))
-       sys.exit(1)
-
-socket_name = args[0]
-
-if (len(args) < 2):
-       service = "spp"
-else:
-       service = args[1]
-
-sk = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
-sk.bind(socket_name)
-sk.listen(1)
-
-proxy_manager = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                               "org.bluez.SerialProxyManager")
-proxy_path = proxy_manager.CreateProxy(service, socket_name)
-
-proxy = dbus.Interface(bus.get_object("org.bluez", proxy_path),
-                                                       "org.bluez.SerialProxy")
-proxy.Enable()
-
-conn, addr = sk.accept()
-
-print("Waiting for message")
-
-while 1:
-       data = conn.recv(1024)
-       if data:
-               print(data)
-               break
-
-proxy.Disable()
-proxy_manager.RemoveProxy(proxy_path)
-conn.close()
diff --git a/test/test-service b/test/test-service
deleted file mode 100755 (executable)
index 8eea9e2..0000000
+++ /dev/null
@@ -1,49 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import dbus
-import time
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-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>")
-       sys.exit(1)
-
-if (args[0] == "addrecord"):
-       if (len(args) < 2):
-               print("Need file parameter")
-       else:
-               f = open(args[1])
-               record = f.read()
-               f.close()
-               handle = service.AddRecord(record)
-               print("0x%x" % (handle))
-               time.sleep(120)
-       sys.exit(0)
-
-print("Unknown command")
-sys.exit(1)
diff --git a/test/test-telephony b/test/test-telephony
deleted file mode 100755 (executable)
index bd7d3b2..0000000
+++ /dev/null
@@ -1,178 +0,0 @@
-#!/usr/bin/python
-
-from __future__ import absolute_import, print_function, unicode_literals
-
-import sys
-import dbus
-from optparse import OptionParser, make_option
-
-bus = dbus.SystemBus()
-
-manager = dbus.Interface(bus.get_object("org.bluez", "/"), "org.bluez.Manager")
-
-option_list = [
-               make_option("-i", "--device", action="store",
-                               type="string", dest="dev_id"),
-               ]
-parser = OptionParser(option_list=option_list)
-
-(options, args) = parser.parse_args()
-
-if options.dev_id:
-       adapter_path = manager.FindAdapter(options.dev_id)
-else:
-       adapter_path = manager.DefaultAdapter()
-
-adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
-
-test = dbus.Interface(bus.get_object("org.bluez", "/org/bluez/test"),
-                       "org.bluez.TelephonyTest")
-
-if len(args) < 1:
-       print("""Usage: %s <command>
-
-       connect <bdaddr>
-       disconnect <bdaddr>
-       outgoing <number>
-       incoming <number>
-       cancel
-       signal <level>
-       battery <level>
-       roaming <yes|no>
-       registration <status>
-       subscriber <number>
-       speakergain <bdaddr> [level]
-       microphonegain <bdaddr> [level]
-       play <bdaddr>
-       stop <bdaddr>
-       """ % sys.argv[0])
-       sys.exit(1)
-
-if args[0] == "connect":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       headset.Connect()
-       sys.exit(0)
-
-if args[0] == "disconnect":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       headset.Disconnect()
-       sys.exit(0)
-
-if args[0] == "speakergain":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       if len(args) > 2:
-               headset.SetProperty('SpeakerGain', dbus.UInt16(args[2]))
-       else:
-               props = headset.GetProperties()
-               print(props['SpeakerGain'])
-
-       sys.exit(0)
-
-if args[0] == "microphonegain":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       if len(args) > 2:
-               headset.SetProperty('MicrophoneGain', dbus.UInt16(args[2]))
-       else:
-               props = headset.GetProperties()
-               print(props['MicrophoneGain'])
-
-       sys.exit(0)
-
-if args[0] == "play":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       headset.Play()
-
-       sys.exit(0)
-
-if args[0] == "stop":
-       if len(args) < 2:
-               print("Need device address parameter")
-               sys.exit(1)
-       device = adapter.FindDevice(args[1])
-       headset = dbus.Interface(bus.get_object("org.bluez", device),
-                                       "org.bluez.Headset")
-       headset.Stop()
-
-       sys.exit(0)
-
-if args[0] == "outgoing":
-       if len(args) > 1:
-               test.OutgoingCall(args[1])
-       else:
-               print("Need number parameter")
-       sys.exit(0)
-
-if args[0] == "incoming":
-       if len(args) > 1:
-               test.IncomingCall(args[1])
-       else:
-               print("Need number parameter")
-       sys.exit(0)
-
-if args[0] == "cancel":
-       test.CancelCall()
-       sys.exit(0)
-
-if args[0] == "signal":
-       if len(args) > 1:
-               test.SignalStrength(args[1])
-       else:
-               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")
-       sys.exit(0)
-
-if args[0] == "roaming":
-       if len(args) > 1:
-               test.RoamingStatus(args[1] == "yes" or False)
-       else:
-               print("Need yes/no parameter")
-       sys.exit(0)
-
-if args[0] == "registration":
-       if len(args) > 1:
-               test.RegistrationStatus(args[1] == "yes" or False)
-       else:
-               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")
-       sys.exit(0)
-
-print("Unknown command")
-sys.exit(1)
diff --git a/test/test-textfile.c b/test/test-textfile.c
deleted file mode 100644 (file)
index e0a0c5b..0000000
+++ /dev/null
@@ -1,191 +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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "textfile.h"
-
-static void print_entry(char *key, char *value, void *data)
-{
-       printf("%s %s\n", key, value);
-}
-
-int main(int argc, char *argv[])
-{
-       char filename[] = "/tmp/textfile";
-       char key[18], value[512], *str;
-       unsigned int i, j, size, max = 10;
-       int fd;
-
-       size = getpagesize();
-       printf("System uses a page size of %d bytes\n\n", size);
-
-       fd = creat(filename, 0644);
-       if (ftruncate(fd, 0) < 0)
-               return -errno;
-
-       memset(value, 0, sizeof(value));
-       for (i = 0; i < (size / sizeof(value)); i++) {
-               if (write(fd, value, sizeof(value)) < 0)
-                       return -errno;
-       }
-
-       close(fd);
-
-       sprintf(key, "11:11:11:11:11:11");
-       str = textfile_get(filename, key);
-
-       if (truncate(filename, 0) < 0)
-               return -errno;
-
-       sprintf(key, "00:00:00:00:00:00");
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       memset(value, 0, sizeof(value));
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       str = textfile_get(filename, key);
-       if (!str)
-               fprintf(stderr, "No value for %s\n", key);
-       else
-               free(str);
-
-       snprintf(value, sizeof(value), "Test");
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       str = textfile_get(filename, key);
-       if (str) {
-               fprintf(stderr, "Found value for %s\n", key);
-               free(str);
-       }
-
-       for (i = 1; i < max + 1; i++) {
-               sprintf(key, "00:00:00:00:00:%02X", i);
-
-               memset(value, 0, sizeof(value));
-               for (j = 0; j < i; j++)
-                       value[j] = 'x';
-
-               printf("%s %s\n", key, value);
-
-               if (textfile_put(filename, key, value) < 0) {
-                       fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-                       break;
-               }
-
-               str = textfile_get(filename, key);
-               if (!str)
-                       fprintf(stderr, "No value for %s\n", key);
-               else
-                       free(str);
-       }
-
-
-       sprintf(key, "00:00:00:00:00:%02X", max);
-
-       memset(value, 0, sizeof(value));
-       for (j = 0; j < max; j++)
-               value[j] = 'y';
-
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       sprintf(key, "00:00:00:00:00:%02X", 1);
-
-       memset(value, 0, sizeof(value));
-       for (j = 0; j < max; j++)
-               value[j] = 'z';
-
-       if (textfile_put(filename, key, value) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       printf("\n");
-
-       for (i = 1; i < max + 1; i++) {
-               sprintf(key, "00:00:00:00:00:%02X", i);
-
-               str = textfile_get(filename, key);
-               if (str) {
-                       printf("%s %s\n", key, str);
-                       free(str);
-               }
-       }
-
-
-       sprintf(key, "00:00:00:00:00:%02X", 2);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       sprintf(key, "00:00:00:00:00:%02X", max - 3);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       printf("\n");
-
-       textfile_foreach(filename, print_entry, NULL);
-
-
-       sprintf(key, "00:00:00:00:00:%02X", 1);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       sprintf(key, "00:00:00:00:00:%02X", max);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       sprintf(key, "00:00:00:00:00:%02X", max + 1);
-
-       if (textfile_del(filename, key) < 0)
-               fprintf(stderr, "%s (%d)\n", strerror(errno), errno);
-
-       printf("\n");
-
-       textfile_foreach(filename, print_entry, NULL);
-
-       return 0;
-}
index 9216264..6c143be 100755 (executable)
@@ -13,12 +13,18 @@ import dbus
 import dbus.service
 import dbus.mainloop.glib
 from optparse import OptionParser, make_option
+import bluezutils
+
+BUS_NAME = 'org.bluez'
+THERMOMETER_MANAGER_INTERFACE = 'org.bluez.ThermometerManager1'
+THERMOMETER_WATCHER_INTERFACE = 'org.bluez.ThermometerWatcher1'
+THERMOMETER_INTERFACE = 'org.bluez.Thermometer1'
 
 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")
+       @dbus.service.method(THERMOMETER_WATCHER_INTERFACE,
+                                       in_signature="oa{sv}", out_signature="")
+       def MeasurementReceived(self, device, measure):
+               print("%s measurement received from %s" % (measure["Measurement"], device))
                print("Exponent: ", measure["Exponent"])
                print("Mantissa: ", measure["Mantissa"])
                print("Unit: ", measure["Unit"])
@@ -29,18 +35,17 @@ class Watcher(dbus.service.Object):
                if "Type" in measure:
                        print("Type: ", measure["Type"])
 
-def property_changed(name, value):
-
-       print("PropertyChanged('%s', '%s')" % (name, value))
+def properties_changed(interface, changed, invalidated):
+       if interface != THERMOMETER_INTERFACE:
+               return
+       for name, value in changed.iteritems():
+               print("Property %s changed:  %s" % (name, str(value)))
 
 if __name__ == "__main__":
        dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
 
        bus = dbus.SystemBus()
 
-       manager = dbus.Interface(bus.get_object("org.bluez", "/"),
-                                       "org.bluez.Manager")
-
        option_list = [
                make_option("-i", "--adapter", action="store",
                        type="string", dest="adapter"),
@@ -58,31 +63,32 @@ if __name__ == "__main__":
                print("\tEnableIntermediateMeasurement")
                sys.exit(1)
 
-       if options.adapter:
-               adapter_path = manager.FindAdapter(options.adapter)
-       else:
-               adapter_path = manager.DefaultAdapter()
-
-       adapter = dbus.Interface(bus.get_object("org.bluez", adapter_path),
-                                                       "org.bluez.Adapter")
+       managed_objects = bluezutils.get_managed_objects()
+       adapter = bluezutils.find_adapter_in_objects(managed_objects,
+                                                               options.adapter)
+       adapter_path = adapter.object_path
 
-       device_path = adapter.FindDevice(options.address)
+       thermometer_manager = dbus.Interface(bus.get_object(BUS_NAME,
+                               adapter_path), THERMOMETER_MANAGER_INTERFACE)
 
-       bus.add_signal_receiver(property_changed, bus_name="org.bluez",
-                               dbus_interface="org.bluez.Thermometer",
-                               signal_name="PropertyChanged")
+       device = bluezutils.find_device_in_objects(managed_objects,
+                                                               options.address,
+                                                               options.adapter)
+       device_path = device.object_path
 
-       thermometer = dbus.Interface(bus.get_object("org.bluez",
-                                       device_path), "org.bluez.Thermometer")
+       bus.add_signal_receiver(properties_changed, bus_name=BUS_NAME,
+                       path=device_path,
+                       dbus_interface="org.freedesktop.DBus.Properties",
+                       signal_name="PropertiesChanged")
 
        path = "/test/watcher"
        watcher = Watcher(bus, path)
 
-       thermometer.RegisterWatcher(path)
+       thermometer_manager.RegisterWatcher(path)
 
        if len(args) > 0:
                if args[0] == "EnableIntermediateMeasurement":
-                       thermometer.EnableIntermediateMeasurement(path)
+                       thermometer_manager.EnableIntermediateMeasurement(path)
                else:
                        print("unknown command")
                        sys.exit(1)
diff --git a/test/uuidtest.c b/test/uuidtest.c
deleted file mode 100644 (file)
index a8b46d7..0000000
+++ /dev/null
@@ -1,319 +0,0 @@
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/uuid.h>
-
-const char *base = "00000000-0000-1000-8000-00805F9B34FB";
-
-uint8_t xbase[] = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
-                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
-
-uint16_t sixteen = 0x1234;
-const char *uuidsixteen128 = "00001234-0000-1000-8000-00805F9B34FB";
-const char *uuidsixteen16 = "0x1234";
-const char *uuidsixteen16a = "1234";
-
-uint8_t xuuidsixteen[] = {0x00, 0x00, 0x12, 0x34, 0x00, 0x00, 0x10, 0x00,
-                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
-
-uint32_t thirtytwo = 0x12345678;
-const char *uuidthirtytwo32 = "0x12345678";
-const char *uuidthirtytwo32a = "12345678";
-const char *uuidthirtytwo128 = "12345678-0000-1000-8000-00805F9B34FB";
-
-uint8_t xuuidthirtytwo[] = {0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x10, 0x00,
-                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb};
-
-const char *malformed[] = {
-       "0",
-       "01",
-       "012",
-       "xxxx",
-       "xxxxx",
-       "0xxxxx",
-       "0123456",
-       "012g4567",
-       "012345678",
-       "0x234567u9",
-       "01234567890",
-       "00001234-0000-1000-8000-00805F9B34F",
-       "00001234-0000-1000-8000 00805F9B34FB",
-       "00001234-0000-1000-8000-00805F9B34FBC",
-       "00001234-0000-1000-800G-00805F9B34FB",
-       NULL,
-       };
-
-int main(int argc, char *argv[])
-{
-       bt_uuid_t u, u2, u3, u4, u5, ub, u128;
-       uint128_t n, i;
-       char buf[512];
-       int s;
-
-       memcpy(&n, xbase, 16);
-       ntoh128(&n, &i);
-
-       if (bt_string_to_uuid(&u, base)) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_string_to_uuid(&ub, base)) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (ub.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (memcmp(&u.value.u128, &i, 16) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (memcmp(&ub.value.u128, &i, 16) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (memcmp(&ub.value.u128, &u.value.u128, 16) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &ub) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       bt_uuid_to_string(&u, buf, sizeof(buf));
-       /* printf("%s\n", buf); */
-
-       if (strcasecmp(buf, base) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       memcpy(&n, xuuidsixteen, 16);
-       ntoh128(&n, &i);
-
-       bt_uuid16_create(&u, sixteen);
-       bt_uuid_to_uuid128(&u, &u128);
-
-       if (bt_string_to_uuid(&u2, uuidsixteen16)) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_string_to_uuid(&u3, uuidsixteen16a)) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_string_to_uuid(&u4, uuidsixteen128)) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       bt_uuid128_create(&u5, i);
-
-       if (u.type != 16) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u128.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u.value.u16 != sixteen) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u2.type != 16) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u3.type != 16) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u4.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u5.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &u2) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u2, &u3) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &u3) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u3, &u4) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u4, &u5) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u5, &u) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &ub) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u5, &ub) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &u128) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&ub, &u128) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       memcpy(&n, xuuidthirtytwo, 16);
-       ntoh128(&n, &i);
-
-       bt_uuid32_create(&u, thirtytwo);
-       bt_uuid_to_uuid128(&u, &u128);
-       bt_string_to_uuid(&u2, uuidthirtytwo32);
-       bt_string_to_uuid(&u3, uuidthirtytwo32a);
-       bt_string_to_uuid(&u4, uuidthirtytwo128);
-       bt_uuid128_create(&u5, i);
-
-       /*
-       bt_uuid_to_string(&u2, buf, sizeof(buf));
-       printf("%s\n", buf);
-
-       bt_uuid_to_string(&u3, buf, sizeof(buf));
-       printf("%s\n", buf);
-
-       bt_uuid_to_string(&u4, buf, sizeof(buf));
-       printf("%s\n", buf);
-       */
-
-       if (u.type != 32) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u128.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u.value.u32 != thirtytwo) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u2.type != 32) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u3.type != 32) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u4.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (u5.type != 128) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &u2) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u2, &u3) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u3, &u4) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u4, &u5) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u5, &u) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &ub) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u5, &ub) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&u, &u128) != 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       if (bt_uuid_cmp(&ub, &u128) == 0) {
-               printf("Fail %d\n", __LINE__);
-               return 1;
-       }
-
-       for (s = 0; malformed[s]; ++s) {
-               if (bt_string_to_uuid(&u3, malformed[s]) == 0) {
-                       printf("Fail %s %d\n", malformed[s], __LINE__);
-                       return 1;
-               }
-       }
-
-       return 0;
-}
diff --git a/thermometer/main.c b/thermometer/main.c
deleted file mode 100644 (file)
index 4447b52..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <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;
-
-       if (thermometer_manager_init(connection) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
-       }
-
-       return 0;
-}
-
-static void thermometer_exit(void)
-{
-       if (!main_opts.gatt_enabled)
-               return;
-
-       thermometer_manager_exit();
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-}
-
-BLUETOOTH_PLUGIN_DEFINE(thermometer, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                                       thermometer_init, thermometer_exit)
diff --git a/thermometer/manager.c b/thermometer/manager.c
deleted file mode 100644 (file)
index 3d5452b..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#include <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "adapter.h"
-#include "device.h"
-#include "att.h"
-#include "gattrib.h"
-#include "gatt.h"
-#include "thermometer.h"
-#include "manager.h"
-
-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 gatt_primary *tattr;
-       GSList *primaries, *l;
-
-       primaries = btd_device_get_primaries(device);
-
-       l = g_slist_find_custom(primaries, HEALTH_THERMOMETER_UUID,
-                                                       primary_uuid_cmp);
-       if (l == NULL)
-               return -EINVAL;
-
-       tattr = l->data;
-
-       return thermometer_register(connection, device, tattr);
-}
-
-static void thermometer_driver_remove(struct btd_device *device)
-{
-       thermometer_unregister(device);
-}
-
-static struct btd_device_driver thermometer_device_driver = {
-       .name   = "thermometer-device-driver",
-       .uuids  = BTD_UUIDS(HEALTH_THERMOMETER_UUID),
-       .probe  = thermometer_driver_probe,
-       .remove = thermometer_driver_remove
-};
-
-int thermometer_manager_init(DBusConnection *conn)
-{
-       int ret;
-
-       ret = btd_register_device_driver(&thermometer_device_driver);
-       if (ret < 0)
-                return ret;
-
-       connection = dbus_connection_ref(conn);
-       return 0;
-}
-
-void thermometer_manager_exit(void)
-{
-       btd_unregister_device_driver(&thermometer_device_driver);
-
-       dbus_connection_unref(connection);
-       connection = NULL;
-}
diff --git a/thermometer/manager.h b/thermometer/manager.h
deleted file mode 100644 (file)
index ed928ad..0000000
+++ /dev/null
@@ -1,24 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int thermometer_manager_init(DBusConnection *conn);
-void thermometer_manager_exit(void);
diff --git a/thermometer/thermometer.c b/thermometer/thermometer.c
deleted file mode 100644 (file)
index 85f0811..0000000
+++ /dev/null
@@ -1,1265 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <gdbus.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-
-#include "dbus-common.h"
-#include "adapter.h"
-#include "device.h"
-#include "error.h"
-#include "log.h"
-#include "gattrib.h"
-#include "attio.h"
-#include "att.h"
-#include "gatt.h"
-#include "thermometer.h"
-
-#define THERMOMETER_INTERFACE "org.bluez.Thermometer"
-
-/* Temperature measurement flag fields */
-#define TEMP_UNITS             0x01
-#define TEMP_TIME_STAMP                0x02
-#define TEMP_TYPE              0x04
-
-#define FLOAT_MAX_MANTISSA     16777216 /* 2^24 */
-
-struct thermometer {
-       DBusConnection          *conn;          /* The connection to the bus */
-       struct btd_device       *dev;           /* Device reference */
-       GAttrib                 *attrib;        /* GATT connection */
-       struct att_range        *svc_range;     /* Thermometer range */
-       guint                   attioid;        /* Att watcher id */
-       guint                   attindid;       /* Att incications id */
-       guint                   attnotid;       /* Att notifications id */
-       GSList                  *chars;         /* Characteristics */
-       GSList                  *fwatchers;     /* Final measurements */
-       GSList                  *iwatchers;     /* Intermediate measurements */
-       gboolean                intermediate;
-       uint8_t                 type;
-       uint16_t                interval;
-       uint16_t                max;
-       uint16_t                min;
-       gboolean                has_type;
-       gboolean                has_interval;
-};
-
-struct characteristic {
-       struct gatt_char                attr;   /* Characteristic */
-       GSList                  *desc;  /* Descriptors */
-       struct thermometer      *t;     /* Thermometer where the char belongs */
-};
-
-struct descriptor {
-       struct characteristic   *ch;
-       uint16_t                handle;
-       bt_uuid_t               uuid;
-};
-
-struct watcher {
-       struct thermometer      *t;
-       guint                   id;
-       char                    *srv;
-       char                    *path;
-};
-
-struct measurement {
-       int16_t         exp;
-       int32_t         mant;
-       uint64_t        time;
-       gboolean        suptime;
-       char            *unit;
-       char            *type;
-       char            *value;
-};
-
-struct tmp_interval_data {
-       struct thermometer      *thermometer;
-       uint16_t                interval;
-};
-
-static GSList *thermometers = NULL;
-
-const char *temp_type[] = {
-       "<reserved>",
-       "Armpit",
-       "Body",
-       "Ear",
-       "Finger",
-       "Intestines",
-       "Mouth",
-       "Rectum",
-       "Toe",
-       "Tympanum"
-};
-
-static const gchar *temptype2str(uint8_t value)
-{
-        if (value > 0 && value < G_N_ELEMENTS(temp_type))
-               return temp_type[value];
-
-       error("Temperature type %d reserved for future use", value);
-       return NULL;
-}
-
-static void destroy_watcher(gpointer user_data)
-{
-       struct watcher *watcher = user_data;
-
-       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;
-
-       g_slist_free_full(c->desc, g_free);
-       g_free(c);
-}
-
-static void destroy_thermometer(gpointer user_data)
-{
-       struct thermometer *t = user_data;
-
-       if (t->attioid > 0)
-               btd_device_remove_attio_callback(t->dev, t->attioid);
-
-       if (t->attindid > 0)
-               g_attrib_unregister(t->attrib, t->attindid);
-
-       if (t->attnotid > 0)
-               g_attrib_unregister(t->attrib, t->attnotid);
-
-       if (t->attrib != NULL)
-               g_attrib_unref(t->attrib);
-
-       if (t->chars != NULL)
-               g_slist_free_full(t->chars, destroy_char);
-
-       if (t->fwatchers != NULL)
-               g_slist_free_full(t->fwatchers, remove_watcher);
-
-       dbus_connection_unref(t->conn);
-       btd_device_unref(t->dev);
-       g_free(t->svc_range);
-       g_free(t);
-}
-
-static gint cmp_device(gconstpointer a, gconstpointer b)
-{
-       const struct thermometer *t = a;
-       const struct btd_device *dev = b;
-
-       if (dev == t->dev)
-               return 0;
-
-       return -1;
-}
-
-static gint cmp_watcher(gconstpointer a, gconstpointer b)
-{
-       const struct watcher *watcher = a;
-       const struct watcher *match = b;
-       int ret;
-
-       ret = g_strcmp0(watcher->srv, match->srv);
-       if (ret != 0)
-               return ret;
-
-       return g_strcmp0(watcher->path, match->path);
-}
-
-static gint cmp_char_uuid(gconstpointer a, gconstpointer b)
-{
-       const struct characteristic *ch = a;
-       const char *uuid = b;
-
-       return g_strcmp0(ch->attr.uuid, uuid);
-}
-
-static gint cmp_char_val_handle(gconstpointer a, gconstpointer b)
-{
-       const struct characteristic *ch = a;
-       const uint16_t *handle = b;
-
-       return ch->attr.value_handle - *handle;
-}
-
-static gint cmp_descriptor(gconstpointer a, gconstpointer b)
-{
-       const struct descriptor *desc = a;
-       const bt_uuid_t *uuid = b;
-
-       return bt_uuid_cmp(&desc->uuid, uuid);
-}
-
-static struct characteristic *get_characteristic(struct thermometer *t,
-                                                       const char *uuid)
-{
-       GSList *l;
-
-       l = g_slist_find_custom(t->chars, uuid, cmp_char_uuid);
-       if (l == NULL)
-               return NULL;
-
-       return l->data;
-}
-
-static struct descriptor *get_descriptor(struct characteristic *ch,
-                                                       const bt_uuid_t *uuid)
-{
-       GSList *l;
-
-       l = g_slist_find_custom(ch->desc, uuid, cmp_descriptor);
-       if (l == NULL)
-               return NULL;
-
-       return l->data;
-}
-
-static void change_property(struct thermometer *t, const char *name,
-                                                       gpointer value) {
-       if (g_strcmp0(name, "Intermediate") == 0) {
-               gboolean *intermediate = value;
-               if (t->intermediate == *intermediate)
-                       return;
-
-               t->intermediate = *intermediate;
-               emit_property_changed(t->conn, device_get_path(t->dev),
-                                       THERMOMETER_INTERFACE, name,
-                                       DBUS_TYPE_BOOLEAN, &t->intermediate);
-       } else if (g_strcmp0(name, "Interval") == 0) {
-               uint16_t *interval = value;
-               if (t->has_interval && t->interval == *interval)
-                       return;
-
-               t->has_interval = TRUE;
-               t->interval = *interval;
-               emit_property_changed(t->conn, device_get_path(t->dev),
-                                       THERMOMETER_INTERFACE, name,
-                                       DBUS_TYPE_UINT16, &t->interval);
-       } else if (g_strcmp0(name, "Maximum") == 0) {
-               uint16_t *max = value;
-               if (t->max == *max)
-                       return;
-
-               t->max = *max;
-               emit_property_changed(t->conn, device_get_path(t->dev),
-                                       THERMOMETER_INTERFACE, name,
-                                       DBUS_TYPE_UINT16, &t->max);
-       } else if (g_strcmp0(name, "Minimum") == 0) {
-               uint16_t *min = value;
-               if (t->min == *min)
-                       return;
-
-               t->min = *min;
-               emit_property_changed(t->conn, device_get_path(t->dev),
-                                       THERMOMETER_INTERFACE, name,
-                                       DBUS_TYPE_UINT16, &t->min);
-       } else
-               DBG("%s is not a thermometer property", name);
-}
-
-static void valid_range_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct descriptor *desc = user_data;
-       uint8_t value[ATT_MAX_MTU];
-       uint16_t max, min;
-       int vlen;
-
-       if (status != 0) {
-               DBG("Valid Range descriptor read failed: %s",
-                                                       att_ecode2str(status));
-               return;
-       }
-
-       if (!dec_read_resp(pdu, len, value, &vlen)) {
-               DBG("Protocol error\n");
-               return;
-       }
-
-       if (vlen < 4) {
-               DBG("Invalid range received");
-               return;
-       }
-
-       min = att_get_u16(&value[0]);
-       max = att_get_u16(&value[2]);
-
-       if (min == 0 || min > max) {
-               DBG("Invalid range");
-               return;
-       }
-
-       change_property(desc->ch->t, "Maximum", &max);
-       change_property(desc->ch->t, "Minimum", &min);
-}
-
-static void 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;
-       char uuidstr[MAX_LEN_UUID_STR];
-       bt_uuid_t btuuid;
-
-       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-
-       if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0) {
-               uint8_t atval[2];
-               uint16_t val;
-               char *msg;
-
-               if (g_strcmp0(ch->attr.uuid,
-                                       TEMPERATURE_MEASUREMENT_UUID) == 0) {
-                       if (g_slist_length(ch->t->fwatchers) == 0)
-                               return;
-
-                       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 = 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 = 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,
-                                                       measurement_cb, msg);
-               return;
-       }
-
-       bt_uuid16_create(&btuuid, GATT_CHARAC_VALID_RANGE_UUID);
-
-       if (bt_uuid_cmp(&desc->uuid, &btuuid) == 0 && g_strcmp0(ch->attr.uuid,
-                                       MEASUREMENT_INTERVAL_UUID) == 0) {
-               gatt_read_char(ch->t->attrib, desc->handle, 0,
-                                               valid_range_desc_cb, desc);
-               return;
-       }
-
-done:
-       bt_uuid_to_string(&desc->uuid, uuidstr, MAX_LEN_UUID_STR);
-       DBG("Ignored descriptor %s in characteristic %s", uuidstr,
-                                                               ch->attr.uuid);
-}
-
-static void discover_desc_cb(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct characteristic *ch = user_data;
-       struct att_data_list *list;
-       uint8_t format;
-       int i;
-
-       if (status != 0) {
-               error("Discover all characteristic descriptors failed [%s]: %s",
-                                       ch->attr.uuid, att_ecode2str(status));
-               return;
-       }
-
-       list = dec_find_info_resp(pdu, len, &format);
-       if (list == NULL)
-               return;
-
-       for (i = 0; i < list->num; i++) {
-               struct descriptor *desc;
-               uint8_t *value;
-
-               value = list->data[i];
-               desc = g_new0(struct descriptor, 1);
-               desc->handle = att_get_u16(value);
-               desc->ch = ch;
-
-               if (format == 0x01)
-                       desc->uuid = att_get_uuid16(&value[2]);
-               else
-                       desc->uuid = att_get_uuid128(&value[2]);
-
-               ch->desc = g_slist_append(ch->desc, desc);
-               process_thermometer_desc(desc);
-       }
-
-       att_data_list_free(list);
-}
-
-static void read_temp_type_cb(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct characteristic *ch = user_data;
-       struct thermometer *t = ch->t;
-       uint8_t value[ATT_MAX_MTU];
-       int vlen;
-
-       if (status != 0) {
-               DBG("Temperature Type value read failed: %s",
-                                                       att_ecode2str(status));
-               return;
-       }
-
-       if (!dec_read_resp(pdu, len, value, &vlen)) {
-               DBG("Protocol error.");
-               return;
-       }
-
-       if (vlen != 1) {
-               DBG("Invalid length for Temperature type");
-               return;
-       }
-
-       t->has_type = TRUE;
-       t->type = value[0];
-}
-
-static void read_interval_cb(guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct characteristic *ch = user_data;
-       uint8_t value[ATT_MAX_MTU];
-       uint16_t interval;
-       int vlen;
-
-       if (status != 0) {
-               DBG("Measurement Interval value read failed: %s",
-                                                       att_ecode2str(status));
-               return;
-       }
-
-       if (!dec_read_resp(pdu, len, value, &vlen)) {
-               DBG("Protocol error\n");
-               return;
-       }
-
-       if (vlen < 2) {
-               DBG("Invalid Interval received");
-               return;
-       }
-
-       interval = att_get_u16(&value[0]);
-       change_property(ch->t, "Interval", &interval);
-}
-
-static void process_thermometer_char(struct characteristic *ch)
-{
-       if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0) {
-               gboolean intermediate = TRUE;
-               change_property(ch->t, "Intermediate", &intermediate);
-               return;
-       } else if (g_strcmp0(ch->attr.uuid, TEMPERATURE_TYPE_UUID) == 0)
-               gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
-                                                       read_temp_type_cb, ch);
-       else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
-               gatt_read_char(ch->t->attrib, ch->attr.value_handle, 0,
-                                                       read_interval_cb, ch);
-}
-
-static void configure_thermometer_cb(GSList *characteristics, guint8 status,
-                                                       gpointer user_data)
-{
-       struct thermometer *t = user_data;
-       GSList *l;
-
-       if (status != 0) {
-               error("Discover thermometer characteristics: %s",
-                                                       att_ecode2str(status));
-               return;
-       }
-
-       for (l = characteristics; l; l = l->next) {
-               struct gatt_char *c = l->data;
-               struct characteristic *ch;
-               uint16_t start, end;
-
-               ch = g_new0(struct characteristic, 1);
-               ch->attr.handle = c->handle;
-               ch->attr.properties = c->properties;
-               ch->attr.value_handle = c->value_handle;
-               memcpy(ch->attr.uuid, c->uuid, MAX_LEN_UUID_STR + 1);
-               ch->t = t;
-
-               t->chars = g_slist_append(t->chars, ch);
-
-               process_thermometer_char(ch);
-
-               start = c->value_handle + 1;
-
-               if (l->next != NULL) {
-                       struct gatt_char *c = l->next->data;
-                       if (start == c->handle)
-                               continue;
-                       end = c->handle - 1;
-               } else if (c->value_handle != t->svc_range->end)
-                       end = t->svc_range->end;
-               else
-                       continue;
-
-               gatt_find_info(t->attrib, start, end, discover_desc_cb, ch);
-       }
-}
-
-static DBusMessage *get_properties(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct thermometer *t = data;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       DBusMessage *reply;
-
-       reply = dbus_message_new_method_return(msg);
-       if (reply == NULL)
-               return NULL;
-
-       dbus_message_iter_init_append(reply, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       dict_append_entry(&dict, "Intermediate", DBUS_TYPE_BOOLEAN,
-                                                       &t->intermediate);
-
-       if (t->has_interval) {
-               dict_append_entry(&dict, "Interval", DBUS_TYPE_UINT16,
-                                                               &t->interval);
-               dict_append_entry(&dict, "Maximum", DBUS_TYPE_UINT16, &t->max);
-               dict_append_entry(&dict, "Minimum", DBUS_TYPE_UINT16, &t->min);
-       }
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       return reply;
-}
-
-static void write_interval_cb (guint8 status, const guint8 *pdu, guint16 len,
-                                                       gpointer user_data)
-{
-       struct tmp_interval_data *data = user_data;
-
-       if (status != 0) {
-               error("Interval Write Request failed %s",
-                                                       att_ecode2str(status));
-               goto done;
-       }
-
-       if (!dec_write_resp(pdu, len)) {
-               error("Interval Write Request: protocol error");
-               goto done;
-       }
-
-       change_property(data->thermometer, "Interval", &data->interval);
-
-done:
-       g_free(user_data);
-}
-
-static DBusMessage *write_attr_interval(struct thermometer *t, DBusMessage *msg,
-                                                               uint16_t value)
-{
-       struct tmp_interval_data *data;
-       struct characteristic *ch;
-       uint8_t atval[2];
-
-       if (t->attrib == NULL)
-               return btd_error_not_connected(msg);
-
-       ch = get_characteristic(t, MEASUREMENT_INTERVAL_UUID);
-       if (ch == NULL)
-               return btd_error_not_available(msg);
-
-       if (value < t->min || value > t->max)
-               return btd_error_invalid_args(msg);
-
-       att_put_u16(value, &atval[0]);
-
-       data = g_new0(struct tmp_interval_data, 1);
-       data->thermometer = t;
-       data->interval = value;
-       gatt_write_char(t->attrib, ch->attr.value_handle, atval, 2,
-                                               write_interval_cb, data);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *set_property(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       struct thermometer *t = data;
-       const char *property;
-       DBusMessageIter iter;
-       DBusMessageIter sub;
-       uint16_t value;
-
-       if (!dbus_message_iter_init(msg, &iter))
-               return btd_error_invalid_args(msg);
-
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&iter, &property);
-       if (g_strcmp0("Interval", property) != 0)
-               return btd_error_invalid_args(msg);
-
-       if (!t->has_interval)
-               return btd_error_not_available(msg);
-
-       dbus_message_iter_next(&iter);
-       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_VARIANT)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_recurse(&iter, &sub);
-
-       if (dbus_message_iter_get_arg_type(&sub) != DBUS_TYPE_UINT16)
-               return btd_error_invalid_args(msg);
-
-       dbus_message_iter_get_basic(&sub, &value);
-
-       return write_attr_interval(t, msg, value);
-}
-
-static void enable_final_measurement(struct thermometer *t)
-{
-       struct characteristic *ch;
-       struct descriptor *desc;
-       bt_uuid_t btuuid;
-       uint8_t atval[2];
-       char *msg;
-
-       if (t->attrib == NULL)
-               return;
-
-       ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
-       if (ch == NULL) {
-               DBG("Temperature measurement characteristic not found");
-               return;
-       }
-
-       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       desc = get_descriptor(ch, &btuuid);
-       if (desc == NULL) {
-               DBG("Client characteristic configuration descriptor not found");
-               return;
-       }
-
-       atval[0] = 0x02;
-       atval[1] = 0x00;
-       msg = g_strdup("Enable final measurement");
-       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void enable_intermediate_measurement(struct thermometer *t)
-{
-       struct characteristic *ch;
-       struct descriptor *desc;
-       bt_uuid_t btuuid;
-       uint8_t atval[2];
-       char *msg;
-
-       if (t->attrib == NULL)
-               return;
-
-       ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
-       if (ch == NULL) {
-               DBG("Intermediate measurement characteristic not found");
-               return;
-       }
-
-       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       desc = get_descriptor(ch, &btuuid);
-       if (desc == NULL) {
-               DBG("Client characteristic configuration descriptor not found");
-               return;
-       }
-
-       atval[0] = 0x01;
-       atval[1] = 0x00;
-       msg = g_strdup("Enable intermediate measurement");
-       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_final_measurement(struct thermometer *t)
-{
-       struct characteristic *ch;
-       struct descriptor *desc;
-       bt_uuid_t btuuid;
-       uint8_t atval[2];
-       char *msg;
-
-       if (t->attrib == NULL)
-               return;
-
-       ch = get_characteristic(t, TEMPERATURE_MEASUREMENT_UUID);
-       if (ch == NULL) {
-               DBG("Temperature measurement characteristic not found");
-               return;
-       }
-
-       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       desc = get_descriptor(ch, &btuuid);
-       if (desc == NULL) {
-               DBG("Client characteristic configuration descriptor not found");
-               return;
-       }
-
-       atval[0] = 0x00;
-       atval[1] = 0x00;
-       msg = g_strdup("Disable final measurement");
-       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void disable_intermediate_measurement(struct thermometer *t)
-{
-       struct characteristic *ch;
-       struct descriptor *desc;
-       bt_uuid_t btuuid;
-       uint8_t atval[2];
-       char *msg;
-
-       if (t->attrib == NULL)
-               return;
-
-       ch = get_characteristic(t, INTERMEDIATE_TEMPERATURE_UUID);
-       if (ch == NULL) {
-               DBG("Intermediate measurement characteristic not found");
-               return;
-       }
-
-       bt_uuid16_create(&btuuid, GATT_CLIENT_CHARAC_CFG_UUID);
-       desc = get_descriptor(ch, &btuuid);
-       if (desc == NULL) {
-               DBG("Client characteristic configuration descriptor not found");
-               return;
-       }
-
-       atval[0] = 0x00;
-       atval[1] = 0x00;
-       msg = g_strdup("Disable intermediate measurement");
-       gatt_write_char(t->attrib, desc->handle, atval, 2, measurement_cb, msg);
-}
-
-static void remove_int_watcher(struct thermometer *t, struct watcher *w)
-{
-       if (!g_slist_find(t->iwatchers, w))
-               return;
-
-       t->iwatchers = g_slist_remove(t->iwatchers, w);
-
-       if (g_slist_length(t->iwatchers) == 0)
-               disable_intermediate_measurement(t);
-}
-
-static void watcher_exit(DBusConnection *conn, void *user_data)
-{
-       struct watcher *watcher = user_data;
-       struct thermometer *t = watcher->t;
-
-       DBG("Thermometer watcher %s disconnected", watcher->path);
-
-       remove_int_watcher(t, watcher);
-
-       t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-       g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
-       if (g_slist_length(t->fwatchers) == 0)
-               disable_final_measurement(t);
-}
-
-static struct watcher *find_watcher(GSList *list, const char *sender,
-                                                       const char *path)
-{
-       struct watcher *match;
-       GSList *l;
-
-       match = g_new0(struct watcher, 1);
-       match->srv = g_strdup(sender);
-       match->path = g_strdup(path);
-
-       l = g_slist_find_custom(list, match, cmp_watcher);
-       destroy_watcher(match);
-
-       if (l != NULL)
-               return l->data;
-
-       return NULL;
-}
-
-static DBusMessage *register_watcher(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct thermometer *t = data;
-       struct watcher *watcher;
-       char *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = find_watcher(t->fwatchers, sender, path);
-       if (watcher != NULL)
-               return btd_error_already_exists(msg);
-
-       DBG("Thermometer watcher %s registered", path);
-
-       watcher = g_new0(struct watcher, 1);
-       watcher->srv = g_strdup(sender);
-       watcher->path = g_strdup(path);
-       watcher->t = t;
-       watcher->id = g_dbus_add_disconnect_watch(conn, sender, watcher_exit,
-                                               watcher, destroy_watcher);
-
-       if (g_slist_length(t->fwatchers) == 0)
-               enable_final_measurement(t);
-
-       t->fwatchers = g_slist_prepend(t->fwatchers, watcher);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *unregister_watcher(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct thermometer *t = data;
-       struct watcher *watcher;
-       char *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = find_watcher(t->fwatchers, sender, path);
-       if (watcher == NULL)
-               return btd_error_does_not_exist(msg);
-
-       DBG("Thermometer watcher %s unregistered", path);
-
-       remove_int_watcher(t, watcher);
-
-       t->fwatchers = g_slist_remove(t->fwatchers, watcher);
-       g_dbus_remove_watch(watcher->t->conn, watcher->id);
-
-       if (g_slist_length(t->fwatchers) == 0)
-               disable_final_measurement(t);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *enable_intermediate(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct thermometer *t = data;
-       struct watcher *watcher;
-       char *path;
-
-       if (!t->intermediate)
-               return btd_error_not_supported(msg);
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = find_watcher(t->fwatchers, sender, path);
-       if (watcher == NULL)
-               return btd_error_does_not_exist(msg);
-
-       if (find_watcher(t->iwatchers, sender, path))
-               return btd_error_already_exists(msg);
-
-       DBG("Intermediate measurement watcher %s registered", path);
-
-       if (g_slist_length(t->iwatchers) == 0)
-               enable_intermediate_measurement(t);
-
-       t->iwatchers = g_slist_prepend(t->iwatchers, watcher);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static DBusMessage *disable_intermediate(DBusConnection *conn, DBusMessage *msg,
-                                                               void *data)
-{
-       const char *sender = dbus_message_get_sender(msg);
-       struct thermometer *t = data;
-       struct watcher *watcher;
-       char *path;
-
-       if (!dbus_message_get_args(msg, NULL, DBUS_TYPE_OBJECT_PATH, &path,
-                                                       DBUS_TYPE_INVALID))
-               return btd_error_invalid_args(msg);
-
-       watcher = find_watcher(t->iwatchers, sender, path);
-       if (watcher == NULL)
-               return btd_error_does_not_exist(msg);
-
-       DBG("Intermediate measurement %s unregistered", path);
-
-       remove_int_watcher(t, watcher);
-
-       return dbus_message_new_method_return(msg);
-}
-
-static 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 const GDBusSignalTable thermometer_signals[] = {
-       { GDBUS_SIGNAL("PropertyChanged",
-                       GDBUS_ARGS({ "name", "s" }, { "value", "v" })) },
-       { }
-};
-
-static void update_watcher(gpointer data, gpointer user_data)
-{
-       struct watcher *w = data;
-       struct measurement *m = user_data;
-       DBusConnection *conn = w->t->conn;
-       DBusMessageIter iter;
-       DBusMessageIter dict;
-       DBusMessage *msg;
-
-       msg = dbus_message_new_method_call(w->srv, w->path,
-                               "org.bluez.ThermometerWatcher",
-                               "MeasurementReceived");
-       if (msg == NULL)
-               return;
-
-       dbus_message_iter_init_append(msg, &iter);
-
-       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY,
-                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
-                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
-                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
-
-       dict_append_entry(&dict, "Exponent", DBUS_TYPE_INT16, &m->exp);
-       dict_append_entry(&dict, "Mantissa", DBUS_TYPE_INT32, &m->mant);
-       dict_append_entry(&dict, "Unit", DBUS_TYPE_STRING, &m->unit);
-
-       if (m->suptime)
-               dict_append_entry(&dict, "Time", DBUS_TYPE_UINT64, &m->time);
-
-       dict_append_entry(&dict, "Type", DBUS_TYPE_STRING, &m->type);
-       dict_append_entry(&dict, "Measurement", DBUS_TYPE_STRING, &m->value);
-
-       dbus_message_iter_close_container(&iter, &dict);
-
-       dbus_message_set_no_reply(msg, TRUE);
-       g_dbus_send_message(conn, msg);
-}
-
-static void recv_measurement(struct thermometer *t, struct measurement *m)
-{
-       GSList *wlist;
-
-       if (g_strcmp0(m->value, "Intermediate") == 0)
-               wlist = t->iwatchers;
-       else
-               wlist = t->fwatchers;
-
-       g_slist_foreach(wlist, update_watcher, m);
-}
-
-static void proc_measurement(struct thermometer *t, const uint8_t *pdu,
-                                               uint16_t len, gboolean final)
-{
-       struct measurement m;
-       const char *type;
-       uint8_t flags;
-       uint32_t raw;
-
-       if (len < 4) {
-               DBG("Mandatory flags are not provided");
-               return;
-       }
-
-       flags = pdu[3];
-       if (flags & TEMP_UNITS)
-               m.unit = "Fahrenheit";
-       else
-               m.unit = "Celsius";
-
-       if (len < 8) {
-               DBG("Temperature measurement value is not provided");
-               return;
-       }
-
-       raw = att_get_u32(&pdu[4]);
-       m.mant = raw & 0x00FFFFFF;
-       m.exp = ((int32_t) raw) >> 24;
-
-       if (m.mant & 0x00800000) {
-               /* convert to C2 negative value */
-               m.mant = m.mant - FLOAT_MAX_MANTISSA;
-       }
-
-       if (flags & TEMP_TIME_STAMP) {
-               struct tm ts;
-               time_t time;
-
-               if (len < 15) {
-                       DBG("Can't get time stamp value");
-                       return;
-               }
-
-               ts.tm_year = att_get_u16(&pdu[8]) - 1900;
-               ts.tm_mon = pdu[10] - 1;
-               ts.tm_mday = pdu[11];
-               ts.tm_hour = pdu[12];
-               ts.tm_min = pdu[13];
-               ts.tm_sec = pdu[14];
-               ts.tm_isdst = -1;
-
-               time = mktime(&ts);
-               m.time = (uint64_t) time;
-               m.suptime = TRUE;
-       } else
-               m.suptime = FALSE;
-
-       if (flags & TEMP_TYPE) {
-               uint8_t index;
-
-               if (m.suptime && len >= 16)
-                       index = 15;
-               else if (!m.suptime && len >= 9)
-                       index = 9;
-               else {
-                       DBG("Can't get temperature type");
-                       return;
-               }
-
-               type = temptype2str(pdu[index]);
-       } else if (t->has_type)
-               type = temptype2str(t->type);
-       else
-               type = NULL;
-
-       m.type = type ? g_strdup(type) : NULL;
-       m.value = final ? "Final" : "Intermediate";
-
-       recv_measurement(t, &m);
-       g_free(m.type);
-}
-
-static void proc_measurement_interval(struct thermometer *t, const uint8_t *pdu,
-                                                               uint16_t len)
-{
-       uint16_t interval;
-
-       if (len < 5) {
-               DBG("Measurement interval value is not provided");
-               return;
-       }
-
-       interval = att_get_u16(&pdu[3]);
-
-       change_property(t, "Interval", &interval);
-}
-
-static void ind_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
-       struct thermometer *t = user_data;
-       const struct characteristic *ch;
-       uint8_t opdu[ATT_MAX_MTU];
-       uint16_t handle, olen;
-       GSList *l;
-
-       if (len < 3) {
-               DBG("Bad pdu received");
-               return;
-       }
-
-       handle = att_get_u16(&pdu[1]);
-       l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
-       if (l == NULL) {
-               DBG("Unexpected handle: 0x%04x", handle);
-               return;
-       }
-
-       ch = l->data;
-
-       if (g_strcmp0(ch->attr.uuid, TEMPERATURE_MEASUREMENT_UUID) == 0)
-               proc_measurement(t, pdu, len, TRUE);
-       else if (g_strcmp0(ch->attr.uuid, MEASUREMENT_INTERVAL_UUID) == 0)
-               proc_measurement_interval(t, pdu, len);
-
-       olen = enc_confirmation(opdu, sizeof(opdu));
-
-       if (olen > 0)
-               g_attrib_send(t->attrib, 0, opdu[0], opdu, olen, NULL, NULL,
-                                                                       NULL);
-}
-
-static void notif_handler(const uint8_t *pdu, uint16_t len, gpointer user_data)
-{
-       struct thermometer *t = user_data;
-       const struct characteristic *ch;
-       uint16_t handle;
-       GSList *l;
-
-       if (len < 3) {
-               DBG("Bad pdu received");
-               return;
-       }
-
-       handle = att_get_u16(&pdu[1]);
-       l = g_slist_find_custom(t->chars, &handle, cmp_char_val_handle);
-       if (l == NULL) {
-               DBG("Unexpected handle: 0x%04x", handle);
-               return;
-       }
-
-       ch = l->data;
-       if (g_strcmp0(ch->attr.uuid, INTERMEDIATE_TEMPERATURE_UUID) == 0)
-               proc_measurement(t, pdu, len, FALSE);
-}
-
-static void attio_connected_cb(GAttrib *attrib, gpointer user_data)
-{
-       struct thermometer *t = user_data;
-
-       t->attrib = g_attrib_ref(attrib);
-
-       t->attindid = g_attrib_register(t->attrib, ATT_OP_HANDLE_IND,
-                                                       ind_handler, t, NULL);
-       t->attnotid = g_attrib_register(t->attrib, ATT_OP_HANDLE_NOTIFY,
-                                                       notif_handler, t, NULL);
-       gatt_discover_char(t->attrib, t->svc_range->start, t->svc_range->end,
-                                       NULL, configure_thermometer_cb, t);
-}
-
-static void attio_disconnected_cb(gpointer user_data)
-{
-       struct thermometer *t = user_data;
-
-       DBG("GATT Disconnected");
-
-       if (t->attindid > 0) {
-               g_attrib_unregister(t->attrib, t->attindid);
-               t->attindid = 0;
-       }
-
-       if (t->attnotid > 0) {
-               g_attrib_unregister(t->attrib, t->attnotid);
-               t->attnotid = 0;
-       }
-
-       g_attrib_unref(t->attrib);
-       t->attrib = NULL;
-}
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
-                                               struct gatt_primary *tattr)
-{
-       const gchar *path = device_get_path(device);
-       struct thermometer *t;
-
-       t = g_new0(struct thermometer, 1);
-       t->conn = dbus_connection_ref(connection);
-       t->dev = btd_device_ref(device);
-       t->svc_range = g_new0(struct att_range, 1);
-       t->svc_range->start = tattr->range.start;
-       t->svc_range->end = tattr->range.end;
-
-       if (!g_dbus_register_interface(t->conn, path, THERMOMETER_INTERFACE,
-                               thermometer_methods, thermometer_signals,
-                               NULL, t, destroy_thermometer)) {
-               error("D-Bus failed to register %s interface",
-                                                       THERMOMETER_INTERFACE);
-               destroy_thermometer(t);
-               return -EIO;
-       }
-
-       thermometers = g_slist_prepend(thermometers, t);
-
-       t->attioid = btd_device_add_attio_callback(device, attio_connected_cb,
-                                               attio_disconnected_cb, t);
-       return 0;
-}
-
-void thermometer_unregister(struct btd_device *device)
-{
-       struct thermometer *t;
-       GSList *l;
-
-       l = g_slist_find_custom(thermometers, device, cmp_device);
-       if (l == NULL)
-               return;
-
-       t = l->data;
-       thermometers = g_slist_remove(thermometers, t);
-       g_dbus_unregister_interface(t->conn, device_get_path(t->dev),
-                                                       THERMOMETER_INTERFACE);
-}
diff --git a/thermometer/thermometer.h b/thermometer/thermometer.h
deleted file mode 100644 (file)
index 330503c..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011 GSyC/LibreSoft, Universidad Rey Juan Carlos.
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int thermometer_register(DBusConnection *connection, struct btd_device *device,
-                                               struct gatt_primary *tattr);
-void thermometer_unregister(struct btd_device *device);
diff --git a/time/main.c b/time/main.c
deleted file mode 100644 (file)
index d876725..0000000
+++ /dev/null
@@ -1,58 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <stdint.h>
-#include <glib.h>
-#include <errno.h>
-
-#include "plugin.h"
-#include "hcid.h"
-#include "log.h"
-#include "server.h"
-
-static int time_init(void)
-{
-       if (!main_opts.gatt_enabled) {
-               DBG("GATT is disabled");
-               return -ENOTSUP;
-       }
-
-       return time_server_init();
-}
-
-static void time_exit(void)
-{
-       if (!main_opts.gatt_enabled)
-               return;
-
-       time_server_exit();
-}
-
-BLUETOOTH_PLUGIN_DEFINE(time, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                       time_init, time_exit)
diff --git a/time/server.c b/time/server.c
deleted file mode 100644 (file)
index 13a7bbe..0000000
+++ /dev/null
@@ -1,154 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
-
-#include <glib.h>
-#include <time.h>
-#include <errno.h>
-#include <bluetooth/uuid.h>
-#include <adapter.h>
-
-#include "gattrib.h"
-#include "att.h"
-#include "gatt.h"
-#include "att-database.h"
-#include "attrib-server.h"
-#include "gatt-service.h"
-#include "log.h"
-#include "server.h"
-
-#define CURRENT_TIME_SVC_UUID          0x1805
-
-#define LOCAL_TIME_INFO_CHR_UUID       0x2A0F
-#define CT_TIME_CHR_UUID               0x2A2B
-
-static int encode_current_time(uint8_t value[10])
-{
-       struct timespec tp;
-       struct tm tm;
-
-       if (clock_gettime(CLOCK_REALTIME, &tp) == -1) {
-               int err = -errno;
-
-               error("clock_gettime: %s", strerror(-err));
-               return err;
-       }
-
-       if (localtime_r(&tp.tv_sec, &tm) == NULL) {
-               error("localtime_r() failed");
-               /* localtime_r() does not set errno */
-               return -EINVAL;
-       }
-
-       att_put_u16(1900 + tm.tm_year, &value[0]); /* Year */
-       value[2] = tm.tm_mon + 1; /* Month */
-       value[3] = tm.tm_mday; /* Day */
-       value[4] = tm.tm_hour; /* Hours */
-       value[5] = tm.tm_min; /* Minutes */
-       value[6] = tm.tm_sec; /* Seconds */
-       value[7] = tm.tm_wday == 0 ? 7 : tm.tm_wday; /* Day of Week */
-       /* From Time Profile spec: "The number of 1/256 fractions of a second."
-        * In 1s there are 256 fractions, in 1ns there are 256/10^9 fractions.
-        * To avoid integer overflow, we use the equivalent 1/3906250 ratio. */
-       value[8] = tp.tv_nsec / 3906250; /* Fractions256 */
-       value[9] = 0x00; /* Adjust Reason */
-
-       return 0;
-}
-
-static uint8_t current_time_read(struct attribute *a,
-                                struct btd_device *device, gpointer user_data)
-{
-       uint8_t value[10];
-
-       if (encode_current_time(value) < 0)
-               return ATT_ECODE_IO;
-
-       /* FIXME: Provide the adapter in next function */
-       attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
-       return 0;
-}
-
-static uint8_t local_time_info_read(struct attribute *a,
-                               struct btd_device *device, gpointer user_data)
-{
-       uint8_t value[2];
-
-       DBG("a=%p", a);
-
-       tzset();
-
-       /* FIXME: POSIX "daylight" variable only indicates whether there is DST
-        * for the local time or not. The offset is unknown. */
-       value[0] = daylight ? 0xff : 0x00;
-
-       /* Convert POSIX "timezone" (seconds West of GMT) to Time Profile
-        * format (offset from UTC in number of 15 minutes increments). */
-       value[1] = (uint8_t) (-1 * timezone / (60 * 15));
-
-       /* FIXME: Provide the adapter in next function */
-       attrib_db_update(NULL, a->handle, NULL, value, sizeof(value), NULL);
-
-       return 0;
-}
-
-static void register_current_time_service(void)
-{
-       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, &uuid,
-                               /* CT Time characteristic */
-                               GATT_OPT_CHR_UUID, CT_TIME_CHR_UUID,
-                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ |
-                                                       ATT_CHAR_PROPER_NOTIFY,
-                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-                                               current_time_read, NULL,
-
-                               /* Local Time Information characteristic */
-                               GATT_OPT_CHR_UUID, LOCAL_TIME_INFO_CHR_UUID,
-                               GATT_OPT_CHR_PROPS, ATT_CHAR_PROPER_READ,
-                               GATT_OPT_CHR_VALUE_CB, ATTRIB_READ,
-                                               local_time_info_read, NULL,
-
-                               GATT_OPT_INVALID);
-}
-
-int time_server_init(void)
-{
-       register_current_time_service();
-
-       return 0;
-}
-
-void time_server_exit(void)
-{
-}
diff --git a/time/server.h b/time/server.h
deleted file mode 100644 (file)
index 621bf2b..0000000
+++ /dev/null
@@ -1,26 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2011  Nokia Corporation
- *  Copyright (C) 2011  Marcel Holtmann <marcel@holtmann.org>
- *
- *
- *  This program is free software; you can redistribute it and/or modify
- *  it under the terms of the GNU General Public License as published by
- *  the Free Software Foundation; either version 2 of the License, or
- *  (at your option) any later version.
- *
- *  This program is distributed in the hope that it will be useful,
- *  but WITHOUT ANY WARRANTY; without even the implied warranty of
- *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- *  GNU General Public License for more details.
- *
- *  You should have received a copy of the GNU General Public License
- *  along with this program; if not, write to the Free Software
- *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
- *
- */
-
-int time_server_init(void);
-void time_server_exit(void);
diff --git a/tools/amptest.c b/tools/amptest.c
new file mode 100644 (file)
index 0000000..16f15bc
--- /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 <unistd.h>
+#include <alloca.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+static int activate_amp_controller(int dev_id)
+{
+       struct hci_dev_info di;
+       struct hci_filter flt;
+       int fd;
+
+       printf("hci%d: Activating controller\n", dev_id);
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open raw HCI socket");
+               return -1;
+       }
+
+       di.dev_id = dev_id;
+
+       if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0) {
+               perror("Failed to get HCI device info");
+               close(fd);
+               return -1;
+       }
+
+       if (!hci_test_bit(HCI_UP, &di.flags)) {
+               if (ioctl(fd, HCIDEVUP, dev_id) < 0) {
+                       if (errno != EALREADY) {
+                               perror("Failed to bring up HCI device");
+                               close(fd);
+                               return -1;
+                       }
+               }
+       }
+
+       close(fd);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return -1;
+       }
+
+       hci_filter_clear(&flt);
+       hci_filter_set_ptype(HCI_EVENT_PKT, &flt);
+       hci_filter_set_event(EVT_CHANNEL_SELECTED, &flt);
+       hci_filter_set_event(EVT_PHYSICAL_LINK_COMPLETE, &flt);
+       hci_filter_set_event(EVT_DISCONNECT_PHYSICAL_LINK_COMPLETE, &flt);
+
+       if (setsockopt(fd, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+               perror("Failed to setup HCI device filter");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static bool read_local_amp_info(int dev_id, uint16_t *max_assoc_len)
+{
+       read_local_amp_info_rp rp;
+       struct hci_request rq;
+       int fd;
+
+       printf("hci%d: Reading local AMP information\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&rp, 0, sizeof(rp));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_STATUS_PARAM;
+       rq.ocf    = OCF_READ_LOCAL_AMP_INFO;
+       rq.rparam = &rp;
+       rq.rlen   = READ_LOCAL_AMP_INFO_RP_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (rp.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", rp.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       printf("\tAMP status: 0x%02x\n", rp.amp_status);
+       printf("\tController type: 0x%02x\n", rp.controller_type);
+       printf("\tMax ASSOC length: %d\n", btohs(rp.max_amp_assoc_length));
+
+       *max_assoc_len = btohs(rp.max_amp_assoc_length);
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool read_local_amp_assoc(int dev_id, uint8_t phy_handle,
+                                                       uint16_t max_assoc_len,
+                                                       uint8_t *assoc_data,
+                                                       uint16_t *assoc_len)
+{
+       read_local_amp_assoc_cp cp;
+       read_local_amp_assoc_rp rp;
+       struct hci_request rq;
+       int fd;
+
+       printf("hci%d: Reading local AMP association\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = phy_handle;
+       cp.length_so_far = htobs(0);
+       cp.assoc_length = htobs(max_assoc_len);
+       memset(&rp, 0, sizeof(rp));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_STATUS_PARAM;
+       rq.ocf    = OCF_READ_LOCAL_AMP_ASSOC;
+       rq.cparam = &cp;
+       rq.clen   = READ_LOCAL_AMP_ASSOC_CP_SIZE;
+       rq.rparam = &rp;
+       rq.rlen   = READ_LOCAL_AMP_ASSOC_RP_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (rp.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", rp.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       printf("\tRemain ASSOC length: %d\n", btohs(rp.length));
+
+       *assoc_len = btohs(rp.length);
+       memcpy(assoc_data, rp.fragment, *assoc_len);
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool write_remote_amp_assoc(int dev_id, uint8_t phy_handle,
+                                                       uint8_t *assoc_data,
+                                                       uint16_t assoc_len)
+{
+       write_remote_amp_assoc_cp cp;
+       write_remote_amp_assoc_rp rp;
+       struct hci_request rq;
+       int fd;
+
+       printf("hci%d: Writing remote AMP association\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = phy_handle;
+       cp.length_so_far = htobs(0);
+       cp.remaining_length = htobs(assoc_len);
+       memcpy(cp.fragment, assoc_data, assoc_len);
+       memset(&rp, 0, sizeof(rp));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_STATUS_PARAM;
+       rq.ocf    = OCF_WRITE_REMOTE_AMP_ASSOC;
+       rq.cparam = &cp;
+       rq.clen   = 5 + assoc_len;
+       rq.rparam = &rp;
+       rq.rlen   = WRITE_REMOTE_AMP_ASSOC_RP_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (rp.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", rp.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool channel_selected_event(int dev_id, int fd, uint8_t phy_handle)
+{
+       printf("hci%d: Waiting for channel selected event\n", dev_id);
+
+       while (1) {
+               uint8_t buf[HCI_MAX_EVENT_SIZE];
+               hci_event_hdr *hdr;
+               struct pollfd p;
+               int n, len;
+
+               p.fd = fd;
+               p.events = POLLIN;
+
+               n = poll(&p, 1, 10000);
+               if (n < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+
+                       perror("Failed to poll HCI device");
+                       return false;
+               }
+
+               if (n == 0) {
+                       fprintf(stderr, "Failure to receive event\n");
+                       return false;
+               }
+
+               len = read(fd, buf, sizeof(buf));
+               if (len < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+
+                       perror("Failed to read from HCI device");
+                       return false;
+               }
+
+               hdr = (void *) (buf + 1);
+
+               if (hdr->evt == EVT_CHANNEL_SELECTED)
+                       break;
+       }
+
+       return true;
+}
+
+static bool create_physical_link(int dev_id, uint8_t phy_handle)
+{
+       create_physical_link_cp cp;
+       evt_cmd_status evt;
+       struct hci_request rq;
+       int i, fd;
+
+       printf("hci%d: Creating physical link\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = phy_handle;
+       cp.key_length = 32;
+       cp.key_type = 0x03;
+       for (i = 0; i < cp.key_length; i++)
+               cp.key[i] = 0x23;
+       memset(&evt, 0, sizeof(evt));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_LINK_CTL;
+       rq.ocf    = OCF_CREATE_PHYSICAL_LINK;
+       rq.event  = EVT_CMD_STATUS;
+       rq.cparam = &cp;
+       rq.clen   = CREATE_PHYSICAL_LINK_CP_SIZE;
+       rq.rparam = &evt;
+       rq.rlen   = EVT_CMD_STATUS_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (evt.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", evt.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool accept_physical_link(int dev_id, uint8_t phy_handle)
+{
+       accept_physical_link_cp cp;
+       evt_cmd_status evt;
+       struct hci_request rq;
+       int i, fd;
+
+       printf("hci%d: Accepting physical link\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = phy_handle;
+       cp.key_length = 32;
+       cp.key_type = 0x03;
+       for (i = 0; i < cp.key_length; i++)
+               cp.key[i] = 0x23;
+       memset(&evt, 0, sizeof(evt));
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_LINK_CTL;
+       rq.ocf    = OCF_ACCEPT_PHYSICAL_LINK;
+       rq.event  = EVT_CMD_STATUS;
+       rq.cparam = &cp;
+       rq.clen   = ACCEPT_PHYSICAL_LINK_CP_SIZE;
+       rq.rparam = &evt;
+       rq.rlen   = EVT_CMD_STATUS_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (evt.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", evt.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool disconnect_physical_link(int dev_id, uint8_t phy_handle,
+                                                       uint8_t reason)
+{
+       disconnect_physical_link_cp cp;
+       evt_cmd_status evt;
+       struct hci_request rq;
+       int fd;
+
+       printf("hci%d: Disconnecting physical link\n", dev_id);
+
+       fd = hci_open_dev(dev_id);
+       if (fd < 0) {
+               perror("Failed to open HCI device");
+               return false;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+       cp.handle = phy_handle;
+       cp.reason = reason;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf    = OGF_LINK_CTL;
+       rq.ocf    = OCF_DISCONNECT_PHYSICAL_LINK;
+       rq.event  = EVT_CMD_STATUS;
+       rq.cparam = &cp;
+       rq.clen   = DISCONNECT_PHYSICAL_LINK_CP_SIZE;
+       rq.rparam = &evt;
+       rq.rlen   = EVT_CMD_STATUS_SIZE;
+
+       if (hci_send_req(fd, &rq, 1000) < 0) {
+               perror("Failed sending HCI request");
+               hci_close_dev(fd);
+               return false;
+       }
+
+       if (evt.status) {
+               fprintf(stderr, "Failed HCI command: 0x%02x\n", evt.status);
+               hci_close_dev(fd);
+               return false;
+       }
+
+       hci_close_dev(fd);
+
+       return true;
+}
+
+static bool physical_link_complete_event(int dev_id, int fd,
+                                                       uint8_t phy_handle)
+{
+       printf("hci%d: Waiting for physical link complete event\n", dev_id);
+
+       while (1) {
+               uint8_t buf[HCI_MAX_EVENT_SIZE];
+               hci_event_hdr *hdr;
+               int len;
+
+               len = read(fd, buf, sizeof(buf));
+               if (len < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+
+                       perror("Failed to read from HCI device");
+                       return false;
+               }
+
+               hdr = (void *) (buf + 1);
+
+               if (hdr->evt == EVT_PHYSICAL_LINK_COMPLETE)
+                       break;
+       }
+
+       return true;
+}
+
+static bool disconnect_physical_link_complete_event(int dev_id, int fd,
+                                                       uint8_t phy_handle)
+{
+       printf("hci%d: Waiting for physical link disconnect event\n", dev_id);
+
+       while (1) {
+               uint8_t buf[HCI_MAX_EVENT_SIZE];
+               hci_event_hdr *hdr;
+               int len;
+
+               len = read(fd, buf, sizeof(buf));
+               if (len < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+
+                       perror("Failed to read from HCI device");
+                       return false;
+               }
+
+               hdr = (void *) (buf + 1);
+
+               if (hdr->evt == EVT_DISCONNECT_PHYSICAL_LINK_COMPLETE)
+                       break;
+       }
+
+       return true;
+}
+
+static int amp1_dev_id = -1;
+static int amp2_dev_id = -1;
+
+static bool find_amp_controller(void)
+{
+       struct hci_dev_list_req *dl;
+       struct hci_dev_req *dr;
+       int fd, i;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open raw HCI socket");
+               return false;
+       }
+
+       dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
+       if (!dl) {
+               perror("Failed allocate HCI device request memory");
+               close(fd);
+               return false;
+       }
+
+       dl->dev_num = HCI_MAX_DEV;
+       dr = dl->dev_req;
+
+       if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
+               perror("Failed to get HCI device list");
+               close(fd);
+               return false;
+       }
+
+       for (i = 0; i< dl->dev_num; i++) {
+               struct hci_dev_info di;
+
+               di.dev_id = (dr + i)->dev_id;
+
+               if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0)
+                       continue;
+
+               if (((di.type & 0x30) >> 4) != HCI_AMP)
+                       continue;
+
+               if (amp1_dev_id < 0)
+                       amp1_dev_id = di.dev_id;
+               else if (amp2_dev_id < 0) {
+                       if (di.dev_id < amp1_dev_id) {
+                               amp2_dev_id = amp1_dev_id;
+                               amp1_dev_id = di.dev_id;
+                       } else
+                               amp2_dev_id = di.dev_id;
+               }
+       }
+
+       close(fd);
+
+       return true;
+}
+
+int main(int argc ,char *argv[])
+{
+       int amp1_event_fd, amp2_event_fd;
+       uint16_t amp1_max_assoc_len, amp2_max_assoc_len;
+       uint8_t *amp1_assoc_data, *amp2_assoc_data;
+       uint16_t amp1_assoc_len, amp2_assoc_len;
+       uint8_t amp1_phy_handle, amp2_phy_handle;
+
+       if (!find_amp_controller())
+               return EXIT_FAILURE;
+
+       if (amp1_dev_id < 0 || amp2_dev_id < 0) {
+               fprintf(stderr, "Two AMP controllers are required\n");
+               return EXIT_FAILURE;
+       }
+
+       printf("hci%d: AMP initiator\n", amp1_dev_id);
+       printf("hci%d: AMP acceptor\n", amp2_dev_id);
+
+       amp1_event_fd = activate_amp_controller(amp1_dev_id);
+       if (amp1_event_fd < 0)
+               return EXIT_FAILURE;
+
+       amp2_event_fd = activate_amp_controller(amp2_dev_id);
+       if (amp2_event_fd < 0) {
+               hci_close_dev(amp1_event_fd);
+               return EXIT_FAILURE;
+       }
+
+       if (!read_local_amp_info(amp1_dev_id, &amp1_max_assoc_len))
+               return EXIT_FAILURE;
+
+       amp1_assoc_data = alloca(amp1_max_assoc_len);
+
+       printf("--> AMP_Get_Info_Request (Amp_ID B)\n");
+
+       if (!read_local_amp_info(amp2_dev_id, &amp2_max_assoc_len))
+               return EXIT_FAILURE;
+
+       amp2_assoc_data = alloca(amp2_max_assoc_len);
+
+       printf("<-- AMP_Get_Info_Response (Amp_ID B, Status)\n");
+
+       printf("--> AMP_Get_AMP_Assoc_Request (Amp_ID B)\n");
+
+       if (!read_local_amp_assoc(amp2_dev_id, 0x00, amp2_max_assoc_len,
+                                       amp2_assoc_data, &amp2_assoc_len))
+               return EXIT_FAILURE;
+
+       printf("<-- AMP_Get_AMP_Assoc_Response (Amp_ID B, AMP_Assoc B)\n");
+
+       amp1_phy_handle = 0x04;
+
+       if (!create_physical_link(amp1_dev_id, amp1_phy_handle))
+               return EXIT_FAILURE;
+
+       if (!write_remote_amp_assoc(amp1_dev_id, amp1_phy_handle,
+                                       amp2_assoc_data, amp2_assoc_len))
+               return EXIT_FAILURE;
+
+       printf("hci%d: Signal MAC to scan\n", amp1_dev_id);
+
+       printf("hci%d: Signal MAC to start\n", amp1_dev_id);
+
+       if (!channel_selected_event(amp1_dev_id, amp1_event_fd,
+                                                       amp1_phy_handle))
+               return EXIT_FAILURE;
+
+       if (!read_local_amp_assoc(amp1_dev_id, amp1_phy_handle,
+                                       amp1_max_assoc_len,
+                                       amp1_assoc_data, &amp1_assoc_len))
+               return EXIT_FAILURE;
+
+       printf("--> AMP_Create_Physical_Link_Request (Remote-Amp-ID B, AMP_Assoc A)\n");
+
+       amp2_phy_handle = 0x05;
+
+       if (!accept_physical_link(amp2_dev_id, amp2_phy_handle))
+               return EXIT_FAILURE;
+
+       if (!write_remote_amp_assoc(amp2_dev_id, amp2_phy_handle,
+                                       amp1_assoc_data, amp1_assoc_len))
+               return EXIT_FAILURE;
+
+       printf("hci%d: Signal MAC to start\n", amp2_dev_id);
+
+       printf("<-- AMP_Create_Physical_Link_Response (Local-Amp-ID B, Status)\n");
+
+       if (!physical_link_complete_event(amp2_dev_id, amp2_event_fd,
+                                                       amp2_phy_handle))
+               return EXIT_FAILURE;
+
+       if (!physical_link_complete_event(amp1_dev_id, amp1_event_fd,
+                                                       amp1_phy_handle))
+               return EXIT_FAILURE;
+
+       /* physical link established */
+
+       if (!disconnect_physical_link(amp1_dev_id, amp1_phy_handle, 0x13))
+               return EXIT_FAILURE;
+
+       if (!disconnect_physical_link_complete_event(amp1_dev_id,
+                                                       amp1_event_fd,
+                                                       amp1_phy_handle))
+               return EXIT_FAILURE;
+
+       if (!disconnect_physical_link_complete_event(amp2_dev_id,
+                                                       amp2_event_fd,
+                                                       amp2_phy_handle))
+               return EXIT_FAILURE;
+
+       hci_close_dev(amp2_event_fd);
+       hci_close_dev(amp1_event_fd);
+
+       return EXIT_SUCCESS;
+}
diff --git a/tools/avctrl.8 b/tools/avctrl.8
deleted file mode 100644 (file)
index 7c3759d..0000000
+++ /dev/null
@@ -1,39 +0,0 @@
-.\"
-.\"    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\"
-.\"
-.TH AVCTRL 8 "JUNE 6, 2005" "" ""
-
-.SH NAME
-avctrl \- Bluetooth Audio/Video control utility
-.SH SYNOPSIS
-.BR "avctrl
-[
-.I options
-]
-<command>
-.SH DESCRIPTION
-.B avctrl
-is used to control the Audio/Video dongles.
-.SH OPTIONS
-.TP
-.BI -h
-Gives a list of possible options.
-.TP
-.BI -q
-Don't display any messages.
-.SH AUTHOR
-Written by Marcel Holtmann <marcel@holtmann.org>.
-.br
diff --git a/tools/avctrl.c b/tools/avctrl.c
deleted file mode 100644 (file)
index 3621a68..0000000
+++ /dev/null
@@ -1,248 +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 <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <usb.h>
-
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
-       return usb_busses;
-}
-#endif
-
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT    0x00
-#endif
-
-#ifndef USB_DIR_IN
-#define USB_DIR_IN     0x80
-#endif
-
-#define HID_REQ_GET_REPORT     0x01
-#define HID_REQ_GET_IDLE       0x02
-#define HID_REQ_GET_PROTOCOL   0x03
-#define HID_REQ_SET_REPORT     0x09
-#define HID_REQ_SET_IDLE       0x0a
-#define HID_REQ_SET_PROTOCOL   0x0b
-
-struct device_info;
-
-struct device_id {
-       uint16_t vendor;
-       uint16_t product;
-       int (*func)(struct device_info *dev, int argc, char *argv[]);
-};
-
-struct device_info {
-       struct usb_device *dev;
-       struct device_id *id;
-};
-
-#define GET_STATE              0x01
-#define GET_REMOTE_BDADDR      0x02
-#define DISCOVER               0x03
-#define SWITCH_TO_DFU          0x04
-#define READ_CODEC             0x05
-
-static int dongle_csr(struct device_info *devinfo, int argc, char *argv[])
-{
-       char buf[8];
-       struct usb_dev_handle *udev;
-       int err, intf = 2;
-
-       memset(buf, 0, sizeof(buf));
-
-       if (!strncasecmp(argv[0], "discover", 4))
-               buf[0] = DISCOVER;
-       else if (!strncasecmp(argv[0], "switch", 3))
-               buf[0] = SWITCH_TO_DFU;
-       else if (!strncasecmp(argv[0], "dfu", 3))
-               buf[0] = SWITCH_TO_DFU;
-       else
-               return -EINVAL;
-
-       udev = usb_open(devinfo->dev);
-       if (!udev)
-               return -errno;
-
-       if (usb_claim_interface(udev, intf) < 0) {
-               err = -errno;
-               usb_close(udev);
-               return err;
-       }
-
-       err = usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                               HID_REQ_SET_REPORT, 0x03 << 8, intf, buf, sizeof(buf), 10000);
-
-       if (err == 0) {
-               err = -1;
-               errno = EALREADY;
-       } else {
-               if (errno == ETIMEDOUT)
-                       err = 0;
-       }
-
-       usb_release_interface(udev, intf);
-       usb_close(udev);
-
-       return err;
-}
-
-static struct device_id device_list[] = {
-       { 0x0a12, 0x1004, dongle_csr },
-       { -1 }
-};
-
-static struct device_id *match_device(uint16_t vendor, uint16_t product)
-{
-       int i;
-
-       for (i = 0; device_list[i].func; i++) {
-               if (vendor == device_list[i].vendor &&
-                               product == device_list[i].product)
-                       return &device_list[i];
-       }
-
-       return NULL;
-}
-
-static int find_devices(struct device_info *devinfo, size_t size)
-{
-       struct usb_bus *bus;
-       struct usb_device *dev;
-       struct device_id *id;
-       unsigned int count = 0;
-
-       usb_find_busses();
-       usb_find_devices();
-
-       for (bus = usb_get_busses(); bus; bus = bus->next)
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       id = match_device(dev->descriptor.idVendor,
-                                               dev->descriptor.idProduct);
-                       if (!id)
-                               continue;
-
-                       if (count < size) {
-                               devinfo[count].dev = dev;
-                               devinfo[count].id = id;
-                               count++;
-                       }
-               }
-
-       return count;
-}
-
-static void usage(void)
-{
-       printf("avctrl - Bluetooth Audio/Video control utility\n\n");
-
-       printf("Usage:\n"
-               "\tavctrl [options] <command>\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-h, --help           Display help\n"
-               "\t-q, --quiet          Don't display any messages\n"
-               "\n");
-
-       printf("Commands:\n"
-               "\tdiscover         Simulate pressing the discover button\n"
-               "\tswitch           Switch the dongle to DFU mode\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "quiet",      0, 0, 'q' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       struct device_info dev[16];
-       int i, opt, num, quiet = 0;
-
-       while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) {
-               switch (opt) {
-               case 'q':
-                       quiet = 1;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       usb_init();
-
-       num = find_devices(dev, sizeof(dev) / sizeof(dev[0]));
-       if (num <= 0) {
-               if (!quiet)
-                       fprintf(stderr, "No Audio/Video devices found\n");
-               exit(1);
-       }
-
-       for (i = 0; i < num; i++) {
-               struct device_id *id = dev[i].id;
-               int err;
-
-               if (!quiet)
-                       printf("Selecting device %04x:%04x ",
-                                               id->vendor, id->product);
-               fflush(stdout);
-
-               err = id->func(&dev[i], argc, argv);
-               if (err < 0) {
-                       if (!quiet)
-                               printf("failed (%s)\n", strerror(-err));
-               } else {
-                       if (!quiet)
-                               printf("was successful\n");
-               }
-       }
-
-       return 0;
-}
index 63b0da6..d237742 100644 (file)
@@ -39,6 +39,8 @@
 #include <sys/ioctl.h>
 #include <sys/socket.h>
 
+#include "profiles/audio/a2dp-codecs.h"
+
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
 #define AVDTP_MEDIA_TYPE_VIDEO         0x01
 #define AVDTP_MEDIA_TYPE_MULTIMEDIA    0x02
 
-#define A2DP_CODEC_SBC                 0x00
-#define A2DP_CODEC_MPEG12              0x01
-#define A2DP_CODEC_MPEG24              0x02
-#define A2DP_CODEC_ATRAC               0x03
-
-#define SBC_SAMPLING_FREQ_16000                (1 << 3)
-#define SBC_SAMPLING_FREQ_32000                (1 << 2)
-#define SBC_SAMPLING_FREQ_44100                (1 << 1)
-#define SBC_SAMPLING_FREQ_48000                (1 << 0)
-
-#define SBC_CHANNEL_MODE_MONO          (1 << 3)
-#define SBC_CHANNEL_MODE_DUAL_CHANNEL  (1 << 2)
-#define SBC_CHANNEL_MODE_STEREO                (1 << 1)
-#define SBC_CHANNEL_MODE_JOINT_STEREO  (1 << 0)
-
-#define SBC_BLOCK_LENGTH_4             (1 << 3)
-#define SBC_BLOCK_LENGTH_8             (1 << 2)
-#define SBC_BLOCK_LENGTH_12            (1 << 1)
-#define SBC_BLOCK_LENGTH_16            (1 << 0)
-
-#define SBC_SUBBANDS_4                 (1 << 1)
-#define SBC_SUBBANDS_8                 (1 << 0)
-
-#define SBC_ALLOCATION_SNR             (1 << 1)
-#define SBC_ALLOCATION_LOUDNESS                (1 << 0)
-
-#define MPEG_CHANNEL_MODE_MONO         (1 << 3)
-#define MPEG_CHANNEL_MODE_DUAL_CHANNEL (1 << 2)
-#define MPEG_CHANNEL_MODE_STEREO       (1 << 1)
-#define MPEG_CHANNEL_MODE_JOINT_STEREO (1 << 0)
-
-#define MPEG_LAYER_MP1                 (1 << 2)
-#define MPEG_LAYER_MP2                 (1 << 1)
-#define MPEG_LAYER_MP3                 (1 << 0)
-
-#define MPEG_SAMPLING_FREQ_16000       (1 << 5)
-#define MPEG_SAMPLING_FREQ_22050       (1 << 4)
-#define MPEG_SAMPLING_FREQ_24000       (1 << 3)
-#define MPEG_SAMPLING_FREQ_32000       (1 << 2)
-#define MPEG_SAMPLING_FREQ_44100       (1 << 1)
-#define MPEG_SAMPLING_FREQ_48000       (1 << 0)
-
-#define MPEG_BIT_RATE_VBR              0x8000
-#define MPEG_BIT_RATE_320000           0x4000
-#define MPEG_BIT_RATE_256000           0x2000
-#define MPEG_BIT_RATE_224000           0x1000
-#define MPEG_BIT_RATE_192000           0x0800
-#define MPEG_BIT_RATE_160000           0x0400
-#define MPEG_BIT_RATE_128000           0x0200
-#define MPEG_BIT_RATE_112000           0x0100
-#define MPEG_BIT_RATE_96000            0x0080
-#define MPEG_BIT_RATE_80000            0x0040
-#define MPEG_BIT_RATE_64000            0x0020
-#define MPEG_BIT_RATE_56000            0x0010
-#define MPEG_BIT_RATE_48000            0x0008
-#define MPEG_BIT_RATE_40000            0x0004
-#define MPEG_BIT_RATE_32000            0x0002
-#define MPEG_BIT_RATE_FREE             0x0001
-
 struct avdtp_service_capability {
        uint8_t category;
        uint8_t length;
@@ -169,28 +112,6 @@ struct avdtp_media_codec_capability {
        uint8_t data[0];
 } __attribute__ ((packed));
 
-struct sbc_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t channel_mode:4;
-       uint8_t frequency:4;
-       uint8_t allocation_method:2;
-       uint8_t subbands:2;
-       uint8_t block_length:4;
-       uint8_t min_bitpool;
-       uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t channel_mode:4;
-       uint8_t crc:1;
-       uint8_t layer:3;
-       uint8_t frequency:6;
-       uint8_t mpf:1;
-       uint8_t rfa:1;
-       uint16_t bitrate;
-} __attribute__ ((packed));
-
 #elif __BYTE_ORDER == __BIG_ENDIAN
 
 struct avdtp_header {
@@ -223,28 +144,6 @@ struct avdtp_media_codec_capability {
        uint8_t data[0];
 } __attribute__ ((packed));
 
-struct sbc_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t frequency:4;
-       uint8_t channel_mode:4;
-       uint8_t block_length:4;
-       uint8_t subbands:2;
-       uint8_t allocation_method:2;
-       uint8_t min_bitpool;
-       uint8_t max_bitpool;
-} __attribute__ ((packed));
-
-struct mpeg_codec_cap {
-       struct avdtp_media_codec_capability cap;
-       uint8_t layer:3;
-       uint8_t crc:1;
-       uint8_t channel_mode:4;
-       uint8_t rfa:1;
-       uint8_t mpf:1;
-       uint8_t frequency:6;
-       uint16_t bitrate;
-} __attribute__ ((packed));
-
 #else
 #error "Unknown byte order"
 #endif
@@ -259,8 +158,20 @@ struct getcap_resp {
        uint8_t caps[0];
 } __attribute__ ((packed));
 
+static void print_vendor(a2dp_vendor_codec_t *vendor)
+{
+       printf("\tMedia Codec: Vendor Specific A2DP Codec");
+
+       printf("\n\t\tVendor ID 0x%02x%02x%02x%02x", vendor->vendor_id[0],
+               vendor->vendor_id[1], vendor->vendor_id[2],
+               vendor->vendor_id[3]);
 
-static void print_mpeg12(struct mpeg_codec_cap *mpeg)
+       printf("\n\t\tVendor Specific Codec ID 0x%02x%02x\n",
+                       vendor->codec_id[0], vendor->codec_id[1]);
+}
+
+
+static void print_mpeg12(a2dp_mpeg_t *mpeg)
 {
        printf("\tMedia Codec: MPEG12\n\t\tChannel Modes: ");
 
@@ -341,7 +252,7 @@ static void print_mpeg12(struct mpeg_codec_cap *mpeg)
                printf("RFC-2250\n");
 }
 
-static void print_sbc(struct sbc_codec_cap *sbc)
+static void print_sbc(a2dp_sbc_t *sbc)
 {
        printf("\tMedia Codec: SBC\n\t\tChannel Modes: ");
 
@@ -388,10 +299,13 @@ static void print_media_codec(struct avdtp_media_codec_capability *cap)
 {
        switch (cap->media_codec_type) {
        case A2DP_CODEC_SBC:
-               print_sbc((void *) cap);
+               print_sbc((void *) cap->data);
                break;
        case A2DP_CODEC_MPEG12:
-               print_mpeg12((void *) cap);
+               print_mpeg12((void *) cap->data);
+               break;
+       case A2DP_CODEC_VENDOR:
+               print_vendor((void *) cap->data);
                break;
        default:
                printf("\tMedia Codec: Unknown\n");
similarity index 100%
rename from test/avtest.c
rename to tools/avtest.c
similarity index 97%
rename from tools/bccmd.8
rename to tools/bccmd.1
index 28cbe88..26c83a6 100644 (file)
@@ -1,4 +1,4 @@
-.TH BCCMD 8 "Jun 20 2006" BlueZ "Linux System Administration"
+.TH BCCMD 1 "Jun 20 2006" BlueZ "Linux System Administration"
 .SH NAME
 bccmd \- Utility for the CSR BCCMD interface
 .SH SYNOPSIS
index 952bf13..ff1b307 100644 (file)
@@ -64,10 +64,8 @@ static inline int transport_open(int transport, char *device, speed_t bcsp_rate)
        switch (transport) {
        case CSR_TRANSPORT_HCI:
                return csr_open_hci(device);
-#ifdef HAVE_LIBUSB
        case CSR_TRANSPORT_USB:
                return csr_open_usb(device);
-#endif
        case CSR_TRANSPORT_BCSP:
                return csr_open_bcsp(device, bcsp_rate);
        case CSR_TRANSPORT_H4:
@@ -85,10 +83,8 @@ static inline int transport_read(int transport, uint16_t varid, uint8_t *value,
        switch (transport) {
        case CSR_TRANSPORT_HCI:
                return csr_read_hci(varid, value, length);
-#ifdef HAVE_LIBUSB
        case CSR_TRANSPORT_USB:
                return csr_read_usb(varid, value, length);
-#endif
        case CSR_TRANSPORT_BCSP:
                return csr_read_bcsp(varid, value, length);
        case CSR_TRANSPORT_H4:
@@ -106,10 +102,8 @@ static inline int transport_write(int transport, uint16_t varid, uint8_t *value,
        switch (transport) {
        case CSR_TRANSPORT_HCI:
                return csr_write_hci(varid, value, length);
-#ifdef HAVE_LIBUSB
        case CSR_TRANSPORT_USB:
                return csr_write_usb(varid, value, length);
-#endif
        case CSR_TRANSPORT_BCSP:
                return csr_write_bcsp(varid, value, length);
        case CSR_TRANSPORT_H4:
@@ -128,11 +122,9 @@ static inline void transport_close(int transport)
        case CSR_TRANSPORT_HCI:
                csr_close_hci();
                break;
-#ifdef HAVE_LIBUSB
        case CSR_TRANSPORT_USB:
                csr_close_usb();
                break;
-#endif
        case CSR_TRANSPORT_BCSP:
                csr_close_bcsp();
                break;
similarity index 98%
rename from test/bdaddr.c
rename to tools/bdaddr.c
index f87fa38..73dffce 100644 (file)
@@ -318,7 +318,7 @@ int main(int argc, char *argv[])
        struct hci_dev_info di;
        struct hci_version ver;
        bdaddr_t bdaddr;
-       char addr[18], oui[9], *comp;
+       char addr[18], *comp;
        int i, dd, opt, dev = 0, reset = 0;
 
        bacpy(&bdaddr, BDADDR_ANY);
@@ -386,8 +386,7 @@ int main(int argc, char *argv[])
        printf("Manufacturer:   %s (%d)\n",
                        bt_compidtostr(ver.manufacturer), ver.manufacturer);
 
-       ba2oui(&bdaddr, oui);
-       comp = ouitocomp(oui);
+       comp = batocomp(&bdaddr);
 
        ba2str(&bdaddr, addr);
        printf("Device address: %s", addr);
@@ -411,8 +410,7 @@ int main(int argc, char *argv[])
 
        for (i = 0; vendor[i].compid != 65535; i++)
                if (ver.manufacturer == vendor[i].compid) {
-                       ba2oui(&bdaddr, oui);
-                       comp = ouitocomp(oui);
+                       comp = batocomp(&bdaddr);
 
                        ba2str(&bdaddr, addr);
                        printf("New BD address: %s", addr);
diff --git a/tools/bluetooth-player.c b/tools/bluetooth-player.c
new file mode 100644 (file)
index 0000000..622d391
--- /dev/null
@@ -0,0 +1,1448 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include <client/display.h>
+
+/* String display constants */
+#define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
+#define COLORED_DEL    COLOR_RED "DEL" COLOR_OFF
+
+#define PROMPT_ON      COLOR_BLUE "[bluetooth]" COLOR_OFF "# "
+#define PROMPT_OFF     "[bluetooth]# "
+
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
+#define BLUEZ_MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
+
+static GMainLoop *main_loop;
+static DBusConnection *dbus_conn;
+static GDBusProxy *default_player;
+static GSList *players = NULL;
+static GSList *folders = NULL;
+static GSList *items = NULL;
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_ON);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_OFF);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+static void cmd_quit(int argc, char *argv[])
+{
+       g_main_loop_quit(main_loop);
+}
+
+static bool check_default_player(void)
+{
+       if (!default_player) {
+               rl_printf("No default player available\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void play_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to play: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Play successful\n");
+}
+
+static GDBusProxy *find_item(const char *path)
+{
+       GSList *l;
+
+       for (l = items; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void cmd_play_item(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       proxy = find_item(argv[1]);
+       if (proxy == NULL) {
+               rl_printf("Item %s not available\n", argv[1]);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Play", NULL, play_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to play\n");
+               return;
+       }
+
+       rl_printf("Attempting to play %s\n", argv[1]);
+}
+
+static void cmd_play(int argc, char *argv[])
+{
+       if (argc > 1)
+               return cmd_play_item(argc, argv);
+
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Play", NULL, play_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to play\n");
+               return;
+       }
+
+       rl_printf("Attempting to play\n");
+}
+
+static void pause_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to pause: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Pause successful\n");
+}
+
+static void cmd_pause(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Pause", NULL,
+                                       pause_reply, NULL, NULL) == FALSE) {
+               rl_printf("Failed to play\n");
+               return;
+       }
+
+       rl_printf("Attempting to pause\n");
+}
+
+static void stop_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to stop: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Stop successful\n");
+}
+
+static void cmd_stop(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Stop", NULL, stop_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to stop\n");
+               return;
+       }
+
+       rl_printf("Attempting to stop\n");
+}
+
+static void next_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to jump to next: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Next successful\n");
+}
+
+static void cmd_next(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Next", NULL, next_reply,
+                                                       NULL, NULL) == FALSE) {
+               rl_printf("Failed to jump to next\n");
+               return;
+       }
+
+       rl_printf("Attempting to jump to next\n");
+}
+
+static void previous_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to jump to previous: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Previous successful\n");
+}
+
+static void cmd_previous(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Previous", NULL,
+                                       previous_reply, NULL, NULL) == FALSE) {
+               rl_printf("Failed to jump to previous\n");
+               return;
+       }
+
+       rl_printf("Attempting to jump to previous\n");
+}
+
+static void fast_forward_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to fast forward: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("FastForward successful\n");
+}
+
+static void cmd_fast_forward(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "FastForward", NULL,
+                               fast_forward_reply, NULL, NULL) == FALSE) {
+               rl_printf("Failed to jump to previous\n");
+               return;
+       }
+
+       rl_printf("Fast forward playback\n");
+}
+
+static void rewind_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to rewind: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Rewind successful\n");
+}
+
+static void cmd_rewind(int argc, char *argv[])
+{
+       if (!check_default_player())
+               return;
+
+       if (g_dbus_proxy_method_call(default_player, "Rewind", NULL,
+                                       rewind_reply, NULL, NULL) == FALSE) {
+               rl_printf("Failed to rewind\n");
+               return;
+       }
+
+       rl_printf("Rewind playback\n");
+}
+
+static void generic_callback(const DBusError *error, void *user_data)
+{
+       char *str = user_data;
+
+       if (dbus_error_is_set(error))
+               rl_printf("Failed to set %s: %s\n", str, error->name);
+       else
+               rl_printf("Changing %s succeeded\n", str);
+}
+
+static void cmd_equalizer(int argc, char *argv[])
+{
+       char *value;
+       DBusMessageIter iter;
+
+       if (!check_default_player())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing on/off argument\n");
+               return;
+       }
+
+       if (!g_dbus_proxy_get_property(default_player, "Equalizer", &iter)) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       value = g_strdup(argv[1]);
+
+       if (g_dbus_proxy_set_property_basic(default_player, "Equalizer",
+                                               DBUS_TYPE_STRING, &value,
+                                               generic_callback, value,
+                                               g_free) == FALSE) {
+               rl_printf("Failed to setting equalizer\n");
+               g_free(value);
+               return;
+       }
+
+       rl_printf("Attempting to set equalizer\n");
+}
+
+static void cmd_repeat(int argc, char *argv[])
+{
+       char *value;
+       DBusMessageIter iter;
+
+       if (!check_default_player())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing mode argument\n");
+               return;
+       }
+
+       if (!g_dbus_proxy_get_property(default_player, "Repeat", &iter)) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       value = g_strdup(argv[1]);
+
+       if (g_dbus_proxy_set_property_basic(default_player, "Repeat",
+                                               DBUS_TYPE_STRING, &value,
+                                               generic_callback, value,
+                                               g_free) == FALSE) {
+               rl_printf("Failed to set repeat\n");
+               g_free(value);
+               return;
+       }
+
+       rl_printf("Attempting to set repeat\n");
+}
+
+static void cmd_shuffle(int argc, char *argv[])
+{
+       char *value;
+       DBusMessageIter iter;
+
+       if (!check_default_player())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing mode argument\n");
+               return;
+       }
+
+       if (!g_dbus_proxy_get_property(default_player, "Shuffle", &iter)) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       value = g_strdup(argv[1]);
+
+       if (g_dbus_proxy_set_property_basic(default_player, "Shuffle",
+                                               DBUS_TYPE_STRING, &value,
+                                               generic_callback, value,
+                                               g_free) == FALSE) {
+               rl_printf("Failed to set shuffle\n");
+               g_free(value);
+               return;
+       }
+
+       rl_printf("Attempting to set shuffle\n");
+}
+
+static void cmd_scan(int argc, char *argv[])
+{
+       char *value;
+       DBusMessageIter iter;
+
+       if (!check_default_player())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing mode argument\n");
+               return;
+       }
+
+       if (!g_dbus_proxy_get_property(default_player, "Shuffle", &iter)) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       value = g_strdup(argv[1]);
+
+       if (g_dbus_proxy_set_property_basic(default_player, "Shuffle",
+                                               DBUS_TYPE_STRING, &value,
+                                               generic_callback, value,
+                                               g_free) == FALSE) {
+               rl_printf("Failed to set scan\n");
+               g_free(value);
+               return;
+       }
+
+       rl_printf("Attempting to set scan\n");
+}
+
+static char *proxy_description(GDBusProxy *proxy, const char *title,
+                                               const char *description)
+{
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       return g_strdup_printf("%s%s%s%s %s ",
+                                       description ? "[" : "",
+                                       description ? : "",
+                                       description ? "] " : "",
+                                       title, path);
+}
+
+static void print_player(GDBusProxy *proxy, const char *description)
+{
+       char *str;
+
+       str = proxy_description(proxy, "Player", description);
+
+       rl_printf("%s%s\n", str, default_player == proxy ? "[default]" : "");
+
+       g_free(str);
+}
+
+static void cmd_list(int argc, char *arg[])
+{
+       GSList *l;
+
+       for (l = players; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+               print_player(proxy, NULL);
+       }
+}
+
+static GDBusProxy *find_player(const char *path)
+{
+       GSList *l;
+
+       for (l = players; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void print_iter(const char *label, const char *name,
+                                               DBusMessageIter *iter)
+{
+       dbus_bool_t valbool;
+       dbus_uint32_t valu32;
+       dbus_uint16_t valu16;
+       dbus_int16_t vals16;
+       const char *valstr;
+       DBusMessageIter subiter;
+
+       if (iter == NULL) {
+               rl_printf("%s%s is nil\n", label, name);
+               return;
+       }
+
+       switch (dbus_message_iter_get_arg_type(iter)) {
+       case DBUS_TYPE_INVALID:
+               rl_printf("%s%s is invalid\n", label, name);
+               break;
+       case DBUS_TYPE_STRING:
+       case DBUS_TYPE_OBJECT_PATH:
+               dbus_message_iter_get_basic(iter, &valstr);
+               rl_printf("%s%s: %s\n", label, name, valstr);
+               break;
+       case DBUS_TYPE_BOOLEAN:
+               dbus_message_iter_get_basic(iter, &valbool);
+               rl_printf("%s%s: %s\n", label, name,
+                                       valbool == TRUE ? "yes" : "no");
+               break;
+       case DBUS_TYPE_UINT32:
+               dbus_message_iter_get_basic(iter, &valu32);
+               rl_printf("%s%s: 0x%06x\n", label, name, valu32);
+               break;
+       case DBUS_TYPE_UINT16:
+               dbus_message_iter_get_basic(iter, &valu16);
+               rl_printf("%s%s: 0x%04x\n", label, name, valu16);
+               break;
+       case DBUS_TYPE_INT16:
+               dbus_message_iter_get_basic(iter, &vals16);
+               rl_printf("%s%s: %d\n", label, name, vals16);
+               break;
+       case DBUS_TYPE_VARIANT:
+               dbus_message_iter_recurse(iter, &subiter);
+               print_iter(label, name, &subiter);
+               break;
+       case DBUS_TYPE_ARRAY:
+               dbus_message_iter_recurse(iter, &subiter);
+               while (dbus_message_iter_get_arg_type(&subiter) !=
+                                                       DBUS_TYPE_INVALID) {
+                       print_iter(label, name, &subiter);
+                       dbus_message_iter_next(&subiter);
+               }
+               break;
+       case DBUS_TYPE_DICT_ENTRY:
+               dbus_message_iter_recurse(iter, &subiter);
+               dbus_message_iter_get_basic(&subiter, &valstr);
+               dbus_message_iter_next(&subiter);
+               print_iter(label, valstr, &subiter);
+               break;
+       default:
+               rl_printf("%s%s has unsupported type\n", label, name);
+               break;
+       }
+}
+
+static void print_property(GDBusProxy *proxy, const char *name)
+{
+       DBusMessageIter iter;
+
+       if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+               return;
+
+       print_iter("\t", name, &iter);
+}
+
+static GDBusProxy *find_folder(const char *path)
+{
+       GSList *l;
+
+       for (l = folders; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void cmd_show_item(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing item address argument\n");
+               return;
+       }
+
+       proxy = find_item(argv[1]);
+       if (!proxy) {
+               rl_printf("Item %s not available\n", argv[1]);
+               return;
+       }
+
+       rl_printf("Item %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(proxy, "Player");
+       print_property(proxy, "Name");
+       print_property(proxy, "Type");
+       print_property(proxy, "FolderType");
+       print_property(proxy, "Playable");
+       print_property(proxy, "Metadata");
+}
+
+static void cmd_show(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+       GDBusProxy *folder;
+       GDBusProxy *item;
+       DBusMessageIter iter;
+       const char *path;
+
+       if (argc < 2) {
+               if (check_default_player() == FALSE)
+                       return;
+
+               proxy = default_player;
+       } else {
+               proxy = find_player(argv[1]);
+               if (!proxy) {
+                       rl_printf("Player %s not available\n", argv[1]);
+                       return;
+               }
+       }
+
+       rl_printf("Player %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(proxy, "Name");
+       print_property(proxy, "Repeat");
+       print_property(proxy, "Equalizer");
+       print_property(proxy, "Shuffle");
+       print_property(proxy, "Scan");
+       print_property(proxy, "Status");
+       print_property(proxy, "Position");
+       print_property(proxy, "Track");
+
+       folder = find_folder(g_dbus_proxy_get_path(proxy));
+       if (folder == NULL)
+               return;
+
+       rl_printf("Folder %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(folder, "Name");
+       print_property(folder, "NumberOfItems");
+
+       if (!g_dbus_proxy_get_property(proxy, "Playlist", &iter))
+               return;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       item = find_item(path);
+       if (item == NULL)
+               return;
+
+       rl_printf("Playlist %s\n", path);
+
+       print_property(item, "Name");
+}
+
+static void cmd_select(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing player address argument\n");
+               return;
+       }
+
+       proxy = find_player(argv[1]);
+       if (proxy == NULL) {
+               rl_printf("Player %s not available\n", argv[1]);
+               return;
+       }
+
+       if (default_player == proxy)
+               return;
+
+       default_player = proxy,
+       print_player(proxy, NULL);
+}
+
+static void change_folder_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to change folder: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("ChangeFolder successful\n");
+}
+
+static void change_folder_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *path = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static void cmd_change_folder(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing item argument\n");
+               return;
+       }
+
+       if (check_default_player() == FALSE)
+               return;
+
+       proxy = find_folder(g_dbus_proxy_get_path(default_player));
+       if (proxy == NULL) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup,
+                               change_folder_reply, argv[1], NULL) == FALSE) {
+               rl_printf("Failed to change current folder\n");
+               return;
+       }
+
+       rl_printf("Attempting to change folder\n");
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+       DBusMessageIter value;
+       char sig[2] = { type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+       dbus_message_iter_append_basic(&value, type, val);
+
+       dbus_message_iter_close_container(iter, &value);
+}
+
+static void dict_append_entry(DBusMessageIter *dict,
+                       const char *key, int type, void *val)
+{
+       DBusMessageIter entry;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) val);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+struct list_items_args {
+       int start;
+       int end;
+};
+
+static void list_items_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct list_items_args *args = user_data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       if (args->start < 0)
+               goto done;
+
+       dict_append_entry(&dict, "Start", DBUS_TYPE_UINT32, &args->start);
+
+       if (args->end < 0)
+               goto done;
+
+       dict_append_entry(&dict, "End", DBUS_TYPE_UINT32, &args->end);
+
+done:
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void list_items_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to list items: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("ListItems successful\n");
+}
+
+static void cmd_list_items(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+       struct list_items_args *args;
+
+       if (check_default_player() == FALSE)
+               return;
+
+       proxy = find_folder(g_dbus_proxy_get_path(default_player));
+       if (proxy == NULL) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       args = g_new0(struct list_items_args, 1);
+       args->start = -1;
+       args->end = -1;
+
+       if (argc < 2)
+               goto done;
+
+       errno = 0;
+       args->start = strtol(argv[1], NULL, 10);
+       if (errno != 0) {
+               rl_printf("%s(%d)\n", strerror(errno), errno);
+               g_free(args);
+               return;
+       }
+
+       if (argc < 3)
+               goto done;
+
+       errno = 0;
+       args->end = strtol(argv[2], NULL, 10);
+       if (errno != 0) {
+               rl_printf("%s(%d)\n", strerror(errno), errno);
+               g_free(args);
+               return;
+       }
+
+done:
+       if (g_dbus_proxy_method_call(proxy, "ListItems", list_items_setup,
+                               list_items_reply, args, g_free) == FALSE) {
+               rl_printf("Failed to change current folder\n");
+               g_free(args);
+               return;
+       }
+
+       rl_printf("Attempting to list items\n");
+}
+
+static void search_setup(DBusMessageIter *iter, void *user_data)
+{
+       char *string = user_data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &string);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void search_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to search: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Search successful\n");
+}
+
+static void cmd_search(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+       char *string;
+
+       if (argc < 2) {
+               rl_printf("Missing string argument\n");
+               return;
+       }
+
+       if (check_default_player() == FALSE)
+               return;
+
+       proxy = find_folder(g_dbus_proxy_get_path(default_player));
+       if (proxy == NULL) {
+               rl_printf("Operation not supported\n");
+               return;
+       }
+
+       string = g_strdup(argv[1]);
+
+       if (g_dbus_proxy_method_call(proxy, "Search", search_setup,
+                               search_reply, string, g_free) == FALSE) {
+               rl_printf("Failed to search\n");
+               g_free(string);
+               return;
+       }
+
+       rl_printf("Attempting to search\n");
+}
+
+static void add_to_nowplaying_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to queue: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("AddToNowPlaying successful\n");
+}
+
+static void cmd_queue(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing item address argument\n");
+               return;
+       }
+
+       proxy = find_item(argv[1]);
+       if (proxy == NULL) {
+               rl_printf("Item %s not available\n", argv[1]);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "AddtoNowPlaying", NULL,
+                                       add_to_nowplaying_reply, NULL,
+                                       NULL) == FALSE) {
+               rl_printf("Failed to play\n");
+               return;
+       }
+
+       rl_printf("Attempting to queue %s\n", argv[1]);
+}
+
+static const struct {
+       const char *cmd;
+       const char *arg;
+       void (*func) (int argc, char *argv[]);
+       const char *desc;
+} cmd_table[] = {
+       { "list",         NULL,       cmd_list, "List available players" },
+       { "show",         "[player]", cmd_show, "Player information" },
+       { "select",       "<player>", cmd_select, "Select default player" },
+       { "play",         "[item]",   cmd_play, "Start playback" },
+       { "pause",        NULL,       cmd_pause, "Pause playback" },
+       { "stop",         NULL,       cmd_stop, "Stop playback" },
+       { "next",         NULL,       cmd_next, "Jump to next item" },
+       { "previous",     NULL,       cmd_previous, "Jump to previous item" },
+       { "fast-forward", NULL,       cmd_fast_forward,
+                                               "Fast forward playback" },
+       { "rewind",       NULL,       cmd_rewind, "Rewind playback" },
+       { "equalizer",    "<on/off>", cmd_equalizer,
+                                               "Enable/Disable equalizer"},
+       { "repeat",       "<singletrack/alltrack/group/off>", cmd_repeat,
+                                               "Set repeat mode"},
+       { "shuffle",      "<alltracks/group/off>", cmd_shuffle,
+                                               "Set shuffle mode"},
+       { "scan",         "<alltracks/group/off>", cmd_scan,
+                                               "Set scan mode"},
+       { "change-folder", "<item>",  cmd_change_folder,
+                                               "Change current folder" },
+       { "list-items", "[start] [end]",  cmd_list_items,
+                                       "List items of current folder" },
+       { "search",     "string",     cmd_search,
+                                       "Search items containing string" },
+       { "queue",       "<item>",    cmd_queue, "Add item to playlist queue" },
+       { "show-item",   "<item>",    cmd_show_item, "Show item information" },
+       { "quit",         NULL,       cmd_quit, "Quit program" },
+       { "exit",         NULL,       cmd_quit },
+       { "help" },
+       {}
+};
+
+static char *cmd_generator(const char *text, int state)
+{
+       static int index, len;
+       const char *cmd;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       while ((cmd = cmd_table[index].cmd)) {
+               index++;
+
+               if (!strncmp(cmd, text, len))
+                       return strdup(cmd);
+       }
+
+       return NULL;
+}
+
+static char **cmd_completion(const char *text, int start, int end)
+{
+       char **matches = NULL;
+
+       if (start == 0) {
+               rl_completion_display_matches_hook = NULL;
+               matches = rl_completion_matches(text, cmd_generator);
+       }
+
+       if (!matches)
+               rl_attempted_completion_over = 1;
+
+       return matches;
+}
+
+static void rl_handler(char *input)
+{
+       int argc;
+       char **argv = NULL;
+       int i;
+
+       if (!input) {
+               rl_insert_text("quit");
+               rl_redisplay();
+               rl_crlf();
+               g_main_loop_quit(main_loop);
+               return;
+       }
+
+       if (!strlen(input))
+               goto done;
+
+       add_history(input);
+
+       argv = g_strsplit(input, " ", -1);
+       if (argv == NULL)
+               goto done;
+
+       for (argc = 0; argv[argc];)
+               argc++;
+
+       if (argc == 0)
+               goto done;
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (strcmp(argv[0], cmd_table[i].cmd))
+                       continue;
+
+               if (cmd_table[i].func) {
+                       cmd_table[i].func(argc, argv);
+                       goto done;
+               }
+       }
+
+       if (strcmp(argv[0], "help")) {
+               printf("Invalid command\n");
+               goto done;
+       }
+
+       printf("Available commands:\n");
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (cmd_table[i].desc)
+                       printf("\t%s %s\t%s\n", cmd_table[i].cmd,
+                                               cmd_table[i].arg ? : "    ",
+                                               cmd_table[i].desc);
+       }
+
+done:
+       g_strfreev(argv);
+       free(input);
+}
+
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { NULL },
+};
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+               rl_replace_line("", 0);
+               rl_crlf();
+               rl_on_new_line();
+               rl_redisplay();
+               break;
+       case SIGTERM:
+               if (__terminated == 0) {
+                       rl_replace_line("", 0);
+                       rl_crlf();
+                       g_main_loop_quit(main_loop);
+               }
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       rl_callback_read_char();
+       return TRUE;
+}
+
+static guint setup_standard_input(void)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fileno(stdin));
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               input_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static void player_added(GDBusProxy *proxy)
+{
+       players = g_slist_append(players, proxy);
+
+       if (default_player == NULL)
+               default_player = proxy;
+
+       print_player(proxy, COLORED_NEW);
+}
+
+static void print_folder(GDBusProxy *proxy, const char *description)
+{
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       rl_printf("%s%s%sFolder %s\n", description ? "[" : "",
+                                       description ? : "",
+                                       description ? "] " : "",
+                                       path);
+}
+
+static void folder_added(GDBusProxy *proxy)
+{
+       folders = g_slist_append(folders, proxy);
+
+       print_folder(proxy, COLORED_NEW);
+}
+
+static void print_item(GDBusProxy *proxy, const char *description)
+{
+       const char *path, *name;
+       DBusMessageIter iter;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       if (g_dbus_proxy_get_property(proxy, "Name", &iter))
+               dbus_message_iter_get_basic(&iter, &name);
+       else
+               name = "<unknown>";
+
+       rl_printf("%s%s%sItem %s %s\n", description ? "[" : "",
+                                       description ? : "",
+                                       description ? "] " : "",
+                                       path, name);
+}
+
+static void item_added(GDBusProxy *proxy)
+{
+       items = g_slist_append(items, proxy);
+
+       print_item(proxy, COLORED_NEW);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE))
+               player_added(proxy);
+       else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE))
+               folder_added(proxy);
+       else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE))
+               item_added(proxy);
+}
+
+static void player_removed(GDBusProxy *proxy)
+{
+       print_player(proxy, COLORED_DEL);
+
+       if (default_player == proxy)
+               default_player = NULL;
+
+       players = g_slist_remove(players, proxy);
+}
+
+static void folder_removed(GDBusProxy *proxy)
+{
+       folders = g_slist_remove(folders, proxy);
+
+       print_folder(proxy, COLORED_DEL);
+}
+
+static void item_removed(GDBusProxy *proxy)
+{
+       items = g_slist_remove(items, proxy);
+
+       print_item(proxy, COLORED_DEL);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE))
+               player_removed(proxy);
+       if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE))
+               folder_removed(proxy);
+       if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE))
+               item_removed(proxy);
+}
+
+static void player_property_changed(GDBusProxy *proxy, const char *name,
+                                               DBusMessageIter *iter)
+{
+       char *str;
+
+       str = proxy_description(proxy, "Player", COLORED_CHG);
+       print_iter(str, name, iter);
+       g_free(str);
+}
+
+static void folder_property_changed(GDBusProxy *proxy, const char *name,
+                                               DBusMessageIter *iter)
+{
+       char *str;
+
+       str = proxy_description(proxy, "Folder", COLORED_CHG);
+       print_iter(str, name, iter);
+       g_free(str);
+}
+
+static void item_property_changed(GDBusProxy *proxy, const char *name,
+                                               DBusMessageIter *iter)
+{
+       char *str;
+
+       str = proxy_description(proxy, "Item", COLORED_CHG);
+       print_iter(str, name, iter);
+       g_free(str);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE))
+               player_property_changed(proxy, name, iter);
+       else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE))
+               folder_property_changed(proxy, name, iter);
+       else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE))
+               item_property_changed(proxy, name, iter);
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       GDBusClient *client;
+       guint signal, input;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               printf("%s\n", VERSION);
+               exit(0);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+       dbus_conn = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+
+       rl_attempted_completion_function = cmd_completion;
+
+       rl_erase_empty_line = 1;
+       rl_callback_handler_install(NULL, rl_handler);
+
+       rl_set_prompt(PROMPT_OFF);
+       rl_redisplay();
+
+       input = setup_standard_input();
+       signal = setup_signalfd();
+       client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+       g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+
+       g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+                                                       property_changed, NULL);
+
+       g_main_loop_run(main_loop);
+
+       g_dbus_client_unref(client);
+       g_source_remove(signal);
+       g_source_remove(input);
+
+       rl_message("");
+       rl_callback_handler_remove();
+
+       dbus_connection_unref(dbus_conn);
+       g_main_loop_unref(main_loop);
+
+       return 0;
+}
diff --git a/tools/btattach.c b/tools/btattach.c
new file mode 100644 (file)
index 0000000..a084440
--- /dev/null
@@ -0,0 +1,210 @@
+/*
+ *
+ *  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 <getopt.h>
+#include <termios.h>
+#include <sys/ioctl.h>
+#include <sys/poll.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+
+#include "hciattach.h"
+
+static int open_serial(const char *path)
+{
+       struct termios ti;
+       int fd, ldisc = N_HCI;
+
+       fd = open(path, O_RDWR | O_NOCTTY);
+       if (fd < 0) {
+               perror("Failed to open serial port");
+               return -1;
+       }
+
+       if (tcflush(fd, TCIOFLUSH) < 0) {
+               perror("Failed to flush serial port");
+               close(fd);
+               return -1;
+       }
+
+       /* Switch TTY to raw mode */
+       memset(&ti, 0, sizeof(ti));
+       cfmakeraw(&ti);
+
+       ti.c_cflag |= (B115200 | CLOCAL | CREAD);
+
+       if (tcsetattr(fd, TCSANOW, &ti) < 0) {
+               perror("Failed to set serial port settings");
+               close(fd);
+               return -1;
+       }
+
+       if (ioctl(fd, TIOCSETD, &ldisc) < 0) {
+               perror("Failed set serial line discipline");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int attach_proto(const char *path, unsigned int proto,
+                                               unsigned int flags)
+{
+       int fd;
+
+       fd = open_serial(path);
+       if (fd < 0)
+               return -1;
+
+       if (ioctl(fd, HCIUARTSETFLAGS, flags) < 0) {
+               perror("Failed to set flags");
+               close(fd);
+               return -1;
+       }
+
+       if (ioctl(fd, HCIUARTSETPROTO, proto) < 0) {
+               perror("Failed to set protocol");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static void usage(void)
+{
+       printf("btattach - Bluetooth serial utility\n"
+               "Usage:\n");
+       printf("\tbtattach [options]\n");
+       printf("options:\n"
+               "\t-B, --bredr <device>   Attach BR/EDR controller\n"
+               "\t-A, --amp <device>     Attach AMP controller\n"
+               "\t-h, --help             Show help options\n");
+}
+
+static const struct option main_options[] = {
+       { "bredr",   required_argument, NULL, 'B' },
+       { "amp",     required_argument, NULL, 'A' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
+int main(int argc, char *argv[])
+{
+       const char *bredr_path = NULL, *amp_path = NULL;
+       struct pollfd p[5];
+       int i, count = 0;
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "B:A:vh",
+                                               main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'B':
+                       bredr_path = optarg;
+                       break;
+               case 'A':
+                       amp_path = optarg;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (argc - optind > 0) {
+               fprintf(stderr, "Invalid command line parameters\n");
+               return EXIT_FAILURE;
+       }
+
+       if (bredr_path) {
+               unsigned long flags;
+               int fd;
+
+               printf("Attaching BR/EDR controller to %s\n", bredr_path);
+
+               flags = (1 << HCI_UART_RESET_ON_INIT);
+
+               fd = attach_proto(bredr_path, HCI_UART_H4, flags);
+               if (fd >= 0)
+                       p[count++].fd = fd;
+       }
+
+       if (amp_path) {
+               unsigned long flags;
+               int fd;
+
+               printf("Attaching AMP controller to %s\n", amp_path);
+
+               flags = (1 << HCI_UART_RESET_ON_INIT) |
+                       (1 << HCI_UART_CREATE_AMP);
+
+               fd = attach_proto(amp_path, HCI_UART_H4, flags);
+               if (fd >= 0)
+                       p[count++].fd = fd;
+       }
+
+       if (count < 1) {
+               fprintf(stderr, "No controller attached\n");
+               return EXIT_FAILURE;
+       }
+
+       for (i = 0; i < count; i++) {
+               p[i].events = POLLERR | POLLHUP;
+               p[i].revents = 0;
+       }
+
+       while (1) {
+               if (poll(p, count, -1) < 0)
+                       break;
+        }
+
+       for (i = 0; i < count; i++)
+               close(p[i].fd);
+
+       return EXIT_SUCCESS;
+}
diff --git a/tools/btinfo.c b/tools/btinfo.c
new file mode 100644 (file)
index 0000000..ed434e6
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *
+ *  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 <unistd.h>
+#include <stdlib.h>
+#include <alloca.h>
+#include <getopt.h>
+#include <stdbool.h>
+#include <poll.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+
+#include "monitor/bt.h"
+
+#define le16_to_cpu(val) (val)
+#define le32_to_cpu(val) (val)
+#define cpu_to_le16(val) (val)
+#define cpu_to_le32(val) (val)
+
+struct bt_h4_pkt {
+       uint8_t type;
+       union {
+               struct {
+                       uint16_t opcode;
+                       uint8_t plen;
+                       union {
+                               uint8_t data;
+                       };
+               } cmd;
+               struct {
+                       uint8_t event;
+                       uint8_t plen;
+                       union {
+                               uint8_t data;
+                               struct bt_hci_evt_cmd_complete cmd_complete;
+                               struct bt_hci_evt_cmd_status cmd_status;
+                       };
+               } evt;
+       };
+} __attribute__ ((packed));
+
+static bool hci_request(int fd, uint16_t opcode,
+                       const void *cmd_data, uint8_t cmd_len,
+                       void *rsp_data, uint8_t rsp_size, uint8_t *rsp_len)
+{
+       struct bt_h4_pkt *cmd = alloca(4 + cmd_len);
+       struct bt_h4_pkt *rsp = alloca(2048);
+       ssize_t len;
+
+       cmd->type = BT_H4_CMD_PKT;
+       cmd->cmd.opcode = cpu_to_le16(opcode);
+       cmd->cmd.plen = cpu_to_le16(cmd_len);
+       if (cmd_len > 0)
+               memcpy(&cmd->cmd.data, cmd_data, cmd_len);
+
+       if (write(fd, cmd, 4 + cmd_len) < 0) {
+               perror("Failed to write command");
+               return false;
+       }
+
+       len = read(fd, rsp, 2048);
+       if (len < 0) {
+               perror("Failed to read event");
+               return false;
+       }
+
+       if (rsp->type != BT_H4_EVT_PKT) {
+               fprintf(stderr, "Unexpected packet type %d\n", rsp->type);
+               return false;
+       }
+
+       if (rsp->evt.event == BT_HCI_EVT_CMD_COMPLETE) {
+               if (opcode != le16_to_cpu(rsp->evt.cmd_complete.opcode))
+                       return false;
+
+               if (rsp_data)
+                       memcpy(rsp_data, (&rsp->evt.data) + 3, rsp->evt.plen - 3);
+
+               if (rsp_len)
+                       *rsp_len = rsp->evt.plen - 3;
+
+               return true;
+       } else if (rsp->evt.event == BT_HCI_EVT_CMD_STATUS) {
+               if (opcode == le16_to_cpu(rsp->evt.cmd_status.opcode))
+                       return false;
+
+               if (rsp->evt.cmd_status.status != BT_HCI_ERR_SUCCESS)
+                       return false;
+
+               if (rsp_len)
+                       *rsp_len = 0;
+
+               return true;
+       }
+
+       return false;
+}
+
+static int cmd_local(int fd, int argc, char *argv[])
+{
+       struct bt_hci_rsp_read_local_features lf;
+       struct bt_hci_rsp_read_local_version lv;
+       struct bt_hci_rsp_read_local_commands lc;
+       struct bt_hci_cmd_read_local_ext_features lef_cmd;
+       struct bt_hci_rsp_read_local_ext_features lef;
+       uint8_t len;
+
+       if (!hci_request(fd, BT_HCI_CMD_RESET, NULL, 0, NULL, 0, &len))
+               return EXIT_FAILURE;
+
+       if (!hci_request(fd, BT_HCI_CMD_READ_LOCAL_FEATURES, NULL, 0,
+                                               &lf, sizeof(lf), &len))
+               return EXIT_FAILURE;
+
+       if (lf.status != BT_HCI_ERR_SUCCESS)
+               return EXIT_FAILURE;
+
+       printf("Features: 0x%02x 0x%02x 0x%02x 0x%02x "
+                                       "0x%02x 0x%02x 0x%02x 0x%02x\n",
+                                       lf.features[0], lf.features[1],
+                                       lf.features[2], lf.features[3],
+                                       lf.features[4], lf.features[5],
+                                       lf.features[6], lf.features[7]);
+
+       if (!hci_request(fd, BT_HCI_CMD_READ_LOCAL_VERSION, NULL, 0,
+                                               &lv, sizeof(lv), &len))
+               return EXIT_FAILURE;
+
+       if (lv.status != BT_HCI_ERR_SUCCESS)
+               return EXIT_FAILURE;
+
+       printf("Version: %d\n", lv.hci_ver);
+       printf("Manufacturer: %d\n", le16_to_cpu(lv.manufacturer));
+
+       if (!hci_request(fd, BT_HCI_CMD_READ_LOCAL_COMMANDS, NULL, 0,
+                                               &lc, sizeof(lc), &len))
+               return EXIT_FAILURE;
+
+       if (lc.status != BT_HCI_ERR_SUCCESS)
+               return EXIT_FAILURE;
+
+       if (!(lf.features[7] & 0x80))
+               return EXIT_SUCCESS;
+
+       lef_cmd.page = 0x01;
+
+       if (!hci_request(fd, BT_HCI_CMD_READ_LOCAL_EXT_FEATURES,
+                                               &lef_cmd, sizeof(lef_cmd),
+                                               &lef, sizeof(lef), &len))
+               return EXIT_FAILURE;
+
+       if (lef.status != BT_HCI_ERR_SUCCESS)
+               return EXIT_FAILURE;
+
+       printf("Host features: 0x%02x 0x%02x 0x%02x 0x%02x "
+                                       "0x%02x 0x%02x 0x%02x 0x%02x\n",
+                                       lef.features[0], lef.features[1],
+                                       lef.features[2], lef.features[3],
+                                       lef.features[4], lef.features[5],
+                                       lef.features[6], lef.features[7]);
+
+       if (lef.max_page < 0x02)
+               return EXIT_SUCCESS;
+
+       lef_cmd.page = 0x02;
+
+       if (!hci_request(fd, BT_HCI_CMD_READ_LOCAL_EXT_FEATURES,
+                                               &lef_cmd, sizeof(lef_cmd),
+                                               &lef, sizeof(lef), &len))
+               return EXIT_FAILURE;
+
+       if (lef.status != BT_HCI_ERR_SUCCESS)
+               return EXIT_FAILURE;
+
+       printf("Extended features: 0x%02x 0x%02x 0x%02x 0x%02x "
+                                       "0x%02x 0x%02x 0x%02x 0x%02x\n",
+                                       lef.features[0], lef.features[1],
+                                       lef.features[2], lef.features[3],
+                                       lef.features[4], lef.features[5],
+                                       lef.features[6], lef.features[7]);
+
+       return EXIT_SUCCESS;
+}
+
+typedef int (*cmd_func_t)(int fd, int argc, char *argv[]);
+
+static const struct {
+       const char *name;
+       cmd_func_t func;
+       const char *help;
+} cmd_table[] = {
+       { "local", cmd_local, "Print local controller details" },
+       { }
+};
+
+static void usage(void)
+{
+       int i;
+
+       printf("btinfo - Bluetooth device testing tool\n"
+               "Usage:\n");
+       printf("\tbtinfo [options] <command>\n");
+       printf("options:\n"
+               "\t-i, --device <hcidev>    Use local HCI device\n"
+               "\t-h, --help               Show help options\n");
+       printf("commands:\n");
+       for (i = 0; cmd_table[i].name; i++)
+               printf("\t%-25s%s\n", cmd_table[i].name, cmd_table[i].help);
+}
+
+static const struct option main_options[] = {
+       { "device",  required_argument, NULL, 'i' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
+int main(int argc, char *argv[])
+{
+       const char *device = NULL;
+       cmd_func_t func = NULL;
+       struct sockaddr_hci addr;
+       int result, fd, i;
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "i:vh",
+                                               main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'i':
+                       device = optarg;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       if (argc - optind < 1) {
+               fprintf(stderr, "Missing command argument\n");
+               return EXIT_FAILURE;
+       }
+
+       for (i = 0; cmd_table[i].name; i++) {
+               if (!strcmp(cmd_table[i].name, argv[optind])) {
+                       func = cmd_table[i].func;
+                       break;
+               }
+       }
+
+       if (!func) {
+               fprintf(stderr, "Unsupported command specified\n");
+               return EXIT_FAILURE;
+       }
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW | SOCK_CLOEXEC, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open channel");
+               return EXIT_FAILURE;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_channel = HCI_CHANNEL_USER;
+
+       if (device)
+               addr.hci_dev = atoi(device);
+       else
+               addr.hci_dev = 0;
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind channel");
+               close(fd);
+               return EXIT_FAILURE;
+       }
+
+       result = func(fd, argc - optind - 1, argv + optind + 1);
+
+       close(fd);
+
+       return result;
+}
similarity index 68%
rename from test/btiotest.c
rename to tools/btiotest.c
index 66a7dd2..a77eba1 100644 (file)
  *  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 <stdint.h>
 
 #include <glib.h>
 
-#include "btio.h"
+#include <btio/btio.h>
 
 #define DEFAULT_ACCEPT_TIMEOUT 2
-static gint opt_update_sec = 0;
+static int opt_update_sec = 0;
 
 struct io_data {
        guint ref;
        GIOChannel *io;
-       BtIOType type;
-       gint reject;
-       gint disconn;
-       gint accept;
+       int reject;
+       int disconn;
+       int accept;
+       int voice;
 };
 
 static void io_data_unref(struct io_data *data)
@@ -63,14 +68,13 @@ static struct io_data *io_data_ref(struct io_data *data)
        return data;
 }
 
-static struct io_data *io_data_new(GIOChannel *io, BtIOType type, gint reject,
-                                               gint disconn, gint accept)
+static struct io_data *io_data_new(GIOChannel *io, int reject, int disconn,
+                                                               int accept)
 {
        struct io_data *data;
 
        data = g_new0(struct io_data, 1);
        data->io = io;
-       data->type = type;
        data->reject = reject;
        data->disconn = disconn;
        data->accept = accept;
@@ -100,9 +104,8 @@ 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)) {
+       if (!bt_io_get(data->io, &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;
@@ -113,9 +116,8 @@ static void update_sec_level(struct io_data *data)
        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)) {
+       if (!bt_io_set(data->io, &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);
        }
@@ -126,15 +128,15 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
        struct io_data *data = user_data;
        GIOCondition cond;
        char addr[18];
-       uint16_t handle;
-       uint8_t cls[3];
+       uint16_t handle, omtu, imtu;
+       uint8_t cls[3], key_size;
 
        if (err) {
                printf("Connecting failed: %s\n", err->message);
                return;
        }
 
-       if (!bt_io_get(io, data->type, &err,
+       if (!bt_io_get(io, &err,
                        BT_IO_OPT_DEST, addr,
                        BT_IO_OPT_HANDLE, &handle,
                        BT_IO_OPT_CLASS, cls,
@@ -148,32 +150,20 @@ static void connect_cb(GIOChannel *io, GError *err, gpointer user_data)
        printf("Successfully connected to %s. handle=%u, class=%02x%02x%02x\n",
                        addr, handle, cls[0], cls[1], cls[2]);
 
-       if (data->type == BT_IO_L2CAP || data->type == BT_IO_SCO) {
-               uint16_t omtu, imtu;
-
-               if (!bt_io_get(io, data->type, &err,
-                                       BT_IO_OPT_OMTU, &omtu,
+       if (!bt_io_get(io, &err, BT_IO_OPT_OMTU, &omtu,
                                        BT_IO_OPT_IMTU, &imtu,
                                        BT_IO_OPT_INVALID)) {
-                       printf("Unable to get L2CAP MTU sizes: %s\n",
-                                                               err->message);
-                       g_clear_error(&err);
-               } else
-                       printf("imtu=%u, omtu=%u\n", imtu, omtu);
-       }
-
-       if (data->type == BT_IO_L2CAP) {
-               uint8_t key_size;
+               printf("Unable to get MTU sizes: %s\n", err->message);
+               g_clear_error(&err);
+       } else
+               printf("imtu=%u, omtu=%u\n", imtu, omtu);
 
-               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 (!bt_io_get(io, &err, BT_IO_OPT_KEY_SIZE, &key_size,
+                                                       BT_IO_OPT_INVALID)) {
+               printf("Unable to get 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);
@@ -234,8 +224,7 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
        struct io_data *data = user_data;
        GError *err = NULL;
 
-       if (!bt_io_get(io, data->type, &err, BT_IO_OPT_DEST, addr,
-                                                       BT_IO_OPT_INVALID)) {
+       if (!bt_io_get(io, &err, BT_IO_OPT_DEST, addr, BT_IO_OPT_INVALID)) {
                printf("bt_io_get(OPT_DEST): %s\n", err->message);
                g_clear_error(&err);
        } else
@@ -250,6 +239,14 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
                return;
        }
 
+       if (data->voice) {
+               if (!bt_io_set(io, &err, BT_IO_OPT_VOICE, data->voice,
+                                                       BT_IO_OPT_INVALID)) {
+                       printf("bt_io_set(OPT_VOICE): %s\n", err->message);
+                       g_clear_error(&err);
+               }
+       }
+
        data->io = g_io_channel_ref(io);
        io_data_ref(data);
 
@@ -263,7 +260,7 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
                        return;
                }
        } else {
-               gint seconds = (data->reject > 0) ?
+               int seconds = (data->reject > 0) ?
                                                data->reject : data->accept;
                g_timeout_add_seconds_full(G_PRIORITY_DEFAULT, seconds,
                                        confirm_timeout, data,
@@ -271,38 +268,40 @@ static void confirm_cb(GIOChannel *io, gpointer user_data)
        }
 }
 
-static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
-                                               uint16_t cid, gint disconn,
-                                               gint sec, gint prio)
+static void l2cap_connect(const char *src, const char *dst, uint8_t addr_type,
+                               uint16_t psm, uint16_t cid, int disconn,
+                               int sec, int prio)
 {
        struct io_data *data;
        GError *err = NULL;
 
        printf("Connecting to %s L2CAP PSM %u\n", dst, psm);
 
-       data = io_data_new(NULL, BT_IO_L2CAP, -1, disconn, -1);
+       data = io_data_new(NULL, -1, disconn, -1);
 
        if (src)
-               data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
-                                               (GDestroyNotify) io_data_unref,
-                                               &err,
-                                               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);
+               data->io = bt_io_connect(connect_cb, data,
+                                       (GDestroyNotify) io_data_unref,
+                                       &err,
+                                       BT_IO_OPT_SOURCE, src,
+                                       BT_IO_OPT_DEST, dst,
+                                       BT_IO_OPT_DEST_TYPE, addr_type,
+                                       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);
        else
-               data->io = bt_io_connect(BT_IO_L2CAP, connect_cb, data,
-                                               (GDestroyNotify) io_data_unref,
-                                               &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);
+               data->io = bt_io_connect(connect_cb, data,
+                                       (GDestroyNotify) io_data_unref,
+                                       &err,
+                                       BT_IO_OPT_DEST, dst,
+                                       BT_IO_OPT_DEST_TYPE, addr_type,
+                                       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);
 
        if (!data->io) {
                printf("Connecting to %s failed: %s\n", dst, err->message);
@@ -311,9 +310,10 @@ static void l2cap_connect(const char *src, const char *dst, uint16_t psm,
        }
 }
 
-static void l2cap_listen(const char *src, uint16_t psm, gint defer,
-                               gint reject, gint disconn, gint accept,
-                               gint sec, gboolean master)
+static void l2cap_listen(const char *src, uint8_t addr_type, uint16_t psm,
+                               uint16_t cid, int defer, int reject,
+                               int disconn, int accept, int sec,
+                               gboolean master)
 {
        struct io_data *data;
        BtIOConnect conn;
@@ -329,24 +329,32 @@ static void l2cap_listen(const char *src, uint16_t psm, gint defer,
                cfm = NULL;
        }
 
-       printf("Listening on L2CAP PSM %u\n", psm);
+       if (cid)
+               printf("Listening on L2CAP CID 0x%04x (%u)\n", cid, cid);
+       else
+               printf("Listening on L2CAP PSM 0x%04x (%u)\n", psm, psm);
+
 
-       data = io_data_new(NULL, BT_IO_L2CAP, reject, disconn, accept);
+       data = io_data_new(NULL, reject, disconn, accept);
 
        if (src)
-               l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
-                                       data, (GDestroyNotify) io_data_unref,
+               l2_srv = bt_io_listen(conn, cfm, data,
+                                       (GDestroyNotify) io_data_unref,
                                        &err,
                                        BT_IO_OPT_SOURCE, src,
+                                       BT_IO_OPT_SOURCE_TYPE, addr_type,
                                        BT_IO_OPT_PSM, psm,
+                                       BT_IO_OPT_CID, cid,
                                        BT_IO_OPT_SEC_LEVEL, sec,
                                        BT_IO_OPT_MASTER, master,
                                        BT_IO_OPT_INVALID);
        else
-               l2_srv = bt_io_listen(BT_IO_L2CAP, conn, cfm,
-                                       data, (GDestroyNotify) io_data_unref,
+               l2_srv = bt_io_listen(conn, cfm, data,
+                                       (GDestroyNotify) io_data_unref,
                                        &err,
+                                       BT_IO_OPT_SOURCE_TYPE, addr_type,
                                        BT_IO_OPT_PSM, psm,
+                                       BT_IO_OPT_CID, cid,
                                        BT_IO_OPT_SEC_LEVEL, sec,
                                        BT_IO_OPT_MASTER, master,
                                        BT_IO_OPT_INVALID);
@@ -361,17 +369,17 @@ static void l2cap_listen(const char *src, uint16_t psm, gint defer,
 }
 
 static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
-                                               gint disconn, gint sec)
+                                               int disconn, int sec)
 {
        struct io_data *data;
        GError *err = NULL;
 
        printf("Connecting to %s RFCOMM channel %u\n", dst, ch);
 
-       data = io_data_new(NULL, BT_IO_RFCOMM, -1, disconn, -1);
+       data = io_data_new(NULL, -1, disconn, -1);
 
        if (src)
-               data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
+               data->io = bt_io_connect(connect_cb, data,
                                                (GDestroyNotify) io_data_unref,
                                                &err,
                                                BT_IO_OPT_SOURCE, src,
@@ -380,7 +388,7 @@ static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
                                                BT_IO_OPT_SEC_LEVEL, sec,
                                                BT_IO_OPT_INVALID);
        else
-               data->io = bt_io_connect(BT_IO_RFCOMM, connect_cb, data,
+               data->io = bt_io_connect(connect_cb, data,
                                                (GDestroyNotify) io_data_unref,
                                                &err,
                                                BT_IO_OPT_DEST, dst,
@@ -396,8 +404,8 @@ static void rfcomm_connect(const char *src, const char *dst, uint8_t ch,
 }
 
 static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
-                               gint reject, gint disconn, gint accept,
-                               gint sec, gboolean master)
+                               int reject, int disconn, int accept,
+                               int sec, gboolean master)
 {
        struct io_data *data;
        BtIOConnect conn;
@@ -413,10 +421,10 @@ static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
                cfm = NULL;
        }
 
-       data = io_data_new(NULL, BT_IO_RFCOMM, reject, disconn, accept);
+       data = io_data_new(NULL, reject, disconn, accept);
 
        if (src)
-               rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
+               rc_srv = bt_io_listen(conn, cfm,
                                        data, (GDestroyNotify) io_data_unref,
                                        &err,
                                        BT_IO_OPT_SOURCE, src,
@@ -425,7 +433,7 @@ static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
                                        BT_IO_OPT_MASTER, master,
                                        BT_IO_OPT_INVALID);
        else
-               rc_srv = bt_io_listen(BT_IO_RFCOMM, conn, cfm,
+               rc_srv = bt_io_listen(conn, cfm,
                                        data, (GDestroyNotify) io_data_unref,
                                        &err,
                                        BT_IO_OPT_CHANNEL, ch,
@@ -439,36 +447,37 @@ static void rfcomm_listen(const char *src, uint8_t ch, gboolean defer,
                exit(EXIT_FAILURE);
        }
 
-       bt_io_get(rc_srv, BT_IO_RFCOMM, &err,
-                       BT_IO_OPT_CHANNEL, &ch,
-                       BT_IO_OPT_INVALID);
+       bt_io_get(rc_srv, &err, BT_IO_OPT_CHANNEL, &ch, BT_IO_OPT_INVALID);
 
        printf("Listening on RFCOMM channel %u\n", ch);
 
        g_io_channel_unref(rc_srv);
 }
 
-static void sco_connect(const char *src, const char *dst, gint disconn)
+static void sco_connect(const char *src, const char *dst, int disconn,
+                                                               int voice)
 {
        struct io_data *data;
        GError *err = NULL;
 
        printf("Connecting SCO to %s\n", dst);
 
-       data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
+       data = io_data_new(NULL, -1, disconn, -1);
 
        if (src)
-               data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
+               data->io = bt_io_connect(connect_cb, data,
                                                (GDestroyNotify) io_data_unref,
                                                &err,
                                                BT_IO_OPT_SOURCE, src,
                                                BT_IO_OPT_DEST, dst,
+                                               BT_IO_OPT_VOICE, voice,
                                                BT_IO_OPT_INVALID);
        else
-               data->io = bt_io_connect(BT_IO_SCO, connect_cb, data,
+               data->io = bt_io_connect(connect_cb, data,
                                                (GDestroyNotify) io_data_unref,
                                                &err,
                                                BT_IO_OPT_DEST, dst,
+                                               BT_IO_OPT_VOICE, voice,
                                                BT_IO_OPT_INVALID);
 
        if (!data->io) {
@@ -478,26 +487,42 @@ static void sco_connect(const char *src, const char *dst, gint disconn)
        }
 }
 
-static void sco_listen(const char *src, gint disconn)
+static void sco_listen(const char *src, gboolean defer, int reject,
+                               int disconn, int accept, int voice)
 {
        struct io_data *data;
+       BtIOConnect conn;
+       BtIOConfirm cfm;
        GIOChannel *sco_srv;
        GError *err = NULL;
 
        printf("Listening for SCO connections\n");
 
-       data = io_data_new(NULL, BT_IO_SCO, -1, disconn, -1);
+       if (defer) {
+               conn = NULL;
+               cfm = confirm_cb;
+       } else {
+               conn = connect_cb;
+               cfm = NULL;
+       }
+
+       data = io_data_new(NULL, reject, disconn, accept);
+
+       data->voice = voice;
 
        if (src)
-               sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
-                                       data, (GDestroyNotify) io_data_unref,
+               sco_srv = bt_io_listen(conn, cfm, data,
+                                       (GDestroyNotify) io_data_unref,
                                        &err,
                                        BT_IO_OPT_SOURCE, src,
+                                       BT_IO_OPT_VOICE, voice,
                                        BT_IO_OPT_INVALID);
        else
-               sco_srv = bt_io_listen(BT_IO_SCO, connect_cb, NULL,
-                                       data, (GDestroyNotify) io_data_unref,
-                                       &err, BT_IO_OPT_INVALID);
+               sco_srv = bt_io_listen(conn, cfm, data,
+                                       (GDestroyNotify) io_data_unref,
+                                       &err,
+                                       BT_IO_OPT_VOICE, voice,
+                                       BT_IO_OPT_INVALID);
 
        if (!sco_srv) {
                printf("Listening failed: %s\n", err->message);
@@ -508,18 +533,20 @@ static void sco_listen(const char *src, gint disconn)
        g_io_channel_unref(sco_srv);
 }
 
-static gint opt_channel = -1;
-static gint opt_psm = 0;
+static int opt_channel = -1;
+static int opt_psm = 0;
 static gboolean opt_sco = FALSE;
 static gboolean opt_defer = FALSE;
+static gint opt_voice = 0;
 static char *opt_dev = NULL;
-static gint opt_reject = -1;
-static gint opt_disconn = -1;
-static gint opt_accept = DEFAULT_ACCEPT_TIMEOUT;
-static gint opt_sec = 0;
+static int opt_reject = -1;
+static int opt_disconn = -1;
+static int opt_accept = DEFAULT_ACCEPT_TIMEOUT;
+static int opt_sec = 0;
 static gboolean opt_master = FALSE;
-static gint opt_priority = 0;
-static gint opt_cid = 0;
+static int opt_priority = 0;
+static int opt_cid = 0;
+static guint8 opt_addr_type = 0;
 
 static GMainLoop *main_loop;
 
@@ -530,10 +557,16 @@ static GOptionEntry options[] = {
                                "L2CAP PSM" },
        { "cid", 'j', 0, G_OPTION_ARG_INT, &opt_cid,
                                "L2CAP CID" },
+       { "addr-type", 't', 0, G_OPTION_ARG_INT, &opt_addr_type,
+                               "Address type "
+                               "(0 BR/EDR 1 LE Public 2 LE Random" },
        { "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" },
+       { "voice", 'V', 0, G_OPTION_ARG_INT, &opt_voice,
+                               "Voice setting "
+                               "(0x0060 CVSD, 0x0003 Transparent)" },
        { "sec-level", 'S', 0, G_OPTION_ARG_INT, &opt_sec,
                                "Security level" },
        { "update-sec-level", 'U', 0, G_OPTION_ARG_INT, &opt_update_sec,
@@ -572,18 +605,19 @@ int main(int argc, char *argv[])
 
        g_option_context_free(context);
 
-       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);
+       printf("accept=%d reject=%d discon=%d defer=%d sec=%d update_sec=%d"
+               " prio=%d voice=0x%04x\n", opt_accept, opt_reject, opt_disconn,
+               opt_defer, opt_sec, opt_update_sec, opt_priority, opt_voice);
 
        if (opt_psm || opt_cid) {
                if (argc > 1)
-                       l2cap_connect(opt_dev, argv[1], opt_psm, opt_cid,
-                                       opt_disconn, opt_sec, opt_priority);
+                       l2cap_connect(opt_dev, argv[1], opt_addr_type,
+                                       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,
-                                       opt_master);
+                       l2cap_listen(opt_dev, opt_addr_type, opt_psm, opt_cid,
+                                       opt_defer, opt_reject, opt_disconn,
+                                       opt_accept, opt_sec, opt_master);
        }
 
        if (opt_channel != -1) {
@@ -598,9 +632,10 @@ int main(int argc, char *argv[])
 
        if (opt_sco) {
                if (argc > 1)
-                       sco_connect(opt_dev, argv[1], opt_disconn);
+                       sco_connect(opt_dev, argv[1], opt_disconn, opt_voice);
                else
-                       sco_listen(opt_dev, opt_disconn);
+                       sco_listen(opt_dev, opt_defer, opt_reject,
+                                       opt_disconn, opt_accept, opt_voice);
        }
 
        signal(SIGTERM, sig_term);
similarity index 56%
rename from mgmt/main.c
rename to tools/btmgmt.c
index b2d6c3c..1d71d74 100644 (file)
 #include <bluetooth/hci_lib.h>
 #include <bluetooth/sdp.h>
 #include <bluetooth/sdp_lib.h>
-#include <bluetooth/mgmt.h>
 
 #include <glib.h>
+
+#include "src/shared/mgmt.h"
 #include "glib-helper.h"
+#include "lib/mgmt.h"
+#include "eir.h"
+
+static GMainLoop *event_loop = NULL;
 
 static bool monitor = false;
 static bool discovery = false;
 static bool resolve_names = true;
 
-typedef void (*cmd_cb)(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data);
-
-static struct pending_cmd {
-       uint16_t op;
-       uint16_t id;
-       cmd_cb cb;
-       void *user_data;
-       struct pending_cmd *next;
-} *pending = NULL;
-
-static int mgmt_send_cmd(int mgmt_sk, uint16_t op, uint16_t id, void *data,
-                               size_t len, cmd_cb func, void *user_data)
-{
-       char buf[1024];
-       struct pending_cmd *cmd;
-       struct mgmt_hdr *hdr = (void *) buf;
-
-       if (len + MGMT_HDR_SIZE > sizeof(buf))
-               return -EINVAL;
-
-       cmd = calloc(1, sizeof(struct pending_cmd));
-       if (cmd == NULL)
-               return -errno;
-
-       cmd->op = op;
-       cmd->id = id;
-       cmd->cb = func;
-       cmd->user_data = user_data;
-
-       memset(buf, 0, sizeof(buf));
-       hdr->opcode = htobs(op);
-       hdr->index = htobs(id);
-       hdr->len = htobs(len);
-       memcpy(buf + MGMT_HDR_SIZE, data, len);
-
-       if (write(mgmt_sk, buf, MGMT_HDR_SIZE + len) < 0) {
-               fprintf(stderr, "Unable to write to socket: %s\n",
-                                                       strerror(errno));
-               free(cmd);
-               return -1;
-       }
-
-       cmd->next = pending;
-       pending = cmd;
-
-       return 0;
-}
-
-static int mgmt_open(void)
-{
-       struct sockaddr_hci addr;
-       int sk;
-
-       sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
-       if (sk < 0) {
-               fprintf(stderr, "socket: %s\n", strerror(errno));
-               return sk;
-       }
-
-       memset(&addr, 0, sizeof(addr));
-       addr.hci_family = AF_BLUETOOTH;
-       addr.hci_dev = HCI_DEV_NONE;
-       addr.hci_channel = HCI_CHANNEL_CONTROL;
-
-       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
-               fprintf(stderr, "bind: %s\n", strerror(errno));
-               close(sk);
-               return -1;
-       }
-
-       return sk;
-}
-
-static void mgmt_check_pending(int mgmt_sk, uint16_t op, uint16_t index,
-                               uint16_t status, void *data, uint16_t len)
-{
-       struct pending_cmd *c, *prev;
-
-       for (c = pending, prev = NULL; c != NULL; prev = c, c = c->next) {
-               if (c->op != op)
-                       continue;
-               if (c->id != index)
-                       continue;
-
-               if (c == pending)
-                       pending = c->next;
-               else
-                       prev->next = c->next;
-
-               c->cb(mgmt_sk, op, index, status, data, len, c->user_data);
-
-               free(c);
-               break;
-       }
-}
-
-static int mgmt_cmd_complete(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_cmd_complete *ev, uint16_t len)
-{
-       uint16_t op;
-
-       if (len < sizeof(*ev)) {
-               fprintf(stderr, "Too short (%u bytes) cmd complete event\n",
-                                                                       len);
-               return -EINVAL;
-       }
-
-       op = bt_get_le16(&ev->opcode);
-
-       len -= sizeof(*ev);
-
-       if (monitor)
-               printf("%s complete, opcode 0x%04x len %u\n", mgmt_opstr(op),
-                                                               op, len);
-
-       mgmt_check_pending(mgmt_sk, op, index, ev->status, ev->data, len);
-
-       return 0;
-}
+static int pending = 0;
 
-static int mgmt_cmd_status(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_cmd_status *ev, uint16_t len)
+static void controller_error(uint16_t index, uint16_t len,
+                               const void *param, void *user_data)
 {
-       uint16_t opcode;
+       const struct mgmt_ev_controller_error *ev = param;
 
        if (len < sizeof(*ev)) {
-               fprintf(stderr, "Too short (%u bytes) cmd status event\n",
-                                                                       len);
-               return -EINVAL;
-       }
-
-       opcode = bt_get_le16(&ev->opcode);
-
-       if (monitor)
-               printf("cmd status, opcode 0x%04x status 0x%02x (%s)\n",
-                               opcode, ev->status, mgmt_errstr(ev->status));
-
-       if (ev->status != 0)
-               mgmt_check_pending(mgmt_sk, opcode, index, ev->status,
-                                                               NULL, 0);
-
-       return 0;
-}
-
-static int mgmt_controller_error(uint16_t index,
-                                       struct mgmt_ev_controller_error *ev,
-                                       uint16_t len)
-{
-       if (len < sizeof(*ev)) {
                fprintf(stderr,
                        "Too short (%u bytes) controller error event\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor)
                printf("hci%u error 0x%02x\n", index, ev->error_code);
-
-       return 0;
 }
 
-static int mgmt_index_added(int mgmt_sk, uint16_t index)
+static void index_added(uint16_t index, uint16_t len,
+                               const void *param, void *user_data)
 {
        if (monitor)
                printf("hci%u added\n", index);
-       return 0;
 }
 
-static int mgmt_index_removed(int mgmt_sk, uint16_t index)
+static void index_removed(uint16_t index, uint16_t len,
+                               const void *param, void *user_data)
 {
        if (monitor)
                printf("hci%u removed\n", index);
-       return 0;
 }
 
 static const char *settings_str[] = {
@@ -233,7 +94,8 @@ static const char *settings_str[] = {
                                "ssp",
                                "br/edr",
                                "hs",
-                               "le" ,
+                               "le",
+                               "advertising",
 };
 
 static void print_settings(uint32_t settings)
@@ -246,12 +108,14 @@ static void print_settings(uint32_t settings)
        }
 }
 
-static int mgmt_new_settings(int mgmt_sk, uint16_t index,
-                                       uint32_t *ev, uint16_t len)
+static void new_settings(uint16_t index, uint16_t len,
+                                       const void *param, void *user_data)
 {
+       const uint32_t *ev = param;
+
        if (len < sizeof(*ev)) {
                fprintf(stderr, "Too short new_settings event (%u)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
@@ -259,37 +123,38 @@ static int mgmt_new_settings(int mgmt_sk, uint16_t index,
                print_settings(bt_get_le32(ev));
                printf("\n");
        }
-
-       return 0;
 }
 
-static int mgmt_discovering(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_discovering *ev, uint16_t len)
+static void discovering(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_discovering *ev = param;
+
        if (len < sizeof(*ev)) {
                fprintf(stderr, "Too short (%u bytes) discovering event\n",
                                                                        len);
-               return -EINVAL;
+               return;
        }
 
-       if (ev->discovering == 0 && discovery)
-               exit(EXIT_SUCCESS);
+       if (ev->discovering == 0 && discovery) {
+               g_main_loop_quit(event_loop);
+               return;
+       }
 
        if (monitor)
                printf("hci%u type %u discovering %s\n", index,
                                ev->type, ev->discovering ? "on" : "off");
-
-       return 0;
 }
 
-static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_new_link_key *ev, uint16_t len)
+static void new_link_key(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_new_link_key *ev = param;
 
        if (len != sizeof(*ev)) {
                fprintf(stderr, "Invalid new_link_key length (%u bytes)\n",
                                                                        len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
@@ -299,8 +164,6 @@ static int mgmt_new_link_key(int mgmt_sk, uint16_t index,
                                "store_hint %u\n", index, addr, ev->key.type,
                                ev->key.pin_len, ev->store_hint);
        }
-
-       return 0;
 }
 
 static const char *typestr(uint8_t type)
@@ -313,23 +176,23 @@ static const char *typestr(uint8_t type)
        return "(unknown)";
 }
 
-static int mgmt_connected(int mgmt_sk, uint16_t index,
-                                       struct mgmt_ev_device_connected *ev,
-                                       uint16_t len)
+static void connected(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_device_connected *ev = param;
        uint16_t eir_len;
 
        if (len < sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid connected event length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        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;
+               return;
        }
 
        if (monitor) {
@@ -338,37 +201,43 @@ static int mgmt_connected(int mgmt_sk, uint16_t index,
                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)
+static void disconnected(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       if (len != sizeof(*ev)) {
+       const struct mgmt_ev_device_disconnected *ev = param;
+
+       if (len < sizeof(struct mgmt_addr_info)) {
                fprintf(stderr,
                        "Invalid disconnected event length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
                char addr[18];
-               ba2str(&ev->bdaddr, addr);
-               printf("hci%u %s type %s disconnected\n", index, addr,
-                                                       typestr(ev->type));
-       }
+               uint8_t reason;
 
-       return 0;
+               if (len < sizeof(*ev))
+                       reason = MGMT_DEV_DISCONN_UNKNOWN;
+               else
+                       reason = ev->reason;
+
+               ba2str(&ev->addr.bdaddr, addr);
+               printf("hci%u %s type %s disconnected with reason %u\n",
+                               index, addr, typestr(ev->addr.type), reason);
+       }
 }
 
-static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_connect_failed *ev,
-                               uint16_t len)
+static void conn_failed(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_connect_failed *ev = param;
+
        if (len != sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid connect_failed event length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
@@ -378,18 +247,17 @@ static int mgmt_conn_failed(int mgmt_sk, uint16_t index,
                                index, addr, typestr(ev->addr.type), ev->status,
                                mgmt_errstr(ev->status));
        }
-
-       return 0;
 }
 
-static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_auth_failed *ev,
-                               uint16_t len)
+static void auth_failed(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_auth_failed *ev = param;
+
        if (len != sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid auth_failed event length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
@@ -398,86 +266,93 @@ static int mgmt_auth_failed(int mgmt_sk, uint16_t index,
                printf("hci%u %s auth failed with status 0x%02x (%s)\n",
                        index, addr, ev->status, mgmt_errstr(ev->status));
        }
-
-       return 0;
 }
 
-static int mgmt_name_changed(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_local_name_changed *ev,
-                               uint16_t len)
+static void local_name_changed(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_local_name_changed *ev = param;
+
        if (len != sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid local_name_changed length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor)
                printf("hci%u name changed: %s\n", index, ev->name);
-
-       return 0;
 }
 
-static void confirm_name_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-                               uint8_t status, void *rsp, uint16_t len,
-                               void *user_data)
+static void confirm_name_rsp(uint8_t status, uint16_t len,
+                                       const void *param, void *user_data)
 {
-       struct mgmt_rp_confirm_name *rp = rsp;
+       const struct mgmt_rp_confirm_name *rp = param;
        char addr[18];
 
        if (len == 0 && status != 0) {
                fprintf(stderr,
-                       "hci%u confirm_name failed with status 0x%02x (%s)\n",
-                                       id, status, mgmt_errstr(status));
+                       "confirm_name failed with status 0x%02x (%s)\n",
+                                       status, mgmt_errstr(status));
                return;
        }
 
        if (len != sizeof(*rp)) {
-               fprintf(stderr,
-                       "hci%u confirm_name rsp length %u instead of %zu\n",
-                       id, len, sizeof(*rp));
+               fprintf(stderr, "confirm_name rsp length %u instead of %zu\n",
+                       len, sizeof(*rp));
                return;
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
        if (status != 0)
-               fprintf(stderr,
-                       "hci%u confirm_name for %s failed: 0x%02x (%s)\n",
-                       id, addr, status, mgmt_errstr(status));
+               fprintf(stderr, "confirm_name for %s failed: 0x%02x (%s)\n",
+                       addr, status, mgmt_errstr(status));
        else
-               printf("hci%u confirm_name succeeded for %s\n", id, addr);
+               printf("confirm_name succeeded for %s\n", addr);
 }
 
-static int mgmt_device_found(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_device_found *ev, uint16_t len)
+static void device_found(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_device_found *ev = param;
+       struct mgmt *mgmt = user_data;
        uint32_t flags;
        uint16_t eir_len;
+       struct eir_data eir;
 
        if (len < sizeof(*ev)) {
                fprintf(stderr,
                        "Too short device_found length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
-       flags = btohs(ev->flags);
+       flags = btohl(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",
+               fprintf(stderr, "dev_found: expected %zu bytes, got %u bytes\n",
                                                sizeof(*ev) + eir_len, len);
-               return -EINVAL;
+               return;
        }
 
+       memset(&eir, 0, sizeof(eir));
+       eir_parse(&eir, ev->eir, eir_len);
+
        if (monitor || discovery) {
                char addr[18];
                ba2str(&ev->addr.bdaddr, addr);
                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);
+                       "flags 0x%04x ", index, addr,
+                       typestr(ev->addr.type), ev->rssi, flags);
+
+               if (eir.name)
+                       printf("name %s\n", eir.name);
+               else
+                       printf("eir_len %u\n", eir_len);
        }
 
+       eir_data_free(&eir);
+
        if (discovery && (flags & MGMT_DEV_FOUND_CONFIRM_NAME)) {
                struct mgmt_cp_confirm_name cp;
 
@@ -488,30 +363,28 @@ static int mgmt_device_found(int mgmt_sk, uint16_t index,
                else
                        cp.name_known = 1;
 
-               mgmt_send_cmd(mgmt_sk, MGMT_OP_CONFIRM_NAME, index,
-                                       &cp, sizeof(cp), confirm_name_rsp,
-                                       NULL);
+               mgmt_reply(mgmt, MGMT_OP_CONFIRM_NAME, index, sizeof(cp), &cp,
+                                               confirm_name_rsp, NULL, NULL);
        }
-
-       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)
+static void pin_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
        if (status != 0) {
                fprintf(stderr,
-                       "hci%u PIN Code reply failed with status 0x%02x (%s)",
-                                       id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+                       "PIN Code reply failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               g_main_loop_quit(event_loop);
+               return;
        }
 
-       printf("hci%u PIN Reply successful\n", id);
+       printf("PIN Reply successful\n");
 }
 
-static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
-                                               struct mgmt_addr_info *addr,
-                                               const char *pin, size_t len)
+static int mgmt_pin_reply(struct mgmt *mgmt, uint16_t index,
+                                       const struct mgmt_addr_info *addr,
+                                       const char *pin, size_t len)
 {
        struct mgmt_cp_pin_code_reply cp;
 
@@ -520,46 +393,48 @@ static int mgmt_pin_reply(int mgmt_sk, uint16_t index,
        cp.pin_len = len;
        memcpy(cp.pin_code, pin, len);
 
-       return mgmt_send_cmd(mgmt_sk, MGMT_OP_PIN_CODE_REPLY, index,
-                                       &cp, sizeof(cp), pin_rsp, NULL);
+       return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_REPLY, index, sizeof(cp), &cp,
+                                                       pin_rsp, NULL, NULL);
 }
 
-static void pin_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void pin_neg_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
        if (status != 0) {
                fprintf(stderr,
-                       "hci%u PIN Neg reply failed with status 0x%02x (%s)",
-                                       id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+                       "PIN Neg reply failed with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               g_main_loop_quit(event_loop);
+               return;
        }
 
-       printf("hci%u PIN Negative Reply successful\n", id);
+       printf("PIN Negative Reply successful\n");
 }
 
-static int mgmt_pin_neg_reply(int mgmt_sk, uint16_t index,
-                                               struct mgmt_addr_info *addr)
+static int mgmt_pin_neg_reply(struct mgmt *mgmt, uint16_t index,
+                                       const struct mgmt_addr_info *addr)
 {
        struct mgmt_cp_pin_code_neg_reply cp;
 
        memset(&cp, 0, sizeof(cp));
        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);
+       return mgmt_reply(mgmt, MGMT_OP_PIN_CODE_NEG_REPLY, index,
+                               sizeof(cp), &cp, pin_neg_rsp, NULL, NULL);
 }
 
-static int mgmt_request_pin(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_pin_code_request *ev,
-                               uint16_t len)
+static void request_pin(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_pin_code_request *ev = param;
+       struct mgmt *mgmt = user_data;
        char pin[18];
        size_t pin_len;
 
        if (len != sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid pin_code request length (%u bytes)\n", len);
-               return -EINVAL;
+               return;
        }
 
        if (monitor) {
@@ -573,8 +448,10 @@ 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->addr);
+       if (fgets(pin, sizeof(pin), stdin) == NULL || pin[0] == '\n') {
+               mgmt_pin_neg_reply(mgmt, index, &ev->addr);
+               return;
+       }
 
        pin_len = strlen(pin);
        if (pin[pin_len - 1] == '\n') {
@@ -582,64 +459,67 @@ static int mgmt_request_pin(int mgmt_sk, uint16_t index,
                pin_len--;
        }
 
-       return mgmt_pin_reply(mgmt_sk, index, &ev->addr, pin, pin_len);
+       mgmt_pin_reply(mgmt, index, &ev->addr, pin, pin_len);
 }
 
-static void confirm_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void confirm_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
        if (status != 0) {
                fprintf(stderr,
-                       "hci%u User Confirm reply failed. status 0x%02x (%s)",
-                                       id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+                       "User Confirm reply failed. status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               g_main_loop_quit(event_loop);
+               return;
        }
 
-       printf("hci%u User Confirm Reply successful\n", id);
+       printf("User Confirm Reply successful\n");
 }
 
-static int mgmt_confirm_reply(int mgmt_sk, uint16_t index, bdaddr_t *bdaddr)
+static int mgmt_confirm_reply(struct mgmt *mgmt, uint16_t index,
+                                                       const bdaddr_t *bdaddr)
 {
        struct mgmt_cp_user_confirm_reply cp;
 
        memset(&cp, 0, sizeof(cp));
        bacpy(&cp.addr.bdaddr, bdaddr);
 
-       return mgmt_send_cmd(mgmt_sk, MGMT_OP_USER_CONFIRM_REPLY, index,
-                                       &cp, sizeof(cp), confirm_rsp, NULL);
+       return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_REPLY, index,
+                               sizeof(cp), &cp, confirm_rsp, NULL, NULL);
 }
 
-static void confirm_neg_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-                               uint8_t status, void *rsp, uint16_t len,
-                               void *user_data)
+static void confirm_neg_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
        if (status != 0) {
                fprintf(stderr,
-                       "hci%u Confirm Neg reply failed. status 0x%02x (%s)",
-                                       id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+                       "Confirm Neg reply failed. status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               g_main_loop_quit(event_loop);
+               return;
        }
 
-       printf("hci%u User Confirm Negative Reply successful\n", id);
+       printf("User Confirm Negative Reply successful\n");
 }
 
-static int mgmt_confirm_neg_reply(int mgmt_sk, uint16_t index,
-                                                       bdaddr_t *bdaddr)
+static int mgmt_confirm_neg_reply(struct mgmt *mgmt, uint16_t index,
+                                                       const bdaddr_t *bdaddr)
 {
        struct mgmt_cp_user_confirm_reply cp;
 
        memset(&cp, 0, sizeof(cp));
        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);
+       return mgmt_reply(mgmt, MGMT_OP_USER_CONFIRM_NEG_REPLY, index,
+                               sizeof(cp), &cp, confirm_neg_rsp, NULL, NULL);
 }
 
 
-static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
-                               struct mgmt_ev_user_confirm_request *ev,
-                               uint16_t len)
+static void user_confirm(uint16_t index, uint16_t len, const void *param,
+                                                       void *user_data)
 {
+       const struct mgmt_ev_user_confirm_request *ev = param;
+       struct mgmt *mgmt = user_data;
        char rsp[5];
        size_t rsp_len;
        uint32_t val;
@@ -648,7 +528,7 @@ static int mgmt_user_confirm(int mgmt_sk, uint16_t index,
        if (len != sizeof(*ev)) {
                fprintf(stderr,
                        "Invalid user_confirm request length (%u)\n", len);
-               return -EINVAL;
+               return;
        }
 
        ba2str(&ev->addr.bdaddr, addr);
@@ -667,8 +547,10 @@ 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->addr.bdaddr);
+       if (fgets(rsp, sizeof(rsp), stdin) == NULL || rsp[0] == '\n') {
+               mgmt_confirm_neg_reply(mgmt, index, &ev->addr.bdaddr);
+               return;
+       }
 
        rsp_len = strlen(rsp);
        if (rsp[rsp_len - 1] == '\n') {
@@ -677,147 +559,69 @@ 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->addr.bdaddr);
+               mgmt_confirm_reply(mgmt, index, &ev->addr.bdaddr);
        else
-               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,
-                                               void *data, uint16_t len)
-{
-       if (monitor)
-               printf("event: %s\n", mgmt_evstr(ev));
-
-       switch (ev) {
-       case MGMT_EV_CMD_COMPLETE:
-               return mgmt_cmd_complete(mgmt_sk, index, data, len);
-       case MGMT_EV_CMD_STATUS:
-               return mgmt_cmd_status(mgmt_sk, index, data, len);
-       case MGMT_EV_CONTROLLER_ERROR:
-               return mgmt_controller_error(index, data, len);
-       case MGMT_EV_INDEX_ADDED:
-               return mgmt_index_added(mgmt_sk, index);
-       case MGMT_EV_INDEX_REMOVED:
-               return mgmt_index_removed(mgmt_sk, index);
-       case MGMT_EV_NEW_SETTINGS:
-               return mgmt_new_settings(mgmt_sk, index, data, len);
-       case MGMT_EV_DISCOVERING:
-               return mgmt_discovering(mgmt_sk, index, data, len);
-       case MGMT_EV_NEW_LINK_KEY:
-               return mgmt_new_link_key(mgmt_sk, index, data, len);
-       case MGMT_EV_DEVICE_CONNECTED:
-               return mgmt_connected(mgmt_sk, index, data, len);
-       case MGMT_EV_DEVICE_DISCONNECTED:
-               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:
-               return mgmt_auth_failed(mgmt_sk, index, data, len);
-       case MGMT_EV_LOCAL_NAME_CHANGED:
-               return mgmt_name_changed(mgmt_sk, index, data, len);
-       case MGMT_EV_DEVICE_FOUND:
-               return mgmt_device_found(mgmt_sk, index, data, len);
-       case MGMT_EV_PIN_CODE_REQUEST:
-               return mgmt_request_pin(mgmt_sk, index, data, len);
-       case MGMT_EV_USER_CONFIRM_REQUEST:
-               return mgmt_user_confirm(mgmt_sk, index, data, len);
-       default:
-               if (monitor)
-                       printf("Unhandled event 0x%04x (%s)\n", ev, mgmt_evstr(ev));
-               return 0;
-       }
+               mgmt_confirm_neg_reply(mgmt, index, &ev->addr.bdaddr);
 }
 
-static int mgmt_process_data(int mgmt_sk)
-{
-       char buf[1024];
-       struct mgmt_hdr *hdr = (void *) buf;
-       uint16_t len, ev, index;
-       ssize_t ret;
-
-       ret = read(mgmt_sk, buf, sizeof(buf));
-       if (ret < 0) {
-               fprintf(stderr, "read: %s\n", strerror(errno));
-               return ret;
-       }
-
-       if (ret < MGMT_HDR_SIZE) {
-               fprintf(stderr, "Too small mgmt packet (%zd bytes)\n", ret);
-               return 0;
-       }
-
-       ev = bt_get_le16(&hdr->opcode);
-       index = bt_get_le16(&hdr->index);
-       len = bt_get_le16(&hdr->len);
-
-       if (monitor)
-               printf("event 0x%04x len 0x%04x index 0x%04x\n", ev, len, index);
-
-       if (ret != MGMT_HDR_SIZE + len) {
-               fprintf(stderr, "Packet length mismatch. ret %zd len %u",
-                                                               ret, len);
-               return 0;
-       }
-
-       mgmt_handle_event(mgmt_sk, ev, index, buf + MGMT_HDR_SIZE, len);
-
-       return 0;
-}
-
-static void cmd_monitor(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_monitor(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        printf("Monitoring mgmt events...\n");
        monitor = true;
 }
 
-static void version_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void version_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_read_version *rp = rsp;
+       const struct mgmt_rp_read_version *rp = param;
 
        if (status != 0) {
                fprintf(stderr, "Reading mgmt version failed with status"
                        " 0x%02x (%s)\n", status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small version reply (%u bytes)\n", len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        printf("MGMT Version %u, revision %u\n", rp->version,
                                                bt_get_le16(&rp->revision));
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_version(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_version(struct mgmt *mgmt, 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) {
+       if (mgmt_send(mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE,
+                               0, NULL, version_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send read_version cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void commands_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_read_commands *rp = rsp;
-       uint16_t num_commands, num_events, *opcode;
+       const struct mgmt_rp_read_commands *rp = param;
+       uint16_t num_commands, num_events;
+       const uint16_t *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);
+               goto done;
        }
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small commands reply (%u bytes)\n", len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        num_commands = bt_get_le16(&rp->num_commands);
@@ -829,7 +633,7 @@ static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        if (len < expected_len) {
                fprintf(stderr, "Too small commands reply (%u != %zu)\n",
                                                        len, expected_len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        opcode = rp->opcodes;
@@ -846,34 +650,39 @@ static void commands_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                printf("\t%s (0x%04x)\n", mgmt_evstr(ev), ev);
        }
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_commands(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_commands(struct mgmt *mgmt, 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) {
+       if (mgmt_send(mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE,
+                               0, NULL, commands_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send read_commands cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void info_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_read_info *rp = rsp;
+       const struct mgmt_rp_read_info *rp = param;
+       int id = GPOINTER_TO_INT(user_data);
        char addr[18];
 
+       pending--;
+
        if (status != 0) {
                fprintf(stderr,
                        "Reading hci%u info failed with status 0x%02x (%s)\n",
                                        id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small info reply (%u bytes)\n", len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        ba2str(&rp->bdaddr, addr);
@@ -891,14 +700,18 @@ static void info_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
        printf("\n\tname %s\n", rp->name);
        printf("\tshort name %s\n", rp->short_name);
 
-       if (pending == NULL)
-               exit(EXIT_SUCCESS);
+       if (pending > 0)
+               return;
+
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void index_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_read_index_list *rp = rsp;
+       const struct mgmt_rp_read_index_list *rp = param;
+       struct mgmt *mgmt = user_data;
        uint16_t count;
        unsigned int i;
 
@@ -906,13 +719,13 @@ static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                fprintf(stderr,
                        "Reading index list failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small index list reply (%u bytes)\n",
                                                                        len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        count = bt_get_le16(&rp->num_controllers);
@@ -921,7 +734,7 @@ static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                fprintf(stderr,
                        "Index count (%u) doesn't match reply length (%u)\n",
                                                                count, len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (monitor)
@@ -929,36 +742,48 @@ static void index_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                                                count, count > 1 ? "s" : "");
 
        if (count == 0)
-               exit(EXIT_SUCCESS);
+               goto done;
 
        if (monitor && count > 0)
                printf("\t");
 
        for (i = 0; i < count; i++) {
                uint16_t index;
+               void *data;
 
                index = bt_get_le16(&rp->index[i]);
 
                if (monitor)
                        printf("hci%u ", index);
 
-               if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
-                                       0, info_rsp, NULL) < 0) {
+               data = GINT_TO_POINTER((int) index);
+
+               if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL,
+                                               info_rsp, data, NULL) == 0) {
                        fprintf(stderr, "Unable to send read_info cmd\n");
-                       exit(EXIT_FAILURE);
+                       goto done;
                }
+
+               pending++;
        }
 
        if (monitor && count > 0)
                printf("\n");
+
+       return;
+
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_info(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
+       void *data;
+
        if (index == MGMT_INDEX_NONE) {
-               if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INDEX_LIST,
-                                       MGMT_INDEX_NONE, NULL, 0,
-                                       index_rsp, NULL) < 0) {
+               if (mgmt_send(mgmt, MGMT_OP_READ_INDEX_LIST,
+                                       MGMT_INDEX_NONE, 0, NULL,
+                                       index_rsp, mgmt, NULL) == 0) {
                        fprintf(stderr, "Unable to send index_list cmd\n");
                        exit(EXIT_FAILURE);
                }
@@ -966,39 +791,79 @@ static void cmd_info(int mgmt_sk, uint16_t index, int argc, char **argv)
                return;
        }
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_READ_INFO, index, NULL,
-                                               0, info_rsp, NULL) < 0) {
+       data = GINT_TO_POINTER((int) index);
+
+       if (mgmt_send(mgmt, MGMT_OP_READ_INFO, index, 0, NULL, info_rsp,
+                                                       data, NULL) == 0) {
                fprintf(stderr, "Unable to send read_info cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void setting_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+/* Wrapper to get the index and opcode to the response callback */
+struct command_data {
+       uint16_t id;
+       uint16_t op;
+       void (*callback) (uint16_t id, uint16_t op, uint8_t status,
+                                       uint16_t len, const void *param);
+};
+
+static void cmd_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       struct command_data *data = user_data;
+
+       data->callback(data->op, data->id, status, len, param);
+}
+
+static unsigned int send_cmd(struct mgmt *mgmt, uint16_t op, uint16_t id,
+                               uint16_t len, const void *param,
+                               void (*cb)(uint16_t id, uint16_t op,
+                                               uint8_t status, uint16_t len,
+                                               const void *param))
+{
+       struct command_data *data;
+       unsigned int send_id;
+
+       data = g_new0(struct command_data, 1);
+       data->id = id;
+       data->op = op;
+       data->callback = cb;
+
+       send_id = mgmt_send(mgmt, op, id, len, param, cmd_rsp, data, g_free);
+       if (send_id == 0)
+               g_free(data);
+
+       return send_id;
+}
+
+static void setting_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
+                                                       const void *param)
 {
-       uint32_t *rp = rsp;
+       const uint32_t *rp = param;
 
        if (status != 0) {
                fprintf(stderr,
                        "%s for hci%u failed with status 0x%02x (%s)\n",
                        mgmt_opstr(op), id, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small %s response (%u bytes)\n",
                                                        mgmt_opstr(op), len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        printf("hci%u %s complete, settings: ", id, mgmt_opstr(op));
        print_settings(bt_get_le32(rp));
        printf("\n");
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
+static void cmd_setting(struct mgmt *mgmt, uint16_t index, uint16_t op,
                                                        int argc, char **argv)
 {
        uint8_t val;
@@ -1018,24 +883,24 @@ static void cmd_setting(int mgmt_sk, uint16_t index, uint16_t op,
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       if (mgmt_send_cmd(mgmt_sk, op, index, &val, sizeof(val),
-                                               setting_rsp, NULL) < 0) {
+       if (send_cmd(mgmt, op, index, sizeof(val), &val, setting_rsp) == 0) {
                fprintf(stderr, "Unable to send %s cmd\n", mgmt_opstr(op));
                exit(EXIT_FAILURE);
        }
 }
 
-static void cmd_power(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_power(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_POWERED, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_POWERED, argc, argv);
 }
 
-static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_discov(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        struct mgmt_cp_set_discoverable cp;
 
        if (argc < 2) {
-               printf("Usage: btmgmt %s <yes/no> [timeout]\n", argv[0]);
+               printf("Usage: btmgmt %s <yes/no/limited> [timeout]\n", argv[0]);
                exit(EXIT_FAILURE);
        }
 
@@ -1045,6 +910,8 @@ static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
                cp.val = 1;
        else if (strcasecmp(argv[1], "off") == 0)
                cp.val = 0;
+       else if (strcasecmp(argv[1], "limited") == 0)
+               cp.val = 2;
        else
                cp.val = atoi(argv[1]);
 
@@ -1054,66 +921,87 @@ static void cmd_discov(int mgmt_sk, uint16_t index, int argc, char **argv)
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DISCOVERABLE, index,
-                               &cp, sizeof(cp), setting_rsp, NULL) < 0) {
+       if (send_cmd(mgmt, MGMT_OP_SET_DISCOVERABLE, index, sizeof(cp), &cp,
+                                                       setting_rsp) == 0) {
                fprintf(stderr, "Unable to send set_discoverable cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void cmd_connectable(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_connectable(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_CONNECTABLE, argc, argv);
 }
 
-static void cmd_pairable(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_fast_conn(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_PAIRABLE, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_FAST_CONNECTABLE, argc, argv);
 }
 
-static void cmd_linksec(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_pairable(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_PAIRABLE, argc, argv);
 }
 
-static void cmd_ssp(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_linksec(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_SSP, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_LINK_SECURITY, argc, argv);
 }
 
-static void cmd_hs(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_ssp(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_HS, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_SSP, argc, argv);
 }
 
-static void cmd_le(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_hs(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
-       cmd_setting(mgmt_sk, index, MGMT_OP_SET_LE, argc, argv);
+       cmd_setting(mgmt, index, MGMT_OP_SET_HS, 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)
+static void cmd_le(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
-       struct mgmt_ev_class_of_dev_changed *rp = rsp;
+       cmd_setting(mgmt, index, MGMT_OP_SET_LE, argc, argv);
+}
+
+static void cmd_advertising(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
+{
+       cmd_setting(mgmt, index, MGMT_OP_SET_ADVERTISING, argc, argv);
+}
+
+static void cmd_bredr(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
+{
+       cmd_setting(mgmt, index, MGMT_OP_SET_BREDR, argc, argv);
+}
+
+static void class_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
+                                                       const void *param)
+{
+       const struct mgmt_ev_class_of_dev_changed *rp = param;
 
        if (len == 0 && status != 0) {
                fprintf(stderr, "%s failed, status 0x%02x (%s)\n",
                                mgmt_opstr(op), status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len != sizeof(*rp)) {
                fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        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);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_class(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        uint8_t class[2];
 
@@ -1128,46 +1016,46 @@ static void cmd_class(int mgmt_sk, uint16_t index, int argc, char **argv)
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_SET_DEV_CLASS, index,
-                               class, sizeof(class), class_rsp, NULL) < 0) {
+       if (send_cmd(mgmt, MGMT_OP_SET_DEV_CLASS, index, sizeof(class), class,
+                                                       class_rsp) == 0) {
                fprintf(stderr, "Unable to send set_dev_class cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void disconnect_rsp(int mgmt_sk, uint16_t op, uint16_t id,
-                               uint8_t status, void *rsp, uint16_t len,
-                               void *user_data)
+static void disconnect_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_disconnect *rp = rsp;
+       const struct mgmt_rp_disconnect *rp = param;
        char addr[18];
 
        if (len == 0 && status != 0) {
                fprintf(stderr, "Disconnect failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len != sizeof(*rp)) {
                fprintf(stderr, "Invalid disconnect response length (%u)\n",
                                                                        len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        ba2str(&rp->addr.bdaddr, addr);
 
-       if (status == 0) {
+       if (status == 0)
                printf("%s disconnected\n", addr);
-               exit(EXIT_SUCCESS);
-       } else {
+       else
                fprintf(stderr,
                        "Disconnecting %s failed with status 0x%02x (%s)\n",
                                addr, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
-       }
+
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_disconnect(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        struct mgmt_cp_disconnect cp;
 
@@ -1181,30 +1069,30 @@ static void cmd_disconnect(int mgmt_sk, uint16_t index, int argc, char **argv)
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_DISCONNECT, index,
-                               &cp, sizeof(cp), disconnect_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_DISCONNECT, index, sizeof(cp), &cp,
+                                       disconnect_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send disconnect cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void con_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_get_connections *rp = rsp;
+       const struct mgmt_rp_get_connections *rp = param;
        uint16_t count, i;
 
        if (len < sizeof(*rp)) {
                fprintf(stderr, "Too small (%u bytes) get_connections rsp\n",
                                                                        len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        count = bt_get_le16(&rp->conn_count);
        if (len != sizeof(*rp) + count * sizeof(struct mgmt_addr_info)) {
                fprintf(stderr, "Invalid get_connections length "
                                        " (count=%u, len=%u)\n", count, len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        for (i = 0; i < count; i++) {
@@ -1215,29 +1103,31 @@ static void con_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                printf("%s type %s\n", addr, typestr(rp->addr[i].type));
        }
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_con(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_con(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        if (index == MGMT_INDEX_NONE)
                index = 0;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_GET_CONNECTIONS, index, NULL, 0,
-                                                       con_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_GET_CONNECTIONS, index, 0, NULL,
+                                               con_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send get_connections cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void find_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void find_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
        if (status != 0) {
                fprintf(stderr,
                        "Unable to start discovery. status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               g_main_loop_quit(event_loop);
+               return;
        }
 
        printf("Discovery started\n");
@@ -1256,7 +1146,7 @@ static struct option find_options[] = {
        { 0, 0, 0, 0 }
 };
 
-static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_find(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_start_discovery cp;
        uint8_t type;
@@ -1297,26 +1187,25 @@ static void cmd_find(int mgmt_sk, uint16_t index, int argc, char **argv)
        memset(&cp, 0, sizeof(cp));
        cp.type = type;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_START_DISCOVERY, index,
-                               &cp, sizeof(cp), find_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_START_DISCOVERY, index, sizeof(cp), &cp,
+                                               find_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send start_discovery cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void name_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void name_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       if (status != 0) {
-               fprintf(stderr, "Unable to set local name. status 0x%02x (%s)",
+       if (status != 0)
+               fprintf(stderr, "Unable to set local name "
+                                               "with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
-       }
 
-       exit(EXIT_SUCCESS);
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_name(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_set_local_name cp;
 
@@ -1334,28 +1223,28 @@ static void cmd_name(int mgmt_sk, uint16_t index, int argc, char **argv)
                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) {
+       if (mgmt_send(mgmt, MGMT_OP_SET_LOCAL_NAME, index, sizeof(cp), &cp,
+                                               name_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send set_name cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void pair_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_pair_device *rp = rsp;
+       const struct mgmt_rp_pair_device *rp = param;
        char addr[18];
 
        if (len == 0 && status != 0) {
                fprintf(stderr, "Pairing failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        if (len != sizeof(*rp)) {
                fprintf(stderr, "Unexpected pair_rsp len %u\n", len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        ba2str(&rp->addr.bdaddr, addr);
@@ -1365,12 +1254,13 @@ static void pair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                        "Pairing with %s (%s) failed. status 0x%02x (%s)\n",
                        addr, typestr(rp->addr.type), status,
                        mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        printf("Paired with %s\n", addr);
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
 static void pair_usage(void)
@@ -1385,7 +1275,7 @@ static struct option pair_options[] = {
        { 0, 0, 0, 0 }
 };
 
-static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_pair(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_pair_device cp;
        uint8_t cap = 0x01;
@@ -1425,28 +1315,115 @@ static void cmd_pair(int mgmt_sk, uint16_t index, int argc, char **argv)
        cp.addr.type = type;
        cp.io_cap = cap;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_PAIR_DEVICE, index, &cp, sizeof(cp),
-                                                       pair_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_PAIR_DEVICE, index, sizeof(cp), &cp,
+                                               pair_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send pair_device cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void cancel_pair_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       struct mgmt_rp_unpair_device *rp = rsp;
+       const struct mgmt_addr_info *rp = param;
        char addr[18];
 
        if (len == 0 && status != 0) {
-               fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+               fprintf(stderr, "Cancel Pairing failed with 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
+               goto done;
+       }
+
+       if (len != sizeof(*rp)) {
+               fprintf(stderr, "Unexpected cancel_pair_rsp len %u\n", len);
+               goto done;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+
+       if (status != 0) {
+               fprintf(stderr,
+                       "Cancel Pairing with %s (%s) failed. 0x%02x (%s)\n",
+                       addr, typestr(rp->type), status,
+                       mgmt_errstr(status));
+               goto done;
+       }
+
+       printf("Pairing Cancelled with %s\n", addr);
+
+done:
+       g_main_loop_quit(event_loop);
+}
+
+static void cancel_pair_usage(void)
+{
+       printf("Usage: btmgmt cancelpair [-t type] <remote address>\n");
+}
+
+static struct option cancel_pair_options[] = {
+       { "help",       0, 0, 'h' },
+       { "type",       1, 0, 't' },
+       { 0, 0, 0, 0 }
+};
+
+static void cmd_cancel_pair(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
+{
+       struct mgmt_addr_info cp;
+       uint8_t type = BDADDR_BREDR;
+       int opt;
+
+       while ((opt = getopt_long(argc, argv, "+t:h", cancel_pair_options,
+                                                               NULL)) != -1) {
+               switch (opt) {
+               case 't':
+                       type = strtol(optarg, NULL, 0);
+                       break;
+               case 'h':
+               default:
+                       cancel_pair_usage();
+                       exit(EXIT_SUCCESS);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       if (argc < 1) {
+               cancel_pair_usage();
                exit(EXIT_FAILURE);
        }
 
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       memset(&cp, 0, sizeof(cp));
+       str2ba(argv[0], &cp.bdaddr);
+       cp.type = type;
+
+       if (mgmt_send(mgmt, MGMT_OP_CANCEL_PAIR_DEVICE, index, sizeof(cp), &cp,
+                                       cancel_pair_rsp, NULL, NULL) == 0) {
+               fprintf(stderr, "Unable to send cancel_pair_device cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void unpair_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       const struct mgmt_rp_unpair_device *rp = param;
+       char addr[18];
+
+       if (len == 0 && status != 0) {
+               fprintf(stderr, "Unpair device failed. status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+               goto done;
+       }
+
        if (len != sizeof(*rp)) {
                fprintf(stderr, "Unexpected unpair_device_rsp len %u\n", len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        ba2str(&rp->addr.bdaddr, addr);
@@ -1455,15 +1432,17 @@ static void unpair_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                fprintf(stderr,
                        "Unpairing %s failed. status 0x%02x (%s)\n",
                                addr, status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        printf("%s unpaired\n", addr);
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_unpair(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        struct mgmt_cp_unpair_device cp;
 
@@ -1479,28 +1458,26 @@ static void cmd_unpair(int mgmt_sk, uint16_t index, int argc, char **argv)
        str2ba(argv[1], &cp.addr.bdaddr);
        cp.disconnect = 1;
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_UNPAIR_DEVICE, index, &cp,
-                                       sizeof(cp), unpair_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_UNPAIR_DEVICE, index, sizeof(cp), &cp,
+                                               unpair_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send unpair_device cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void keys_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void keys_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       if (status != 0) {
+       if (status != 0)
                fprintf(stderr, "Load keys failed with status 0x%02x (%s)\n",
                                                status, mgmt_errstr(status));
-               exit(EXIT_FAILURE);
-       }
-
-       printf("Keys successfully loaded\n");
+       else
+               printf("Keys successfully loaded\n");
 
-       exit(EXIT_SUCCESS);
+       g_main_loop_quit(event_loop);
 }
 
-static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_keys(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_load_link_keys cp;
 
@@ -1509,28 +1486,28 @@ static void cmd_keys(int mgmt_sk, uint16_t index, int argc, char **argv)
 
        memset(&cp, 0, sizeof(cp));
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_LOAD_LINK_KEYS, index,
-                               &cp, sizeof(cp), keys_rsp, NULL) < 0) {
+       if (mgmt_send(mgmt, MGMT_OP_LOAD_LINK_KEYS, index, sizeof(cp), &cp,
+                                               keys_rsp, NULL, NULL) == 0) {
                fprintf(stderr, "Unable to send load_keys cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
-                               void *rsp, uint16_t len, void *user_data)
+static void block_rsp(uint16_t op, uint16_t id, uint8_t status, uint16_t len,
+                                                       const void *param)
 {
-       struct mgmt_addr_info *rp = rsp;
+       const struct mgmt_addr_info *rp = param;
        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);
+               goto done;
        }
 
        if (len != sizeof(*rp)) {
                fprintf(stderr, "Unexpected %s len %u\n", mgmt_opstr(op), len);
-               exit(EXIT_FAILURE);
+               goto done;
        }
 
        ba2str(&rp->bdaddr, addr);
@@ -1539,12 +1516,13 @@ static void block_rsp(int mgmt_sk, uint16_t op, uint16_t id, uint8_t status,
                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);
+               goto done;
        }
 
        printf("%s %s succeeded\n", mgmt_opstr(op), addr);
 
-       exit(EXIT_SUCCESS);
+done:
+       g_main_loop_quit(event_loop);
 }
 
 static void block_usage(void)
@@ -1558,7 +1536,7 @@ static struct option block_options[] = {
        { 0, 0, 0, 0 }
 };
 
-static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_block(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_block_device cp;
        uint8_t type = BDADDR_BREDR;
@@ -1593,8 +1571,8 @@ static void cmd_block(int mgmt_sk, uint16_t index, int argc, char **argv)
        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) {
+       if (send_cmd(mgmt, MGMT_OP_BLOCK_DEVICE, index, sizeof(cp), &cp,
+                                                       block_rsp) == 0) {
                fprintf(stderr, "Unable to send block_device cmd\n");
                exit(EXIT_FAILURE);
        }
@@ -1605,7 +1583,8 @@ 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)
+static void cmd_unblock(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        struct mgmt_cp_unblock_device cp;
        uint8_t type = BDADDR_BREDR;
@@ -1640,8 +1619,8 @@ static void cmd_unblock(int mgmt_sk, uint16_t index, int argc, char **argv)
        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) {
+       if (send_cmd(mgmt, MGMT_OP_UNBLOCK_DEVICE, index, sizeof(cp), &cp,
+                                                       block_rsp) == 0) {
                fprintf(stderr, "Unable to send unblock_device cmd\n");
                exit(EXIT_FAILURE);
        }
@@ -1657,7 +1636,8 @@ static void uuid_to_uuid128(uuid_t *uuid128, const uuid_t *uuid)
                memcpy(uuid128, uuid, sizeof(*uuid));
 }
 
-static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_add_uuid(struct mgmt *mgmt, uint16_t index, int argc,
+                                                       char **argv)
 {
        struct mgmt_cp_add_uuid cp;
        uint128_t uint128;
@@ -1684,14 +1664,15 @@ static void cmd_add_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
 
        cp.svc_hint = atoi(argv[2]);
 
-       if (mgmt_send_cmd(mgmt_sk, MGMT_OP_ADD_UUID, index,
-                               &cp, sizeof(cp), class_rsp, NULL) < 0) {
+       if (send_cmd(mgmt, MGMT_OP_ADD_UUID, index, sizeof(cp), &cp,
+                                                       class_rsp) == 0) {
                fprintf(stderr, "Unable to send add_uuid cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_remove_uuid(struct mgmt *mgmt, uint16_t index, int argc,
+                                                               char **argv)
 {
        struct mgmt_cp_remove_uuid cp;
        uint128_t uint128;
@@ -1716,33 +1697,33 @@ static void cmd_remove_uuid(int mgmt_sk, uint16_t index, int argc, char **argv)
        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) {
+       if (send_cmd(mgmt, MGMT_OP_REMOVE_UUID, index, sizeof(cp), &cp,
+                                                       class_rsp) == 0) {
                fprintf(stderr, "Unable to send remove_uuid cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
-static void cmd_clr_uuids(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_clr_uuids(struct mgmt *mgmt, 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);
+       cmd_remove_uuid(mgmt, 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)
+static void did_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
 {
-       if (status != 0) {
-               fprintf(stderr, "Set Device ID failed with status 0x%02x (%s)\n",
+       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");
+       else
+               printf("Device ID successfully set\n");
 
-       exit(EXIT_SUCCESS);
+       g_main_loop_quit(event_loop);
 }
 
 static void did_usage(void)
@@ -1751,7 +1732,7 @@ static void did_usage(void)
        printf("       possible source values: bluetooth, usb\n");
 }
 
-static void cmd_did(int mgmt_sk, uint16_t index, int argc, char **argv)
+static void cmd_did(struct mgmt *mgmt, uint16_t index, int argc, char **argv)
 {
        struct mgmt_cp_set_device_id cp;
        uint16_t vendor, product, version , source;
@@ -1788,16 +1769,56 @@ done:
        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");
+       if (mgmt_send(mgmt, MGMT_OP_SET_DEVICE_ID, index, sizeof(cp), &cp,
+                                               did_rsp, NULL, NULL) == 0) {
+               fprintf(stderr, "Unable to send set_device_id cmd\n");
+               exit(EXIT_FAILURE);
+       }
+}
+
+static void static_addr_rsp(uint8_t status, uint16_t len, const void *param,
+                                                       void *user_data)
+{
+       if (status != 0)
+               fprintf(stderr, "Set static address failed "
+                                               "with status 0x%02x (%s)\n",
+                                               status, mgmt_errstr(status));
+       else
+               printf("Static address successfully set\n");
+
+       g_main_loop_quit(event_loop);
+}
+
+static void static_addr_usage(void)
+{
+       printf("Usage: btmgmt static-addr <address>\n");
+}
+
+static void cmd_static_addr(struct mgmt *mgmt, uint16_t index,
+                                                       int argc, char **argv)
+{
+       struct mgmt_cp_set_static_address cp;
+
+       if (argc < 2) {
+               static_addr_usage();
+               exit(EXIT_FAILURE);
+       }
+
+       if (index == MGMT_INDEX_NONE)
+               index = 0;
+
+       str2ba(argv[1], &cp.bdaddr);
+
+       if (mgmt_send(mgmt, MGMT_OP_SET_STATIC_ADDRESS, index, sizeof(cp), &cp,
+                                       static_addr_rsp, NULL, NULL) == 0) {
+               fprintf(stderr, "Unable to send set_static_address cmd\n");
                exit(EXIT_FAILURE);
        }
 }
 
 static struct {
        char *cmd;
-       void (*func)(int mgmt_sk, uint16_t index, int argc, char **argv);
+       void (*func)(struct mgmt *mgmt, uint16_t index, int argc, char **argv);
        char *doc;
 } command[] = {
        { "monitor",    cmd_monitor,    "Monitor events"                },
@@ -1807,25 +1828,30 @@ static struct {
        { "power",      cmd_power,      "Toggle powered state"          },
        { "discov",     cmd_discov,     "Toggle discoverable state"     },
        { "connectable",cmd_connectable,"Toggle connectable state"      },
+       { "fast-conn",  cmd_fast_conn,  "Toggle fast 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"             },
+       { "advertising",cmd_advertising,"Toggle LE advertising",        },
+       { "bredr",      cmd_bredr,      "Toggle BR/EDR 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"     },
+       { "cancelpair", cmd_cancel_pair,"Cancel pairing"                },
        { "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"                   },
+       { "rm-uuid",    cmd_remove_uuid, "Remove UUID"                  },
        { "clr-uuids",  cmd_clr_uuids,  "Clear UUIDs",                  },
        { "did",        cmd_did,        "Set Device ID",                },
+       { "static-addr",cmd_static_addr,"Set static address",           },
        { NULL, NULL, 0 }
 };
 
@@ -1860,9 +1886,9 @@ static struct option main_options[] = {
 
 int main(int argc, char *argv[])
 {
-       int opt, i, mgmt_sk;
+       int opt, i;
        uint16_t index = MGMT_INDEX_NONE;
-       struct pollfd pollfd;
+       struct mgmt *mgmt;
 
        while ((opt = getopt_long(argc, argv, "+hvi:",
                                                main_options, NULL)) != -1) {
@@ -1893,9 +1919,12 @@ int main(int argc, char *argv[])
                return 0;
        }
 
-       mgmt_sk = mgmt_open();
-       if (mgmt_sk < 0) {
-               fprintf(stderr, "Unable to open mgmt socket\n");
+       event_loop = g_main_loop_new(NULL, FALSE);
+
+       mgmt = mgmt_new_default();
+       if (!mgmt) {
+               fprintf(stderr, "Unable to open mgmt_socket\n");
+               g_main_loop_unref(event_loop);
                return -1;
        }
 
@@ -1903,31 +1932,53 @@ int main(int argc, char *argv[])
                if (strcmp(command[i].cmd, argv[0]) != 0)
                        continue;
 
-               command[i].func(mgmt_sk, index, argc, argv);
+               command[i].func(mgmt, index, argc, argv);
                break;
        }
 
        if (command[i].cmd == NULL) {
                fprintf(stderr, "Unknown command: %s\n", argv[0]);
-               close(mgmt_sk);
+               mgmt_unref(mgmt);
+               g_main_loop_unref(event_loop);
                return -1;
        }
 
-       pollfd.fd = mgmt_sk;
-       pollfd.events = POLLIN;
-       pollfd.revents = 0;
-
-       while (poll(&pollfd, 1, -1) >= 0) {
-               if (pollfd.revents & (POLLHUP | POLLERR | POLLNVAL))
-                       break;
-
-               if (pollfd.revents & POLLIN)
-                       mgmt_process_data(mgmt_sk);
-
-               pollfd.revents = 0;
-       }
-
-       close(mgmt_sk);
+       mgmt_register(mgmt, MGMT_EV_CONTROLLER_ERROR, index, controller_error,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_INDEX_ADDED, index, index_added,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_INDEX_REMOVED, index, index_removed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_NEW_SETTINGS, index, new_settings,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DISCOVERING, index, discovering,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_NEW_LINK_KEY, index, new_link_key,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_CONNECTED, index, connected,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_DISCONNECTED, index, disconnected,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_CONNECT_FAILED, index, conn_failed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_AUTH_FAILED, index, auth_failed,
+                                                               NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_LOCAL_NAME_CHANGED, index,
+                                       local_name_changed, NULL, NULL);
+       mgmt_register(mgmt, MGMT_EV_DEVICE_FOUND, index, device_found,
+                                                               mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_PIN_CODE_REQUEST, index, request_pin,
+                                                               mgmt, NULL);
+       mgmt_register(mgmt, MGMT_EV_USER_CONFIRM_REQUEST, index, user_confirm,
+                                                               mgmt, NULL);
+
+       g_main_loop_run(event_loop);
+
+       mgmt_cancel_all(mgmt);
+       mgmt_unregister_all(mgmt);
+       mgmt_unref(mgmt);
+
+       g_main_loop_unref(event_loop);
 
        return 0;
 }
diff --git a/tools/btsnoop.c b/tools/btsnoop.c
new file mode 100644 (file)
index 0000000..306e643
--- /dev/null
@@ -0,0 +1,620 @@
+/*
+ *
+ *  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 <stdint.h>
+#include <stdbool.h>
+#include <string.h>
+#include <getopt.h>
+#include <arpa/inet.h>
+#include <sys/stat.h>
+
+#include "monitor/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 int create_btsnoop(const char *path)
+{
+       struct btsnoop_hdr hdr;
+       ssize_t written;
+       int fd;
+
+       fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_CLOEXEC,
+                               S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       if (fd < 0) {
+               perror("failed to output file");
+               return -1;
+       }
+
+       memcpy(hdr.id, btsnoop_id, sizeof(btsnoop_id));
+       hdr.version = htonl(btsnoop_version);
+       hdr.type = htonl(2001);
+
+       written = write(fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (written < 0) {
+               perror("failed to write output header");
+               close(fd);
+               return -1;
+       }
+
+       return fd;
+}
+
+static int open_btsnoop(const char *path, uint32_t *type)
+{
+       struct btsnoop_hdr hdr;
+       ssize_t len;
+       int fd;
+
+       fd = open(path, O_RDONLY | O_CLOEXEC);
+       if (fd < 0) {
+               perror("failed to open input file");
+               return -1;
+       }
+
+       len = read(fd, &hdr, BTSNOOP_HDR_SIZE);
+       if (len < 0 || len != BTSNOOP_HDR_SIZE) {
+               perror("failed to read input header");
+               close(fd);
+               return -1;
+       }
+
+       if (memcmp(hdr.id, btsnoop_id, sizeof(btsnoop_id))) {
+               fprintf(stderr, "not a valid btsnoop header\n");
+               close(fd);
+               return -1;
+       }
+
+       if (ntohl(hdr.version) != btsnoop_version) {
+               fprintf(stderr, "invalid btsnoop version\n");
+               close(fd);
+               return -1;
+       }
+
+       if (type)
+               *type = ntohl(hdr.type);
+
+       return fd;
+}
+
+#define MAX_MERGE 8
+
+static void command_merge(const char *output, int argc, char *argv[])
+{
+       struct btsnoop_pkt input_pkt[MAX_MERGE];
+       unsigned char buf[2048];
+       int output_fd, input_fd[MAX_MERGE], num_input = 0;
+       int i, select_input;
+       ssize_t len, written;
+       uint32_t toread, flags;
+       uint16_t index, opcode;
+
+       if (argc > MAX_MERGE) {
+               fprintf(stderr, "only up to %d files allowed\n", MAX_MERGE);
+               return;
+       }
+
+       for (i = 0; i < argc; i++) {
+               uint32_t type;
+               int fd;
+
+               fd = open_btsnoop(argv[i], &type);
+               if (fd < 0)
+                       break;
+
+               if (type != 1002) {
+                       fprintf(stderr, "unsupported link data type %u\n",
+                                                                       type);
+                       close(fd);
+                       break;
+               }
+
+               input_fd[num_input++] = fd;
+       }
+
+       if (num_input != argc) {
+               fprintf(stderr, "failed to open all input files\n");
+               goto close_input;
+       }
+
+       output_fd = create_btsnoop(output);
+       if (output_fd < 0)
+               goto close_input;
+
+       for (i = 0; i < num_input; i++) {
+               len = read(input_fd[i], &input_pkt[i], BTSNOOP_PKT_SIZE);
+               if (len < 0 || len != BTSNOOP_PKT_SIZE) {
+                       close(input_fd[i]);
+                       input_fd[i] = -1;
+               }
+       }
+
+next_packet:
+       select_input = -1;
+
+       for (i = 0; i < num_input; i++) {
+               uint64_t ts;
+
+               if (input_fd[i] < 0)
+                       continue;
+
+               if (select_input < 0) {
+                       select_input = i;
+                       continue;
+               }
+
+               ts = ntoh64(input_pkt[i].ts);
+
+               if (ts < ntoh64(input_pkt[select_input].ts))
+                       select_input = i;
+       }
+
+       if (select_input < 0)
+               goto close_output;
+
+       toread = ntohl(input_pkt[select_input].size);
+       flags = ntohl(input_pkt[select_input].flags);
+
+       len = read(input_fd[select_input], buf, toread);
+       if (len < 0 || len != (ssize_t) toread) {
+               close(input_fd[select_input]);
+               input_fd[select_input] = -1;
+               goto next_packet;
+       }
+
+       written = input_pkt[select_input].size = htonl(toread - 1);
+       written = input_pkt[select_input].len = htonl(toread - 1);
+
+       switch (buf[0]) {
+       case 0x01:
+               opcode = BTSNOOP_OPCODE_COMMAND_PKT;
+               break;
+       case 0x02:
+               if (flags & 0x01)
+                       opcode = BTSNOOP_OPCODE_ACL_RX_PKT;
+               else
+                       opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+               break;
+       case 0x03:
+               if (flags & 0x01)
+                       opcode = BTSNOOP_OPCODE_SCO_RX_PKT;
+               else
+                       opcode = BTSNOOP_OPCODE_ACL_TX_PKT;
+               break;
+       case 0x04:
+               opcode = BTSNOOP_OPCODE_EVENT_PKT;
+               break;
+       default:
+               goto skip_write;
+       }
+
+       index = select_input;
+       input_pkt[select_input].flags = htonl((index << 16) | opcode);
+
+       written = write(output_fd, &input_pkt[select_input], BTSNOOP_PKT_SIZE);
+       if (written != BTSNOOP_PKT_SIZE) {
+               fprintf(stderr, "write of packet header failed\n");
+               goto close_output;
+       }
+
+       written = write(output_fd, buf + 1, toread - 1);
+       if (written != (ssize_t) toread - 1) {
+               fprintf(stderr, "write of packet data failed\n");
+               goto close_output;
+       }
+
+skip_write:
+       len = read(input_fd[select_input],
+                               &input_pkt[select_input], BTSNOOP_PKT_SIZE);
+       if (len < 0 || len != BTSNOOP_PKT_SIZE) {
+               close(input_fd[select_input]);
+               input_fd[select_input] = -1;
+       }
+
+       goto next_packet;
+
+close_output:
+       close(output_fd);
+
+close_input:
+       for (i = 0; i < num_input; i++)
+               close(input_fd[i]);
+}
+
+static void command_extract_eir(const char *input)
+{
+       struct btsnoop_pkt pkt;
+       unsigned char buf[2048];
+       ssize_t len;
+       uint32_t type, toread, flags;
+       uint16_t opcode;
+       int fd, count = 0;
+
+       fd = open_btsnoop(input, &type);
+       if (fd < 0)
+               return;
+
+       if (type != 2001) {
+               fprintf(stderr, "unsupported link data type %u\n", type);
+               close(fd);
+               return;
+       }
+
+next_packet:
+       len = read(fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (len < 0 || len != BTSNOOP_PKT_SIZE)
+               goto close_input;
+
+       toread = ntohl(pkt.size);
+       flags = ntohl(pkt.flags);
+
+       opcode = flags & 0x00ff;
+
+       len = read(fd, buf, toread);
+       if (len < 0 || len != (ssize_t) toread) {
+               fprintf(stderr, "failed to read packet data\n");
+               goto close_input;
+       }
+
+       switch (opcode) {
+       case BTSNOOP_OPCODE_EVENT_PKT:
+               /* extended inquiry result event */
+               if (buf[0] == 0x2f) {
+                       uint8_t *eir_ptr, eir_len, i;
+
+                       eir_len = buf[1] - 15;
+                       eir_ptr = buf + 17;
+
+                       if (eir_len < 1 || eir_len > 240)
+                               break;
+
+                       printf("\t[Extended Inquiry Data with %u bytes]\n",
+                                                               eir_len);
+                       printf("\t\t");
+                       for (i = 0; i < eir_len; i++) {
+                               printf("0x%02x", eir_ptr[i]);
+                               if (((i + 1) % 8) == 0) {
+                                       if (i < eir_len - 1)
+                                               printf(",\n\t\t");
+                               } else {
+                                       if (i < eir_len - 1)
+                                               printf(", ");
+                               }
+                       }
+                       printf("\n");
+
+                       count++;
+               }
+               break;
+       }
+
+       goto next_packet;
+
+close_input:
+       close(fd);
+}
+
+static void command_extract_ad(const char *input)
+{
+       struct btsnoop_pkt pkt;
+       unsigned char buf[2048];
+       ssize_t len;
+       uint32_t type, toread, flags;
+       uint16_t opcode;
+       int fd, count = 0;
+
+       fd = open_btsnoop(input, &type);
+       if (fd < 0)
+               return;
+
+       if (type != 2001) {
+               fprintf(stderr, "unsupported link data type %u\n", type);
+               close(fd);
+               return;
+       }
+
+next_packet:
+       len = read(fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (len < 0 || len != BTSNOOP_PKT_SIZE)
+               goto close_input;
+
+       toread = ntohl(pkt.size);
+       flags = ntohl(pkt.flags);
+
+       opcode = flags & 0x00ff;
+
+       len = read(fd, buf, toread);
+       if (len < 0 || len != (ssize_t) toread) {
+               fprintf(stderr, "failed to read packet data\n");
+               goto close_input;
+       }
+
+       switch (opcode) {
+       case BTSNOOP_OPCODE_EVENT_PKT:
+               /* advertising report */
+               if (buf[0] == 0x3e && buf[2] == 0x02) {
+                       uint8_t *ad_ptr, ad_len, i;
+
+                       ad_len = buf[12];
+                       ad_ptr = buf + 13;
+
+                       if (ad_len < 1 || ad_len > 40)
+                               break;
+
+                       printf("\t[Advertising Data with %u bytes]\n", ad_len);
+                       printf("\t\t");
+                       for (i = 0; i < ad_len; i++) {
+                               printf("0x%02x", ad_ptr[i]);
+                               if (((i + 1) % 8) == 0) {
+                                       if (i < ad_len - 1)
+                                               printf(",\n\t\t");
+                               } else {
+                                       if (i < ad_len - 1)
+                                               printf(", ");
+                               }
+                       }
+                       printf("\n");
+
+                       count++;
+               }
+               break;
+       }
+
+       goto next_packet;
+
+close_input:
+       close(fd);
+}
+static const uint8_t conn_complete[] = { 0x04, 0x03, 0x0B, 0x00 };
+static const uint8_t disc_complete[] = { 0x04, 0x05, 0x04, 0x00 };
+
+static void command_extract_sdp(const char *input)
+{
+       struct btsnoop_pkt pkt;
+       unsigned char buf[2048];
+       ssize_t len;
+       uint32_t type, toread;
+       uint16_t current_cid = 0x0000;
+       uint8_t pdu_buf[512];
+       uint16_t pdu_len = 0;
+       bool pdu_first = false;
+       int fd, count = 0;
+
+       fd = open_btsnoop(input, &type);
+       if (fd < 0)
+               return;
+
+       if (type != 1002) {
+               fprintf(stderr, "unsupported link data type %u\n", type);
+               close(fd);
+               return;
+       }
+
+next_packet:
+       len = read(fd, &pkt, BTSNOOP_PKT_SIZE);
+       if (len < 0 || len != BTSNOOP_PKT_SIZE)
+               goto close_input;
+
+       toread = ntohl(pkt.size);
+
+       len = read(fd, buf, toread);
+       if (len < 0 || len != (ssize_t) toread) {
+               fprintf(stderr, "failed to read packet data\n");
+               goto close_input;
+       }
+
+       if (buf[0] == 0x02) {
+               uint8_t acl_flags;
+
+               /* first 4 bytes are handle and data len */
+               acl_flags = buf[2] >> 4;
+
+               /* use only packet with ACL start flag */
+               if (acl_flags & 0x02) {
+                       if (current_cid == 0x0040 && pdu_len > 0) {
+                               int i;
+                               if (!pdu_first)
+                                       printf(",\n");
+                               printf("\t\traw_pdu(");
+                               for (i = 0; i < pdu_len; i++) {
+                                       printf("0x%02x", pdu_buf[i]);
+                                       if (((i + 1) % 8) == 0) {
+                                               if (i < pdu_len - 1)
+                                                       printf(",\n\t\t\t");
+                                       } else {
+                                               if (i < pdu_len - 1)
+                                                       printf(", ");
+                                       }
+                               }
+                               printf(")");
+                               pdu_first = false;
+                       }
+
+                       /* next 4 bytes are data len and cid */
+                       current_cid = buf[8] << 8 | buf[7];
+                       memcpy(pdu_buf, buf + 9, len - 9);
+                       pdu_len = len - 9;
+               } else if (acl_flags & 0x01) {
+                       memcpy(pdu_buf + pdu_len, buf + 5, len - 5);
+                       pdu_len += len - 5;
+               }
+       }
+
+       if ((size_t) len > sizeof(conn_complete)) {
+               if (memcmp(buf, conn_complete, sizeof(conn_complete)) == 0) {
+                       printf("\tdefine_test(\"/test/%u\",\n", ++count);
+                       pdu_first = true;
+               }
+       }
+
+       if ((size_t) len > sizeof(disc_complete)) {
+               if (memcmp(buf, disc_complete, sizeof(disc_complete)) == 0) {
+                       printf(");\n");
+               }
+       }
+
+       goto next_packet;
+
+close_input:
+       close(fd);
+}
+
+static void usage(void)
+{
+       printf("btsnoop trace file handling tool\n"
+               "Usage:\n");
+       printf("\tbtsnoop <command> [files]\n");
+       printf("commands:\n"
+               "\t-m, --merge <output>   Merge multiple btsnoop files\n"
+               "\t-e, --extract <input>  Extract data from btsnoop file\n"
+               "\t-h, --help             Show help options\n");
+}
+
+static const struct option main_options[] = {
+       { "merge",   required_argument, NULL, 'm' },
+       { "extract", required_argument, NULL, 'e' },
+       { "type",    required_argument, NULL, 't' },
+       { "version", no_argument,       NULL, 'v' },
+       { "help",    no_argument,       NULL, 'h' },
+       { }
+};
+
+enum { INVALID, MERGE, EXTRACT };
+
+int main(int argc, char *argv[])
+{
+       const char *output_path = NULL;
+       const char *input_path = NULL;
+       const char *type = NULL;
+       unsigned short command = INVALID;
+
+       for (;;) {
+               int opt;
+
+               opt = getopt_long(argc, argv, "m:e:t:vh", main_options, NULL);
+               if (opt < 0)
+                       break;
+
+               switch (opt) {
+               case 'm':
+                       command = MERGE;
+                       output_path = optarg;
+                       break;
+               case 'e':
+                       command = EXTRACT;
+                       input_path = optarg;
+                       break;
+               case 't':
+                       type = optarg;
+                       break;
+               case 'v':
+                       printf("%s\n", VERSION);
+                       return EXIT_SUCCESS;
+               case 'h':
+                       usage();
+                       return EXIT_SUCCESS;
+               default:
+                       return EXIT_FAILURE;
+               }
+       }
+
+       switch (command) {
+       case MERGE:
+               if (argc - optind < 1) {
+                       fprintf(stderr, "input files required\n");
+                       return EXIT_FAILURE;
+               }
+
+               command_merge(output_path, argc - optind, argv + optind);
+               break;
+
+       case EXTRACT:
+               if (argc - optind > 0) {
+                       fprintf(stderr, "extra arguments not allowed\n");
+                       return EXIT_FAILURE;
+               }
+
+               if (!type) {
+                       fprintf(stderr, "no extract type specified\n");
+                       return EXIT_FAILURE;
+               }
+
+               if (!strcasecmp(type, "eir"))
+                       command_extract_eir(input_path);
+               else if (!strcasecmp(type, "ad"))
+                       command_extract_ad(input_path);
+               else if (!strcasecmp(type, "sdp"))
+                       command_extract_sdp(input_path);
+               else
+                       fprintf(stderr, "extract type not supported\n");
+               break;
+
+       default:
+               usage();
+               return EXIT_FAILURE;
+       }
+
+       return EXIT_SUCCESS;
+}
index edce9da..72338dc 100644 (file)
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <stdlib.h>
 #include <bluetooth/sdp_lib.h>
 #include <bluetooth/cmtp.h>
 
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
 static volatile sig_atomic_t __io_canceled = 0;
 
 static void sig_hup(int sig)
diff --git a/tools/cltest.c b/tools/cltest.c
new file mode 100644 (file)
index 0000000..16b7553
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *
+ *  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 <alloca.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/poll.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include <bluetooth/bluetooth.h>
+#include <bluetooth/hci.h>
+#include <bluetooth/hci_lib.h>
+#include <bluetooth/l2cap.h>
+
+#include "monitor/mainloop.h"
+
+static bool send_message(const bdaddr_t *src, const bdaddr_t *dst,
+                                                       uint16_t psm)
+{
+       const unsigned char buf[] = { 0x42, 0x23 };
+       struct sockaddr_l2 addr;
+       ssize_t len;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
+       if (fd < 0) {
+               perror("Failed to create transmitter socket");
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, src);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind transmitter socket");
+               close(fd);
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, dst);
+       addr.l2_psm = htobs(psm);
+
+       if (connect(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to connect transmitter socket");
+               close(fd);
+               return false;
+       }
+
+       len = send(fd, buf, sizeof(buf), 0);
+       if (len < 0) {
+               perror("Failed to send message");
+               close(fd);
+               return false;
+       }
+
+       return true;
+}
+
+static void receiver_callback(int fd, uint32_t events, void *user_data)
+{
+       unsigned char buf[512];
+       struct sockaddr_l2 addr;
+       socklen_t addrlen = sizeof(addr);
+       char str[18];
+       ssize_t len, i;
+
+       if (events & (EPOLLERR | EPOLLHUP)) {
+               close(fd);
+               mainloop_remove_fd(fd);
+               return;
+       }
+
+       len = recvfrom(fd, buf, sizeof(buf), 0,
+                               (struct sockaddr *) &addr, &addrlen);
+       if (len < 0) {
+               perror("Failed to receive data");
+               return;
+       }
+
+       if (addrlen > 0) {
+               ba2str(&addr.l2_bdaddr, str);
+               printf("RX Address: %s PSM: %d CID: %d\n", str,
+                               btohs(addr.l2_psm), btohs(addr.l2_cid));
+       }
+
+       printf("RX Data:");
+       for (i = 0; i < len; i++)
+               printf(" 0x%02x", buf[i]);
+       printf("\n");
+}
+
+static bool create_receiver(const bdaddr_t *bdaddr, uint16_t psm)
+{
+       struct sockaddr_l2 addr;
+       int fd;
+
+       fd = socket(PF_BLUETOOTH, SOCK_DGRAM | SOCK_CLOEXEC, BTPROTO_L2CAP);
+       if (fd < 0) {
+               perror("Failed to create receiver socket");
+               return false;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, bdaddr);
+       addr.l2_psm = htobs(psm);
+
+       if (bind(fd, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               perror("Failed to bind receiver socket");
+               close(fd);
+               return false;
+       }
+
+       mainloop_add_fd(fd, EPOLLIN, receiver_callback, NULL, NULL);
+
+       return true;
+}
+
+static bool activate_controller(int fd, struct hci_dev_info *di)
+{
+       if (!hci_test_bit(HCI_UP, &di->flags)) {
+               char addr[18];
+
+               ba2str(&di->bdaddr, addr);
+               printf("Activating controller %s\n", addr);
+
+               if (ioctl(fd, HCIDEVUP, di->dev_id) < 0) {
+                       if (errno != EALREADY) {
+                               perror("Failed to bring up HCI device");
+                               return false;
+                       }
+               }
+       }
+       return true;
+}
+
+static bool enable_connections(int fd, struct hci_dev_info *di)
+{
+       if (!hci_test_bit(HCI_PSCAN, &di->flags)) {
+               struct hci_dev_req dr;
+               char addr[18];
+
+               ba2str(&di->bdaddr, addr);
+               printf("Enabling connections on %s\n", addr);
+
+               dr.dev_id  = di->dev_id;
+               dr.dev_opt = SCAN_PAGE;
+
+               if (ioctl(fd, HCISETSCAN, (unsigned long) &dr) < 0) {
+                       perror("Failed to enable connections");
+                       return false;
+               }
+       }
+       return true;
+}
+
+static bdaddr_t bdaddr_src;
+static bdaddr_t bdaddr_dst;
+
+static bool find_controllers(void)
+{
+       struct hci_dev_list_req *dl;
+       struct hci_dev_req *dr;
+       bool result;
+       int fd, i;
+
+       fd = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (fd < 0) {
+               perror("Failed to open raw HCI socket");
+               return false;
+       }
+
+       dl = malloc(HCI_MAX_DEV * sizeof(struct hci_dev_req) + sizeof(uint16_t));
+       if (!dl) {
+               perror("Failed allocate HCI device request memory");
+               result = false;
+               goto done;
+       }
+
+       dl->dev_num = HCI_MAX_DEV;
+       dr = dl->dev_req;
+
+       if (ioctl(fd, HCIGETDEVLIST, (void *) dl) < 0) {
+               perror("Failed to get HCI device list");
+               result = false;
+               goto done;
+       }
+
+       result = true;
+
+       for (i = 0; i< dl->dev_num && result; i++) {
+               struct hci_dev_info di;
+
+               di.dev_id = (dr + i)->dev_id;
+
+               if (ioctl(fd, HCIGETDEVINFO, (void *) &di) < 0)
+                       continue;
+
+               if (((di.type & 0x30) >> 4) != HCI_BREDR)
+                       continue;
+
+               if (!bacmp(&bdaddr_src, BDADDR_ANY)) {
+                       bacpy(&bdaddr_src, &di.bdaddr);
+                       result = activate_controller(fd, &di);
+               } else if (!bacmp(&bdaddr_dst, BDADDR_ANY)) {
+                       bacpy(&bdaddr_dst, &di.bdaddr);
+                       result = activate_controller(fd, &di);
+                       if (result)
+                               result = enable_connections(fd, &di);
+               }
+       }
+
+done:
+       close(fd);
+       return result;
+}
+
+int main(int argc ,char *argv[])
+{
+       char addr_src[18], addr_dst[18];
+
+       bacpy(&bdaddr_src, BDADDR_ANY);
+       bacpy(&bdaddr_dst, BDADDR_ANY);
+
+       if (!find_controllers())
+               return EXIT_FAILURE;
+
+       if (!bacmp(&bdaddr_src, BDADDR_ANY) ||
+                               !bacmp(&bdaddr_dst, BDADDR_ANY)) {
+               fprintf(stderr, "Two controllers are required\n");
+               return EXIT_FAILURE;
+       }
+
+       ba2str(&bdaddr_src, addr_src);
+       ba2str(&bdaddr_dst, addr_dst);
+
+       printf("%s -> %s\n", addr_src, addr_dst);
+
+       mainloop_init();
+
+       create_receiver(&bdaddr_dst, 0x0021);
+       send_message(&bdaddr_src, &bdaddr_dst, 0x0021);
+
+       return mainloop_run();
+}
index 19903b0..a483bc1 100644 (file)
 
 #include <stdio.h>
 #include <errno.h>
+#include <ctype.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
 #include <string.h>
-
-#include <usb.h>
+#include <dirent.h>
+#include <sys/ioctl.h>
 
 #include "csr.h"
 
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
+#define USB_TYPE_CLASS                 (0x01 << 5)
+
+#define USB_RECIP_DEVICE               0x00
+
+#define USB_ENDPOINT_IN                        0x80
+#define USB_ENDPOINT_OUT               0x00
+
+struct usbfs_ctrltransfer {
+       uint8_t  bmRequestType;
+       uint8_t  bRequest;
+       uint16_t wValue;
+       uint16_t wIndex;
+       uint16_t wLength;
+       uint32_t timeout;       /* in milliseconds */
+       void *data;             /* pointer to data */
+};
+
+struct usbfs_bulktransfer {
+       unsigned int ep;
+       unsigned int len;
+       unsigned int timeout;   /* in milliseconds */
+       void *data;             /* pointer to data */
+};
+
+#define USBFS_IOCTL_CONTROL    _IOWR('U', 0, struct usbfs_ctrltransfer)
+#define USBFS_IOCTL_BULK       _IOWR('U', 2, struct usbfs_bulktransfer)
+#define USBFS_IOCTL_CLAIMINTF  _IOR('U', 15, unsigned int)
+#define USBFS_IOCTL_RELEASEINTF        _IOR('U', 16, unsigned int)
+
+static int read_value(const char *name, const char *attr, const char *format)
 {
-       return usb_busses;
+       char path[PATH_MAX];
+       FILE *file;
+       int n, value;
+
+       snprintf(path, sizeof(path), "/sys/bus/usb/devices/%s/%s", name, attr);
+
+       file = fopen(path, "r");
+       if (!file)
+               return -1;
+
+       n = fscanf(file, format, &value);
+       if (n != 1)
+               return -1;
+
+       return value;
 }
-#endif
 
-#ifdef NEED_USB_INTERRUPT_READ
-static inline int usb_interrupt_read(usb_dev_handle *dev, int ep, char *bytes, int size, int timeout)
+static char *check_device(const char *name)
 {
-       return usb_bulk_read(dev, ep, bytes, size, timeout);
-}
-#endif
+       char path[PATH_MAX];
+       int busnum, devnum, vendor, product;
 
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT    0x00
-#endif
+       busnum = read_value(name, "busnum", "%d");
+       if (busnum < 0)
+               return NULL;
 
-static uint16_t seqnum = 0x0000;
+       devnum = read_value(name, "devnum", "%d");
+       if (devnum < 0)
+               return NULL;
 
-static struct usb_dev_handle *udev = NULL;
+       snprintf(path, sizeof(path), "/dev/bus/usb/%03u/%03u", busnum, devnum);
 
-int csr_open_usb(char *device)
+       vendor = read_value(name, "idVendor", "%04x");
+       if (vendor < 0)
+               return NULL;
+
+       product = read_value(name, "idProduct", "%04x");
+       if (product < 0)
+               return NULL;
+
+       if (vendor != 0x0a12 || product != 0x0001)
+               return NULL;
+
+       return strdup(path);
+}
+
+static char *find_device(void)
 {
-       struct usb_bus *bus;
-       struct usb_device *dev;
+       char *path = NULL;
+       DIR *dir;
 
-       usb_init();
+       dir = opendir("/sys/bus/usb/devices");
+       if (!dir)
+               return NULL;
 
-       usb_find_busses();
-       usb_find_devices();
+       while (1) {
+               struct dirent *d;
 
-       for (bus = usb_get_busses(); bus; bus = bus->next) {
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
-                               continue;
+               d = readdir(dir);
+               if (!d)
+                       break;
 
-                       if (dev->descriptor.idVendor != 0x0a12 ||
-                                       dev->descriptor.idProduct != 0x0001)
-                               continue;
+               if ((!isdigit(d->d_name[0]) && strncmp(d->d_name, "usb", 3))
+                                               || strchr(d->d_name, ':'))
+                       continue;
 
-                       goto found;
-               }
+               path = check_device(d->d_name);
+               if (path)
+                       break;
        }
 
-       fprintf(stderr, "Device not available\n");
+       closedir(dir);
 
-       return -1;
+       return path;
+}
 
-found:
-       udev = usb_open(dev);
-       if (!udev) {
+static uint16_t seqnum = 0x0000;
+static int handle = -1;
+
+int csr_open_usb(char *device)
+{
+       int interface = 0;
+       char *path;
+
+       path = find_device();
+       if (!path) {
+               fprintf(stderr, "Device not available\n");
+               return -1;
+       }
+
+       handle = open(path, O_RDWR, O_CLOEXEC | O_NONBLOCK);
+
+       free(path);
+
+       if (handle < 0) {
                fprintf(stderr, "Can't open device: %s (%d)\n",
                                                strerror(errno), errno);
                return -1;
        }
 
-       if (usb_claim_interface(udev, 0) < 0) {
+       if (ioctl(handle, USBFS_IOCTL_CLAIMINTF, &interface) < 0) {
                fprintf(stderr, "Can't claim interface: %s (%d)\n",
                                                strerror(errno), errno);
-               usb_close(udev);
+               close(handle);
+               handle = -1;
                return -1;
        }
 
        return 0;
 }
 
-static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t *value, uint16_t length)
+static int control_write(int fd, void *data, unsigned short size)
+{
+       struct usbfs_ctrltransfer transfer;
+
+       transfer.bmRequestType = USB_TYPE_CLASS | USB_ENDPOINT_OUT |
+                                                       USB_RECIP_DEVICE;
+       transfer.bRequest = 0;
+       transfer.wValue = 0;
+       transfer.wIndex = 0;
+       transfer.wLength = size,
+       transfer.timeout = 2000;
+       transfer.data = data;
+
+       if (ioctl(fd, USBFS_IOCTL_CONTROL, &transfer) < 0) {
+               fprintf(stderr, "Control transfer failed: %s (%d)\n",
+                                               strerror(errno), errno);
+               return -1;
+       }
+
+       return 0;
+}
+
+static int interrupt_read(int fd, unsigned char endpoint,
+                                       void *data, unsigned short size)
+{
+       struct usbfs_bulktransfer transfer;
+
+       transfer.ep = endpoint;
+       transfer.len = size,
+       transfer.timeout = 20;
+       transfer.data = data;
+
+       return ioctl(fd, USBFS_IOCTL_BULK, &transfer);
+}
+
+static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid,
+                                       uint8_t *value, uint16_t length)
 {
        unsigned char cp[254], rp[254];
        uint8_t cmd[10];
@@ -128,11 +243,9 @@ static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t
        memcpy(cp + 4, cmd, sizeof(cmd));
        memcpy(cp + 14, value, length);
 
-       usb_interrupt_read(udev, 0x81, (void *) rp, sizeof(rp), 2);
+       interrupt_read(handle, USB_ENDPOINT_IN | 0x01, rp, sizeof(rp));
 
-       if (usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_DEVICE,
-                               0, 0, 0, (void *) cp, (size * 2) + 4, 1000) < 0)
-               return -1;
+       control_write(handle, cp, (size * 2) + 4);
 
        switch (varid) {
        case CSR_VARID_COLD_RESET:
@@ -143,8 +256,10 @@ static int do_command(uint16_t command, uint16_t seqnum, uint16_t varid, uint8_t
        }
 
        do {
-               len = usb_interrupt_read(udev, 0x81,
-                       (void *) (rp + offset), sizeof(rp) - offset, 10);
+               len = interrupt_read(handle, USB_ENDPOINT_IN | 0x01,
+                                       rp + offset, sizeof(rp) - offset);
+               if (len < 0)
+                       break;
                offset += len;
        } while (len > 0);
 
@@ -175,6 +290,10 @@ int csr_write_usb(uint16_t varid, uint8_t *value, uint16_t length)
 
 void csr_close_usb(void)
 {
-       usb_release_interface(udev, 0);
-       usb_close(udev);
+       int interface = 0;
+
+       ioctl(handle, USBFS_IOCTL_RELEASEINTF, &interface);
+
+       close(handle);
+       handle = -1;
 }
diff --git a/tools/dfu.c b/tools/dfu.c
deleted file mode 100644 (file)
index 39ec088..0000000
+++ /dev/null
@@ -1,168 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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 <string.h>
-
-#include <usb.h>
-
-#include "dfu.h"
-
-#ifndef USB_DIR_OUT
-#define USB_DIR_OUT    0x00
-#endif
-
-#ifndef USB_DIR_IN
-#define USB_DIR_IN     0x80
-#endif
-
-#ifndef USB_DT_DFU
-#define USB_DT_DFU     0x21
-#endif
-
-#define DFU_PACKETSIZE         0x03ff          /* CSR default value: 1023 */
-#define DFU_TIMEOUT            10000
-
-static uint32_t dfu_crc32_table[] = {
-       0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f,
-       0xe963a535, 0x9e6495a3, 0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988,
-       0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, 0x1db71064, 0x6ab020f2,
-       0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7,
-       0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9,
-       0xfa0f3d63, 0x8d080df5, 0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172,
-       0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, 0x35b5a8fa, 0x42b2986c,
-       0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59,
-       0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423,
-       0xcfba9599, 0xb8bda50f, 0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924,
-       0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, 0x76dc4190, 0x01db7106,
-       0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433,
-       0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d,
-       0x91646c97, 0xe6635c01, 0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e,
-       0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, 0x65b0d9c6, 0x12b7e950,
-       0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65,
-       0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7,
-       0xa4d1c46d, 0xd3d6f4fb, 0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0,
-       0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, 0x5005713c, 0x270241aa,
-       0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f,
-       0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81,
-       0xb7bd5c3b, 0xc0ba6cad, 0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a,
-       0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, 0xe3630b12, 0x94643b84,
-       0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1,
-       0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb,
-       0x196c3671, 0x6e6b06e7, 0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc,
-       0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, 0xd6d6a3e8, 0xa1d1937e,
-       0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b,
-       0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55,
-       0x316e8eef, 0x4669be79, 0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236,
-       0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, 0xc5ba3bbe, 0xb2bd0b28,
-       0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d,
-       0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f,
-       0x72076785, 0x05005713, 0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38,
-       0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, 0x86d3d2d4, 0xf1d4e242,
-       0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777,
-       0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69,
-       0x616bffd3, 0x166ccf45, 0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2,
-       0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, 0xaed16a4a, 0xd9d65adc,
-       0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9,
-       0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693,
-       0x54de5729, 0x23d967bf, 0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94,
-       0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d
-};
-
-uint32_t crc32_init(void)
-{
-       return 0xffffffff;
-}
-
-uint32_t crc32_byte(uint32_t accum, uint8_t delta)
-{
-       return dfu_crc32_table[(accum ^ delta) & 0xff] ^ (accum >> 8);
-}
-
-int dfu_detach(struct usb_dev_handle *udev, int intf)
-{
-       if (!udev)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_DIR_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-               DFU_DETACH, 0x1388, intf, NULL, 0, DFU_TIMEOUT);
-}
-
-int dfu_upload(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size)
-{
-       if (!udev)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
-               DFU_UPLOAD, block, intf, buffer, size, DFU_TIMEOUT);
-}
-
-int dfu_download(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size)
-{
-       if (!udev)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
-               DFU_DNLOAD, block, intf, buffer, size, DFU_TIMEOUT);
-}
-
-int dfu_get_status(struct usb_dev_handle *udev, int intf, struct dfu_status *status)
-{
-       if (!udev || !status)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
-               DFU_GETSTATUS, 0, intf, (char *) status, DFU_STATUS_SIZE, DFU_TIMEOUT);
-}
-
-int dfu_clear_status(struct usb_dev_handle *udev, int intf)
-{
-       if (!udev)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
-               DFU_CLRSTATUS, 0, intf, NULL, 0, DFU_TIMEOUT);
-}
-
-int dfu_get_state(struct usb_dev_handle *udev, int intf, uint8_t *state)
-{
-       if (!udev || !state)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
-               DFU_GETSTATE, 0, intf, (char *) state, 1, DFU_TIMEOUT);
-}
-
-int dfu_abort(struct usb_dev_handle *udev, int intf)
-{
-       if (!udev)
-               return -EIO;
-
-       return usb_control_msg(udev, USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE,
-               DFU_ABORT, 0, intf, NULL, 0, DFU_TIMEOUT);
-}
diff --git a/tools/dfu.h b/tools/dfu.h
deleted file mode 100644 (file)
index 7f999f4..0000000
+++ /dev/null
@@ -1,107 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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>
-
-/* CRC interface */
-uint32_t crc32_init(void);
-uint32_t crc32_byte(uint32_t accum, uint8_t delta);
-
-/* DFU descriptor */
-struct usb_dfu_descriptor {
-       u_int8_t  bLength;
-       u_int8_t  bDescriptorType;
-       u_int8_t  bmAttributes;
-       u_int16_t wDetachTimeout;
-       u_int16_t wTransferSize;
-};
-
-/* DFU commands */
-#define DFU_DETACH             0
-#define DFU_DNLOAD             1
-#define DFU_UPLOAD             2
-#define DFU_GETSTATUS          3
-#define DFU_CLRSTATUS          4
-#define DFU_GETSTATE           5
-#define DFU_ABORT              6
-
-/* DFU status */
-struct dfu_status {
-       uint8_t bStatus;
-       uint8_t bwPollTimeout[3];
-       uint8_t bState;
-       uint8_t iString;
-} __attribute__ ((packed));
-#define DFU_STATUS_SIZE 6
-
-/* DFU status */
-#define DFU_OK                 0x00
-#define DFU_ERR_TARGET         0x01
-#define DFU_ERR_FILE           0x02
-#define DFU_ERR_WRITE          0x03
-#define DFU_ERR_ERASE          0x04
-#define DFU_ERR_CHECK_ERASED   0x05
-#define DFU_ERR_PROG           0x06
-#define DFU_ERR_VERIFY         0x07
-#define DFU_ERR_ADDRESS                0x08
-#define DFU_ERR_NOTDONE                0x09
-#define DFU_ERR_FIRMWARE       0x0a
-#define DFU_ERR_VENDOR         0x0b
-#define DFU_ERR_USBR           0x0c
-#define DFU_ERR_POR            0x0d
-#define DFU_ERR_UNKNOWN                0x0e
-#define DFU_ERR_STALLEDPKT     0x0f
-
-/* DFU state */
-#define DFU_STATE_APP_IDLE             0
-#define DFU_STATE_APP_DETACH           1
-#define DFU_STATE_DFU_IDLE             2
-#define DFU_STATE_DFU_DNLOAD_SYNC      3
-#define DFU_STATE_DFU_DNLOAD_BUSY      4
-#define DFU_STATE_DFU_DNLOAD_IDLE      5
-#define DFU_STATE_DFU_MANIFEST_SYNC    6
-#define DFU_STATE_DFU_MANIFEST         7
-#define DFU_STATE_MANIFEST_WAIT_RESET  8
-#define DFU_STATE_UPLOAD_IDLE          9
-#define DFU_STATE_ERROR                        10
-
-/* DFU suffix */
-struct dfu_suffix {
-       uint16_t bcdDevice;
-       uint16_t idProduct;
-       uint16_t idVendor;
-       uint16_t bcdDFU;
-       uint8_t  ucDfuSignature[3];
-       uint8_t  bLength;
-       uint32_t dwCRC;
-} __attribute__ ((packed));
-#define DFU_SUFFIX_SIZE 16
-
-/* DFU interface */
-int dfu_detach(struct usb_dev_handle *udev, int intf);
-int dfu_upload(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size);
-int dfu_download(struct usb_dev_handle *udev, int intf, int block, char *buffer, int size);
-int dfu_get_status(struct usb_dev_handle *udev, int intf, struct dfu_status *status);
-int dfu_clear_status(struct usb_dev_handle *udev, int intf);
-int dfu_get_state(struct usb_dev_handle *udev, int intf, uint8_t *state);
-int dfu_abort(struct usb_dev_handle *udev, int intf);
diff --git a/tools/dfubabel.1 b/tools/dfubabel.1
deleted file mode 100644 (file)
index 5e0f805..0000000
+++ /dev/null
@@ -1,38 +0,0 @@
-.\"
-.\"    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\"
-.\"
-.TH DFUBABEL 8 "JUNE 6, 2005" "" ""
-
-.SH NAME
-dfubabel \- Babel DFU mode switching utility
-.SH SYNOPSIS
-.BR "dfubabel
-[
-.I options
-]
-.SH DESCRIPTION
-.B dfubabel
-is used to switch Babel devices into DFU mode.
-.SH OPTIONS
-.TP
-.BI -h
-Gives a list of possible options.
-.TP
-.BI -q
-Don't display any messages.
-.SH AUTHOR
-Written by Marcel Holtmann <marcel@holtmann.org>.
-.br
diff --git a/tools/dfubabel.c b/tools/dfubabel.c
deleted file mode 100644 (file)
index 612accc..0000000
+++ /dev/null
@@ -1,211 +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 <fcntl.h>
-#include <stdint.h>
-#include <string.h>
-#include <getopt.h>
-
-#include <usb.h>
-
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
-       return usb_busses;
-}
-#endif
-
-struct device_info;
-
-struct device_id {
-       uint16_t vendor;
-       uint16_t product;
-       int (*func)(struct device_info *dev, int argc, char *argv[]);
-};
-
-struct device_info {
-       struct usb_device *dev;
-       struct device_id *id;
-};
-
-static int switch_babel(struct device_info *devinfo, int argc, char *argv[])
-{
-       char buf[3];
-       struct usb_dev_handle *udev;
-       int err;
-
-       memset(buf, 0, sizeof(buf));
-
-       buf[0] = 0x00;
-       buf[1] = 0x06;
-       buf[2] = 0x00;
-
-       udev = usb_open(devinfo->dev);
-       if (!udev)
-               return -errno;
-
-       if (usb_claim_interface(udev, 0) < 0) {
-               err = -errno;
-               usb_close(udev);
-               return err;
-       }
-
-       err = usb_bulk_write(udev, 0x02, buf, sizeof(buf), 10000);
-
-       if (err == 0) {
-               err = -1;
-               errno = EALREADY;
-       } else {
-               if (errno == ETIMEDOUT)
-                       err = 0;
-       }
-
-       usb_release_interface(udev, 0);
-       usb_close(udev);
-
-       return err;
-}
-
-static struct device_id device_list[] = {
-       { 0x0a12, 0x0042, switch_babel },
-       { -1 }
-};
-
-static struct device_id *match_device(uint16_t vendor, uint16_t product)
-{
-       int i;
-
-       for (i = 0; device_list[i].func; i++) {
-               if (vendor == device_list[i].vendor &&
-                               product == device_list[i].product)
-                       return &device_list[i];
-       }
-
-       return NULL;
-}
-
-static int find_devices(struct device_info *devinfo, size_t size)
-{
-       struct usb_bus *bus;
-       struct usb_device *dev;
-       struct device_id *id;
-       unsigned int count = 0;
-
-       usb_find_busses();
-       usb_find_devices();
-
-       for (bus = usb_get_busses(); bus; bus = bus->next)
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       id = match_device(dev->descriptor.idVendor,
-                                               dev->descriptor.idProduct);
-                       if (!id)
-                               continue;
-
-                       if (count < size) {
-                               devinfo[count].dev = dev;
-                               devinfo[count].id = id;
-                               count++;
-                       }
-               }
-
-       return count;
-}
-
-static void usage(void)
-{
-       printf("dfubabel - Babel DFU mode switching utility\n\n");
-
-       printf("Usage:\n"
-               "\tdfubabel [options]\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-h, --help           Display help\n"
-               "\t-q, --quiet          Don't display any messages\n"
-               "\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "quiet",      0, 0, 'q' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       struct device_info dev[16];
-       int i, opt, num, quiet = 0;
-
-       while ((opt = getopt_long(argc, argv, "+qh", main_options, NULL)) != -1) {
-               switch (opt) {
-               case 'q':
-                       quiet = 1;
-                       break;
-               case 'h':
-                       usage();
-                       exit(0);
-               default:
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       usb_init();
-
-       num = find_devices(dev, sizeof(dev) / sizeof(dev[0]));
-       if (num <= 0) {
-               if (!quiet)
-                       fprintf(stderr, "No Babel devices found\n");
-               exit(1);
-       }
-
-       for (i = 0; i < num; i++) {
-               struct device_id *id = dev[i].id;
-               int err;
-
-               if (!quiet)
-                       printf("Switching device %04x:%04x ",
-                                               id->vendor, id->product);
-               fflush(stdout);
-
-               err = id->func(&dev[i], argc, argv);
-               if (err < 0) {
-                       if (!quiet)
-                               printf("failed (%s)\n", strerror(-err));
-               } else {
-                       if (!quiet)
-                               printf("was successful\n");
-               }
-       }
-
-       return 0;
-}
diff --git a/tools/dfutool.1 b/tools/dfutool.1
deleted file mode 100644 (file)
index 115114b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-.\"
-.\"    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., 675 Mass Ave, Cambridge, MA 02139, USA.
-.\"
-.\"
-.TH DFUTOOL 1 "APRIL 21, 2005" "" ""
-
-.SH NAME
-dfutool \- Device Firmware Upgrade utility
-.SH SYNOPSIS
-.BR "dfutool
-[
-.I options
-] <
-.I command
->
-.SH DESCRIPTION
-.B dfutool
-is used to verify, archive and upgrade firmware files.
-.SH OPTIONS
-.TP
-.BI -h
-Gives a list of possible commands.
-.TP
-.BI -d " <device>"
-The command specifies the device to use.
-.SH COMMANDS
-.TP
-.BI verify " <dfu-file>"
-Display information about the firmware file.
-.TP
-.BI modify " <dfu-file>"
-Change DFU specific values in the firmware file.
-.TP
-.BI upgrade " <dfu-file>"
-Upgrade the device with a new firmware.
-.TP
-.BI archive " <dfu-file>"
-Archive the current firmware of the device.
-.SH AUTHOR
-Written by Marcel Holtmann <marcel@holtmann.org>.
-.br
diff --git a/tools/dfutool.c b/tools/dfutool.c
deleted file mode 100644 (file)
index 16dd62e..0000000
+++ /dev/null
@@ -1,791 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  Copyright (C) 2003-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 <fcntl.h>
-#include <unistd.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <getopt.h>
-#include <string.h>
-#include <libgen.h>
-#include <endian.h>
-#include <byteswap.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-
-#include <usb.h>
-
-#include "dfu.h"
-
-#if __BYTE_ORDER == __LITTLE_ENDIAN
-#define cpu_to_le16(d)  (d)
-#define cpu_to_le32(d)  (d)
-#define le16_to_cpu(d)  (d)
-#define le32_to_cpu(d)  (d)
-#elif __BYTE_ORDER == __BIG_ENDIAN
-#define cpu_to_le16(d)  bswap_16(d)
-#define cpu_to_le32(d)  bswap_32(d)
-#define le16_to_cpu(d)  bswap_16(d)
-#define le32_to_cpu(d)  bswap_32(d)
-#else
-#error "Unknown byte order"
-#endif
-
-#ifdef NEED_USB_GET_BUSSES
-static inline struct usb_bus *usb_get_busses(void)
-{
-       return usb_busses;
-}
-#endif
-
-#ifndef USB_CLASS_WIRELESS
-#define USB_CLASS_WIRELESS     0xe0
-#endif
-
-#ifndef USB_CLASS_APPLICATION
-#define USB_CLASS_APPLICATION  0xfe
-#endif
-
-static int get_interface_number(struct usb_device *dev)
-{
-       int c, i, a;
-
-       for (c = 0; c < dev->descriptor.bNumConfigurations; c++) {
-               struct usb_config_descriptor *config = &dev->config[c];
-
-               for (i = 0; i < config->bNumInterfaces; i++) {
-                       struct usb_interface *interface = &config->interface[i];
-
-                       for (a = 0; a < interface->num_altsetting; a++) {
-                               struct usb_interface_descriptor *desc = &interface->altsetting[a];
-
-                               if (desc->bInterfaceClass != USB_CLASS_APPLICATION)
-                                       continue;
-                               if (desc->bInterfaceSubClass != 0x01)
-                                       continue;
-                               if (desc->bInterfaceProtocol != 0x00)
-                                       continue;
-
-                               return desc->bInterfaceNumber;
-                       }
-               }
-       }
-
-       return -1;
-}
-
-static void print_device(struct usb_device *dev)
-{
-       printf("Bus %s Device %s: ID %04x:%04x Interface %d%s\n",
-               dev->bus->dirname, dev->filename,
-               dev->descriptor.idVendor, dev->descriptor.idProduct,
-               get_interface_number(dev),
-               dev->descriptor.bDeviceClass == USB_CLASS_APPLICATION ? " (DFU mode)" : "");
-}
-
-static struct usb_dev_handle *open_device(char *device, struct dfu_suffix *suffix)
-{
-       struct usb_bus *bus;
-       struct usb_device *dev, *dfu_dev[10];
-       struct usb_dev_handle *udev;
-       struct dfu_status status;
-       char str[8];
-       int i, intf, sel = 0, num = 0, try = 5, bus_id = -1, dev_id = -1;
-
-       printf("Scanning USB busses ... ");
-       fflush(stdout);
-
-       usb_find_busses();
-       usb_find_devices();
-
-       for (bus = usb_get_busses(); bus; bus = bus->next) {
-               if (bus_id > 0) {
-                       snprintf(str, sizeof(str) - 1, "%03i", bus_id);
-                       if (strcmp(str, bus->dirname))
-                               continue;
-               }
-
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       if (bus_id > 0 && dev_id > 0) {
-                               snprintf(str, sizeof(str) - 1, "%03i", dev_id);
-                               if (strcmp(str, dev->filename))
-                                       continue;
-                       }
-
-                       if (dev->descriptor.bDeviceClass == USB_CLASS_HUB)
-                               continue;
-
-                       if (num > 9 || get_interface_number(dev) < 0)
-                               continue;
-
-                       dfu_dev[num++] = dev;
-               }
-       }
-
-       if (num < 1) {
-               printf("\rCan't find any DFU devices\n");
-               return NULL;
-       }
-
-       printf("\rAvailable devices with DFU support:\n\n");
-       for (i = 0; i < num; i++) {
-               printf("\t%2d) ", i + 1);
-               print_device(dfu_dev[i]);
-       }
-       printf("\n");
-
-       do {
-               printf("\rSelect device (abort with 0): ");
-               fflush(stdout);
-               memset(str, 0, sizeof(str));
-               if (!fgets(str, sizeof(str) - 1, stdin))
-                       continue;
-               sel = atoi(str);
-       } while (!isdigit(str[0]) || sel < 0 || sel > num );
-
-       if (sel < 1)
-               return NULL;
-
-       sel--;
-       intf = get_interface_number(dfu_dev[sel]);
-       printf("\n");
-
-       udev = usb_open(dfu_dev[sel]);
-       if (!udev) {
-               printf("Can't open device: %s (%d)\n", strerror(errno), errno);
-               return NULL;
-       }
-
-       if (usb_claim_interface(udev, intf) < 0) {
-               printf("Can't claim interface: %s (%d)\n", strerror(errno), errno);
-               usb_close(udev);
-               return NULL;
-       }
-
-       if (dfu_get_status(udev, intf, &status) < 0) {
-               printf("Can't get status: %s (%d)\n", strerror(errno), errno);
-               goto error;
-       }
-
-       if (status.bState == DFU_STATE_ERROR) {
-               if (dfu_clear_status(udev, intf) < 0) {
-                       printf("Can't clear status: %s (%d)\n", strerror(errno), errno);
-                       goto error;
-               }
-               if (dfu_abort(udev, intf) < 0) {
-                       printf("Can't abort previous action: %s (%d)\n", strerror(errno), errno);
-                       goto error;
-               }
-               if (dfu_get_status(udev, intf, &status) < 0) {
-                       printf("Can't get status: %s (%d)\n", strerror(errno), errno);
-                       goto error;
-               }
-       }
-
-       if (status.bState == DFU_STATE_DFU_IDLE) {
-               if (suffix) {
-                       suffix->idVendor  = cpu_to_le16(0x0000);
-                       suffix->idProduct = cpu_to_le16(0x0000);
-                       suffix->bcdDevice = cpu_to_le16(0x0000);
-               }
-               return udev;
-       }
-
-       if (status.bState != DFU_STATE_APP_IDLE) {
-               printf("Device is not idle, can't detach it (state %d)\n", status.bState);
-               goto error;
-       }
-
-       printf("Switching device into DFU mode ... ");
-       fflush(stdout);
-
-       if (suffix) {
-               suffix->idVendor  = cpu_to_le16(dfu_dev[sel]->descriptor.idVendor);
-               suffix->idProduct = cpu_to_le16(dfu_dev[sel]->descriptor.idProduct);
-               suffix->bcdDevice = cpu_to_le16(dfu_dev[sel]->descriptor.bcdDevice);
-       }
-
-       if (dfu_detach(udev, intf) < 0) {
-               printf("\rCan't detach device: %s (%d)\n", strerror(errno), errno);
-               goto error;
-       }
-
-       if (dfu_get_status(udev, intf, &status) < 0) {
-               printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
-               goto error;
-       }
-
-       if (status.bState != DFU_STATE_APP_DETACH) {
-               printf("\rDevice is not in detach mode, try again\n");
-               goto error;
-       }
-
-       usb_release_interface(udev, intf);
-       usb_reset(udev);
-       usb_close(udev);
-
-       bus = dfu_dev[sel]->bus;
-       num = 0;
-
-       while (num != 1 && try-- > 0) {
-               sleep(1);
-               usb_find_devices();
-
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       if (dev->descriptor.bDeviceClass != USB_CLASS_APPLICATION)
-                               continue;
-
-                       if (suffix && dev->descriptor.idVendor != le16_to_cpu(suffix->idVendor))
-                               continue;
-
-                       if (num > 9 || get_interface_number(dev) != 0)
-                               continue;
-
-                       dfu_dev[num++] = dev;
-               }
-       }
-
-       if (num != 1) {
-               printf("\rCan't identify device with DFU mode\n");
-               goto error;
-       }
-
-       printf("\r");
-
-       intf = 0;
-
-       udev = usb_open(dfu_dev[0]);
-       if (!udev) {
-               printf("Can't open device: %s (%d)\n", strerror(errno), errno);
-               return NULL;
-       }
-
-       if (usb_claim_interface(udev, intf) < 0) {
-               printf("Can't claim interface: %s (%d)\n", strerror(errno), errno);
-               usb_close(udev);
-               return NULL;
-       }
-
-       if (dfu_get_status(udev, intf, &status) < 0) {
-               printf("Can't get status: %s (%d)\n", strerror(errno), errno);
-               goto error;
-       }
-
-       if (status.bState != DFU_STATE_DFU_IDLE) {
-               printf("Device is not in DFU mode, can't use it\n");
-               goto error;
-       }
-
-       return udev;
-
-error:
-       usb_release_interface(udev, intf);
-       usb_close(udev);
-       return NULL;
-}
-
-static void usage(void);
-
-static void cmd_verify(char *device, int argc, char **argv)
-{
-       struct stat st;
-       struct dfu_suffix *suffix;
-       uint32_t crc;
-       uint16_t bcd;
-       char str[16];
-       unsigned char *buf;
-       size_t size;
-       char *filename;
-       unsigned int i, len;
-       int fd;
-
-       if (argc < 2) {
-               usage();
-               exit(1);
-       }
-
-       filename = argv[1];
-
-       if (stat(filename, &st) < 0) {
-               perror("Can't access firmware");
-               exit(1);
-       }
-
-       size = st.st_size;
-
-       if (!(buf = malloc(size))) {
-               perror("Unable to allocate file buffer");
-               exit(1);
-       }
-
-       if ((fd = open(filename, O_RDONLY)) < 0) {
-               perror("Can't open firmware");
-               free(buf);
-               exit(1);
-       }
-
-       if (read(fd, buf, size) < (ssize_t) size) {
-               perror("Can't load firmware");
-               free(buf);
-               close(fd);
-               exit(1);
-       }
-
-       printf("Filename\t%s\n", basename(filename));
-       printf("Filesize\t%zd\n", size);
-
-       crc = crc32_init();
-       for (i = 0; i < size - 4; i++)
-               crc = crc32_byte(crc, buf[i]);
-       printf("Checksum\t%08x\n", crc);
-
-       printf("\n");
-       len = buf[size - 5];
-       printf("DFU suffix\t");
-       for (i = 0; i < len; i++) {
-               printf("%02x ", buf[size - len + i]);
-       }
-       printf("\n\n");
-
-       suffix = (struct dfu_suffix *) (buf + size - DFU_SUFFIX_SIZE);
-
-       printf("idVendor\t%04x\n", le16_to_cpu(suffix->idVendor));
-       printf("idProduct\t%04x\n", le16_to_cpu(suffix->idProduct));
-       printf("bcdDevice\t%x\n", le16_to_cpu(suffix->bcdDevice));
-
-       printf("\n");
-
-       bcd = le16_to_cpu(suffix->bcdDFU);
-
-       printf("bcdDFU\t\t%x.%x\n", bcd >> 8, bcd & 0xff);
-       printf("ucDfuSignature\t%c%c%c\n", suffix->ucDfuSignature[2],
-               suffix->ucDfuSignature[1], suffix->ucDfuSignature[0]);
-       printf("bLength\t\t%d\n", suffix->bLength);
-       printf("dwCRC\t\t%08x\n", le32_to_cpu(suffix->dwCRC));
-       printf("\n");
-
-       memset(str, 0, sizeof(str));
-       memcpy(str, buf, 8);
-
-       if (!strcmp(str, "CSR-dfu1") || !strcmp(str, "CSR-dfu2")) {
-               crc = crc32_init();
-               for (i = 0; i < size - DFU_SUFFIX_SIZE; i++)
-                       crc = crc32_byte(crc, buf[i]);
-
-               printf("Firmware type\t%s\n", str);
-               printf("Firmware check\t%s checksum\n", crc == 0 ? "valid" : "corrupt");
-               printf("\n");
-       }
-
-       free(buf);
-
-       close(fd);
-}
-
-static void cmd_modify(char *device, int argc, char **argv)
-{
-}
-
-static void cmd_upgrade(char *device, int argc, char **argv)
-{
-       struct usb_dev_handle *udev;
-       struct dfu_status status;
-       struct dfu_suffix suffix;
-       struct stat st;
-       char *buf;
-       size_t filesize;
-       unsigned long count, timeout = 0;
-       char *filename;
-       uint32_t crc, dwCRC;
-       unsigned int i;
-       int fd, block, len, size, sent = 0, try = 10;
-
-       if (argc < 2) {
-               usage();
-               exit(1);
-       }
-
-       filename = argv[1];
-
-       if (stat(filename, &st) < 0) {
-               perror("Can't access firmware");
-               exit(1);
-       }
-
-       filesize = st.st_size;
-
-       if (!(buf = malloc(filesize))) {
-               perror("Unable to allocate file buffer");
-               exit(1);
-       }
-
-       if ((fd = open(filename, O_RDONLY)) < 0) {
-               perror("Can't open firmware");
-               free(buf);
-               exit(1);
-       }
-
-       if (read(fd, buf, filesize) < (ssize_t) filesize) {
-               perror("Can't load firmware");
-               free(buf);
-               close(fd);
-               exit(1);
-       }
-
-       memcpy(&suffix, buf + filesize - DFU_SUFFIX_SIZE, sizeof(suffix));
-       dwCRC = le32_to_cpu(suffix.dwCRC);
-
-       printf("Filename\t%s\n", basename(filename));
-       printf("Filesize\t%zd\n", filesize);
-
-       crc = crc32_init();
-       for (i = 0; i < filesize - 4; i++)
-               crc = crc32_byte(crc, buf[i]);
-
-       printf("Checksum\t%08x (%s)\n", crc,
-                       crc == dwCRC ? "valid" : "corrupt");
-
-       if (crc != dwCRC) {
-               free(buf);
-               close(fd);
-               exit(1);
-       }
-
-       printf("\n");
-
-       udev = open_device(device, &suffix);
-       if (!udev)
-               exit(1);
-
-       printf("\r" "          " "          " "          " "          " "          ");
-       printf("\rFirmware download ... ");
-       fflush(stdout);
-
-       count = filesize - DFU_SUFFIX_SIZE;
-       block = 0;
-
-       while (count) {
-               size = (count > 1023) ? 1023 : count;
-
-               if (dfu_get_status(udev, 0, &status) < 0) {
-                       if (try-- > 0) {
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
-                       goto done;
-               }
-
-               if (status.bStatus != DFU_OK) {
-                       if (try-- > 0) {
-                               dfu_clear_status(udev, 0);
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rFirmware download ... aborting (status %d state %d)\n",
-                                               status.bStatus, status.bState);
-                       goto done;
-               }
-
-               if (status.bState != DFU_STATE_DFU_IDLE &&
-                               status.bState != DFU_STATE_DFU_DNLOAD_IDLE) {
-                       sleep(1);
-                       continue;
-               }
-
-               timeout = (status.bwPollTimeout[2] << 16) |
-                               (status.bwPollTimeout[1] << 8) |
-                                       status.bwPollTimeout[0];
-
-               usleep(timeout * 1000);
-
-               len = dfu_download(udev, 0, block, buf + sent, size);
-               if (len < 0) {
-                       if (try-- > 0) {
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rCan't upload next block: %s (%d)\n", strerror(errno), errno);
-                       goto done;
-               }
-
-               printf("\rFirmware download ... %d bytes ", block * 1023 + len);
-               fflush(stdout);
-
-               sent  += len;
-               count -= len;
-               block++;
-       }
-
-       printf("\r" "          " "          " "          " "          " "          ");
-       printf("\rFinishing firmware download ... ");
-       fflush(stdout);
-
-       sleep(1);
-
-       if (dfu_get_status(udev, 0, &status) < 0) {
-               printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
-               goto done;
-       }
-
-       timeout = (status.bwPollTimeout[2] << 16) |
-                       (status.bwPollTimeout[1] << 8) |
-                               status.bwPollTimeout[0];
-
-       usleep(timeout * 1000);
-
-       if (count == 0) {
-               len = dfu_download(udev, 0, block, NULL, 0);
-               if (len < 0) {
-                       printf("\rCan't send final block: %s (%d)\n", strerror(errno), errno);
-                       goto done;
-               }
-       }
-
-       printf("\r" "          " "          " "          " "          " "          ");
-       printf("\rWaiting for device ... ");
-       fflush(stdout);
-
-       sleep(10);
-
-       printf("\n");
-
-done:
-       free(buf);
-       close(fd);
-
-       usb_release_interface(udev, 0);
-       usb_reset(udev);
-       usb_close(udev);
-}
-
-static void cmd_archive(char *device, int argc, char **argv)
-{
-       struct usb_dev_handle *udev;
-       struct dfu_status status;
-       struct dfu_suffix suffix;
-       char buf[2048];
-       unsigned long timeout = 0;
-       char *filename;
-       uint32_t crc;
-       int fd, i, n, len, try = 8;
-
-       if (argc < 2) {
-               usage();
-               exit(1);
-       }
-
-       filename = argv[1];
-
-       udev = open_device(device, &suffix);
-       if (!udev)
-               exit(1);
-
-       fd = open(filename, O_WRONLY | O_CREAT | O_TRUNC, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
-       if (fd < 0) {
-               printf("Can't open firmware file: %s (%d)\n", strerror(errno), errno);
-               goto done;
-       }
-
-       printf("\r" "          " "          " "          " "          " "          ");
-       printf("\rFirmware upload ... ");
-       fflush(stdout);
-
-       crc = crc32_init();
-       n = 0;
-       while (1) {
-               if (dfu_get_status(udev, 0, &status) < 0) {
-                       if (try-- > 0) {
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rCan't get status: %s (%d)\n", strerror(errno), errno);
-                       goto done;
-               }
-
-               if (status.bStatus != DFU_OK) {
-                       if (try-- > 0) {
-                               dfu_clear_status(udev, 0);
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rFirmware upload ... aborting (status %d state %d)\n",
-                                               status.bStatus, status.bState);
-                       goto done;
-               }
-
-               if (status.bState != DFU_STATE_DFU_IDLE &&
-                               status.bState != DFU_STATE_UPLOAD_IDLE) {
-                       sleep(1);
-                       continue;
-               }
-
-               timeout = (status.bwPollTimeout[2] << 16) |
-                               (status.bwPollTimeout[1] << 8) |
-                                       status.bwPollTimeout[0];
-
-               usleep(timeout * 1000);
-
-               len = dfu_upload(udev, 0, n, buf, 1023);
-               if (len < 0) {
-                       if (try-- > 0) {
-                               sleep(1);
-                               continue;
-                       }
-                       printf("\rCan't upload next block: %s (%d)\n", strerror(errno), errno);
-                       goto done;
-               }
-
-               printf("\rFirmware upload ... %d bytes ", n * 1023 + len);
-               fflush(stdout);
-
-               for (i = 0; i < len; i++)
-                       crc = crc32_byte(crc, buf[i]);
-
-               if (len > 0) {
-                       if (write(fd, buf, len) < 0) {
-                               printf("\rCan't write next block: %s (%d)\n", strerror(errno), errno);
-                               goto done;
-                       }
-               }
-
-               n++;
-               if (len != 1023)
-                       break;
-       }
-       printf("\n");
-
-       suffix.bcdDFU = cpu_to_le16(0x0100);
-       suffix.ucDfuSignature[0] = 'U';
-       suffix.ucDfuSignature[1] = 'F';
-       suffix.ucDfuSignature[2] = 'D';
-       suffix.bLength = DFU_SUFFIX_SIZE;
-
-       memcpy(buf, &suffix, DFU_SUFFIX_SIZE);
-       for (i = 0; i < DFU_SUFFIX_SIZE - 4; i++)
-               crc = crc32_byte(crc, buf[i]);
-
-       suffix.dwCRC = cpu_to_le32(crc);
-
-       if (write(fd, &suffix, DFU_SUFFIX_SIZE) < 0)
-               printf("Can't write suffix block: %s (%d)\n", strerror(errno), errno);
-
-done:
-       close(fd);
-
-       usb_release_interface(udev, 0);
-       usb_reset(udev);
-       usb_close(udev);
-}
-
-struct {
-       char *cmd;
-       char *alt;
-       void (*func)(char *device, int argc, char **argv);
-       char *opt;
-       char *doc;
-} command[] = {
-       { "verify",  "check",    cmd_verify,  "<dfu-file>", "Check firmware file"         },
-       { "modify",  "change",   cmd_modify,  "<dfu-file>", "Change firmware attributes"  },
-       { "upgrade", "download", cmd_upgrade, "<dfu-file>", "Download a new firmware"     },
-       { "archive", "upload",   cmd_archive, "<dfu-file>", "Upload the current firmware" },
-       { NULL, NULL, NULL, 0, 0 }
-};
-
-static void usage(void)
-{
-       int i;
-
-       printf("dfutool - Device Firmware Upgrade utility ver %s\n\n", VERSION);
-
-       printf("Usage:\n"
-               "\tdfutool [options] <command>\n"
-               "\n");
-
-       printf("Options:\n"
-               "\t-d, --device <device>   USB device\n"
-               "\t-h, --help              Display help\n"
-               "\n");
-
-       printf("Commands:\n");
-       for (i = 0; command[i].cmd; i++)
-               printf("\t%-8s %-10s\t%s\n", command[i].cmd,
-               command[i].opt ? command[i].opt : " ",
-               command[i].doc);
-       printf("\n");
-}
-
-static struct option main_options[] = {
-       { "help",       0, 0, 'h' },
-       { "device",     1, 0, 'd' },
-       { 0, 0, 0, 0 }
-};
-
-int main(int argc, char *argv[])
-{
-       char *device = NULL;
-       int i, opt;
-
-       while ((opt = getopt_long(argc, argv, "+d:h", main_options, NULL)) != -1) {
-               switch(opt) {
-               case 'd':
-                       device = strdup(optarg);
-                       break;
-
-               case 'h':
-                       usage();
-                       exit(0);
-
-               default:
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-       optind = 0;
-
-       if (argc < 1) {
-               usage();
-               exit(1);
-       }
-
-       usb_init();
-
-       for (i = 0; command[i].cmd; i++) {
-               if (strcmp(command[i].cmd, argv[0]) && strcmp(command[i].alt, argv[0]))
-                       continue;
-               command[i].func(device, argc, argv);
-               exit(0);
-       }
-
-       usage();
-       exit(1);
-}
diff --git a/tools/gap-tester.c b/tools/gap-tester.c
new file mode 100644 (file)
index 0000000..d788626
--- /dev/null
@@ -0,0 +1,139 @@
+/*
+ *
+ *  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 <gdbus.h>
+
+#include "src/shared/tester.h"
+#include "src/shared/hciemu.h"
+
+static DBusConnection *dbus_conn = NULL;
+static GDBusClient *dbus_client = NULL;
+static GDBusProxy *adapter_proxy = NULL;
+
+static struct hciemu *hciemu_stack = NULL;
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       tester_print("Connected to daemon");
+
+       hciemu_stack = hciemu_new(HCIEMU_TYPE_BREDRLE);
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       tester_print("Disconnected from daemon");
+
+       dbus_connection_unref(dbus_conn);
+       dbus_conn = NULL;
+
+       tester_teardown_complete();
+}
+
+static gboolean compare_string_property(GDBusProxy *proxy, const char *name,
+                                                       const char *value)
+{
+       DBusMessageIter iter;
+       const char *str;
+
+       if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+               return FALSE;
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_STRING)
+               return FALSE;
+
+       dbus_message_iter_get_basic(&iter, &str);
+
+       return g_str_equal(str, value);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (g_str_equal(interface, "org.bluez.Adapter1") == TRUE) {
+               if (compare_string_property(proxy, "Address",
+                               hciemu_get_address(hciemu_stack)) == TRUE) {
+                       adapter_proxy = proxy;
+                       tester_print("Found adapter");
+
+                       tester_setup_complete();
+               }
+       }
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (g_str_equal(interface, "org.bluez.Adapter1") == TRUE) {
+               if (adapter_proxy == proxy) {
+                       adapter_proxy = NULL;
+                       tester_print("Adapter removed");
+
+                       g_dbus_client_unref(dbus_client);
+                       dbus_client = NULL;
+               }
+       }
+}
+
+static void test_setup(const void *test_data)
+{
+       dbus_conn = g_dbus_setup_private(DBUS_BUS_SYSTEM, NULL, NULL);
+
+       dbus_client = g_dbus_client_new(dbus_conn, "org.bluez", "/org/bluez");
+
+       g_dbus_client_set_connect_watch(dbus_client, connect_handler, NULL);
+       g_dbus_client_set_disconnect_watch(dbus_client,
+                                               disconnect_handler, NULL);
+
+       g_dbus_client_set_proxy_handlers(dbus_client, proxy_added,
+                                               proxy_removed, NULL, NULL);
+}
+
+static void test_run(const void *test_data)
+{
+       tester_test_passed();
+}
+
+static void test_teardown(const void *test_data)
+{
+       hciemu_unref(hciemu_stack);
+       hciemu_stack = NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       tester_init(&argc, &argv);
+
+       tester_add("Adapter setup", NULL, test_setup, test_run, test_teardown);
+
+       return tester_run();
+}
similarity index 98%
rename from tools/hciattach.8
rename to tools/hciattach.1
index cc97cad..d506034 100644 (file)
@@ -1,4 +1,4 @@
-.TH HCIATTACH 8 "Jan 22 2002" BlueZ "Linux System Administration"
+.TH HCIATTACH 1 "Jan 22 2002" BlueZ "Linux System Administration"
 .SH NAME
 hciattach \- attach serial devices via UART HCI to BlueZ stack
 .SH SYNOPSIS
index d19fa33..db01b85 100644 (file)
@@ -27,7 +27,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
 
 #include "hciattach.h"
 
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
 struct uart_t {
        char *type;
        int  m_id;
@@ -68,6 +63,7 @@ struct uart_t {
 };
 
 #define FLOW_CTL       0x0001
+#define AMP_DEV                0x0002
 #define ENABLE_PM      1
 #define DISABLE_PM     0
 
@@ -1154,6 +1150,10 @@ struct uart_t uart[] = {
        { "3wire",      0x0000, 0x0000, HCI_UART_3WIRE, 115200, 115200,
                        0, DISABLE_PM, NULL, NULL, NULL },
 
+       /* AMP controller UART */
+       { "amp",        0x0000, 0x0000, HCI_UART_H4, 115200, 115200,
+                       AMP_DEV, DISABLE_PM, NULL, NULL, NULL },
+
        { NULL, 0 }
 };
 
@@ -1187,6 +1187,9 @@ static int init_uart(char *dev, struct uart_t *u, int send_break, int raw)
        if (raw)
                flags |= 1 << HCI_UART_RAW_DEVICE;
 
+       if (u->flags & AMP_DEV)
+               flags |= 1 << HCI_UART_CREATE_AMP;
+
        fd = open(dev, O_RDWR | O_NOCTTY);
        if (fd < 0) {
                perror("Can't open serial port");
index a24dbc4..1b23ad7 100644 (file)
@@ -44,7 +44,7 @@
 #define HCI_UART_RESET_ON_INIT 1
 #define HCI_UART_CREATE_AMP    2
 
-int read_hci_event(int fd, unsigned charbuf, int size);
+int read_hci_event(int fd, unsigned char *buf, int size);
 int set_speed(int fd, struct termios *ti, int speed);
 
 int texas_init(int fd, int *speed, struct termios *ti);
index 9129993..749098e 100644 (file)
@@ -148,14 +148,13 @@ static int validate_events(struct patch_entry *event,
  */
 static int get_next_patch_entry(int fd, struct patch_entry *entry)
 {
-       int len, size;
+       int size;
        char rb;
 
        if (read(fd, &rb, 1) <= 0)
                return 0;
 
        entry->type = rb;
-       len = 0;
 
        switch (entry->type) {
        case PATCH_TYPE_CMD:
@@ -176,7 +175,7 @@ static int get_next_patch_entry(int fd, struct patch_entry *entry)
        case PATCH_TYPE_EVT:
                entry->data[0] = HCI_EVENT_PKT;
 
-               if (read(fd, &entry->data[len], 2) < 0)
+               if (read(fd, &entry->data[1], 2) < 0)
                        return -1;
 
                size = (int)entry->data[2];
@@ -193,7 +192,7 @@ static int get_next_patch_entry(int fd, struct patch_entry *entry)
                return -1;
        }
 
-       return len;
+       return entry->len;
 }
 
 /**
index 158e568..8322b45 100644 (file)
@@ -55,7 +55,7 @@
 
 #define TI_MANUFACTURER_ID     13
 
-#define FIRMWARE_DIRECTORY     "/lib/firmware/"
+#define FIRMWARE_DIRECTORY     "/lib/firmware/ti-connectivity/"
 
 #define ACTION_SEND_COMMAND    1
 #define ACTION_WAIT_EVENT      2
@@ -109,10 +109,10 @@ struct bts_action_serial {
        uint32_t flow_control;
 }__attribute__ ((packed));
 
-static FILE *bts_load_script(const char* file_name, uint32_t* version)
+static FILE *bts_load_script(const char *file_name, uint32_t *version)
 {
        struct bts_header header;
-       FILEfp;
+       FILE *fp;
 
        fp = fopen(file_name, "rb");
        if (!fp) {
@@ -141,8 +141,8 @@ errclose:
        return NULL;
 }
 
-static unsigned long bts_fetch_action(FILE* fp, unsigned char* action_buf,
-                               unsigned long buf_size, uint16_taction_type)
+static unsigned long bts_fetch_action(FILE *fp, unsigned char *action_buf,
+                               unsigned long buf_size, uint16_t *action_type)
 {
        struct bts_action action_hdr;
        unsigned long nread;
@@ -169,7 +169,7 @@ static unsigned long bts_fetch_action(FILE* fp, unsigned char* action_buf,
        return nread * sizeof(uint8_t);
 }
 
-static void bts_unload_script(FILEfp)
+static void bts_unload_script(FILE *fp)
 {
        if (fp)
                fclose(fp);
@@ -237,7 +237,7 @@ static int brf_set_serial_params(struct bts_action_serial *serial_action,
        return 0;
 }
 
-static int brf_send_command_socket(int fd, struct bts_action_sendsend_action)
+static int brf_send_command_socket(int fd, struct bts_action_send *send_action)
 {
        char response[1024] = {0};
        hci_command_hdr *cmd = (hci_command_hdr *) send_action->data;
@@ -267,7 +267,8 @@ static int brf_send_command_socket(int fd, struct bts_action_send* send_action)
        return 0;
 }
 
-static int brf_send_command_file(int fd, struct bts_action_send* send_action, long size)
+static int brf_send_command_file(int fd, struct bts_action_send *send_action,
+                                                               long size)
 {
        unsigned char response[1024] = {0};
        long ret = 0;
@@ -296,7 +297,8 @@ static int brf_send_command_file(int fd, struct bts_action_send* send_action, lo
 }
 
 
-static int brf_send_command(int fd, struct bts_action_send* send_action, long size, int hcill_installed)
+static int brf_send_command(int fd, struct bts_action_send *send_action,
+                                               long size, int hcill_installed)
 {
        int ret = 0;
        char *fixed_action;
@@ -320,7 +322,9 @@ static int brf_do_action(uint16_t brf_type, uint8_t *brf_action, long brf_size,
        switch (brf_type) {
        case ACTION_SEND_COMMAND:
                DPRINTF("W");
-               ret = brf_send_command(fd, (struct bts_action_send*) brf_action, brf_size, hcill_installed);
+               ret = brf_send_command(fd,
+                                       (struct bts_action_send *) brf_action,
+                                       brf_size, hcill_installed);
                break;
        case ACTION_WAIT_EVENT:
                DPRINTF("R");
similarity index 96%
rename from tools/hciconfig.8
rename to tools/hciconfig.1
index 35956c4..633ffa3 100644 (file)
@@ -1,4 +1,4 @@
-.TH HCICONFIG 8 "Nov 11 2002" BlueZ "Linux System Administration"
+.TH HCICONFIG 1 "Nov 11 2002" BlueZ "Linux System Administration"
 .SH NAME
 hciconfig \- configure Bluetooth devices
 .SH SYNOPSIS
@@ -212,18 +212,13 @@ bytes and SCO buffer size to
 .I pkt
 packets.
 .TP
-.BI putkey " <bdaddr>"
-This command stores the link key for
-.I bdaddr
-on the device.
-.TP
 .BI delkey " <bdaddr>"
 This command deletes the stored link key for
 .I bdaddr
 from the device.
 .TP
 .BI oobdata
-Display local OOB data.
+Get local OOB data (invalidates previously read data).
 .TP
 .BI commands
 Display supported commands.
index f1458b9..fe45167 100644 (file)
@@ -242,6 +242,72 @@ static void cmd_le_adv(int ctl, int hdev, char *opt)
 {
        struct hci_request rq;
        le_set_advertise_enable_cp advertise_cp;
+       le_set_advertising_parameters_cp adv_params_cp;
+       uint8_t status;
+       int dd, ret;
+
+       if (hdev < 0)
+               hdev = hci_get_route(NULL);
+
+       dd = hci_open_dev(hdev);
+       if (dd < 0) {
+               perror("Could not open device");
+               exit(1);
+       }
+
+       memset(&adv_params_cp, 0, sizeof(adv_params_cp));
+       adv_params_cp.min_interval = htobs(0x0800);
+       adv_params_cp.max_interval = htobs(0x0800);
+       if (opt)
+               adv_params_cp.advtype = atoi(opt);
+       adv_params_cp.chan_map = 7;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_SET_ADVERTISING_PARAMETERS;
+       rq.cparam = &adv_params_cp;
+       rq.clen = LE_SET_ADVERTISING_PARAMETERS_CP_SIZE;
+       rq.rparam = &status;
+       rq.rlen = 1;
+
+       ret = hci_send_req(dd, &rq, 1000);
+       if (ret < 0)
+               goto done;
+
+       memset(&advertise_cp, 0, sizeof(advertise_cp));
+       advertise_cp.enable = 0x01;
+
+       memset(&rq, 0, sizeof(rq));
+       rq.ogf = OGF_LE_CTL;
+       rq.ocf = OCF_LE_SET_ADVERTISE_ENABLE;
+       rq.cparam = &advertise_cp;
+       rq.clen = LE_SET_ADVERTISE_ENABLE_CP_SIZE;
+       rq.rparam = &status;
+       rq.rlen = 1;
+
+       ret = hci_send_req(dd, &rq, 1000);
+
+done:
+       hci_close_dev(dd);
+
+       if (ret < 0) {
+               fprintf(stderr, "Can't set advertise mode on hci%d: %s (%d)\n",
+                                               hdev, strerror(errno), errno);
+               exit(1);
+       }
+
+       if (status) {
+               fprintf(stderr,
+                       "LE set advertise enable on hci%d returned status %d\n",
+                                                               hdev, status);
+               exit(1);
+       }
+}
+
+static void cmd_no_le_adv(int ctl, int hdev, char *opt)
+{
+       struct hci_request rq;
+       le_set_advertise_enable_cp advertise_cp;
        uint8_t status;
        int dd, ret;
 
@@ -255,10 +321,6 @@ static void cmd_le_adv(int ctl, int hdev, char *opt)
        }
 
        memset(&advertise_cp, 0, sizeof(advertise_cp));
-       if (strcmp(opt, "noleadv") == 0)
-               advertise_cp.enable = 0x00;
-       else
-               advertise_cp.enable = 0x01;
 
        memset(&rq, 0, sizeof(rq));
        rq.ogf = OGF_LE_CTL;
@@ -953,69 +1015,6 @@ static void cmd_voice(int ctl, int hdev, char *opt)
        }
 }
 
-static int get_link_key(const bdaddr_t *local, const bdaddr_t *peer,
-                       uint8_t *key)
-{
-       char filename[PATH_MAX + 1], addr[18], tmp[3], *str;
-       int i;
-
-       ba2str(local, addr);
-       create_name(filename, PATH_MAX, STORAGEDIR, addr, "linkkeys");
-
-       ba2str(peer, addr);
-       str = textfile_get(filename, addr);
-       if (!str)
-               return -EIO;
-
-       memset(tmp, 0, sizeof(tmp));
-       for (i = 0; i < 16; i++) {
-               memcpy(tmp, str + (i * 2), 2);
-               key[i] = (uint8_t) strtol(tmp, NULL, 16);
-       }
-
-       free(str);
-
-       return 0;
-}
-
-static void cmd_putkey(int ctl, int hdev, char *opt)
-{
-       struct hci_dev_info di;
-       bdaddr_t bdaddr;
-       uint8_t key[16];
-       int dd;
-
-       if (!opt)
-               return;
-
-       dd = hci_open_dev(hdev);
-       if (dd < 0) {
-               fprintf(stderr, "Can't open device hci%d: %s (%d)\n",
-                                               hdev, strerror(errno), errno);
-               exit(1);
-       }
-
-       if (hci_devinfo(hdev, &di) < 0) {
-               fprintf(stderr, "Can't get device info for hci%d: %s (%d)\n",
-                                               hdev, strerror(errno), errno);
-               exit(1);
-       }
-
-       str2ba(opt, &bdaddr);
-       if (get_link_key(&di.bdaddr, &bdaddr, key) < 0) {
-               fprintf(stderr, "Can't find link key for %s on hci%d\n", opt, hdev);
-               exit(1);
-       }
-
-       if (hci_write_stored_link_key(dd, &bdaddr, key, 1000) < 0) {
-               fprintf(stderr, "Can't write stored link key on hci%d: %s (%d)\n",
-                                               hdev, strerror(errno), errno);
-               exit(1);
-       }
-
-       hci_close_dev(dd);
-}
-
 static void cmd_delkey(int ctl, int hdev, char *opt)
 {
        bdaddr_t bdaddr;
@@ -1138,13 +1137,17 @@ static void cmd_version(int ctl, int hdev, char *opt)
        }
 
        hciver = hci_vertostr(ver.hci_ver);
-       lmpver = lmp_vertostr(ver.lmp_ver);
+       if (((di.type & 0x30) >> 4) == HCI_BREDR)
+               lmpver = lmp_vertostr(ver.lmp_ver);
+       else
+               lmpver = pal_vertostr(ver.lmp_ver);
 
        print_dev_hdr(&di);
        printf("\tHCI Version: %s (0x%x)  Revision: 0x%x\n"
-               "\tLMP Version: %s (0x%x)  Subversion: 0x%x\n"
+               "\t%s Version: %s (0x%x)  Subversion: 0x%x\n"
                "\tManufacturer: %s (%d)\n",
                hciver ? hciver : "n/a", ver.hci_ver, ver.hci_rev,
+               (((di.type & 0x30) >> 4) == HCI_BREDR) ? "LMP" : "PAL",
                lmpver ? lmpver : "n/a", ver.lmp_ver, ver.lmp_subver,
                bt_compidtostr(ver.manufacturer), ver.manufacturer);
 
@@ -1845,7 +1848,7 @@ static void print_dev_hdr(struct hci_dev_info *di)
        ba2str(&di->bdaddr, addr);
 
        printf("%s:\tType: %s  Bus: %s\n", di->name,
-                                       hci_typetostr(di->type >> 4),
+                                       hci_typetostr((di->type & 0x30) >> 4),
                                        hci_bustostr(di->type & 0x0f));
        printf("\tBD Address: %s  ACL MTU: %d:%d  SCO MTU: %d:%d\n",
                                        addr, di->acl_mtu, di->acl_pkts,
@@ -1869,18 +1872,22 @@ static void print_dev_info(int ctl, struct hci_dev_info *di)
        printf("\tTX bytes:%d acl:%d sco:%d commands:%d errors:%d\n",
                st->byte_tx, st->acl_tx, st->sco_tx, st->cmd_tx, st->err_tx);
 
-       if (all && !hci_test_bit(HCI_RAW, &di->flags) &&
-                       (bacmp(&di->bdaddr, BDADDR_ANY) || (di->type >> 4))) {
+       if (all && !hci_test_bit(HCI_RAW, &di->flags)) {
                print_dev_features(di, 0);
-               print_pkt_type(di);
-               print_link_policy(di);
-               print_link_mode(di);
 
-               if (hci_test_bit(HCI_UP, &di->flags)) {
-                       cmd_name(ctl, di->dev_id, NULL);
-                       cmd_class(ctl, di->dev_id, NULL);
-                       cmd_version(ctl, di->dev_id, NULL);
+               if (((di->type & 0x30) >> 4) == HCI_BREDR) {
+                       print_pkt_type(di);
+                       print_link_policy(di);
+                       print_link_mode(di);
+
+                       if (hci_test_bit(HCI_UP, &di->flags)) {
+                               cmd_name(ctl, di->dev_id, NULL);
+                               cmd_class(ctl, di->dev_id, NULL);
+                       }
                }
+
+               if (hci_test_bit(HCI_UP, &di->flags))
+                       cmd_version(ctl, di->dev_id, NULL);
        }
 
        printf("\n");
@@ -1911,7 +1918,7 @@ static struct {
        { "class",      cmd_class,      "[class]",      "Get/Set class of device" },
        { "voice",      cmd_voice,      "[voice]",      "Get/Set voice setting" },
        { "iac",        cmd_iac,        "[iac]",        "Get/Set inquiry access code" },
-       { "inqtpl",     cmd_inq_tpl,    "[level]",      "Get/Set inquiry transmit power level" },
+       { "inqtpl",     cmd_inq_tpl,    "[level]",      "Get/Set inquiry transmit power level" },
        { "inqmode",    cmd_inq_mode,   "[mode]",       "Get/Set inquiry mode" },
        { "inqdata",    cmd_inq_data,   "[data]",       "Get/Set inquiry data" },
        { "inqtype",    cmd_inq_type,   "[type]",       "Get/Set inquiry scan type" },
@@ -1922,9 +1929,8 @@ static struct {
        { "sspmode",    cmd_ssp_mode,   "[mode]",       "Get/Set Simple Pairing Mode" },
        { "aclmtu",     cmd_aclmtu,     "<mtu:pkt>",    "Set ACL MTU and number of packets" },
        { "scomtu",     cmd_scomtu,     "<mtu:pkt>",    "Set SCO MTU and number of packets" },
-       { "putkey",     cmd_putkey,     "<bdaddr>",     "Store link key on the device" },
        { "delkey",     cmd_delkey,     "<bdaddr>",     "Delete link key from the device" },
-       { "oobdata",    cmd_oob_data,   0,              "Display local OOB data" },
+       { "oobdata",    cmd_oob_data,   0,              "Get local OOB data" },
        { "commands",   cmd_commands,   0,              "Display supported commands" },
        { "features",   cmd_features,   0,              "Display device features" },
        { "version",    cmd_version,    0,              "Display version information" },
@@ -1932,8 +1938,10 @@ static struct {
        { "block",      cmd_block,      "<bdaddr>",     "Add a device to the blacklist" },
        { "unblock",    cmd_unblock,    "<bdaddr>",     "Remove a device from the blacklist" },
        { "lerandaddr", cmd_le_addr,    "<bdaddr>",     "Set LE Random Address" },
-       { "leadv",      cmd_le_adv,     0,              "Enable LE advertising" },
-       { "noleadv",    cmd_le_adv,     0,              "Disable LE advertising" },
+       { "leadv",      cmd_le_adv,     "[type]",       "Enable LE advertising"
+               "\n\t\t\t0 - Connectable undirected advertising (default)"
+               "\n\t\t\t3 - Non connectable undirected advertising"},
+       { "noleadv",    cmd_no_le_adv,  0,              "Disable LE advertising" },
        { "lestates",   cmd_le_states,  0,              "Display the supported LE states" },
        { NULL, NULL, 0 }
 };
diff --git a/tools/hcidump.1 b/tools/hcidump.1
new file mode 100644 (file)
index 0000000..5c1441b
--- /dev/null
@@ -0,0 +1,118 @@
+.TH HCIDUMP 1 "Nov 12 2002" BlueZ "Linux System Administration"
+.SH NAME
+hcidump \- Parse HCI data
+.SH SYNOPSIS
+.B hcidump [-h]
+.br
+.B hcidump [option [option...]] [filter]
+
+.SH DESCRIPTION
+.LP
+.B
+hcidump
+reads raw HCI data coming from and going to a Bluetooth device (which can be
+specified with the option
+.BR -i ,
+default is the first available one) and prints to screen commands, events and
+data in a human-readable form. Optionally, the dump can be written to a file
+rather than parsed, and the dump file can be parsed in a subsequent moment.
+.SH OPTIONS
+.TP
+.BI -h
+Prints usage info and exits
+.TP
+.BI -i " <hciX>"
+Data is read from
+.IR hciX ,
+which must be the name of an installed Bluetooth device. If not specified,
+and if
+.B
+-r
+option is not set, data is read from the first available Bluetooth device.
+.TP
+.BI -l " <len>" "\fR,\fP \-\^\-snap-len=" "<len>"
+Sets max length of processed packets to
+.IR len .
+.TP
+.BI -p " <psm>" "\fR,\fP \-\^\-psm=" "<psm>"
+Sets default Protocol Service Multiplexer to
+.IR psm .
+.TP
+.BI -m " <compid>" "\fR,\fP \-\^\-manufacturer=" "<compid>"
+Sets default company id for manufacturer to
+.IR compid .
+.TP
+.BI -w " <file>" "\fR,\fP \-\^\-save-dump=" "<file>"
+Parse output is not printed to screen, instead data read from device is saved in file
+.IR file .
+The saved dump file can be subsequently parsed with option
+.BR -r .
+.TP
+.BI -r " <file>" "\fR,\fP \-\^\-read-dump=" "<file>"
+Data is not read from a Bluetooth device, but from file
+.IR file .
+.I
+file
+is created with option
+.BR -t ", " "\-\^\-timestamp"
+Prepend a time stamp to every packet.
+.TP
+.BR -a ", " "\-\^\-ascii"
+For every packet, not only is the packet type displayed, but also all data in ASCII.
+.TP
+.BR -x ", " "\-\^\-hex"
+For every packet, not only is the packet type displayed, but also all data in hex.
+.TP
+.BR -X ", " "\-\^\-ext"
+For every packet, not only is the packet type displayed, but also all data in hex and ASCII.
+.TP
+.BR -R ", " "\-\^\-raw"
+For every packet, only the raw data is displayed.
+.TP
+.BR -C ", " "\-\^\-cmtp=" "<psm>"
+Sets the PSM value for the CAPI Message Transport Protocol.
+.TP
+.BR -H ", " "\-\^\-hcrp=" "<psm>"
+Sets the PSM value for the Hardcopy Control Channel.
+.TP
+.BR -O ", " "\-\^\-obex=" "<channel>"
+Sets the RFCOMM channel value for the Object Exchange Protocol.
+.TP
+.BR -P ", " "\-\^\-ppp=" "<channel>"
+Sets the RFCOMM channel value for the Point-to-Point Protocol.
+.TP
+.BR -D ", " "\-\^\-pppdump=" "<file>"
+Extract PPP traffic with pppdump format.
+.TP
+.BR -A ", " "\-\^\-audio=" "<file>"
+Extract SCO audio data.
+.TP
+.BR -Y ", " "\-\^\-novendor"
+Don't display any vendor commands or events and don't show any pin code or link key in plain text.
+.SH FILTERS
+.B
+filter
+is a space-separated list of packet categories: available categories are
+.IR lmp ,
+.IR hci ,
+.IR sco ,
+.IR l2cap ,
+.IR rfcomm ,
+.IR sdp ,
+.IR bnep ,
+.IR cmtp ,
+.IR hidp ,
+.IR hcrp ,
+.IR avdtp ,
+.IR avctp ,
+.IR obex ,
+.IR capi
+and
+.IR ppp .
+If filters are used, only packets belonging to the specified categories are
+dumped. By default, all packets are dumped.
+.SH AUTHORS
+Written by Maxim Krasnyansky <maxk@qualcomm.com>
+and Marcel Holtmann <marcel@holtmann.org>
+.PP
+man page by Fabrizio Gennari <fabrizio.gennari@philips.com>
diff --git a/tools/hcidump.c b/tools/hcidump.c
new file mode 100644 (file)
index 0000000..055c8fa
--- /dev/null
@@ -0,0 +1,848 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <getopt.h>
+#include <sys/poll.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/ioctl.h>
+#include <sys/socket.h>
+
+#include "parser/parser.h"
+#include "parser/sdp.h"
+
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
+#define SNAP_LEN       HCI_MAX_FRAME_SIZE
+
+/* Modes */
+enum {
+       PARSE,
+       READ,
+       WRITE,
+       PPPDUMP,
+       AUDIO
+};
+
+/* Default options */
+static int  snap_len = SNAP_LEN;
+static int  mode = PARSE;
+static int  permcheck = 1;
+static char *dump_file = NULL;
+static char *pppdump_file = NULL;
+static char *audio_file = NULL;
+
+struct hcidump_hdr {
+       uint16_t        len;
+       uint8_t         in;
+       uint8_t         pad;
+       uint32_t        ts_sec;
+       uint32_t        ts_usec;
+} __attribute__ ((packed));
+#define HCIDUMP_HDR_SIZE (sizeof(struct hcidump_hdr))
+
+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 uint8_t btsnoop_id[] = { 0x62, 0x74, 0x73, 0x6e, 0x6f, 0x6f, 0x70, 0x00 };
+
+static uint32_t btsnoop_version = 0;
+static uint32_t btsnoop_type = 0;
+
+struct pktlog_hdr {
+       uint32_t        len;
+       uint64_t        ts;
+       uint8_t         type;
+} __attribute__ ((packed));
+#define PKTLOG_HDR_SIZE (sizeof(struct pktlog_hdr))
+
+static inline int read_n(int fd, char *buf, int len)
+{
+       int t = 0, w;
+
+       while (len > 0) {
+               if ((w = read(fd, buf, len)) < 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+                       return -1;
+               }
+               if (!w)
+                       return 0;
+               len -= w; buf += w; t += w;
+       }
+       return t;
+}
+
+static inline int write_n(int fd, char *buf, int len)
+{
+       int t = 0, w;
+
+       while (len > 0) {
+               if ((w = write(fd, buf, len)) < 0) {
+                       if (errno == EINTR || errno == EAGAIN)
+                               continue;
+                       return -1;
+               }
+               if (!w)
+                       return 0;
+               len -= w; buf += w; t += w;
+       }
+       return t;
+}
+
+static int process_frames(int dev, int sock, int fd, unsigned long flags)
+{
+       struct cmsghdr *cmsg;
+       struct msghdr msg;
+       struct iovec  iv;
+       struct hcidump_hdr *dh;
+       struct btsnoop_pkt *dp;
+       struct frame frm;
+       struct pollfd fds[2];
+       int nfds = 0;
+       char *buf, *ctrl;
+       int len, hdr_size = HCIDUMP_HDR_SIZE;
+
+       if (sock < 0)
+               return -1;
+
+       if (snap_len < SNAP_LEN)
+               snap_len = SNAP_LEN;
+
+       if (flags & DUMP_BTSNOOP)
+               hdr_size = BTSNOOP_PKT_SIZE;
+
+       buf = malloc(snap_len + hdr_size);
+       if (!buf) {
+               perror("Can't allocate data buffer");
+               return -1;
+       }
+
+       dh = (void *) buf;
+       dp = (void *) buf;
+       frm.data = buf + hdr_size;
+
+       ctrl = malloc(100);
+       if (!ctrl) {
+               free(buf);
+               perror("Can't allocate control buffer");
+               return -1;
+       }
+
+       if (dev == HCI_DEV_NONE)
+               printf("system: ");
+       else
+               printf("device: hci%d ", dev);
+
+       printf("snap_len: %d filter: 0x%lx\n", snap_len, parser.filter);
+
+       memset(&msg, 0, sizeof(msg));
+
+       fds[nfds].fd = sock;
+       fds[nfds].events = POLLIN;
+       fds[nfds].revents = 0;
+       nfds++;
+
+       while (1) {
+               int i, n = poll(fds, nfds, -1);
+               if (n <= 0)
+                       continue;
+
+               for (i = 0; i < nfds; i++) {
+                       if (fds[i].revents & (POLLHUP | POLLERR | POLLNVAL)) {
+                               if (fds[i].fd == sock)
+                                       printf("device: disconnected\n");
+                               else
+                                       printf("client: disconnect\n");
+                               return 0;
+                       }
+               }
+
+               iv.iov_base = frm.data;
+               iv.iov_len  = snap_len;
+
+               msg.msg_iov = &iv;
+               msg.msg_iovlen = 1;
+               msg.msg_control = ctrl;
+               msg.msg_controllen = 100;
+
+               len = recvmsg(sock, &msg, MSG_DONTWAIT);
+               if (len < 0) {
+                       if (errno == EAGAIN || errno == EINTR)
+                               continue;
+                       perror("Receive failed");
+                       return -1;
+               }
+
+               /* Process control message */
+               frm.data_len = len;
+               frm.dev_id = dev;
+               frm.in = 0;
+               frm.pppdump_fd = parser.pppdump_fd;
+               frm.audio_fd   = parser.audio_fd;
+
+               cmsg = CMSG_FIRSTHDR(&msg);
+               while (cmsg) {
+                       int dir;
+                       switch (cmsg->cmsg_type) {
+                       case HCI_CMSG_DIR:
+                               memcpy(&dir, CMSG_DATA(cmsg), sizeof(int));
+                               frm.in = (uint8_t) dir;
+                               break;
+                       case HCI_CMSG_TSTAMP:
+                               memcpy(&frm.ts, CMSG_DATA(cmsg),
+                                               sizeof(struct timeval));
+                               break;
+                       }
+                       cmsg = CMSG_NXTHDR(&msg, cmsg);
+               }
+
+               frm.ptr = frm.data;
+               frm.len = frm.data_len;
+
+               switch (mode) {
+               case WRITE:
+                       /* Save or send dump */
+                       if (flags & DUMP_BTSNOOP) {
+                               uint64_t ts;
+                               uint8_t pkt_type = ((uint8_t *) frm.data)[0];
+                               dp->size = htonl(frm.data_len);
+                               dp->len  = dp->size;
+                               dp->flags = ntohl(frm.in & 0x01);
+                               dp->drops = 0;
+                               ts = (frm.ts.tv_sec - 946684800ll) * 1000000ll + frm.ts.tv_usec;
+                               dp->ts = hton64(ts + 0x00E03AB44A676000ll);
+                               if (pkt_type == HCI_COMMAND_PKT ||
+                                               pkt_type == HCI_EVENT_PKT)
+                                       dp->flags |= ntohl(0x02);
+                       } else {
+                               dh->len = htobs(frm.data_len);
+                               dh->in  = frm.in;
+                               dh->ts_sec  = htobl(frm.ts.tv_sec);
+                               dh->ts_usec = htobl(frm.ts.tv_usec);
+                       }
+
+                       if (write_n(fd, buf, frm.data_len + hdr_size) < 0) {
+                               perror("Write error");
+                               return -1;
+                       }
+                       break;
+
+               default:
+                       /* Parse and print */
+                       parse(&frm);
+                       break;
+               }
+       }
+
+       return 0;
+}
+
+static void read_dump(int fd)
+{
+       struct hcidump_hdr dh;
+       struct btsnoop_pkt dp;
+       struct pktlog_hdr ph;
+       struct frame frm;
+       int err;
+
+       frm.data = malloc(HCI_MAX_FRAME_SIZE);
+       if (!frm.data) {
+               perror("Can't allocate data buffer");
+               exit(1);
+       }
+
+       while (1) {
+               if (parser.flags & DUMP_PKTLOG)
+                       err = read_n(fd, (void *) &ph, PKTLOG_HDR_SIZE);
+               else if (parser.flags & DUMP_BTSNOOP)
+                       err = read_n(fd, (void *) &dp, BTSNOOP_PKT_SIZE);
+               else
+                       err = read_n(fd, (void *) &dh, HCIDUMP_HDR_SIZE);
+
+               if (err < 0)
+                       goto failed;
+               if (!err)
+                       return;
+
+               if (parser.flags & DUMP_PKTLOG) {
+                       switch (ph.type) {
+                       case 0x00:
+                               ((uint8_t *) frm.data)[0] = HCI_COMMAND_PKT;
+                               frm.in = 0;
+                               break;
+                       case 0x01:
+                               ((uint8_t *) frm.data)[0] = HCI_EVENT_PKT;
+                               frm.in = 1;
+                               break;
+                       case 0x02:
+                               ((uint8_t *) frm.data)[0] = HCI_ACLDATA_PKT;
+                               frm.in = 0;
+                               break;
+                       case 0x03:
+                               ((uint8_t *) frm.data)[0] = HCI_ACLDATA_PKT;
+                               frm.in = 1;
+                               break;
+                       default:
+                               lseek(fd, ntohl(ph.len) - 9, SEEK_CUR);
+                               continue;
+                       }
+
+                       frm.data_len = ntohl(ph.len) - 8;
+                       err = read_n(fd, frm.data + 1, frm.data_len - 1);
+               } else if (parser.flags & DUMP_BTSNOOP) {
+                       uint32_t opcode;
+                       uint8_t pkt_type;
+
+                       switch (btsnoop_type) {
+                       case 1001:
+                               if (ntohl(dp.flags) & 0x02) {
+                                       if (ntohl(dp.flags) & 0x01)
+                                               pkt_type = HCI_EVENT_PKT;
+                                       else
+                                               pkt_type = HCI_COMMAND_PKT;
+                               } else
+                                       pkt_type = HCI_ACLDATA_PKT;
+
+                               ((uint8_t *) frm.data)[0] = pkt_type;
+
+                               frm.data_len = ntohl(dp.len) + 1;
+                               err = read_n(fd, frm.data + 1, frm.data_len - 1);
+                               break;
+
+                       case 1002:
+                               frm.data_len = ntohl(dp.len);
+                               err = read_n(fd, frm.data, frm.data_len);
+                               break;
+
+                       case 2001:
+                               opcode = ntohl(dp.flags) & 0xffff;
+
+                               switch (opcode) {
+                               case 2:
+                                       pkt_type = HCI_COMMAND_PKT;
+                                       frm.in = 0;
+                                       break;
+                               case 3:
+                                       pkt_type = HCI_EVENT_PKT;
+                                       frm.in = 1;
+                                       break;
+                               case 4:
+                                       pkt_type = HCI_ACLDATA_PKT;
+                                       frm.in = 0;
+                                       break;
+                               case 5:
+                                       pkt_type = HCI_ACLDATA_PKT;
+                                       frm.in = 1;
+                                       break;
+                               case 6:
+                                       pkt_type = HCI_SCODATA_PKT;
+                                       frm.in = 0;
+                                       break;
+                               case 7:
+                                       pkt_type = HCI_SCODATA_PKT;
+                                       frm.in = 1;
+                                       break;
+                               default:
+                                       pkt_type = 0xff;
+                                       break;
+                               }
+
+                               ((uint8_t *) frm.data)[0] = pkt_type;
+
+                               frm.data_len = ntohl(dp.len) + 1;
+                               err = read_n(fd, frm.data + 1, frm.data_len - 1);
+                       }
+               } else {
+                       frm.data_len = btohs(dh.len);
+                       err = read_n(fd, frm.data, frm.data_len);
+               }
+
+               if (err < 0)
+                       goto failed;
+               if (!err)
+                       return;
+
+               frm.ptr = frm.data;
+               frm.len = frm.data_len;
+
+               if (parser.flags & DUMP_PKTLOG) {
+                       uint64_t ts;
+                       ts = ntoh64(ph.ts);
+                       frm.ts.tv_sec = ts >> 32;
+                       frm.ts.tv_usec = ts & 0xffffffff;
+               } else if (parser.flags & DUMP_BTSNOOP) {
+                       uint64_t ts;
+                       frm.in = ntohl(dp.flags) & 0x01;
+                       ts = ntoh64(dp.ts) - 0x00E03AB44A676000ll;
+                       frm.ts.tv_sec = (ts / 1000000ll) + 946684800ll;
+                       frm.ts.tv_usec = ts % 1000000ll;
+               } else {
+                       frm.in = dh.in;
+                       frm.ts.tv_sec  = btohl(dh.ts_sec);
+                       frm.ts.tv_usec = btohl(dh.ts_usec);
+               }
+
+               parse(&frm);
+       }
+
+failed:
+       perror("Read failed");
+       exit(1);
+}
+
+static int open_file(char *file, int mode, unsigned long flags)
+{
+       unsigned char buf[BTSNOOP_HDR_SIZE];
+       struct btsnoop_hdr *hdr = (struct btsnoop_hdr *) buf;
+       int fd, len, open_flags;
+
+       if (mode == WRITE || mode == PPPDUMP || mode == AUDIO)
+               open_flags = O_WRONLY | O_CREAT | O_TRUNC;
+       else
+               open_flags = O_RDONLY;
+
+       fd = open(file, open_flags, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+       if (fd < 0) {
+               perror("Can't open dump file");
+               exit(1);
+       }
+
+       if (mode == READ) {
+               len = read(fd, buf, BTSNOOP_HDR_SIZE);
+               if (len != BTSNOOP_HDR_SIZE) {
+                       lseek(fd, 0, SEEK_SET);
+                       return fd;
+               }
+
+               if (!memcmp(hdr->id, btsnoop_id, sizeof(btsnoop_id))) {
+                       parser.flags |= DUMP_BTSNOOP;
+
+                       btsnoop_version = ntohl(hdr->version);
+                       btsnoop_type = ntohl(hdr->type);
+
+                       printf("btsnoop version: %d datalink type: %d\n",
+                                               btsnoop_version, btsnoop_type);
+
+                       if (btsnoop_version != 1) {
+                               fprintf(stderr, "Unsupported BTSnoop version\n");
+                               exit(1);
+                       }
+
+                       if (btsnoop_type != 1001 && btsnoop_type != 1002 &&
+                                                       btsnoop_type != 2001) {
+                               fprintf(stderr, "Unsupported BTSnoop datalink type\n");
+                               exit(1);
+                       }
+               } else {
+                       if (buf[0] == 0x00 && buf[1] == 0x00) {
+                               parser.flags |= DUMP_PKTLOG;
+                               printf("packet logger data format\n");
+                       }
+
+                       parser.flags &= ~DUMP_BTSNOOP;
+                       lseek(fd, 0, SEEK_SET);
+                       return fd;
+               }
+       } else {
+               if (flags & DUMP_BTSNOOP) {
+                       btsnoop_version = 1;
+                       btsnoop_type = 1002;
+
+                       memcpy(hdr->id, btsnoop_id, sizeof(btsnoop_id));
+                       hdr->version = htonl(btsnoop_version);
+                       hdr->type = htonl(btsnoop_type);
+
+                       printf("btsnoop version: %d datalink type: %d\n",
+                                               btsnoop_version, btsnoop_type);
+
+                       len = write(fd, buf, BTSNOOP_HDR_SIZE);
+                       if (len < 0) {
+                               perror("Can't create dump header");
+                               exit(1);
+                       }
+
+                       if (len != BTSNOOP_HDR_SIZE) {
+                               fprintf(stderr, "Header size mismatch\n");
+                               exit(1);
+                       }
+               }
+       }
+
+       return fd;
+}
+
+static int open_socket(int dev, unsigned long flags)
+{
+       struct sockaddr_hci addr;
+       struct hci_filter flt;
+       struct hci_dev_info di;
+       int sk, dd, opt;
+
+       if (permcheck && dev != HCI_DEV_NONE) {
+               dd = hci_open_dev(dev);
+               if (dd < 0) {
+                       perror("Can't open device");
+                       return -1;
+               }
+
+               if (hci_devinfo(dev, &di) < 0) {
+                       perror("Can't get device info");
+                       return -1;
+               }
+
+               opt = hci_test_bit(HCI_RAW, &di.flags);
+               if (ioctl(dd, HCISETRAW, opt) < 0) {
+                       if (errno == EACCES) {
+                               perror("Can't access device");
+                               return -1;
+                       }
+               }
+
+               hci_close_dev(dd);
+       }
+
+       /* Create HCI socket */
+       sk = socket(AF_BLUETOOTH, SOCK_RAW, BTPROTO_HCI);
+       if (sk < 0) {
+               perror("Can't create raw socket");
+               return -1;
+       }
+
+       opt = 1;
+       if (setsockopt(sk, SOL_HCI, HCI_DATA_DIR, &opt, sizeof(opt)) < 0) {
+               perror("Can't enable data direction info");
+               return -1;
+       }
+
+       opt = 1;
+       if (setsockopt(sk, SOL_HCI, HCI_TIME_STAMP, &opt, sizeof(opt)) < 0) {
+               perror("Can't enable time stamp");
+               return -1;
+       }
+
+       /* Setup filter */
+       hci_filter_clear(&flt);
+       hci_filter_all_ptypes(&flt);
+       hci_filter_all_events(&flt);
+       if (setsockopt(sk, SOL_HCI, HCI_FILTER, &flt, sizeof(flt)) < 0) {
+               perror("Can't set filter");
+               return -1;
+       }
+
+       /* Bind socket to the HCI device */
+       memset(&addr, 0, sizeof(addr));
+       addr.hci_family = AF_BLUETOOTH;
+       addr.hci_dev = dev;
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               printf("Can't attach to device hci%d. %s(%d)\n",
+                                       dev, strerror(errno), errno);
+               return -1;
+       }
+
+       return sk;
+}
+
+static struct {
+       char *name;
+       int  flag;
+} filters[] = {
+       { "lmp",        FILT_LMP        },
+       { "hci",        FILT_HCI        },
+       { "sco",        FILT_SCO        },
+       { "l2cap",      FILT_L2CAP      },
+       { "a2mp",       FILT_A2MP       },
+       { "rfcomm",     FILT_RFCOMM     },
+       { "sdp",        FILT_SDP        },
+       { "bnep",       FILT_BNEP       },
+       { "cmtp",       FILT_CMTP       },
+       { "hidp",       FILT_HIDP       },
+       { "hcrp",       FILT_HCRP       },
+       { "att",        FILT_ATT        },
+       { "smp",        FILT_SMP        },
+       { "avdtp",      FILT_AVDTP      },
+       { "avctp",      FILT_AVCTP      },
+       { "obex",       FILT_OBEX       },
+       { "capi",       FILT_CAPI       },
+       { "ppp",        FILT_PPP        },
+       { "sap",        FILT_SAP        },
+       { "csr",        FILT_CSR        },
+       { "dga",        FILT_DGA        },
+       { 0 }
+};
+
+static unsigned long parse_filter(int argc, char **argv)
+{
+       unsigned long filter = 0;
+       int i,n;
+
+       for (i = 0; i < argc; i++) {
+               for (n = 0; filters[n].name; n++) {
+                       if (!strcasecmp(filters[n].name, argv[i])) {
+                               filter |= filters[n].flag;
+                               break;
+                       }
+               }
+       }
+
+       return filter;
+}
+
+static void usage(void)
+{
+       printf(
+       "Usage: hcidump [OPTION...] [filter]\n"
+       "  -i, --device=hci_dev       HCI device\n"
+       "  -l, --snap-len=len         Snap len (in bytes)\n"
+       "  -p, --psm=psm              Default PSM\n"
+       "  -m, --manufacturer=compid  Default manufacturer\n"
+       "  -w, --save-dump=file       Save dump to a file\n"
+       "  -r, --read-dump=file       Read dump from a file\n"
+       "  -t, --ts                   Display time stamps\n"
+       "  -a, --ascii                Dump data in ascii\n"
+       "  -x, --hex                  Dump data in hex\n"
+       "  -X, --ext                  Dump data in hex and ascii\n"
+       "  -R, --raw                  Dump raw data\n"
+       "  -C, --cmtp=psm             PSM for CMTP\n"
+       "  -H, --hcrp=psm             PSM for HCRP\n"
+       "  -O, --obex=port            Channel/PSM for OBEX\n"
+       "  -P, --ppp=channel          Channel for PPP\n"
+       "  -S, --sap=channel          Channel for SAP\n"
+       "  -D, --pppdump=file         Extract PPP traffic\n"
+       "  -A, --audio=file           Extract SCO audio data\n"
+       "  -Y, --novendor             No vendor commands or events\n"
+       "  -h, --help                 Give this help list\n"
+       "  -v, --version              Give version information\n"
+       "      --usage                Give a short usage message\n"
+       );
+}
+
+static struct option main_options[] = {
+       { "device",             1, 0, 'i' },
+       { "snap-len",           1, 0, 'l' },
+       { "psm",                1, 0, 'p' },
+       { "manufacturer",       1, 0, 'm' },
+       { "save-dump",          1, 0, 'w' },
+       { "read-dump",          1, 0, 'r' },
+       { "timestamp",          0, 0, 't' },
+       { "ascii",              0, 0, 'a' },
+       { "hex",                0, 0, 'x' },
+       { "ext",                0, 0, 'X' },
+       { "raw",                0, 0, 'R' },
+       { "cmtp",               1, 0, 'C' },
+       { "hcrp",               1, 0, 'H' },
+       { "obex",               1, 0, 'O' },
+       { "ppp",                1, 0, 'P' },
+       { "sap",                1, 0, 'S' },
+       { "pppdump",            1, 0, 'D' },
+       { "audio",              1, 0, 'A' },
+       { "novendor",           0, 0, 'Y' },
+       { "nopermcheck",        0, 0, 'Z' },
+       { "help",               0, 0, 'h' },
+       { "version",            0, 0, 'v' },
+       { 0 }
+};
+
+int main(int argc, char *argv[])
+{
+       unsigned long flags = 0;
+       unsigned long filter = 0;
+       int device = 0;
+       int defpsm = 0;
+       int defcompid = DEFAULT_COMPID;
+       int opt, pppdump_fd = -1, audio_fd = -1;
+       uint16_t obex_port;
+
+       while ((opt = getopt_long(argc, argv,
+                               "i:l:p:m:w:r:taxXRC:H:O:P:S:D:A:YZhv",
+                               main_options, NULL)) != -1) {
+               switch(opt) {
+               case 'i':
+                       if (strcasecmp(optarg, "none") && strcasecmp(optarg, "system"))
+                               device = atoi(optarg + 3);
+                       else
+                               device = HCI_DEV_NONE;
+                       break;
+
+               case 'l':
+                       snap_len = atoi(optarg);
+                       break;
+
+               case 'p':
+                       defpsm = atoi(optarg);
+                       break;
+
+               case 'm':
+                       defcompid = atoi(optarg);
+                       break;
+
+               case 'w':
+                       mode = WRITE;
+                       dump_file = strdup(optarg);
+                       break;
+
+               case 'r':
+                       mode = READ;
+                       dump_file = strdup(optarg);
+                       break;
+
+               case 't':
+                       flags |= DUMP_TSTAMP;
+                       break;
+
+               case 'a':
+                       flags |= DUMP_ASCII;
+                       break;
+
+               case 'x':
+                       flags |= DUMP_HEX;
+                       break;
+
+               case 'X':
+                       flags |= DUMP_EXT;
+                       break;
+
+               case 'R':
+                       flags |= DUMP_RAW;
+                       break;
+
+               case 'C':
+                       set_proto(0, atoi(optarg), 0, SDP_UUID_CMTP);
+                       break;
+
+               case 'H':
+                       set_proto(0, atoi(optarg), 0, SDP_UUID_HARDCOPY_CONTROL_CHANNEL);
+                       break;
+
+               case 'O':
+                       obex_port = atoi(optarg);
+                       if (obex_port > 31)
+                               set_proto(0, obex_port, 0, SDP_UUID_OBEX);
+                       else
+                               set_proto(0, 0, obex_port, SDP_UUID_OBEX);
+                       break;
+
+               case 'P':
+                       set_proto(0, 0, atoi(optarg), SDP_UUID_LAN_ACCESS_PPP);
+                       break;
+
+               case 'S':
+                       set_proto(0, 0, atoi(optarg), SDP_UUID_SIM_ACCESS);
+                       break;
+
+               case 'D':
+                       pppdump_file = strdup(optarg);
+                       break;
+
+               case 'A':
+                       audio_file = strdup(optarg);
+                       break;
+
+               case 'Y':
+                       flags |= DUMP_NOVENDOR;
+                       break;
+
+               case 'Z':
+                       permcheck = 0;
+                       break;
+
+               case 'v':
+                       printf("%s\n", VERSION);
+                       exit(0);
+
+               case 'h':
+               default:
+                       usage();
+                       exit(0);
+               }
+       }
+
+       argc -= optind;
+       argv += optind;
+       optind = 0;
+
+       printf("HCI sniffer - Bluetooth packet analyzer ver %s\n", VERSION);
+
+       if (argc > 0)
+               filter = parse_filter(argc, argv);
+
+       /* Default settings */
+       if (!filter)
+               filter = ~0L;
+
+       if (pppdump_file)
+               pppdump_fd = open_file(pppdump_file, PPPDUMP, flags);
+
+       if (audio_file)
+               audio_fd = open_file(audio_file, AUDIO, flags);
+
+       switch (mode) {
+       case PARSE:
+               flags |= DUMP_VERBOSE;
+               init_parser(flags, filter, defpsm, defcompid,
+                                                       pppdump_fd, audio_fd);
+               process_frames(device, open_socket(device, flags), -1, flags);
+               break;
+
+       case READ:
+               flags |= DUMP_VERBOSE;
+               init_parser(flags, filter, defpsm, defcompid,
+                                                       pppdump_fd, audio_fd);
+               read_dump(open_file(dump_file, mode, flags));
+               break;
+
+       case WRITE:
+               flags |= DUMP_BTSNOOP;
+               process_frames(device, open_socket(device, flags),
+                               open_file(dump_file, mode, flags), flags);
+               break;
+       }
+
+       return 0;
+}
index 66e5c20..f2e4fa4 100644 (file)
@@ -40,6 +40,8 @@
 #include <sys/socket.h>
 #include <signal.h>
 
+#include <glib.h>
+
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/hci_lib.h>
@@ -409,13 +411,32 @@ static char *major_classes[] = {
 
 static char *get_device_name(const bdaddr_t *local, const bdaddr_t *peer)
 {
-       char filename[PATH_MAX + 1], addr[18];
+       char filename[PATH_MAX + 1];
+       char local_addr[18], peer_addr[18];
+       GKeyFile *key_file;
+       char *str = NULL;
+       int len;
+
+       ba2str(local, local_addr);
+       ba2str(peer, peer_addr);
 
-       ba2str(local, addr);
-       create_name(filename, PATH_MAX, STORAGEDIR, addr, "names");
+       snprintf(filename, PATH_MAX, STORAGEDIR "/%s/cache/%s", local_addr,
+                       peer_addr);
+       filename[PATH_MAX] = '\0';
+       key_file = g_key_file_new();
 
-       ba2str(peer, addr);
-       return textfile_get(filename, addr);
+       if (g_key_file_load_from_file(key_file, filename, 0, NULL)) {
+               str = g_key_file_get_string(key_file, "General", "Name", NULL);
+               if (str) {
+                       len = strlen(str);
+                       if (len > HCI_MAX_NAME_LENGTH)
+                               str[HCI_MAX_NAME_LENGTH] = '\0';
+               }
+       }
+
+       g_key_file_free(key_file);
+
+       return str;
 }
 
 /* Display local devices */
@@ -560,7 +581,7 @@ static void cmd_scan(int dev_id, int argc, char **argv)
        uint8_t lap[3] = { 0x33, 0x8b, 0x9e };
        int num_rsp, length, flags;
        uint8_t cls[3], features[8];
-       char addr[18], name[249], oui[9], *comp, *tmp;
+       char addr[18], name[249], *comp, *tmp;
        struct hci_version version;
        struct hci_dev_info di;
        struct hci_conn_info_req *cr;
@@ -705,9 +726,10 @@ static void cmd_scan(int dev_id, int argc, char **argv)
                        (info+i)->pscan_rep_mode, btohs((info+i)->clock_offset));
 
                if (extoui) {
-                       ba2oui(&(info+i)->bdaddr, oui);
-                       comp = ouitocomp(oui);
+                       comp = batocomp(&(info+i)->bdaddr);
                        if (comp) {
+                               char oui[9];
+                               ba2oui(&(info+i)->bdaddr, oui);
                                printf("OUI company:\t%s (%s)\n", comp, oui);
                                free(comp);
                        }
@@ -877,7 +899,7 @@ static void cmd_info(int dev_id, int argc, char **argv)
        bdaddr_t bdaddr;
        uint16_t handle;
        uint8_t features[8], max_page = 0;
-       char name[249], oui[9], *comp, *tmp;
+       char name[249], *comp, *tmp;
        struct hci_version version;
        struct hci_dev_info di;
        struct hci_conn_info_req *cr;
@@ -942,9 +964,10 @@ static void cmd_info(int dev_id, int argc, char **argv)
 
        printf("\tBD Address:  %s\n", argv[0]);
 
-       ba2oui(&bdaddr, oui);
-       comp = ouitocomp(oui);
+       comp = batocomp(&bdaddr);
        if (comp) {
+               char oui[9];
+               ba2oui(&bdaddr, oui);
                printf("\tOUI Company: %s (%s)\n", comp, oui);
                free(comp);
        }
@@ -2487,6 +2510,7 @@ static struct option lescan_options[] = {
        { "help",       0, 0, 'h' },
        { "privacy",    0, 0, 'p' },
        { "passive",    0, 0, 'P' },
+       { "whitelist",  0, 0, 'w' },
        { "discovery",  1, 0, 'd' },
        { "duplicates", 0, 0, 'D' },
        { 0, 0, 0, 0 }
@@ -2496,6 +2520,7 @@ static const char *lescan_help =
        "Usage:\n"
        "\tlescan [--privacy] enable privacy\n"
        "\tlescan [--passive] set scan type passive (default active)\n"
+       "\tlescan [--whitelist] scan for address in the whitelist only\n"
        "\tlescan [--discovery=g|l] enable general or limited discovery"
                "procedure\n"
        "\tlescan [--duplicates] don't filter duplicates\n";
@@ -2506,6 +2531,7 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
        uint8_t own_type = 0x00;
        uint8_t scan_type = 0x01;
        uint8_t filter_type = 0;
+       uint8_t filter_policy = 0x00;
        uint16_t interval = htobs(0x0010);
        uint16_t window = htobs(0x0010);
        uint8_t filter_dup = 1;
@@ -2518,6 +2544,9 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
                case 'P':
                        scan_type = 0x00; /* Passive */
                        break;
+               case 'w':
+                       filter_policy = 0x01; /* Whitelist */
+                       break;
                case 'd':
                        filter_type = optarg[0];
                        if (filter_type != 'g' && filter_type != 'l') {
@@ -2548,7 +2577,7 @@ static void cmd_lescan(int dev_id, int argc, char **argv)
        }
 
        err = hci_le_set_scan_parameters(dd, scan_type, interval, window,
-                                                       own_type, 0x00, 1000);
+                                               own_type, filter_policy, 1000);
        if (err < 0) {
                perror("Set scan parameters failed");
                exit(1);
similarity index 97%
rename from tools/hid2hci.8
rename to tools/hid2hci.1
index 6ea7ed8..8c5d520 100644 (file)
@@ -14,7 +14,7 @@
 .\"    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 .\"
 .\"
-.TH HID2HCI 8 "MAY 15, 2009" "" ""
+.TH HID2HCI 1 "MAY 15, 2009" "" ""
 
 .SH NAME
 hid2hci \- Bluetooth HID to HCI mode switching utility
index e3a5b2e..bb8a521 100644 (file)
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
+#include <unistd.h>
 #include <stdint.h>
+#include <stdlib.h>
 #include <string.h>
+#include <dirent.h>
 #include <getopt.h>
 #include <sys/ioctl.h>
 #include <linux/types.h>
 #include <linux/hiddev.h>
-#include <usb.h>
 
 #include "libudev.h"
 
+#define USB_REQ_SET_CONFIGURATION      0x09
+
+#define USB_TYPE_CLASS                 (0x01 << 5)
+#define USB_TYPE_VENDOR                        (0x02 << 5)
+
+#define USB_RECIP_DEVICE               0x00
+#define USB_RECIP_INTERFACE            0x01
+
+#define USB_ENDPOINT_OUT               0x00
+
+struct usbfs_ctrltransfer {
+       uint8_t  bmRequestType;
+       uint8_t  bRequest;
+       uint16_t wValue;
+       uint16_t wIndex;
+       uint16_t wLength;
+       uint32_t timeout;       /* in milliseconds */
+       void *data;             /* pointer to data */
+};
+
+
+#define USBFS_DISCONNECT_IF_DRIVER     0x01
+#define USBFS_DISCONNECT_EXCEPT_DRIVER 0x02
+
+struct usbfs_disconnect{
+       unsigned int interface;
+       unsigned int flags;
+       char driver[256];
+};
+
+#define USBFS_IOCTL_CONTROL    _IOWR('U', 0, struct usbfs_ctrltransfer)
+#define USBFS_IOCTL_DISCONNECT _IOR('U', 27, struct usbfs_disconnect)
+
+static int control_message(int fd, int requesttype, int request,
+                                       int value, int index,
+                                       char *bytes, int size, int timeout)
+{
+       struct usbfs_ctrltransfer transfer;
+
+       transfer.bmRequestType = requesttype;
+       transfer.bRequest = request;
+       transfer.wValue = value;
+       transfer.wIndex = index;
+       transfer.wLength = size,
+       transfer.timeout = timeout;
+       transfer.data = bytes;
+
+       if (ioctl(fd, USBFS_IOCTL_CONTROL, &transfer) < 0) {
+               fprintf(stderr, "Control transfer failed: %s (%d)\n",
+                                               strerror(errno), errno);
+               return -1;
+       }
+
+       return 0;
+}
+
 enum mode {
        HCI = 0,
        HID = 1,
 };
 
-static int usb_switch_csr(struct usb_dev_handle *dev, enum mode mode)
+static int usb_switch_csr(int fd, enum mode mode)
 {
        int err;
 
-       err = usb_control_msg(dev,
-                       USB_ENDPOINT_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE,
-                       0, mode, 0, NULL, 0, 10000);
+       err = control_message(fd, USB_ENDPOINT_OUT | USB_TYPE_VENDOR  |
+                                                       USB_RECIP_DEVICE,
+                                               0, mode, 0, NULL, 0, 10000);
        if (err == 0) {
                err = -1;
                errno = EALREADY;
@@ -119,9 +177,10 @@ out:
        return err;
 }
 
-static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
+static int usb_switch_dell(int fd, enum mode mode)
 {
        char report[] = { 0x7f, 0x00, 0x00, 0x00 };
+       struct usbfs_disconnect disconnect;
        int err;
 
        switch (mode) {
@@ -133,17 +192,21 @@ static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
                break;
        }
 
-       /* Don't need to check return, as might not be in use */
-       usb_detach_kernel_driver_np(dev, 0);
-
-       if (usb_claim_interface(dev, 0) < 0)
-               return -EIO;
+       disconnect.interface = 0;
+       disconnect.flags = USBFS_DISCONNECT_EXCEPT_DRIVER;
+       strcpy(disconnect.driver, "usbfs");
 
-       err = usb_control_msg(dev,
-                       USB_ENDPOINT_OUT | USB_TYPE_CLASS | USB_RECIP_INTERFACE,
-                       USB_REQ_SET_CONFIGURATION, 0x7f | (0x03 << 8), 0,
-                       report, sizeof(report), 5000);
+       if (ioctl(fd, USBFS_IOCTL_DISCONNECT, &disconnect) < 0) {
+               fprintf(stderr, "Can't claim interface: %s (%d)\n",
+                                               strerror(errno), errno);
+               return -1;
+       }
 
+       err = control_message(fd, USB_ENDPOINT_OUT | USB_TYPE_CLASS |
+                                                       USB_RECIP_INTERFACE,
+                               USB_REQ_SET_CONFIGURATION,
+                               0x7f | (0x03 << 8), 0,
+                               report, sizeof(report), 5000);
        if (err == 0) {
                err = -1;
                errno = EALREADY;
@@ -151,57 +214,34 @@ static int usb_switch_dell(struct usb_dev_handle *dev, enum mode mode)
                if (errno == ETIMEDOUT)
                        err = 0;
        }
+
        return err;
 }
 
-/*
- * libusb needs to scan and open all devices, just to to find the
- * device we already have. This should be fixed in libusb.
- */
-static struct usb_device *usb_device_open_from_udev(struct udev_device *usb_dev)
+static int find_device(struct udev_device *udev_dev)
 {
-       struct usb_bus *bus;
-       const char *str;
-       int busnum;
-       int devnum;
-
-       str = udev_device_get_sysattr_value(usb_dev, "busnum");
-       if (str == NULL)
-               return NULL;
-       busnum = strtol(str, NULL, 0);
-
-       str = udev_device_get_sysattr_value(usb_dev, "devnum");
-       if (str == NULL)
-               return NULL;
-       devnum = strtol(str, NULL, 0);
-
-       usb_init();
-       usb_find_busses();
-       usb_find_devices();
-
-       for (bus = usb_get_busses(); bus; bus = bus->next) {
-               struct usb_device *dev;
-
-               if (strtol(bus->dirname, NULL, 10) != busnum)
-                       continue;
-
-               for (dev = bus->devices; dev; dev = dev->next) {
-                       if (dev->devnum == devnum)
-                               return dev;
-               }
-       }
+       char path[PATH_MAX];
+       const char *busnum, *devnum;
+       int fd;
 
-       return NULL;
-}
+       busnum = udev_device_get_sysattr_value(udev_dev, "busnum");
+       if (!busnum)
+               return -1;
 
-static struct usb_dev_handle *find_device(struct udev_device *udev_dev)
-{
-       struct usb_device *dev;
+       devnum = udev_device_get_sysattr_value(udev_dev, "devnum");
+       if (!devnum)
+               return -1;
+
+       snprintf(path, sizeof(path), "/dev/bus/usb/%s/%s", busnum, devnum);
+
+       fd = open(path, O_RDWR, O_CLOEXEC);
+       if (fd < 0) {
+               fprintf(stderr, "Can't open device: %s (%d)\n",
+                                               strerror(errno), errno);
+               return -1;
+       }
 
-       dev = usb_device_open_from_udev(udev_dev);
-       if (dev == NULL)
-               return NULL;
-       return usb_open(dev);
+       return fd;
 }
 
 static void usage(const char *error)
@@ -212,9 +252,9 @@ static void usage(const char *error)
                printf("hid2hci - Bluetooth HID to HCI mode switching utility\n\n");
 
        printf("Usage: hid2hci [options]\n"
-               "  --mode=               mode to switch to [hid|hci] (default hci)\n"
-               "  --devpath=            sys device path\n"
-               "  --method=             method to use to switch [csr|logitech-hid|dell]\n"
+               "  --mode=       mode to switch to [hid|hci] (default hci)\n"
+               "  --devpath=    sys device path\n"
+               "  --method=     method to use to switch [csr|logitech-hid|dell]\n"
                "  --help\n\n");
 }
 
@@ -236,7 +276,7 @@ int main(int argc, char *argv[])
        struct udev *udev;
        struct udev_device *udev_dev = NULL;
        char syspath[PATH_MAX];
-       int (*usb_switch)(struct usb_dev_handle *dev, enum mode mode) = NULL;
+       int (*usb_switch)(int fd, enum mode mode) = NULL;
        enum mode mode = HCI;
        const char *devpath = NULL;
        int err = -1;
@@ -302,14 +342,15 @@ int main(int argc, char *argv[])
        case METHOD_CSR:
        case METHOD_DELL: {
                struct udev_device *dev;
-               struct usb_dev_handle *handle;
+               int handle;
                const char *type;
 
                /* get the parent usb_device if needed */
                dev = udev_dev;
                type = udev_device_get_devtype(dev);
                if (type == NULL || strcmp(type, "usb_device") != 0) {
-                       dev = udev_device_get_parent_with_subsystem_devtype(dev, "usb", "usb_device");
+                       dev = udev_device_get_parent_with_subsystem_devtype(dev,
+                                                       "usb", "usb_device");
                        if (dev == NULL) {
                                fprintf(stderr, "error: could not find usb_device for '%s'\n", devpath);
                                goto exit;
@@ -317,12 +358,13 @@ int main(int argc, char *argv[])
                }
 
                handle = find_device(dev);
-               if (handle == NULL) {
+               if (handle < 0) {
                        fprintf(stderr, "error: unable to handle '%s'\n",
                                udev_device_get_syspath(dev));
                        goto exit;
                }
                err = usb_switch(handle, mode);
+               close(handle);
                break;
        }
        case METHOD_LOGITECH_HID: {
similarity index 97%
rename from scripts/bluetooth-hid2hci.rules
rename to tools/hid2hci.rules
index 0687c8a..db6bb03 100644 (file)
@@ -1,7 +1,7 @@
 # do not edit this file, it will be overwritten on update
 
 ACTION=="remove", GOTO="hid2hci_end"
-SUBSYSTEM!="usb", GOTO="hid2hci_end"
+SUBSYSTEM!="usb*", GOTO="hid2hci_end"
 
 # Variety of Dell Bluetooth devices - match on a mouse device that is
 # self powered and where a HID report needs to be sent to switch modes
diff --git a/tools/hwdb.c b/tools/hwdb.c
new file mode 100644 (file)
index 0000000..3b712e1
--- /dev/null
@@ -0,0 +1,82 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  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 <bluetooth/bluetooth.h>
+
+static const struct {
+       uint16_t vendor;
+       uint16_t product;
+       const char *str;
+} product_table[] = {
+       { 0x0078, 0x0001, "Nike+ FuelBand"      },
+       { 0x0097, 0x0002, "COOKOO watch"        },
+       { }
+};
+
+int main(int argc, char *argv[])
+{
+       uint16_t id;
+
+       printf("# This file is part of systemd.\n");
+       printf("#\n");
+       printf("# Data imported from:\n");
+       printf("#  http://www.bluetooth.org/Technical/AssignedNumbers/identifiers.htm\n");
+
+       for (id = 0;; id++) {
+               const char *str;
+               int i;
+
+               str = bt_compidtostr(id);
+               if (!str)
+                       break;
+
+               if (!strcmp(str, "internal use"))
+                       break;
+
+               if (!strcmp(str, "not assigned"))
+                       continue;
+
+               printf("\n");
+               printf("bluetooth:v%04X*\n", id);
+               printf(" ID_VENDOR_FROM_DATABASE=%s\n", str);
+
+               for (i = 0; product_table[i].str; i++) {
+                       if (product_table[i].vendor != id)
+                               continue;
+
+                       printf("\n");
+                       printf("bluetooth:v%04Xp%04X*\n",
+                                               id, product_table[i].product);
+                       printf(" ID_PRODUCT_FROM_DATABASE=%s\n",
+                                                       product_table[i].str);
+               }
+       }
+
+       return 0;
+}
diff --git a/tools/l2cap-tester.c b/tools/l2cap-tester.c
new file mode 100644 (file)
index 0000000..df8f1bf
--- /dev/null
@@ -0,0 +1,739 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/l2cap.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hciemu.h"
+
+struct test_data {
+       const void *test_data;
+       struct mgmt *mgmt;
+       uint16_t mgmt_index;
+       struct hciemu *hciemu;
+       enum hciemu_type hciemu_type;
+       unsigned int io_id;
+};
+
+struct l2cap_client_data {
+       uint16_t client_psm;
+       uint16_t server_psm;
+       int expect_err;
+};
+
+struct l2cap_server_data {
+       uint16_t server_psm;
+       uint8_t send_req_code;
+       const void *send_req;
+       uint16_t send_req_len;
+       uint8_t expect_rsp_code;
+       const void *expect_rsp;
+       uint16_t expect_rsp_len;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct mgmt_rp_read_info *rp = param;
+       char addr[18];
+       uint16_t manufacturer;
+       uint32_t supported_settings, current_settings;
+
+       tester_print("Read Info callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+       manufacturer = btohs(rp->manufacturer);
+       supported_settings = btohl(rp->supported_settings);
+       current_settings = btohl(rp->current_settings);
+
+       tester_print("  Address: %s", addr);
+       tester_print("  Version: 0x%02x", rp->version);
+       tester_print("  Manufacturer: 0x%04x", manufacturer);
+       tester_print("  Supported settings: 0x%08x", supported_settings);
+       tester_print("  Current settings: 0x%08x", current_settings);
+       tester_print("  Class: 0x%02x%02x%02x",
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+       tester_print("  Name: %s", rp->name);
+       tester_print("  Short name: %s", rp->short_name);
+
+       if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Added callback");
+       tester_print("  Index: 0x%04x", index);
+
+       data->mgmt_index = index;
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+                                       read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Removed callback");
+       tester_print("  Index: 0x%04x", index);
+
+       if (index != data->mgmt_index)
+               return;
+
+       mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+       mgmt_unref(data->mgmt);
+       data->mgmt = NULL;
+
+       tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Read Index List callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                       index_added_callback, NULL, NULL);
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                       index_removed_callback, NULL, NULL);
+
+       data->hciemu = hciemu_new(data->hciemu_type);
+       if (!data->hciemu) {
+               tester_warn("Failed to setup HCI emulation");
+               tester_pre_setup_failed();
+       }
+
+       tester_print("New hciemu instance created");
+}
+
+static void test_pre_setup(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       data->mgmt = mgmt_new_default();
+       if (!data->mgmt) {
+               tester_warn("Failed to setup management interface");
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (tester_use_debug())
+               mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+                                       read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       if (data->io_id > 0) {
+               g_source_remove(data->io_id);
+               data->io_id = 0;
+       }
+
+       hciemu_unref(data->hciemu);
+       data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+       struct test_data *data = test_data;
+
+       free(data);
+}
+
+#define test_l2cap_bredr(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_BREDR; \
+               user->io_id = 0; \
+               user->test_data = data; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, test_data_free); \
+       } while (0)
+
+#define test_l2cap_le(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_LE; \
+               user->io_id = 0; \
+               user->test_data = data; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, test_data_free); \
+       } while (0)
+
+static const struct l2cap_client_data client_connect_success_test = {
+       .client_psm = 0x1001,
+       .server_psm = 0x1001,
+};
+
+static const struct l2cap_client_data client_connect_nval_psm_test = {
+       .client_psm = 0x1001,
+       .expect_err = ECONNREFUSED,
+};
+
+static const uint8_t l2cap_connect_req[] = { 0x01, 0x10, 0x41, 0x00 };
+
+static const struct l2cap_server_data l2cap_server_success_test = {
+       .server_psm = 0x1001,
+       .send_req_code = BT_L2CAP_PDU_CONN_REQ,
+       .send_req = l2cap_connect_req,
+       .send_req_len = sizeof(l2cap_connect_req),
+       .expect_rsp_code = BT_L2CAP_PDU_CONN_RSP,
+};
+
+static const uint8_t l2cap_nval_psm_rsp[] = {  0x00, 0x00,     /* dcid */
+                                               0x41, 0x00,     /* scid */
+                                               0x02, 0x00,     /* nval PSM */
+                                               0x00, 0x00      /* status */
+                                       };
+
+static const struct l2cap_server_data l2cap_server_nval_psm_test = {
+       .send_req_code = BT_L2CAP_PDU_CONN_REQ,
+       .send_req = l2cap_connect_req,
+       .send_req_len = sizeof(l2cap_connect_req),
+       .expect_rsp_code = BT_L2CAP_PDU_CONN_RSP,
+       .expect_rsp = l2cap_nval_psm_rsp,
+       .expect_rsp_len = sizeof(l2cap_nval_psm_rsp),
+};
+
+static const uint8_t l2cap_nval_conn_req[] = { 0x00 };
+static const uint8_t l2cap_nval_pdu_rsp[] = { 0x00, 0x00 };
+
+static const struct l2cap_server_data l2cap_server_nval_pdu_test1 = {
+       .send_req_code = BT_L2CAP_PDU_CONN_REQ,
+       .send_req = l2cap_nval_conn_req,
+       .send_req_len = sizeof(l2cap_nval_conn_req),
+       .expect_rsp_code = BT_L2CAP_PDU_CMD_REJECT,
+       .expect_rsp = l2cap_nval_pdu_rsp,
+       .expect_rsp_len = sizeof(l2cap_nval_pdu_rsp),
+};
+
+static const uint8_t l2cap_nval_dc_req[] = { 0x12, 0x34, 0x56, 0x78 };
+static const uint8_t l2cap_nval_cid_rsp[] = { 0x02, 0x00 };
+
+static const struct l2cap_server_data l2cap_server_nval_cid_test1 = {
+       .send_req_code = BT_L2CAP_PDU_DISCONN_REQ,
+       .send_req = l2cap_nval_dc_req,
+       .send_req_len = sizeof(l2cap_nval_dc_req),
+       .expect_rsp_code = BT_L2CAP_PDU_CMD_REJECT,
+       .expect_rsp = l2cap_nval_cid_rsp,
+       .expect_rsp_len = sizeof(l2cap_nval_cid_rsp),
+};
+
+static const uint8_t l2cap_nval_cfg_req[] = { 0x12, 0x34, 0x00, 0x00 };
+static const uint8_t l2cap_nval_cfg_rsp[] = { 0x02, 0x00 };
+
+static const struct l2cap_server_data l2cap_server_nval_cid_test2 = {
+       .send_req_code = BT_L2CAP_PDU_CONFIG_REQ,
+       .send_req = l2cap_nval_cfg_req,
+       .send_req_len = sizeof(l2cap_nval_cfg_req),
+       .expect_rsp_code = BT_L2CAP_PDU_CMD_REJECT,
+       .expect_rsp = l2cap_nval_cfg_rsp,
+       .expect_rsp_len = sizeof(l2cap_nval_cfg_rsp),
+};
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+                                       const void *param, uint8_t len,
+                                       void *user_data)
+{
+       switch (opcode) {
+       case BT_HCI_CMD_WRITE_SCAN_ENABLE:
+       case BT_HCI_CMD_LE_SET_ADV_ENABLE:
+               break;
+       default:
+               return;
+       }
+
+       tester_print("Client set connectable status 0x%02x", status);
+
+       if (status)
+               tester_setup_failed();
+       else
+               tester_setup_complete();
+}
+
+static void setup_powered_client_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       struct bthost *bthost;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
+       if (data->hciemu_type == HCIEMU_TYPE_LE)
+               bthost_set_adv_enable(bthost, 0x01);
+       else
+               bthost_write_scan_enable(bthost, 0x03);
+}
+
+static void setup_powered_server_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       tester_setup_complete();
+}
+
+static void setup_powered_client(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       if (data->hciemu_type == HCIEMU_TYPE_BREDR)
+               mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       else
+               mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                       sizeof(param), param, setup_powered_client_callback,
+                       NULL, NULL);
+}
+
+static void setup_powered_server(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       if (data->hciemu_type == HCIEMU_TYPE_BREDR) {
+               mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                               sizeof(param), param,
+                               NULL, NULL, NULL);
+               mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       } else {
+               mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+               mgmt_send(data->mgmt, MGMT_OP_SET_ADVERTISING, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+       }
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                       sizeof(param), param, setup_powered_server_callback,
+                       NULL, NULL);
+}
+
+static void test_basic(const void *test_data)
+{
+       int sk;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_L2CAP);
+       if (sk < 0) {
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               tester_test_failed();
+               return;
+       }
+
+       close(sk);
+
+       tester_test_passed();
+}
+
+static gboolean l2cap_connect_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct l2cap_client_data *l2data = data->test_data;
+       int err, sk_err, sk;
+       socklen_t len = sizeof(sk_err);
+
+       data->io_id = 0;
+
+       sk = g_io_channel_unix_get_fd(io);
+
+       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+               err = -errno;
+       else
+               err = -sk_err;
+
+       if (err < 0)
+               tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+       else
+               tester_print("Successfully connected");
+
+       if (-err != l2data->expect_err)
+               tester_test_failed();
+       else
+               tester_test_passed();
+
+       return FALSE;
+}
+
+static int create_l2cap_sock(struct test_data *data, uint16_t psm)
+{
+       const uint8_t *master_bdaddr;
+       struct sockaddr_l2 addr;
+       int sk, err;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
+                                                       BTPROTO_L2CAP);
+       if (sk < 0) {
+               err = -errno;
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               return err;
+       }
+
+       master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+       if (!master_bdaddr) {
+               tester_warn("No master bdaddr");
+               return -ENODEV;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       addr.l2_psm = htobs(psm);
+       bacpy(&addr.l2_bdaddr, (void *) master_bdaddr);
+       if (data->hciemu_type == HCIEMU_TYPE_LE)
+               addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
+       else
+               addr.l2_bdaddr_type = BDADDR_BREDR;
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               err = -errno;
+               tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               close(sk);
+               return err;
+       }
+
+       return sk;
+}
+
+static int connect_l2cap_sock(struct test_data *data, int sk, uint16_t psm)
+{
+       const uint8_t *client_bdaddr;
+       struct sockaddr_l2 addr;
+       int err;
+
+       client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+       if (!client_bdaddr) {
+               tester_warn("No client bdaddr");
+               return -ENODEV;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.l2_family = AF_BLUETOOTH;
+       bacpy(&addr.l2_bdaddr, (void *) client_bdaddr);
+       addr.l2_psm = htobs(psm);
+       if (data->hciemu_type == HCIEMU_TYPE_LE)
+               addr.l2_bdaddr_type = BDADDR_LE_PUBLIC;
+       else
+               addr.l2_bdaddr_type = BDADDR_BREDR;
+
+       err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+       if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
+               err = -errno;
+               tester_warn("Can't connect socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               return err;
+       }
+
+       return 0;
+}
+
+static void test_connect(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct l2cap_client_data *l2data = data->test_data;
+       GIOChannel *io;
+       int sk;
+
+       if (l2data->server_psm) {
+               struct bthost *bthost = hciemu_client_get_host(data->hciemu);
+               bthost_set_server_psm(bthost, l2data->server_psm);
+       }
+
+       sk = create_l2cap_sock(data, 0);
+       if (sk < 0) {
+               tester_test_failed();
+               return;
+       }
+
+       if (connect_l2cap_sock(data, sk, l2data->client_psm) < 0) {
+               close(sk);
+               tester_test_failed();
+               return;
+       }
+
+       io = g_io_channel_unix_new(sk);
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       data->io_id = g_io_add_watch(io, G_IO_OUT, l2cap_connect_cb, NULL);
+
+       g_io_channel_unref(io);
+
+       tester_print("Connect in progress");
+}
+
+static gboolean l2cap_listen_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct test_data *data = tester_get_data();
+       int sk, new_sk;
+
+       data->io_id = 0;
+
+       sk = g_io_channel_unix_get_fd(io);
+
+       new_sk = accept(sk, NULL, NULL);
+       if (new_sk < 0) {
+               tester_warn("accept failed: %s (%u)", strerror(errno), errno);
+               tester_test_failed();
+               return FALSE;
+       }
+
+       tester_print("Successfully connected");
+
+       close(new_sk);
+
+       tester_test_passed();
+
+       return FALSE;
+}
+
+static void client_l2cap_rsp(uint8_t code, const void *data, uint16_t len,
+                                                       void *user_data)
+{
+       struct test_data *test_data = user_data;
+       const struct l2cap_server_data *l2data = test_data->test_data;
+
+       tester_print("Client received response code 0x%02x", code);
+
+       if (code != l2data->expect_rsp_code) {
+               tester_warn("Unexpected L2CAP response code (expected 0x%02x)",
+                                               l2data->expect_rsp_code);
+               goto failed;
+       }
+
+       if (!l2data->expect_rsp) {
+               tester_test_passed();
+               return;
+       }
+
+       if (l2data->expect_rsp_len != len) {
+               tester_warn("Unexpected L2CAP response length (%u != %u)",
+                                               len, l2data->expect_rsp_len);
+               goto failed;
+       }
+
+       if (memcmp(l2data->expect_rsp, data, len) != 0) {
+               tester_warn("Unexpected L2CAP response");
+               goto failed;
+       }
+
+       tester_test_passed();
+       return;
+
+failed:
+       tester_test_failed();
+}
+
+static void client_new_conn(uint16_t handle, void *user_data)
+{
+       struct test_data *data = user_data;
+       const struct l2cap_server_data *l2data = data->test_data;
+       struct bthost *bthost;
+
+       tester_print("New client connection with handle 0x%04x", handle);
+
+       if (l2data->send_req) {
+               bthost_l2cap_rsp_cb cb;
+
+               if (l2data->expect_rsp_code)
+                       cb = client_l2cap_rsp;
+               else
+                       cb = NULL;
+
+               tester_print("Sending L2CAP Request from client");
+
+               bthost = hciemu_client_get_host(data->hciemu);
+               bthost_l2cap_req(bthost, handle, l2data->send_req_code,
+                                       l2data->send_req, l2data->send_req_len,
+                                       cb, data);
+       }
+}
+
+static void test_server(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct l2cap_server_data *l2data = data->test_data;
+       const uint8_t *master_bdaddr;
+       uint8_t addr_type;
+       struct bthost *bthost;
+       GIOChannel *io;
+       int sk;
+
+       if (l2data->server_psm) {
+               sk = create_l2cap_sock(data, l2data->server_psm);
+               if (sk < 0) {
+                       tester_test_failed();
+                       return;
+               }
+
+               if (listen(sk, 5) < 0) {
+                       tester_warn("listening on socket failed: %s (%u)",
+                                       strerror(errno), errno);
+                       tester_test_failed();
+                       return;
+               }
+
+               io = g_io_channel_unix_new(sk);
+               g_io_channel_set_close_on_unref(io, TRUE);
+
+               data->io_id = g_io_add_watch(io, G_IO_IN, l2cap_listen_cb,
+                                                                       NULL);
+               g_io_channel_unref(io);
+
+               tester_print("Listening for connections");
+       }
+
+       master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+       if (!master_bdaddr) {
+               tester_warn("No master bdaddr");
+               tester_test_failed();
+               return;
+       }
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_connect_cb(bthost, client_new_conn, data);
+
+       if (data->hciemu_type == HCIEMU_TYPE_BREDR)
+               addr_type = BDADDR_BREDR;
+       else
+               addr_type = BDADDR_LE_PUBLIC;
+
+       bthost_hci_connect(bthost, master_bdaddr, addr_type);
+}
+
+int main(int argc, char *argv[])
+{
+       tester_init(&argc, &argv);
+
+       test_l2cap_bredr("Basic L2CAP Socket - Success", NULL,
+                                       setup_powered_client, test_basic);
+
+       test_l2cap_bredr("L2CAP BR/EDR Client - Success",
+                                       &client_connect_success_test,
+                                       setup_powered_client, test_connect);
+       test_l2cap_bredr("L2CAP BR/EDR Client - Invalid PSM",
+                                       &client_connect_nval_psm_test,
+                                       setup_powered_client, test_connect);
+
+       test_l2cap_bredr("L2CAP BR/EDR Server - Success",
+                                       &l2cap_server_success_test,
+                                       setup_powered_server, test_server);
+       test_l2cap_bredr("L2CAP BR/EDR Server - Invalid PSM",
+                                       &l2cap_server_nval_psm_test,
+                                       setup_powered_server, test_server);
+       test_l2cap_bredr("L2CAP BR/EDR Server - Invalid PDU",
+                               &l2cap_server_nval_pdu_test1,
+                               setup_powered_server, test_server);
+       test_l2cap_bredr("L2CAP BR/EDR Server - Invalid Disconnect CID",
+                               &l2cap_server_nval_cid_test1,
+                               setup_powered_server, test_server);
+       test_l2cap_bredr("L2CAP BR/EDR Server - Invalid Config CID",
+                               &l2cap_server_nval_cid_test2,
+                               setup_powered_server, test_server);
+
+       return tester_run();
+}
similarity index 96%
rename from tools/l2ping.8
rename to tools/l2ping.1
index 8b77ee2..4d09b05 100644 (file)
@@ -1,4 +1,4 @@
-.TH L2PING 8 "Jan 22 2002" BlueZ "Linux System Administration"
+.TH L2PING 1 "Jan 22 2002" BlueZ "Linux System Administration"
 .SH NAME
 l2ping \- Send L2CAP echo request and receive answer
 .SH SYNOPSIS
similarity index 93%
rename from test/l2test.c
rename to tools/l2test.c
index f66486d..125532b 100644 (file)
@@ -107,7 +107,7 @@ static char *filename = NULL;
 static int rfcmode = 0;
 static int master = 0;
 static int auth = 0;
-static int encrypt = 0;
+static int encr = 0;
 static int secure = 0;
 static int socktype = SOCK_SEQPACKET;
 static int linger = 0;
@@ -120,8 +120,8 @@ static int chan_policy = -1;
 static int bdaddr_type = 0;
 
 struct lookup_table {
-       char    *name;
-       int     flag;
+       const char *name;
+       int flag;
 };
 
 static struct lookup_table l2cap_modes[] = {
@@ -160,6 +160,17 @@ static int get_lookup_flag(struct lookup_table *table, char *name)
        return -1;
 }
 
+static const char *get_lookup_str(struct lookup_table *table, int flag)
+{
+       int i;
+
+       for (i = 0; table[i].name; i++)
+               if (table[i].flag == flag)
+                       return table[i].name;
+
+       return NULL;
+}
+
 static void print_lookup_values(struct lookup_table *table, char *header)
 {
        int i;
@@ -175,7 +186,7 @@ static float tv2fl(struct timeval tv)
        return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
 }
 
-static char *ltoh(unsigned long c, chars)
+static char *ltoh(unsigned long c, char *s)
 {
        int c1;
 
@@ -199,7 +210,7 @@ static char *ltoh(unsigned long c, char* s)
        return s;
 }
 
-static char *ctoh(char c, chars)
+static char *ctoh(char c, char *s)
 {
        char c1;
 
@@ -254,6 +265,7 @@ static int do_connect(char *svr)
        struct l2cap_conninfo conn;
        socklen_t optlen;
        int sk, opt;
+       char ba[18];
 
        /* Create socket */
        sk = socket(PF_BLUETOOTH, socktype, BTPROTO_L2CAP);
@@ -267,6 +279,7 @@ static int do_connect(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        bacpy(&addr.l2_bdaddr, &bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                syslog(LOG_ERR, "Can't bind socket: %s (%d)",
@@ -340,7 +353,7 @@ static int do_connect(char *svr)
                opt |= L2CAP_LM_MASTER;
        if (auth)
                opt |= L2CAP_LM_AUTH;
-       if (encrypt)
+       if (encr)
                opt |= L2CAP_LM_ENCRYPT;
        if (secure)
                opt |= L2CAP_LM_SECURE;
@@ -417,7 +430,37 @@ static int do_connect(char *svr)
                goto error;
        }
 
-       syslog(LOG_INFO, "Connected [imtu %d, omtu %d, flush_to %d, "
+       /* Check for remote address */
+       memset(&addr, 0, sizeof(addr));
+       optlen = sizeof(addr);
+
+       if (getpeername(sk, (struct sockaddr *) &addr, &optlen) < 0) {
+               syslog(LOG_ERR, "Can't get socket name: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       ba2str(&addr.l2_bdaddr, ba);
+       syslog(LOG_INFO, "Connected to %s (%s, psm %d, scid %d)", ba,
+               get_lookup_str(bdaddr_types, addr.l2_bdaddr_type),
+               addr.l2_psm, addr.l2_cid);
+
+       /* Check for socket address */
+       memset(&addr, 0, sizeof(addr));
+       optlen = sizeof(addr);
+
+       if (getsockname(sk, (struct sockaddr *) &addr, &optlen) < 0) {
+               syslog(LOG_ERR, "Can't get socket name: %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
+       ba2str(&addr.l2_bdaddr, ba);
+       syslog(LOG_INFO, "Local device %s (%s, psm %d, scid %d)", ba,
+               get_lookup_str(bdaddr_types, addr.l2_bdaddr_type),
+               addr.l2_psm, addr.l2_cid);
+
+       syslog(LOG_INFO, "Options [imtu %d, omtu %d, flush_to %d, "
                "mode %d, handle %d, class 0x%02x%02x%02x, priority %d, rcvbuf %d]",
                opts.imtu, opts.omtu, opts.flush_to, opts.mode, conn.hci_handle,
                conn.dev_class[2], conn.dev_class[1], conn.dev_class[0], opt,
@@ -454,12 +497,11 @@ static void do_listen(void (*handler)(int sk))
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        bacpy(&addr.l2_bdaddr, &bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
        if (cid)
                addr.l2_cid = htobs(cid);
        else if (psm)
                addr.l2_psm = htobs(psm);
-       else
-               goto error;
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                syslog(LOG_ERR, "Can't bind socket: %s (%d)",
@@ -475,7 +517,7 @@ static void do_listen(void (*handler)(int sk))
                opt |= L2CAP_LM_MASTER;
        if (auth)
                opt |= L2CAP_LM_AUTH;
-       if (encrypt)
+       if (encr)
                opt |= L2CAP_LM_ENCRYPT;
        if (secure)
                opt |= L2CAP_LM_SECURE;
@@ -610,7 +652,7 @@ static void do_listen(void (*handler)(int sk))
                        }
                }
 
-               if (priority > 0 && setsockopt(sk, SOL_SOCKET, SO_PRIORITY,
+               if (priority > 0 && setsockopt(nsk, SOL_SOCKET, SO_PRIORITY,
                                        &priority, sizeof(priority)) < 0) {
                        syslog(LOG_ERR, "Can't set socket priority: %s (%d)",
                                                strerror(errno), errno);
@@ -626,10 +668,29 @@ static void do_listen(void (*handler)(int sk))
                }
 
                ba2str(&addr.l2_bdaddr, ba);
-               syslog(LOG_INFO, "Connect from %s [imtu %d, omtu %d, "
+               syslog(LOG_INFO, "Connect from %s (%s, psm %d, dcid %d)", ba,
+                               get_lookup_str(bdaddr_types, addr.l2_bdaddr_type),
+                               addr.l2_psm, addr.l2_cid);
+
+               /* Check for socket address */
+               memset(&addr, 0, sizeof(addr));
+               optlen = sizeof(addr);
+
+               if (getsockname(nsk, (struct sockaddr *) &addr, &optlen) < 0) {
+                       syslog(LOG_ERR, "Can't get socket name: %s (%d)",
+                                                       strerror(errno), errno);
+                       goto error;
+               }
+
+               ba2str(&addr.l2_bdaddr, ba);
+               syslog(LOG_INFO, "Local device %s (%s, psm %d, scid %d)", ba,
+                               get_lookup_str(bdaddr_types, addr.l2_bdaddr_type),
+                               addr.l2_psm, addr.l2_cid);
+
+               syslog(LOG_INFO, "Options [imtu %d, omtu %d, "
                                "flush_to %d, mode %d, handle %d, "
                                "class 0x%02x%02x%02x, priority %d, rcvbuf %d]",
-                               ba, opts.imtu, opts.omtu, opts.flush_to,
+                               opts.imtu, opts.omtu, opts.flush_to,
                                opts.mode, conn.hci_handle, conn.dev_class[2],
                                conn.dev_class[1], conn.dev_class[0], opt,
                                rcvbuf);
@@ -823,7 +884,7 @@ static void recv_mode(int sk)
                        }
 
                        /* Check sequence */
-                       sq = btohl(*(uint32_t *) buf);
+                       sq = bt_get_le32(buf);
                        if (seq != sq) {
                                syslog(LOG_INFO, "seq missmatch: %d -> %d", seq, sq);
                                seq = sq;
@@ -831,7 +892,7 @@ static void recv_mode(int sk)
                        seq++;
 
                        /* Check length */
-                       l = btohs(*(uint16_t *) (buf + 4));
+                       l = bt_get_le16(buf + 4);
                        if (len != l) {
                                syslog(LOG_INFO, "size missmatch: %d -> %d", len, l);
                                continue;
@@ -890,8 +951,9 @@ static void do_send(int sk)
 
        seq = 0;
        while ((num_frames == -1) || (num_frames-- > 0)) {
-               *(uint32_t *) buf = htobl(seq);
-               *(uint16_t *) (buf + 4) = htobs(data_size);
+               bt_put_le32(seq, buf);
+               bt_put_le16(data_size, buf + 4);
+
                seq++;
 
                sent = 0;
@@ -1020,6 +1082,7 @@ static void info_request(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        bacpy(&addr.l2_bdaddr, &bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                perror("Can't bind socket");
@@ -1158,6 +1221,7 @@ static void do_pairing(char *svr)
        memset(&addr, 0, sizeof(addr));
        addr.l2_family = AF_BLUETOOTH;
        bacpy(&addr.l2_bdaddr, &bdaddr);
+       addr.l2_bdaddr_type = bdaddr_type;
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                perror("Can't bind socket");
@@ -1407,7 +1471,7 @@ int main(int argc, char *argv[])
                        break;
 
                case 'E':
-                       encrypt = 1;
+                       encr = 1;
                        break;
 
                case 'S':
diff --git a/tools/lexer.c b/tools/lexer.c
deleted file mode 100644 (file)
index 5228bc0..0000000
+++ /dev/null
@@ -1,1848 +0,0 @@
-
-#line 3 "tools/lexer.c"
-
-#define  YY_INT_ALIGNED short int
-
-/* A lexical scanner generated by flex */
-
-#define FLEX_SCANNER
-#define YY_FLEX_MAJOR_VERSION 2
-#define YY_FLEX_MINOR_VERSION 5
-#define YY_FLEX_SUBMINOR_VERSION 35
-#if YY_FLEX_SUBMINOR_VERSION > 0
-#define FLEX_BETA
-#endif
-
-/* First, we deal with  platform-specific or compiler-specific issues. */
-
-/* begin standard C headers. */
-#include <stdio.h>
-#include <string.h>
-#include <errno.h>
-#include <stdlib.h>
-
-/* end standard C headers. */
-
-/* flex integer type definitions */
-
-#ifndef FLEXINT_H
-#define FLEXINT_H
-
-/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */
-
-#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
-
-/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h,
- * if you want the limit (max/min) macros for int types. 
- */
-#ifndef __STDC_LIMIT_MACROS
-#define __STDC_LIMIT_MACROS 1
-#endif
-
-#include <inttypes.h>
-typedef int8_t flex_int8_t;
-typedef uint8_t flex_uint8_t;
-typedef int16_t flex_int16_t;
-typedef uint16_t flex_uint16_t;
-typedef int32_t flex_int32_t;
-typedef uint32_t flex_uint32_t;
-#else
-typedef signed char flex_int8_t;
-typedef short int flex_int16_t;
-typedef int flex_int32_t;
-typedef unsigned char flex_uint8_t; 
-typedef unsigned short int flex_uint16_t;
-typedef unsigned int flex_uint32_t;
-
-/* Limits of integral types. */
-#ifndef INT8_MIN
-#define INT8_MIN               (-128)
-#endif
-#ifndef INT16_MIN
-#define INT16_MIN              (-32767-1)
-#endif
-#ifndef INT32_MIN
-#define INT32_MIN              (-2147483647-1)
-#endif
-#ifndef INT8_MAX
-#define INT8_MAX               (127)
-#endif
-#ifndef INT16_MAX
-#define INT16_MAX              (32767)
-#endif
-#ifndef INT32_MAX
-#define INT32_MAX              (2147483647)
-#endif
-#ifndef UINT8_MAX
-#define UINT8_MAX              (255U)
-#endif
-#ifndef UINT16_MAX
-#define UINT16_MAX             (65535U)
-#endif
-#ifndef UINT32_MAX
-#define UINT32_MAX             (4294967295U)
-#endif
-
-#endif /* ! C99 */
-
-#endif /* ! FLEXINT_H */
-
-#ifdef __cplusplus
-
-/* The "const" storage-class-modifier is valid. */
-#define YY_USE_CONST
-
-#else  /* ! __cplusplus */
-
-/* C99 requires __STDC__ to be defined as 1. */
-#if defined (__STDC__)
-
-#define YY_USE_CONST
-
-#endif /* defined (__STDC__) */
-#endif /* ! __cplusplus */
-
-#ifdef YY_USE_CONST
-#define yyconst const
-#else
-#define yyconst
-#endif
-
-/* Returned upon end-of-file. */
-#define YY_NULL 0
-
-/* Promotes a possibly negative, possibly signed char to an unsigned
- * integer for use as an array index.  If the signed char is negative,
- * we want to instead treat it as an 8-bit unsigned char, hence the
- * double cast.
- */
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)
-
-/* Enter a start condition.  This macro really ought to take a parameter,
- * but we do it the disgusting crufty way forced on us by the ()-less
- * definition of BEGIN.
- */
-#define BEGIN (yy_start) = 1 + 2 *
-
-/* Translate the current start state into a value that can be later handed
- * to BEGIN to return to the state.  The YYSTATE alias is for lex
- * compatibility.
- */
-#define YY_START (((yy_start) - 1) / 2)
-#define YYSTATE YY_START
-
-/* Action number for EOF rule of a given start state. */
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)
-
-/* Special action meaning "start processing a new file". */
-#define YY_NEW_FILE yyrestart(yyin  )
-
-#define YY_END_OF_BUFFER_CHAR 0
-
-/* Size of default input buffer. */
-#ifndef YY_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k.
- * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case.
- * Ditto for the __ia64__ case accordingly.
- */
-#define YY_BUF_SIZE 32768
-#else
-#define YY_BUF_SIZE 16384
-#endif /* __ia64__ */
-#endif
-
-/* The state buf must be large enough to hold one state per character in the main buffer.
- */
-#define YY_STATE_BUF_SIZE   ((YY_BUF_SIZE + 2) * sizeof(yy_state_type))
-
-#ifndef YY_TYPEDEF_YY_BUFFER_STATE
-#define YY_TYPEDEF_YY_BUFFER_STATE
-typedef struct yy_buffer_state *YY_BUFFER_STATE;
-#endif
-
-extern int yyleng;
-
-extern FILE *yyin, *yyout;
-
-#define EOB_ACT_CONTINUE_SCAN 0
-#define EOB_ACT_END_OF_FILE 1
-#define EOB_ACT_LAST_MATCH 2
-
-    #define YY_LESS_LINENO(n)
-    
-/* Return all but the first "n" matched characters back to the input stream. */
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               *yy_cp = (yy_hold_char); \
-               YY_RESTORE_YY_MORE_OFFSET \
-               (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \
-               YY_DO_BEFORE_ACTION; /* set up yytext again */ \
-               } \
-       while ( 0 )
-
-#define unput(c) yyunput( c, (yytext_ptr)  )
-
-#ifndef YY_TYPEDEF_YY_SIZE_T
-#define YY_TYPEDEF_YY_SIZE_T
-typedef size_t yy_size_t;
-#endif
-
-#ifndef YY_STRUCT_YY_BUFFER_STATE
-#define YY_STRUCT_YY_BUFFER_STATE
-struct yy_buffer_state
-       {
-       FILE *yy_input_file;
-
-       char *yy_ch_buf;                /* input buffer */
-       char *yy_buf_pos;               /* current position in input buffer */
-
-       /* Size of input buffer in bytes, not including room for EOB
-        * characters.
-        */
-       yy_size_t yy_buf_size;
-
-       /* Number of characters read into yy_ch_buf, not including EOB
-        * characters.
-        */
-       int yy_n_chars;
-
-       /* Whether we "own" the buffer - i.e., we know we created it,
-        * and can realloc() it to grow it, and should free() it to
-        * delete it.
-        */
-       int yy_is_our_buffer;
-
-       /* Whether this is an "interactive" input source; if so, and
-        * if we're using stdio for input, then we want to use getc()
-        * instead of fread(), to make sure we stop fetching input after
-        * each newline.
-        */
-       int yy_is_interactive;
-
-       /* Whether we're considered to be at the beginning of a line.
-        * If so, '^' rules will be active on the next match, otherwise
-        * not.
-        */
-       int yy_at_bol;
-
-    int yy_bs_lineno; /**< The line count. */
-    int yy_bs_column; /**< The column count. */
-    
-       /* Whether to try to fill the input buffer when we reach the
-        * end of it.
-        */
-       int yy_fill_buffer;
-
-       int yy_buffer_status;
-
-#define YY_BUFFER_NEW 0
-#define YY_BUFFER_NORMAL 1
-       /* When an EOF's been seen but there's still some text to process
-        * then we mark the buffer as YY_EOF_PENDING, to indicate that we
-        * shouldn't try reading from the input source any more.  We might
-        * still have a bunch of tokens to match, though, because of
-        * possible backing-up.
-        *
-        * When we actually see the EOF, we change the status to "new"
-        * (via yyrestart()), so that the user can continue scanning by
-        * just pointing yyin at a new input file.
-        */
-#define YY_BUFFER_EOF_PENDING 2
-
-       };
-#endif /* !YY_STRUCT_YY_BUFFER_STATE */
-
-/* Stack of input buffers. */
-static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */
-static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */
-static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */
-
-/* We provide macros for accessing buffer states in case in the
- * future we want to put the buffer states in a more general
- * "scanner state".
- *
- * Returns the top of the stack, or NULL.
- */
-#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \
-                          ? (yy_buffer_stack)[(yy_buffer_stack_top)] \
-                          : NULL)
-
-/* Same as previous macro, but useful when we know that the buffer stack is not
- * NULL or when we need an lvalue. For internal use only.
- */
-#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)]
-
-/* yy_hold_char holds the character lost when yytext is formed. */
-static char yy_hold_char;
-static int yy_n_chars;         /* number of characters read into yy_ch_buf */
-int yyleng;
-
-/* Points to current character in buffer. */
-static char *yy_c_buf_p = (char *) 0;
-static int yy_init = 0;                /* whether we need to initialize */
-static int yy_start = 0;       /* start state number */
-
-/* Flag which is used to allow yywrap()'s to do buffer switches
- * instead of setting up a fresh yyin.  A bit of a hack ...
- */
-static int yy_did_buffer_switch_on_eof;
-
-void yyrestart (FILE *input_file  );
-void yy_switch_to_buffer (YY_BUFFER_STATE new_buffer  );
-YY_BUFFER_STATE yy_create_buffer (FILE *file,int size  );
-void yy_delete_buffer (YY_BUFFER_STATE b  );
-void yy_flush_buffer (YY_BUFFER_STATE b  );
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer  );
-void yypop_buffer_state (void );
-
-static void yyensure_buffer_stack (void );
-static void yy_load_buffer_state (void );
-static void yy_init_buffer (YY_BUFFER_STATE b,FILE *file  );
-
-#define YY_FLUSH_BUFFER yy_flush_buffer(YY_CURRENT_BUFFER )
-
-YY_BUFFER_STATE yy_scan_buffer (char *base,yy_size_t size  );
-YY_BUFFER_STATE yy_scan_string (yyconst char *yy_str  );
-YY_BUFFER_STATE yy_scan_bytes (yyconst char *bytes,int len  );
-
-void *yyalloc (yy_size_t  );
-void *yyrealloc (void *,yy_size_t  );
-void yyfree (void *  );
-
-#define yy_new_buffer yy_create_buffer
-
-#define yy_set_interactive(is_interactive) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){ \
-        yyensure_buffer_stack (); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \
-       }
-
-#define yy_set_bol(at_bol) \
-       { \
-       if ( ! YY_CURRENT_BUFFER ){\
-        yyensure_buffer_stack (); \
-               YY_CURRENT_BUFFER_LVALUE =    \
-            yy_create_buffer(yyin,YY_BUF_SIZE ); \
-       } \
-       YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \
-       }
-
-#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol)
-
-/* Begin user sect3 */
-
-typedef unsigned char YY_CHAR;
-
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;
-
-typedef int yy_state_type;
-
-extern int yylineno;
-
-int yylineno = 1;
-
-extern char *yytext;
-#define yytext_ptr yytext
-
-static yy_state_type yy_get_previous_state (void );
-static yy_state_type yy_try_NUL_trans (yy_state_type current_state  );
-static int yy_get_next_buffer (void );
-static void yy_fatal_error (yyconst char msg[]  );
-
-/* Done after the current pattern has been matched and before the
- * corresponding action - sets up yytext.
- */
-#define YY_DO_BEFORE_ACTION \
-       (yytext_ptr) = yy_bp; \
-       yyleng = (size_t) (yy_cp - yy_bp); \
-       (yy_hold_char) = *yy_cp; \
-       *yy_cp = '\0'; \
-       (yy_c_buf_p) = yy_cp;
-
-#define YY_NUM_RULES 9
-#define YY_END_OF_BUFFER 10
-/* This struct is not used in this scanner,
-   but its presence is necessary. */
-struct yy_trans_info
-       {
-       flex_int32_t yy_verify;
-       flex_int32_t yy_nxt;
-       };
-static yyconst flex_int16_t yy_accept[36] =
-    {   0,
-        0,    0,   10,    8,    1,    7,    8,    8,    6,    3,
-        6,    0,    4,    0,    2,    6,    3,    6,    3,    0,
-        0,    0,    0,    0,    0,    0,    0,    0,    0,    0,
-        0,    0,    0,    5,    0
-    } ;
-
-static yyconst flex_int32_t yy_ec[256] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    2,    3,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    2,    1,    4,    5,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    6,    1,    1,    7,    7,    7,
-        7,    7,    7,    7,    7,    7,    7,    8,    1,    1,
-        1,    1,    1,    1,    9,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        1,    1,    1,    1,    6,    1,    9,    9,    9,    9,
-
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,
-        9,    9,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,
-        1,    1,    1,    1,    1
-    } ;
-
-static yyconst flex_int32_t yy_meta[10] =
-    {   0,
-        1,    1,    2,    1,    1,    3,    4,    1,    4
-    } ;
-
-static yyconst flex_int16_t yy_base[49] =
-    {   0,
-        0,    0,   46,   47,   47,   47,   41,   41,    0,    4,
-       36,   38,   37,   37,   47,    0,    7,   31,   31,    0,
-        0,   29,    0,    0,   28,    0,    0,   27,    0,    0,
-       26,    0,    0,   47,   47,   15,   19,   21,   29,   28,
-       27,   26,   25,   24,   23,   22,   13,    8
-    } ;
-
-static yyconst flex_int16_t yy_def[49] =
-    {   0,
-       35,    1,   35,   35,   35,   35,   36,   37,   38,   35,
-       10,   36,   36,   37,   35,   38,   38,   38,   38,   39,
-       40,   35,   41,   42,   35,   43,   44,   35,   45,   46,
-       35,   47,   48,   35,    0,   35,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35,   35,   35
-    } ;
-
-static yyconst flex_int16_t yy_nxt[57] =
-    {   0,
-        4,    5,    6,    7,    8,    9,   10,    4,   11,   16,
-       17,   34,   18,   19,   20,   12,   33,   12,   12,   14,
-       14,   14,   14,   16,   16,   31,   30,   28,   27,   25,
-       24,   22,   21,   32,   29,   26,   23,   19,   20,   15,
-       13,   13,   18,   15,   13,   35,    3,   35,   35,   35,
-       35,   35,   35,   35,   35,   35
-    } ;
-
-static yyconst flex_int16_t yy_chk[57] =
-    {   0,
-        1,    1,    1,    1,    1,    1,    1,    1,    1,   10,
-       10,   48,   10,   17,   17,   36,   47,   36,   36,   37,
-       37,   37,   37,   38,   38,   46,   45,   44,   43,   42,
-       41,   40,   39,   31,   28,   25,   22,   19,   18,   14,
-       13,   12,   11,    8,    7,    3,   35,   35,   35,   35,
-       35,   35,   35,   35,   35,   35
-    } ;
-
-static yy_state_type yy_last_accepting_state;
-static char *yy_last_accepting_cpos;
-
-extern int yy_flex_debug;
-int yy_flex_debug = 0;
-
-/* The intent behind this definition is that it'll catch
- * any uses of REJECT which flex missed.
- */
-#define REJECT reject_used_but_not_detected
-#define yymore() yymore_used_but_not_detected
-#define YY_MORE_ADJ 0
-#define YY_RESTORE_YY_MORE_OFFSET
-char *yytext;
-#line 1 "lexer.l"
-#line 2 "lexer.l"
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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
-
-/* Nasty workaround, but flex defines isatty() twice */
-#define _UNISTD_H
-
-#include <stdio.h>
-#include <errno.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "kword.h"
-#include "parser.h"
-
-int yylex(void);
-
-#define YY_NO_INPUT
-
-#define ECHO {;}
-#define YY_DECL int yylex(void)
-
-int yyerror(char *str);
-
-#line 529 "tools/lexer.c"
-
-#define INITIAL 0
-
-#ifndef YY_NO_UNISTD_H
-/* Special case for "unistd.h", since it is non-ANSI. We include it way
- * down here because we want the user's section 1 to have been scanned first.
- * The user has a chance to override it with an option.
- */
-#include <unistd.h>
-#endif
-
-#ifndef YY_EXTRA_TYPE
-#define YY_EXTRA_TYPE void *
-#endif
-
-static int yy_init_globals (void );
-
-/* Accessor methods to globals.
-   These are made visible to non-reentrant scanners for convenience. */
-
-int yylex_destroy (void );
-
-int yyget_debug (void );
-
-void yyset_debug (int debug_flag  );
-
-YY_EXTRA_TYPE yyget_extra (void );
-
-void yyset_extra (YY_EXTRA_TYPE user_defined  );
-
-FILE *yyget_in (void );
-
-void yyset_in  (FILE * in_str  );
-
-FILE *yyget_out (void );
-
-void yyset_out  (FILE * out_str  );
-
-int yyget_leng (void );
-
-char *yyget_text (void );
-
-int yyget_lineno (void );
-
-void yyset_lineno (int line_number  );
-
-/* Macros after this point can all be overridden by user definitions in
- * section 1.
- */
-
-#ifndef YY_SKIP_YYWRAP
-#ifdef __cplusplus
-extern "C" int yywrap (void );
-#else
-extern int yywrap (void );
-#endif
-#endif
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char *,yyconst char *,int );
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * );
-#endif
-
-#ifndef YY_NO_INPUT
-
-#ifdef __cplusplus
-static int yyinput (void );
-#else
-static int input (void );
-#endif
-
-#endif
-
-/* Amount of stuff to slurp up with each read. */
-#ifndef YY_READ_BUF_SIZE
-#ifdef __ia64__
-/* On IA-64, the buffer size is 16k, not 8k */
-#define YY_READ_BUF_SIZE 16384
-#else
-#define YY_READ_BUF_SIZE 8192
-#endif /* __ia64__ */
-#endif
-
-/* Copy whatever the last rule matched to the standard output. */
-#ifndef ECHO
-/* This used to be an fputs(), but since the string might contain NUL's,
- * we now use fwrite().
- */
-#define ECHO do { if (fwrite( yytext, yyleng, 1, yyout )) {} } while (0)
-#endif
-
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,
- * is returned in "result".
- */
-#ifndef YY_INPUT
-#define YY_INPUT(buf,result,max_size) \
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \
-               { \
-               int c = '*'; \
-               size_t n; \
-               for ( n = 0; n < max_size && \
-                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \
-                       buf[n] = (char) c; \
-               if ( c == '\n' ) \
-                       buf[n++] = (char) c; \
-               if ( c == EOF && ferror( yyin ) ) \
-                       YY_FATAL_ERROR( "input in flex scanner failed" ); \
-               result = n; \
-               } \
-       else \
-               { \
-               errno=0; \
-               while ( (result = fread(buf, 1, max_size, yyin))==0 && ferror(yyin)) \
-                       { \
-                       if( errno != EINTR) \
-                               { \
-                               YY_FATAL_ERROR( "input in flex scanner failed" ); \
-                               break; \
-                               } \
-                       errno=0; \
-                       clearerr(yyin); \
-                       } \
-               }\
-\
-
-#endif
-
-/* No semi-colon after return; correct usage is to write "yyterminate();" -
- * we don't want an extra ';' after the "return" because that will cause
- * some compilers to complain about unreachable statements.
- */
-#ifndef yyterminate
-#define yyterminate() return YY_NULL
-#endif
-
-/* Number of entries by which start-condition stack grows. */
-#ifndef YY_START_STACK_INCR
-#define YY_START_STACK_INCR 25
-#endif
-
-/* Report a fatal error. */
-#ifndef YY_FATAL_ERROR
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )
-#endif
-
-/* end tables serialization structures and prototypes */
-
-/* Default declaration of generated scanner - a define so the user can
- * easily add parameters.
- */
-#ifndef YY_DECL
-#define YY_DECL_IS_OURS 1
-
-extern int yylex (void);
-
-#define YY_DECL int yylex (void)
-#endif /* !YY_DECL */
-
-/* Code executed at the beginning of each rule, after yytext and yyleng
- * have been set up.
- */
-#ifndef YY_USER_ACTION
-#define YY_USER_ACTION
-#endif
-
-/* Code executed at the end of each rule. */
-#ifndef YY_BREAK
-#define YY_BREAK break;
-#endif
-
-#define YY_RULE_SETUP \
-       YY_USER_ACTION
-
-/** The main scanner function which does all the work.
- */
-YY_DECL
-{
-       register yy_state_type yy_current_state;
-       register char *yy_cp, *yy_bp;
-       register int yy_act;
-    
-#line 64 "lexer.l"
-
-
-#line 717 "tools/lexer.c"
-
-       if ( !(yy_init) )
-               {
-               (yy_init) = 1;
-
-#ifdef YY_USER_INIT
-               YY_USER_INIT;
-#endif
-
-               if ( ! (yy_start) )
-                       (yy_start) = 1; /* first start state */
-
-               if ( ! yyin )
-                       yyin = stdin;
-
-               if ( ! yyout )
-                       yyout = stdout;
-
-               if ( ! YY_CURRENT_BUFFER ) {
-                       yyensure_buffer_stack ();
-                       YY_CURRENT_BUFFER_LVALUE =
-                               yy_create_buffer(yyin,YY_BUF_SIZE );
-               }
-
-               yy_load_buffer_state( );
-               }
-
-       while ( 1 )             /* loops until end-of-file is reached */
-               {
-               yy_cp = (yy_c_buf_p);
-
-               /* Support of yytext. */
-               *yy_cp = (yy_hold_char);
-
-               /* yy_bp points to the position in yy_ch_buf of the start of
-                * the current run.
-                */
-               yy_bp = yy_cp;
-
-               yy_current_state = (yy_start);
-yy_match:
-               do
-                       {
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];
-                       if ( yy_accept[yy_current_state] )
-                               {
-                               (yy_last_accepting_state) = yy_current_state;
-                               (yy_last_accepting_cpos) = yy_cp;
-                               }
-                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                               {
-                               yy_current_state = (int) yy_def[yy_current_state];
-                               if ( yy_current_state >= 36 )
-                                       yy_c = yy_meta[(unsigned int) yy_c];
-                               }
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-                       ++yy_cp;
-                       }
-               while ( yy_base[yy_current_state] != 47 );
-
-yy_find_action:
-               yy_act = yy_accept[yy_current_state];
-               if ( yy_act == 0 )
-                       { /* have to back up */
-                       yy_cp = (yy_last_accepting_cpos);
-                       yy_current_state = (yy_last_accepting_state);
-                       yy_act = yy_accept[yy_current_state];
-                       }
-
-               YY_DO_BEFORE_ACTION;
-
-do_action:     /* This label is used only to access EOF actions. */
-
-               switch ( yy_act )
-       { /* beginning of action switch */
-                       case 0: /* must back up */
-                       /* undo the effects of YY_DO_BEFORE_ACTION */
-                       *yy_cp = (yy_hold_char);
-                       yy_cp = (yy_last_accepting_cpos);
-                       yy_current_state = (yy_last_accepting_state);
-                       goto yy_find_action;
-
-case 1:
-YY_RULE_SETUP
-#line 66 "lexer.l"
-{
-                       /* Skip spaces and tabs */
-                       ;
-               }
-       YY_BREAK
-case 2:
-/* rule 2 can match eol */
-YY_RULE_SETUP
-#line 71 "lexer.l"
-{
-                       /* Skip comments */
-                       lineno++; 
-               }
-       YY_BREAK
-case 3:
-YY_RULE_SETUP
-#line 76 "lexer.l"
-{
-                       yylval.number = atoi(yytext);
-                       return NUMBER;
-               }
-       YY_BREAK
-case 4:
-YY_RULE_SETUP
-#line 81 "lexer.l"
-{
-                       yylval.string = yytext;
-                       return STRING;
-               }
-       YY_BREAK
-case 5:
-YY_RULE_SETUP
-#line 86 "lexer.l"
-{
-                       bdaddr_t *ba = malloc(sizeof(bdaddr_t));
-                       str2ba(yytext, ba);
-                       yylval.bdaddr = ba;
-                       return BDADDR;
-               }
-       YY_BREAK
-case 6:
-YY_RULE_SETUP
-#line 93 "lexer.l"
-{
-                       int keyword = rfcomm_find_keyword(rfcomm_keyword, yytext);
-                       if (keyword != -1)
-                               return keyword;
-
-                       if (strncmp(yytext, "rfcomm", 6) == 0) {
-                               yylval.number = atoi(yytext + 6);
-                               return RFCOMM;
-                       }
-
-                       yylval.string = yytext;
-                       return WORD;
-               }
-       YY_BREAK
-case 7:
-/* rule 7 can match eol */
-YY_RULE_SETUP
-#line 107 "lexer.l"
-{
-                       lineno++;
-               }
-       YY_BREAK
-case 8:
-YY_RULE_SETUP
-#line 111 "lexer.l"
-{
-                       return *yytext;
-               }
-       YY_BREAK
-case 9:
-YY_RULE_SETUP
-#line 115 "lexer.l"
-ECHO;
-       YY_BREAK
-#line 880 "tools/lexer.c"
-case YY_STATE_EOF(INITIAL):
-       yyterminate();
-
-       case YY_END_OF_BUFFER:
-               {
-               /* Amount of text matched not including the EOB char. */
-               int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1;
-
-               /* Undo the effects of YY_DO_BEFORE_ACTION. */
-               *yy_cp = (yy_hold_char);
-               YY_RESTORE_YY_MORE_OFFSET
-
-               if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW )
-                       {
-                       /* We're scanning a new file or input source.  It's
-                        * possible that this happened because the user
-                        * just pointed yyin at a new source and called
-                        * yylex().  If so, then we have to assure
-                        * consistency between YY_CURRENT_BUFFER and our
-                        * globals.  Here is the right place to do so, because
-                        * this is the first action (other than possibly a
-                        * back-up) that will match for the new input source.
-                        */
-                       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-                       YY_CURRENT_BUFFER_LVALUE->yy_input_file = yyin;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL;
-                       }
-
-               /* Note that here we test for yy_c_buf_p "<=" to the position
-                * of the first EOB in the buffer, since yy_c_buf_p will
-                * already have been incremented past the NUL character
-                * (since all states make transitions on EOB to the
-                * end-of-buffer state).  Contrast this with the test
-                * in input().
-                */
-               if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-                       { /* This was really a NUL. */
-                       yy_state_type yy_next_state;
-
-                       (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text;
-
-                       yy_current_state = yy_get_previous_state(  );
-
-                       /* Okay, we're now positioned to make the NUL
-                        * transition.  We couldn't have
-                        * yy_get_previous_state() go ahead and do it
-                        * for us because it doesn't know how to deal
-                        * with the possibility of jamming (and we don't
-                        * want to build jamming into it because then it
-                        * will run more slowly).
-                        */
-
-                       yy_next_state = yy_try_NUL_trans( yy_current_state );
-
-                       yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-
-                       if ( yy_next_state )
-                               {
-                               /* Consume the NUL. */
-                               yy_cp = ++(yy_c_buf_p);
-                               yy_current_state = yy_next_state;
-                               goto yy_match;
-                               }
-
-                       else
-                               {
-                               yy_cp = (yy_c_buf_p);
-                               goto yy_find_action;
-                               }
-                       }
-
-               else switch ( yy_get_next_buffer(  ) )
-                       {
-                       case EOB_ACT_END_OF_FILE:
-                               {
-                               (yy_did_buffer_switch_on_eof) = 0;
-
-                               if ( yywrap( ) )
-                                       {
-                                       /* Note: because we've taken care in
-                                        * yy_get_next_buffer() to have set up
-                                        * yytext, we can now set up
-                                        * yy_c_buf_p so that if some total
-                                        * hoser (like flex itself) wants to
-                                        * call the scanner after we return the
-                                        * YY_NULL, it'll still work - another
-                                        * YY_NULL will get returned.
-                                        */
-                                       (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ;
-
-                                       yy_act = YY_STATE_EOF(YY_START);
-                                       goto do_action;
-                                       }
-
-                               else
-                                       {
-                                       if ( ! (yy_did_buffer_switch_on_eof) )
-                                               YY_NEW_FILE;
-                                       }
-                               break;
-                               }
-
-                       case EOB_ACT_CONTINUE_SCAN:
-                               (yy_c_buf_p) =
-                                       (yytext_ptr) + yy_amount_of_matched_text;
-
-                               yy_current_state = yy_get_previous_state(  );
-
-                               yy_cp = (yy_c_buf_p);
-                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-                               goto yy_match;
-
-                       case EOB_ACT_LAST_MATCH:
-                               (yy_c_buf_p) =
-                               &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)];
-
-                               yy_current_state = yy_get_previous_state(  );
-
-                               yy_cp = (yy_c_buf_p);
-                               yy_bp = (yytext_ptr) + YY_MORE_ADJ;
-                               goto yy_find_action;
-                       }
-               break;
-               }
-
-       default:
-               YY_FATAL_ERROR(
-                       "fatal flex scanner internal error--no action found" );
-       } /* end of action switch */
-               } /* end of scanning one token */
-} /* end of yylex */
-
-/* yy_get_next_buffer - try to read in a new buffer
- *
- * Returns a code representing an action:
- *     EOB_ACT_LAST_MATCH -
- *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position
- *     EOB_ACT_END_OF_FILE - end of file
- */
-static int yy_get_next_buffer (void)
-{
-       register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf;
-       register char *source = (yytext_ptr);
-       register int number_to_move, i;
-       int ret_val;
-
-       if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] )
-               YY_FATAL_ERROR(
-               "fatal flex scanner internal error--end of buffer missed" );
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 )
-               { /* Don't try to fill the buffer, so this is an EOF. */
-               if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 )
-                       {
-                       /* We matched a single character, the EOB, so
-                        * treat this as a final EOF.
-                        */
-                       return EOB_ACT_END_OF_FILE;
-                       }
-
-               else
-                       {
-                       /* We matched some text prior to the EOB, first
-                        * process it.
-                        */
-                       return EOB_ACT_LAST_MATCH;
-                       }
-               }
-
-       /* Try to read more data. */
-
-       /* First move last chars to start of buffer. */
-       number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1;
-
-       for ( i = 0; i < number_to_move; ++i )
-               *(dest++) = *(source++);
-
-       if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING )
-               /* don't do the read, it's not guaranteed to return an EOF,
-                * just force an EOF
-                */
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0;
-
-       else
-               {
-                       int num_to_read =
-                       YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1;
-
-               while ( num_to_read <= 0 )
-                       { /* Not enough room in the buffer - grow it. */
-
-                       /* just a shorter name for the current buffer */
-                       YY_BUFFER_STATE b = YY_CURRENT_BUFFER;
-
-                       int yy_c_buf_p_offset =
-                               (int) ((yy_c_buf_p) - b->yy_ch_buf);
-
-                       if ( b->yy_is_our_buffer )
-                               {
-                               int new_size = b->yy_buf_size * 2;
-
-                               if ( new_size <= 0 )
-                                       b->yy_buf_size += b->yy_buf_size / 8;
-                               else
-                                       b->yy_buf_size *= 2;
-
-                               b->yy_ch_buf = (char *)
-                                       /* Include room in for 2 EOB chars. */
-                                       yyrealloc((void *) b->yy_ch_buf,b->yy_buf_size + 2  );
-                               }
-                       else
-                               /* Can't grow it, we don't own it. */
-                               b->yy_ch_buf = 0;
-
-                       if ( ! b->yy_ch_buf )
-                               YY_FATAL_ERROR(
-                               "fatal error - scanner input buffer overflow" );
-
-                       (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset];
-
-                       num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size -
-                                               number_to_move - 1;
-
-                       }
-
-               if ( num_to_read > YY_READ_BUF_SIZE )
-                       num_to_read = YY_READ_BUF_SIZE;
-
-               /* Read in more data. */
-               YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]),
-                       (yy_n_chars), (size_t) num_to_read );
-
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       if ( (yy_n_chars) == 0 )
-               {
-               if ( number_to_move == YY_MORE_ADJ )
-                       {
-                       ret_val = EOB_ACT_END_OF_FILE;
-                       yyrestart(yyin  );
-                       }
-
-               else
-                       {
-                       ret_val = EOB_ACT_LAST_MATCH;
-                       YY_CURRENT_BUFFER_LVALUE->yy_buffer_status =
-                               YY_BUFFER_EOF_PENDING;
-                       }
-               }
-
-       else
-               ret_val = EOB_ACT_CONTINUE_SCAN;
-
-       if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) {
-               /* Extend the array by 50%, plus the number we really need. */
-               yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1);
-               YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) yyrealloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size  );
-               if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf )
-                       YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" );
-       }
-
-       (yy_n_chars) += number_to_move;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR;
-       YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR;
-
-       (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0];
-
-       return ret_val;
-}
-
-/* yy_get_previous_state - get the state just before the EOB char was reached */
-
-    static yy_state_type yy_get_previous_state (void)
-{
-       register yy_state_type yy_current_state;
-       register char *yy_cp;
-    
-       yy_current_state = (yy_start);
-
-       for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp )
-               {
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);
-               if ( yy_accept[yy_current_state] )
-                       {
-                       (yy_last_accepting_state) = yy_current_state;
-                       (yy_last_accepting_cpos) = yy_cp;
-                       }
-               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-                       {
-                       yy_current_state = (int) yy_def[yy_current_state];
-                       if ( yy_current_state >= 36 )
-                               yy_c = yy_meta[(unsigned int) yy_c];
-                       }
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-               }
-
-       return yy_current_state;
-}
-
-/* yy_try_NUL_trans - try to make a transition on the NUL character
- *
- * synopsis
- *     next_state = yy_try_NUL_trans( current_state );
- */
-    static yy_state_type yy_try_NUL_trans  (yy_state_type yy_current_state )
-{
-       register int yy_is_jam;
-       register char *yy_cp = (yy_c_buf_p);
-
-       register YY_CHAR yy_c = 1;
-       if ( yy_accept[yy_current_state] )
-               {
-               (yy_last_accepting_state) = yy_current_state;
-               (yy_last_accepting_cpos) = yy_cp;
-               }
-       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )
-               {
-               yy_current_state = (int) yy_def[yy_current_state];
-               if ( yy_current_state >= 36 )
-                       yy_c = yy_meta[(unsigned int) yy_c];
-               }
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];
-       yy_is_jam = (yy_current_state == 35);
-
-       return yy_is_jam ? 0 : yy_current_state;
-}
-
-#ifndef YY_NO_INPUT
-#ifdef __cplusplus
-    static int yyinput (void)
-#else
-    static int input  (void)
-#endif
-
-{
-       int c;
-    
-       *(yy_c_buf_p) = (yy_hold_char);
-
-       if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR )
-               {
-               /* yy_c_buf_p now points to the character we want to return.
-                * If this occurs *before* the EOB characters, then it's a
-                * valid NUL; if not, then we've hit the end of the buffer.
-                */
-               if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] )
-                       /* This was really a NUL. */
-                       *(yy_c_buf_p) = '\0';
-
-               else
-                       { /* need more input */
-                       int offset = (yy_c_buf_p) - (yytext_ptr);
-                       ++(yy_c_buf_p);
-
-                       switch ( yy_get_next_buffer(  ) )
-                               {
-                               case EOB_ACT_LAST_MATCH:
-                                       /* This happens because yy_g_n_b()
-                                        * sees that we've accumulated a
-                                        * token and flags that we need to
-                                        * try matching the token before
-                                        * proceeding.  But for input(),
-                                        * there's no matching to consider.
-                                        * So convert the EOB_ACT_LAST_MATCH
-                                        * to EOB_ACT_END_OF_FILE.
-                                        */
-
-                                       /* Reset buffer status. */
-                                       yyrestart(yyin );
-
-                                       /*FALLTHROUGH*/
-
-                               case EOB_ACT_END_OF_FILE:
-                                       {
-                                       if ( yywrap( ) )
-                                               return EOF;
-
-                                       if ( ! (yy_did_buffer_switch_on_eof) )
-                                               YY_NEW_FILE;
-#ifdef __cplusplus
-                                       return yyinput();
-#else
-                                       return input();
-#endif
-                                       }
-
-                               case EOB_ACT_CONTINUE_SCAN:
-                                       (yy_c_buf_p) = (yytext_ptr) + offset;
-                                       break;
-                               }
-                       }
-               }
-
-       c = *(unsigned char *) (yy_c_buf_p);    /* cast for 8-bit char's */
-       *(yy_c_buf_p) = '\0';   /* preserve yytext */
-       (yy_hold_char) = *++(yy_c_buf_p);
-
-       return c;
-}
-#endif /* ifndef YY_NO_INPUT */
-
-/** Immediately switch to a different input stream.
- * @param input_file A readable stream.
- * 
- * @note This function does not reset the start condition to @c INITIAL .
- */
-    void yyrestart  (FILE * input_file )
-{
-    
-       if ( ! YY_CURRENT_BUFFER ){
-        yyensure_buffer_stack ();
-               YY_CURRENT_BUFFER_LVALUE =
-            yy_create_buffer(yyin,YY_BUF_SIZE );
-       }
-
-       yy_init_buffer(YY_CURRENT_BUFFER,input_file );
-       yy_load_buffer_state( );
-}
-
-/** Switch to a different input buffer.
- * @param new_buffer The new input buffer.
- * 
- */
-    void yy_switch_to_buffer  (YY_BUFFER_STATE  new_buffer )
-{
-    
-       /* TODO. We should be able to replace this entire function body
-        * with
-        *              yypop_buffer_state();
-        *              yypush_buffer_state(new_buffer);
-     */
-       yyensure_buffer_stack ();
-       if ( YY_CURRENT_BUFFER == new_buffer )
-               return;
-
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *(yy_c_buf_p) = (yy_hold_char);
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-       yy_load_buffer_state( );
-
-       /* We don't actually know whether we did this switch during
-        * EOF (yywrap()) processing, but the only time this flag
-        * is looked at is after yywrap() is called, so it's safe
-        * to go ahead and always set it.
-        */
-       (yy_did_buffer_switch_on_eof) = 1;
-}
-
-static void yy_load_buffer_state  (void)
-{
-       (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars;
-       (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos;
-       yyin = YY_CURRENT_BUFFER_LVALUE->yy_input_file;
-       (yy_hold_char) = *(yy_c_buf_p);
-}
-
-/** Allocate and initialize an input buffer state.
- * @param file A readable stream.
- * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE.
- * 
- * @return the allocated buffer state.
- */
-    YY_BUFFER_STATE yy_create_buffer  (FILE * file, int  size )
-{
-       YY_BUFFER_STATE b;
-    
-       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_buf_size = size;
-
-       /* yy_ch_buf has to be 2 characters longer than the size given because
-        * we need to put in 2 end-of-buffer characters.
-        */
-       b->yy_ch_buf = (char *) yyalloc(b->yy_buf_size + 2  );
-       if ( ! b->yy_ch_buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );
-
-       b->yy_is_our_buffer = 1;
-
-       yy_init_buffer(b,file );
-
-       return b;
-}
-
-/** Destroy the buffer.
- * @param b a buffer created with yy_create_buffer()
- * 
- */
-    void yy_delete_buffer (YY_BUFFER_STATE  b )
-{
-    
-       if ( ! b )
-               return;
-
-       if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */
-               YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0;
-
-       if ( b->yy_is_our_buffer )
-               yyfree((void *) b->yy_ch_buf  );
-
-       yyfree((void *) b  );
-}
-
-#ifndef __cplusplus
-extern int isatty (int );
-#endif /* __cplusplus */
-    
-/* Initializes or reinitializes a buffer.
- * This function is sometimes called more than once on the same buffer,
- * such as during a yyrestart() or at EOF.
- */
-    static void yy_init_buffer  (YY_BUFFER_STATE  b, FILE * file )
-
-{
-       int oerrno = errno;
-    
-       yy_flush_buffer(b );
-
-       b->yy_input_file = file;
-       b->yy_fill_buffer = 1;
-
-    /* If b is the current buffer, then yy_init_buffer was _probably_
-     * called from yyrestart() or through yy_get_next_buffer.
-     * In that case, we don't want to reset the lineno or column.
-     */
-    if (b != YY_CURRENT_BUFFER){
-        b->yy_bs_lineno = 1;
-        b->yy_bs_column = 0;
-    }
-
-        b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;
-    
-       errno = oerrno;
-}
-
-/** Discard all buffered characters. On the next scan, YY_INPUT will be called.
- * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER.
- * 
- */
-    void yy_flush_buffer (YY_BUFFER_STATE  b )
-{
-       if ( ! b )
-               return;
-
-       b->yy_n_chars = 0;
-
-       /* We always need two end-of-buffer characters.  The first causes
-        * a transition to the end-of-buffer state.  The second causes
-        * a jam in that state.
-        */
-       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;
-       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;
-
-       b->yy_buf_pos = &b->yy_ch_buf[0];
-
-       b->yy_at_bol = 1;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       if ( b == YY_CURRENT_BUFFER )
-               yy_load_buffer_state( );
-}
-
-/** Pushes the new state onto the stack. The new state becomes
- *  the current state. This function will allocate the stack
- *  if necessary.
- *  @param new_buffer The new state.
- *  
- */
-void yypush_buffer_state (YY_BUFFER_STATE new_buffer )
-{
-       if (new_buffer == NULL)
-               return;
-
-       yyensure_buffer_stack();
-
-       /* This block is copied from yy_switch_to_buffer. */
-       if ( YY_CURRENT_BUFFER )
-               {
-               /* Flush out information for old buffer. */
-               *(yy_c_buf_p) = (yy_hold_char);
-               YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p);
-               YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars);
-               }
-
-       /* Only push if top exists. Otherwise, replace top. */
-       if (YY_CURRENT_BUFFER)
-               (yy_buffer_stack_top)++;
-       YY_CURRENT_BUFFER_LVALUE = new_buffer;
-
-       /* copied from yy_switch_to_buffer. */
-       yy_load_buffer_state( );
-       (yy_did_buffer_switch_on_eof) = 1;
-}
-
-/** Removes and deletes the top of the stack, if present.
- *  The next element becomes the new top.
- *  
- */
-void yypop_buffer_state (void)
-{
-       if (!YY_CURRENT_BUFFER)
-               return;
-
-       yy_delete_buffer(YY_CURRENT_BUFFER );
-       YY_CURRENT_BUFFER_LVALUE = NULL;
-       if ((yy_buffer_stack_top) > 0)
-               --(yy_buffer_stack_top);
-
-       if (YY_CURRENT_BUFFER) {
-               yy_load_buffer_state( );
-               (yy_did_buffer_switch_on_eof) = 1;
-       }
-}
-
-/* Allocates the stack if it does not exist.
- *  Guarantees space for at least one push.
- */
-static void yyensure_buffer_stack (void)
-{
-       int num_to_alloc;
-    
-       if (!(yy_buffer_stack)) {
-
-               /* First allocation is just for 2 elements, since we don't know if this
-                * scanner will even need a stack. We use 2 instead of 1 to avoid an
-                * immediate realloc on the next call.
-         */
-               num_to_alloc = 1;
-               (yy_buffer_stack) = (struct yy_buffer_state**)yyalloc
-                                                               (num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               );
-               if ( ! (yy_buffer_stack) )
-                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-                                                                 
-               memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*));
-                               
-               (yy_buffer_stack_max) = num_to_alloc;
-               (yy_buffer_stack_top) = 0;
-               return;
-       }
-
-       if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){
-
-               /* Increase the buffer to prepare for a possible push. */
-               int grow_size = 8 /* arbitrary grow size */;
-
-               num_to_alloc = (yy_buffer_stack_max) + grow_size;
-               (yy_buffer_stack) = (struct yy_buffer_state**)yyrealloc
-                                                               ((yy_buffer_stack),
-                                                               num_to_alloc * sizeof(struct yy_buffer_state*)
-                                                               );
-               if ( ! (yy_buffer_stack) )
-                       YY_FATAL_ERROR( "out of dynamic memory in yyensure_buffer_stack()" );
-
-               /* zero only the new slots.*/
-               memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*));
-               (yy_buffer_stack_max) = num_to_alloc;
-       }
-}
-
-/** Setup the input buffer state to scan directly from a user-specified character buffer.
- * @param base the character buffer
- * @param size the size in bytes of the character buffer
- * 
- * @return the newly allocated buffer state object. 
- */
-YY_BUFFER_STATE yy_scan_buffer  (char * base, yy_size_t  size )
-{
-       YY_BUFFER_STATE b;
-    
-       if ( size < 2 ||
-            base[size-2] != YY_END_OF_BUFFER_CHAR ||
-            base[size-1] != YY_END_OF_BUFFER_CHAR )
-               /* They forgot to leave room for the EOB's. */
-               return 0;
-
-       b = (YY_BUFFER_STATE) yyalloc(sizeof( struct yy_buffer_state )  );
-       if ( ! b )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );
-
-       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */
-       b->yy_buf_pos = b->yy_ch_buf = base;
-       b->yy_is_our_buffer = 0;
-       b->yy_input_file = 0;
-       b->yy_n_chars = b->yy_buf_size;
-       b->yy_is_interactive = 0;
-       b->yy_at_bol = 1;
-       b->yy_fill_buffer = 0;
-       b->yy_buffer_status = YY_BUFFER_NEW;
-
-       yy_switch_to_buffer(b  );
-
-       return b;
-}
-
-/** Setup the input buffer state to scan a string. The next call to yylex() will
- * scan from a @e copy of @a str.
- * @param yystr a NUL-terminated string to scan
- * 
- * @return the newly allocated buffer state object.
- * @note If you want to scan bytes that may contain NUL values, then use
- *       yy_scan_bytes() instead.
- */
-YY_BUFFER_STATE yy_scan_string (yyconst char * yystr )
-{
-    
-       return yy_scan_bytes(yystr,strlen(yystr) );
-}
-
-/** Setup the input buffer state to scan the given bytes. The next call to yylex() will
- * scan from a @e copy of @a bytes.
- * @param yybytes the byte buffer to scan
- * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes.
- * 
- * @return the newly allocated buffer state object.
- */
-YY_BUFFER_STATE yy_scan_bytes  (yyconst char * yybytes, int  _yybytes_len )
-{
-       YY_BUFFER_STATE b;
-       char *buf;
-       yy_size_t n;
-       int i;
-    
-       /* Get memory for full buffer, including space for trailing EOB's. */
-       n = _yybytes_len + 2;
-       buf = (char *) yyalloc(n  );
-       if ( ! buf )
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );
-
-       for ( i = 0; i < _yybytes_len; ++i )
-               buf[i] = yybytes[i];
-
-       buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR;
-
-       b = yy_scan_buffer(buf,n );
-       if ( ! b )
-               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );
-
-       /* It's okay to grow etc. this buffer, and we should throw it
-        * away when we're done.
-        */
-       b->yy_is_our_buffer = 1;
-
-       return b;
-}
-
-#ifndef YY_EXIT_FAILURE
-#define YY_EXIT_FAILURE 2
-#endif
-
-static void yy_fatal_error (yyconst char* msg )
-{
-       (void) fprintf( stderr, "%s\n", msg );
-       exit( YY_EXIT_FAILURE );
-}
-
-/* Redefine yyless() so it works in section 3 code. */
-
-#undef yyless
-#define yyless(n) \
-       do \
-               { \
-               /* Undo effects of setting up yytext. */ \
-        int yyless_macro_arg = (n); \
-        YY_LESS_LINENO(yyless_macro_arg);\
-               yytext[yyleng] = (yy_hold_char); \
-               (yy_c_buf_p) = yytext + yyless_macro_arg; \
-               (yy_hold_char) = *(yy_c_buf_p); \
-               *(yy_c_buf_p) = '\0'; \
-               yyleng = yyless_macro_arg; \
-               } \
-       while ( 0 )
-
-/* Accessor  methods (get/set functions) to struct members. */
-
-/** Get the current line number.
- * 
- */
-int yyget_lineno  (void)
-{
-        
-    return yylineno;
-}
-
-/** Get the input stream.
- * 
- */
-FILE *yyget_in  (void)
-{
-        return yyin;
-}
-
-/** Get the output stream.
- * 
- */
-FILE *yyget_out  (void)
-{
-        return yyout;
-}
-
-/** Get the length of the current token.
- * 
- */
-int yyget_leng  (void)
-{
-        return yyleng;
-}
-
-/** Get the current token.
- * 
- */
-
-char *yyget_text  (void)
-{
-        return yytext;
-}
-
-/** Set the current line number.
- * @param line_number
- * 
- */
-void yyset_lineno (int  line_number )
-{
-    
-    yylineno = line_number;
-}
-
-/** Set the input stream. This does not discard the current
- * input buffer.
- * @param in_str A readable stream.
- * 
- * @see yy_switch_to_buffer
- */
-void yyset_in (FILE *  in_str )
-{
-        yyin = in_str ;
-}
-
-void yyset_out (FILE *  out_str )
-{
-        yyout = out_str ;
-}
-
-int yyget_debug  (void)
-{
-        return yy_flex_debug;
-}
-
-void yyset_debug (int  bdebug )
-{
-        yy_flex_debug = bdebug ;
-}
-
-static int yy_init_globals (void)
-{
-        /* Initialization is the same as for the non-reentrant scanner.
-     * This function is called from yylex_destroy(), so don't allocate here.
-     */
-
-    (yy_buffer_stack) = 0;
-    (yy_buffer_stack_top) = 0;
-    (yy_buffer_stack_max) = 0;
-    (yy_c_buf_p) = (char *) 0;
-    (yy_init) = 0;
-    (yy_start) = 0;
-
-/* Defined in main.c */
-#ifdef YY_STDINIT
-    yyin = stdin;
-    yyout = stdout;
-#else
-    yyin = (FILE *) 0;
-    yyout = (FILE *) 0;
-#endif
-
-    /* For future reference: Set errno on error, since we are called by
-     * yylex_init()
-     */
-    return 0;
-}
-
-/* yylex_destroy is for both reentrant and non-reentrant scanners. */
-int yylex_destroy  (void)
-{
-    
-    /* Pop the buffer stack, destroying each element. */
-       while(YY_CURRENT_BUFFER){
-               yy_delete_buffer(YY_CURRENT_BUFFER  );
-               YY_CURRENT_BUFFER_LVALUE = NULL;
-               yypop_buffer_state();
-       }
-
-       /* Destroy the stack itself. */
-       yyfree((yy_buffer_stack) );
-       (yy_buffer_stack) = NULL;
-
-    /* Reset the globals. This is important in a non-reentrant scanner so the next time
-     * yylex() is called, initialization will occur. */
-    yy_init_globals( );
-
-    return 0;
-}
-
-/*
- * Internal utility routines.
- */
-
-#ifndef yytext_ptr
-static void yy_flex_strncpy (char* s1, yyconst char * s2, int n )
-{
-       register int i;
-       for ( i = 0; i < n; ++i )
-               s1[i] = s2[i];
-}
-#endif
-
-#ifdef YY_NEED_STRLEN
-static int yy_flex_strlen (yyconst char * s )
-{
-       register int n;
-       for ( n = 0; s[n]; ++n )
-               ;
-
-       return n;
-}
-#endif
-
-void *yyalloc (yy_size_t  size )
-{
-       return (void *) malloc( size );
-}
-
-void *yyrealloc  (void * ptr, yy_size_t  size )
-{
-       /* The cast to (char *) in the following accommodates both
-        * implementations that use char* generic pointers, and those
-        * that use void* generic pointers.  It works with the latter
-        * because both ANSI C and C++ allow castless assignment from
-        * any pointer type to void*, and deal with argument conversions
-        * as though doing an assignment.
-        */
-       return (void *) realloc( (char *) ptr, size );
-}
-
-void yyfree (void * ptr )
-{
-       free( (char *) ptr );   /* see yyrealloc() for (char *) cast */
-}
-
-#define YYTABLES_NAME "yytables"
-
-#line 115 "lexer.l"
-
-
-
-int yywrap(void) 
-{
-       return 1;
-}
-
diff --git a/tools/lexer.l b/tools/lexer.l
deleted file mode 100644 (file)
index ff9ce81..0000000
+++ /dev/null
@@ -1,120 +0,0 @@
-%{
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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
-
-/* Nasty workaround, but flex defines isatty() twice */
-#define _UNISTD_H
-
-#include <stdio.h>
-#include <errno.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "kword.h"
-#include "parser.h"
-
-int yylex(void);
-
-#define YY_NO_INPUT
-
-#define ECHO {;}
-#define YY_DECL int yylex(void)
-
-int yyerror(char *str);
-
-%}
-
-%option nounput
-
-space          [ \t]
-linebreak      \n
-comment                \#.*\n
-keyword                [A-Za-z0-9\_\-]+
-
-number         [0-9]+
-string         \".*\"
-bdaddr         [A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}:[A-Za-z0-9]{2}
-
-%%
-
-{space}                {
-                       /* Skip spaces and tabs */
-                       ;
-               }
-
-{comment}      {
-                       /* Skip comments */
-                       lineno++; 
-               }
-
-{number}       {
-                       yylval.number = atoi(yytext);
-                       return NUMBER;
-               }
-
-{string}       {
-                       yylval.string = yytext;
-                       return STRING;
-               }
-
-{bdaddr}       {
-                       bdaddr_t *ba = malloc(sizeof(bdaddr_t));
-                       str2ba(yytext, ba);
-                       yylval.bdaddr = ba;
-                       return BDADDR;
-               }
-
-{keyword}      {
-                       int keyword = rfcomm_find_keyword(rfcomm_keyword, yytext);
-                       if (keyword != -1)
-                               return keyword;
-
-                       if (strncmp(yytext, "rfcomm", 6) == 0) {
-                               yylval.number = atoi(yytext + 6);
-                               return RFCOMM;
-                       }
-
-                       yylval.string = yytext;
-                       return WORD;
-               }
-
-{linebreak}    {
-                       lineno++;
-               }
-
-.              {
-                       return *yytext;
-               }
-
-%%
-
-int yywrap(void) 
-{
-       return 1;
-}
diff --git a/tools/magic.btsnoop b/tools/magic.btsnoop
new file mode 100644 (file)
index 0000000..ebb845d
--- /dev/null
@@ -0,0 +1,21 @@
+
+#------------------------------------------------------------------------------
+# BTSnoop:  file(1) magic for BTSnoop files
+#
+# From <marcel@holtmann.org>
+0      string          btsnoop\0               BTSnoop
+>8     belong          x                       version %ld,
+>>8    belong          !1
+>>>12  belong          x                       type %ld
+>8     belong          =1
+>>12   belong          <1001                   type %ld
+>>12   belong          >1000
+>>>12  belong          =1001                   Unencapsulated HCI
+>>>12  belong          =1002                   HCI UART (H4)
+>>>12  belong          =1003                   HCI BCSP
+>>>12  belong          =1004                   HCI Serial (H5)
+>>>12  belong          >1004
+>>>>12 belong          <2001                   type %ld
+>>>>12 belong          =2001                   Bluetooth monitor
+>>>>12 belong          =2002                   Bluetooth simulator
+>>>>12 belong          >2002                   type %ld
diff --git a/tools/mgmt-tester.c b/tools/mgmt-tester.c
new file mode 100644 (file)
index 0000000..2ef72cf
--- /dev/null
@@ -0,0 +1,3108 @@
+/*
+ *
+ *  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 <stdlib.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hciemu.h"
+
+static gboolean option_wait_powered = FALSE;
+
+struct test_data {
+       const void *test_data;
+       uint8_t expected_version;
+       uint16_t expected_manufacturer;
+       uint32_t expected_supported_settings;
+       uint32_t initial_settings;
+       struct mgmt *mgmt;
+       struct mgmt *mgmt_alt;
+       unsigned int mgmt_settings_id;
+       unsigned int mgmt_alt_settings_id;
+       unsigned int mgmt_alt_ev_id;
+       uint8_t mgmt_version;
+       uint16_t mgmt_revision;
+       uint16_t mgmt_index;
+       struct hciemu *hciemu;
+       enum hciemu_type hciemu_type;
+       int unmet_conditions;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_print("%s%s", prefix, str);
+}
+
+static void read_version_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct mgmt_rp_read_version *rp = param;
+
+       tester_print("Read Version callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       data->mgmt_version = rp->version;
+       data->mgmt_revision = btohs(rp->revision);
+
+       tester_print("  Version %u.%u",
+                               data->mgmt_version, data->mgmt_revision);
+}
+
+static void read_commands_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       tester_print("Read Commands callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct mgmt_rp_read_info *rp = param;
+       char addr[18];
+       uint16_t manufacturer;
+       uint32_t supported_settings, current_settings;
+
+       tester_print("Read Info callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+       manufacturer = btohs(rp->manufacturer);
+       supported_settings = btohl(rp->supported_settings);
+       current_settings = btohl(rp->current_settings);
+
+       tester_print("  Address: %s", addr);
+       tester_print("  Version: 0x%02x", rp->version);
+       tester_print("  Manufacturer: 0x%04x", manufacturer);
+       tester_print("  Supported settings: 0x%08x", supported_settings);
+       tester_print("  Current settings: 0x%08x", current_settings);
+       tester_print("  Class: 0x%02x%02x%02x",
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+       tester_print("  Name: %s", rp->name);
+       tester_print("  Short name: %s", rp->short_name);
+
+       if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (rp->version != data->expected_version) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (manufacturer != data->expected_manufacturer) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (supported_settings != data->expected_supported_settings) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (current_settings != data->initial_settings) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (rp->dev_class[0] != 0x00 || rp->dev_class[1] != 0x00 ||
+                                               rp->dev_class[2] != 0x00) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Added callback");
+       tester_print("  Index: 0x%04x", index);
+
+       data->mgmt_index = index;
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+                                       read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Removed callback");
+       tester_print("  Index: 0x%04x", index);
+
+       if (index != data->mgmt_index)
+               return;
+
+       mgmt_unregister_index(data->mgmt, data->mgmt_index);
+       mgmt_unregister_index(data->mgmt_alt, data->mgmt_index);
+
+       mgmt_unref(data->mgmt);
+       data->mgmt = NULL;
+
+       mgmt_unref(data->mgmt_alt);
+       data->mgmt_alt = NULL;
+
+       tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Read Index List callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                       index_added_callback, NULL, NULL);
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                       index_removed_callback, NULL, NULL);
+
+       data->hciemu = hciemu_new(data->hciemu_type);
+       if (!data->hciemu) {
+               tester_warn("Failed to setup HCI emulation");
+               tester_pre_setup_failed();
+       }
+}
+
+static void test_pre_setup(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       data->mgmt = mgmt_new_default();
+       if (!data->mgmt) {
+               tester_warn("Failed to setup management interface");
+               tester_pre_setup_failed();
+               return;
+       }
+
+       data->mgmt_alt = mgmt_new_default();
+       if (!data->mgmt_alt) {
+               tester_warn("Failed to setup alternate management interface");
+               tester_pre_setup_failed();
+
+               mgmt_unref(data->mgmt);
+               data->mgmt = NULL;
+               return;
+       }
+
+       if (tester_use_debug()) {
+               mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+               mgmt_set_debug(data->mgmt_alt, mgmt_debug, "mgmt-alt: ", NULL);
+       }
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_VERSION, MGMT_INDEX_NONE, 0, NULL,
+                                       read_version_callback, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_COMMANDS, MGMT_INDEX_NONE, 0, NULL,
+                                       read_commands_callback, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+                                       read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       hciemu_unref(data->hciemu);
+       data->hciemu = NULL;
+}
+
+static void test_add_condition(struct test_data *data)
+{
+       data->unmet_conditions++;
+
+       tester_print("Test condition added, total %d", data->unmet_conditions);
+}
+
+static void test_condition_complete(struct test_data *data)
+{
+       data->unmet_conditions--;
+
+       tester_print("Test condition complete, %d left",
+                                               data->unmet_conditions);
+
+       if (data->unmet_conditions > 0)
+               return;
+
+       tester_test_passed();
+}
+
+#define test_bredrle(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+               user->test_data = data; \
+               user->expected_version = 0x06; \
+               user->expected_manufacturer = 0x003f; \
+               user->expected_supported_settings = 0x000007ff; \
+               user->initial_settings = 0x00000080; \
+               user->unmet_conditions = 0; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, free); \
+       } while (0)
+
+#define test_bredr(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_BREDR; \
+               user->test_data = data; \
+               user->expected_version = 0x05; \
+               user->expected_manufacturer = 0x003f; \
+               user->expected_supported_settings = 0x000001ff; \
+               user->initial_settings = 0x00000080; \
+               user->unmet_conditions = 0; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, free); \
+       } while (0)
+
+#define test_le(name, data, setup, func) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_LE; \
+               user->test_data = data; \
+               user->expected_version = 0x06; \
+               user->expected_manufacturer = 0x003f; \
+               user->expected_supported_settings = 0x00000611; \
+               user->initial_settings = 0x00000200; \
+               user->unmet_conditions = 0; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, free); \
+       } while (0)
+
+static void controller_setup(const void *test_data)
+{
+       tester_test_passed();
+}
+
+struct generic_data {
+       uint16_t setup_expect_hci_command;
+       const void *setup_expect_hci_param;
+       uint8_t setup_expect_hci_len;
+       bool send_index_none;
+       uint16_t send_opcode;
+       const void *send_param;
+       uint16_t send_len;
+       uint8_t expect_status;
+       const void *expect_param;
+       uint16_t expect_len;
+       uint32_t expect_settings_set;
+       uint32_t expect_settings_unset;
+       uint16_t expect_alt_ev;
+       const void *expect_alt_ev_param;
+       uint16_t expect_alt_ev_len;
+       uint16_t expect_hci_command;
+       const void *expect_hci_param;
+       uint8_t expect_hci_len;
+};
+
+static const char dummy_data[] = { 0x00 };
+
+static const struct generic_data invalid_command_test = {
+       .send_opcode = 0xffff,
+       .expect_status = MGMT_STATUS_UNKNOWN_COMMAND,
+};
+
+static const struct generic_data read_version_success_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_VERSION,
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_len = 3,
+};
+
+static const struct generic_data read_version_invalid_param_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_VERSION,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_version_invalid_index_test = {
+       .send_opcode = MGMT_OP_READ_VERSION,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_commands_invalid_param_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_COMMANDS,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_commands_invalid_index_test = {
+       .send_opcode = MGMT_OP_READ_COMMANDS,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_index_list_invalid_param_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_INDEX_LIST,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_index_list_invalid_index_test = {
+       .send_opcode = MGMT_OP_READ_INDEX_LIST,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const struct generic_data read_info_invalid_param_test = {
+       .send_opcode = MGMT_OP_READ_INFO,
+       .send_param = dummy_data,
+       .send_len = sizeof(dummy_data),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data read_info_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_READ_INFO,
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_powered_on_param[] = { 0x01 };
+static const char set_powered_invalid_param[] = { 0x02 };
+static const char set_powered_garbage_param[] = { 0x01, 0x00 };
+static const char set_powered_settings_param[] = { 0x81, 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_powered_on_success_test = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_settings_param,
+       .expect_len = sizeof(set_powered_settings_param),
+       .expect_settings_set = MGMT_SETTING_POWERED,
+};
+
+static const struct generic_data set_powered_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_powered_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_invalid_param,
+       .send_len = sizeof(set_powered_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_powered_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_garbage_param,
+       .send_len = sizeof(set_powered_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_powered_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_powered_off_param[] = { 0x00 };
+static const char set_powered_off_settings_param[] = { 0x80, 0x00, 0x00, 0x00 };
+static const char set_powered_off_class_of_dev[] = { 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_powered_off_success_test = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_off_param,
+       .send_len = sizeof(set_powered_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_off_settings_param,
+       .expect_len = sizeof(set_powered_off_settings_param),
+       .expect_settings_unset = MGMT_SETTING_POWERED,
+};
+
+static const struct generic_data set_powered_off_class_test = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_off_param,
+       .send_len = sizeof(set_powered_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_powered_off_settings_param,
+       .expect_len = sizeof(set_powered_off_settings_param),
+       .expect_settings_unset = MGMT_SETTING_POWERED,
+       .expect_alt_ev = MGMT_EV_CLASS_OF_DEV_CHANGED,
+       .expect_alt_ev_param = set_powered_off_class_of_dev,
+       .expect_alt_ev_len = sizeof(set_powered_off_class_of_dev),
+};
+
+static const struct generic_data set_powered_off_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_powered_off_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_invalid_param,
+       .send_len = sizeof(set_powered_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_powered_off_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_garbage_param,
+       .send_len = sizeof(set_powered_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const char set_connectable_on_param[] = { 0x01 };
+static const char set_connectable_invalid_param[] = { 0x02 };
+static const char set_connectable_garbage_param[] = { 0x01, 0x00 };
+static const char set_connectable_settings_param_1[] = { 0x82, 0x00, 0x00, 0x00 };
+static const char set_connectable_settings_param_2[] = { 0x83, 0x00, 0x00, 0x00 };
+static const char set_connectable_scan_enable_param[] = { 0x02 };
+
+static const struct generic_data set_connectable_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_settings_param_1,
+       .expect_len = sizeof(set_connectable_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_CONNECTABLE,
+};
+
+static const struct generic_data set_connectable_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_settings_param_2,
+       .expect_len = sizeof(set_connectable_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_connectable_scan_enable_param,
+       .expect_hci_len = sizeof(set_connectable_scan_enable_param),
+};
+
+static const struct generic_data set_connectable_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_connectable_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_invalid_param,
+       .send_len = sizeof(set_connectable_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_connectable_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_garbage_param,
+       .send_len = sizeof(set_connectable_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_connectable_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_on_param,
+       .send_len = sizeof(set_connectable_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_connectable_off_param[] = { 0x00 };
+static const char set_connectable_off_settings_1[] = { 0x80, 0x00, 0x00, 0x00 };
+static const char set_connectable_off_settings_2[] = { 0x81, 0x00, 0x00, 0x00 };
+static const char set_connectable_off_scan_enable_param[] = { 0x00 };
+
+static const struct generic_data set_connectable_off_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_settings_1,
+       .expect_len = sizeof(set_connectable_off_settings_1),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+};
+
+static const struct generic_data set_connectable_off_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_CONNECTABLE,
+       .send_param = set_connectable_off_param,
+       .send_len = sizeof(set_connectable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_connectable_off_settings_2,
+       .expect_len = sizeof(set_connectable_off_settings_2),
+       .expect_settings_unset = MGMT_SETTING_CONNECTABLE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_connectable_off_scan_enable_param,
+       .expect_hci_len = sizeof(set_connectable_off_scan_enable_param),
+};
+
+static const char set_fast_conn_on_param[] = { 0x01 };
+static const char set_fast_conn_on_settings_1[] = { 0x87, 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_fast_conn_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_FAST_CONNECTABLE,
+       .send_param = set_fast_conn_on_param,
+       .send_len = sizeof(set_fast_conn_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_fast_conn_on_settings_1,
+       .expect_len = sizeof(set_fast_conn_on_settings_1),
+       .expect_settings_set = MGMT_SETTING_FAST_CONNECTABLE,
+};
+
+static const char set_pairable_on_param[] = { 0x01 };
+static const char set_pairable_invalid_param[] = { 0x02 };
+static const char set_pairable_garbage_param[] = { 0x01, 0x00 };
+static const char set_pairable_settings_param[] = { 0x90, 0x00, 0x00, 0x00 };
+
+static const struct generic_data set_pairable_on_success_test = {
+       .send_opcode = MGMT_OP_SET_PAIRABLE,
+       .send_param = set_pairable_on_param,
+       .send_len = sizeof(set_pairable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_pairable_settings_param,
+       .expect_len = sizeof(set_pairable_settings_param),
+       .expect_settings_set = MGMT_SETTING_PAIRABLE,
+};
+
+static const struct generic_data set_pairable_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_PAIRABLE,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_pairable_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_PAIRABLE,
+       .send_param = set_pairable_invalid_param,
+       .send_len = sizeof(set_pairable_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_pairable_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_PAIRABLE,
+       .send_param = set_pairable_garbage_param,
+       .send_len = sizeof(set_pairable_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_pairable_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_PAIRABLE,
+       .send_param = set_pairable_on_param,
+       .send_len = sizeof(set_pairable_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const uint8_t set_discoverable_on_param[] = { 0x01, 0x00, 0x00 };
+static const uint8_t set_discoverable_timeout_param[] = { 0x01, 0x0a, 0x00 };
+static const uint8_t set_discoverable_invalid_param[] = { 0x02, 0x00, 0x00 };
+static const uint8_t set_discoverable_off_param[] = { 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_offtimeout_param[] = { 0x00, 0x01, 0x00 };
+static const uint8_t set_discoverable_garbage_param[] = { 0x01, 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_on_settings_param_1[] = { 0x8a, 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_on_settings_param_2[] = { 0x8b, 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_off_settings_param_1[] = { 0x82, 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_off_settings_param_2[] = { 0x83, 0x00, 0x00, 0x00 };
+static const uint8_t set_discoverable_on_scan_enable_param[] = { 0x03 };
+static const uint8_t set_discoverable_off_scan_enable_param[] = { 0x02 };
+
+static const struct generic_data set_discoverable_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_discoverable_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_invalid_param,
+       .send_len = sizeof(set_discoverable_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_discoverable_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_garbage_param,
+       .send_len = sizeof(set_discoverable_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_discoverable_on_invalid_param_test_4 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_offtimeout_param,
+       .send_len = sizeof(set_discoverable_offtimeout_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_discoverable_on_not_powered_test_1 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_timeout_param,
+       .send_len = sizeof(set_discoverable_timeout_param),
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+};
+
+static const struct generic_data set_discoverable_on_rejected_test_1 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_on_param,
+       .send_len = sizeof(set_discoverable_on_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data set_discoverable_on_rejected_test_2 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_on_param,
+       .send_len = sizeof(set_discoverable_on_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data set_discoverable_on_rejected_test_3 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_timeout_param,
+       .send_len = sizeof(set_discoverable_timeout_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data set_discoverable_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_on_param,
+       .send_len = sizeof(set_discoverable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_on_settings_param_1,
+       .expect_len = sizeof(set_discoverable_on_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_DISCOVERABLE,
+};
+
+static const struct generic_data set_discoverable_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_on_param,
+       .send_len = sizeof(set_discoverable_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_on_settings_param_2,
+       .expect_len = sizeof(set_discoverable_on_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_DISCOVERABLE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_discoverable_on_scan_enable_param,
+       .expect_hci_len = sizeof(set_discoverable_on_scan_enable_param),
+};
+
+static const struct generic_data set_discoverable_off_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_off_param,
+       .send_len = sizeof(set_discoverable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_off_settings_param_1,
+       .expect_len = sizeof(set_discoverable_off_settings_param_1),
+};
+
+static const struct generic_data set_discoverable_off_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_DISCOVERABLE,
+       .send_param = set_discoverable_off_param,
+       .send_len = sizeof(set_discoverable_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_discoverable_off_settings_param_2,
+       .expect_len = sizeof(set_discoverable_off_settings_param_2),
+       .expect_hci_command = BT_HCI_CMD_WRITE_SCAN_ENABLE,
+       .expect_hci_param = set_discoverable_off_scan_enable_param,
+       .expect_hci_len = sizeof(set_discoverable_off_scan_enable_param),
+};
+
+static const char set_link_sec_on_param[] = { 0x01 };
+static const char set_link_sec_invalid_param[] = { 0x02 };
+static const char set_link_sec_garbage_param[] = { 0x01, 0x00 };
+static const char set_link_sec_settings_param_1[] = { 0xa0, 0x00, 0x00, 0x00 };
+static const char set_link_sec_settings_param_2[] = { 0xa1, 0x00, 0x00, 0x00 };
+static const char set_link_sec_auth_enable_param[] = { 0x01 };
+
+static const struct generic_data set_link_sec_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_on_param,
+       .send_len = sizeof(set_link_sec_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_link_sec_settings_param_1,
+       .expect_len = sizeof(set_link_sec_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_LINK_SECURITY,
+};
+
+static const struct generic_data set_link_sec_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_on_param,
+       .send_len = sizeof(set_link_sec_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_link_sec_settings_param_2,
+       .expect_len = sizeof(set_link_sec_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_LINK_SECURITY,
+       .expect_hci_command = BT_HCI_CMD_WRITE_AUTH_ENABLE,
+       .expect_hci_param = set_link_sec_auth_enable_param,
+       .expect_hci_len = sizeof(set_link_sec_auth_enable_param),
+};
+
+static const struct generic_data set_link_sec_on_success_test_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_link_sec_settings_param_2,
+       .expect_len = sizeof(set_link_sec_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_LINK_SECURITY,
+       .expect_hci_command = BT_HCI_CMD_WRITE_AUTH_ENABLE,
+       .expect_hci_param = set_link_sec_auth_enable_param,
+       .expect_hci_len = sizeof(set_link_sec_auth_enable_param),
+};
+
+static const struct generic_data set_link_sec_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_link_sec_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_invalid_param,
+       .send_len = sizeof(set_link_sec_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_link_sec_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_garbage_param,
+       .send_len = sizeof(set_link_sec_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_link_sec_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_on_param,
+       .send_len = sizeof(set_link_sec_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_link_sec_off_param[] = { 0x00 };
+static const char set_link_sec_off_settings_1[] = { 0x80, 0x00, 0x00, 0x00 };
+static const char set_link_sec_off_settings_2[] = { 0x81, 0x00, 0x00, 0x00 };
+static const char set_link_sec_off_auth_enable_param[] = { 0x00 };
+
+static const struct generic_data set_link_sec_off_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_off_param,
+       .send_len = sizeof(set_link_sec_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_link_sec_off_settings_1,
+       .expect_len = sizeof(set_link_sec_off_settings_1),
+       .expect_settings_unset = MGMT_SETTING_LINK_SECURITY,
+};
+
+static const struct generic_data set_link_sec_off_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_LINK_SECURITY,
+       .send_param = set_link_sec_off_param,
+       .send_len = sizeof(set_link_sec_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_link_sec_off_settings_2,
+       .expect_len = sizeof(set_link_sec_off_settings_2),
+       .expect_settings_unset = MGMT_SETTING_LINK_SECURITY,
+       .expect_hci_command = BT_HCI_CMD_WRITE_AUTH_ENABLE,
+       .expect_hci_param = set_link_sec_off_auth_enable_param,
+       .expect_hci_len = sizeof(set_link_sec_off_auth_enable_param),
+};
+
+static const char set_ssp_on_param[] = { 0x01 };
+static const char set_ssp_invalid_param[] = { 0x02 };
+static const char set_ssp_garbage_param[] = { 0x01, 0x00 };
+static const char set_ssp_settings_param_1[] = { 0xc0, 0x00, 0x00, 0x00 };
+static const char set_ssp_settings_param_2[] = { 0xc1, 0x00, 0x00, 0x00 };
+static const char set_ssp_on_write_ssp_mode_param[] = { 0x01 };
+
+static const struct generic_data set_ssp_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_SSP,
+       .send_param = set_ssp_on_param,
+       .send_len = sizeof(set_ssp_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_ssp_settings_param_1,
+       .expect_len = sizeof(set_ssp_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_SSP,
+};
+
+static const struct generic_data set_ssp_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_SSP,
+       .send_param = set_ssp_on_param,
+       .send_len = sizeof(set_ssp_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_ssp_settings_param_2,
+       .expect_len = sizeof(set_ssp_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_SSP,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE,
+       .expect_hci_param = set_ssp_on_write_ssp_mode_param,
+       .expect_hci_len = sizeof(set_ssp_on_write_ssp_mode_param),
+};
+
+static const struct generic_data set_ssp_on_success_test_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_ssp_settings_param_2,
+       .expect_len = sizeof(set_ssp_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_SSP,
+       .expect_hci_command = BT_HCI_CMD_WRITE_SIMPLE_PAIRING_MODE,
+       .expect_hci_param = set_ssp_on_write_ssp_mode_param,
+       .expect_hci_len = sizeof(set_ssp_on_write_ssp_mode_param),
+};
+
+static const struct generic_data set_ssp_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_SSP,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_ssp_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_SSP,
+       .send_param = set_ssp_invalid_param,
+       .send_len = sizeof(set_ssp_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_ssp_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_SSP,
+       .send_param = set_ssp_garbage_param,
+       .send_len = sizeof(set_ssp_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_ssp_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_SSP,
+       .send_param = set_ssp_on_param,
+       .send_len = sizeof(set_ssp_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_hs_on_param[] = { 0x01 };
+static const char set_hs_invalid_param[] = { 0x02 };
+static const char set_hs_garbage_param[] = { 0x01, 0x00 };
+static const char set_hs_settings_param_1[] = { 0xc0, 0x01, 0x00, 0x00 };
+
+static const struct generic_data set_hs_on_success_test = {
+       .send_opcode = MGMT_OP_SET_HS,
+       .send_param = set_hs_on_param,
+       .send_len = sizeof(set_hs_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_hs_settings_param_1,
+       .expect_len = sizeof(set_hs_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_HS,
+};
+
+static const struct generic_data set_hs_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_HS,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_hs_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_HS,
+       .send_param = set_hs_invalid_param,
+       .send_len = sizeof(set_hs_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_hs_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_HS,
+       .send_param = set_hs_garbage_param,
+       .send_len = sizeof(set_hs_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_hs_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_HS,
+       .send_param = set_hs_on_param,
+       .send_len = sizeof(set_hs_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_le_on_param[] = { 0x01 };
+static const char set_le_invalid_param[] = { 0x02 };
+static const char set_le_garbage_param[] = { 0x01, 0x00 };
+static const char set_le_settings_param_1[] = { 0x80, 0x02, 0x00, 0x00 };
+static const char set_le_settings_param_2[] = { 0x81, 0x02, 0x00, 0x00 };
+static const char set_le_on_write_le_host_param[] = { 0x01, 0x01 };
+
+static const struct generic_data set_le_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_LE,
+       .send_param = set_le_on_param,
+       .send_len = sizeof(set_le_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_le_settings_param_1,
+       .expect_len = sizeof(set_le_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_LE,
+};
+
+static const struct generic_data set_le_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_LE,
+       .send_param = set_le_on_param,
+       .send_len = sizeof(set_le_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_le_settings_param_2,
+       .expect_len = sizeof(set_le_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_LE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED,
+       .expect_hci_param = set_le_on_write_le_host_param,
+       .expect_hci_len = sizeof(set_le_on_write_le_host_param),
+};
+
+static const struct generic_data set_le_on_success_test_3 = {
+       .send_opcode = MGMT_OP_SET_POWERED,
+       .send_param = set_powered_on_param,
+       .send_len = sizeof(set_powered_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_le_settings_param_2,
+       .expect_len = sizeof(set_le_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_LE,
+       .expect_hci_command = BT_HCI_CMD_WRITE_LE_HOST_SUPPORTED,
+       .expect_hci_param = set_le_on_write_le_host_param,
+       .expect_hci_len = sizeof(set_le_on_write_le_host_param),
+};
+
+static const struct generic_data set_le_on_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_LE,
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_le_on_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_LE,
+       .send_param = set_le_invalid_param,
+       .send_len = sizeof(set_le_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_le_on_invalid_param_test_3 = {
+       .send_opcode = MGMT_OP_SET_LE,
+       .send_param = set_le_garbage_param,
+       .send_len = sizeof(set_le_garbage_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data set_le_on_invalid_index_test = {
+       .send_index_none = true,
+       .send_opcode = MGMT_OP_SET_LE,
+       .send_param = set_le_on_param,
+       .send_len = sizeof(set_le_on_param),
+       .expect_status = MGMT_STATUS_INVALID_INDEX,
+};
+
+static const char set_adv_on_param[] = { 0x01 };
+static const char set_adv_settings_param_1[] = { 0x80, 0x06, 0x00, 0x00 };
+static const char set_adv_settings_param_2[] = { 0x81, 0x06, 0x00, 0x00 };
+static const char set_adv_on_set_adv_enable_param[] = { 0x01 };
+
+static const struct generic_data set_adv_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_ADVERTISING,
+       .send_param = set_adv_on_param,
+       .send_len = sizeof(set_adv_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_adv_settings_param_1,
+       .expect_len = sizeof(set_adv_settings_param_1),
+       .expect_settings_set = MGMT_SETTING_ADVERTISING,
+};
+
+static const struct generic_data set_adv_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_ADVERTISING,
+       .send_param = set_adv_on_param,
+       .send_len = sizeof(set_adv_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_adv_settings_param_2,
+       .expect_len = sizeof(set_adv_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_ADVERTISING,
+       .expect_hci_command = BT_HCI_CMD_LE_SET_ADV_ENABLE,
+       .expect_hci_param = set_adv_on_set_adv_enable_param,
+       .expect_hci_len = sizeof(set_adv_on_set_adv_enable_param),
+};
+
+static const struct generic_data set_adv_on_rejected_test_1 = {
+       .send_opcode = MGMT_OP_SET_ADVERTISING,
+       .send_param = set_adv_on_param,
+       .send_len = sizeof(set_adv_on_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const char set_bredr_off_param[] = { 0x00 };
+static const char set_bredr_on_param[] = { 0x01 };
+static const char set_bredr_invalid_param[] = { 0x02 };
+static const char set_bredr_settings_param_1[] = { 0x00, 0x02, 0x00, 0x00 };
+static const char set_bredr_settings_param_2[] = { 0x80, 0x02, 0x00, 0x00 };
+static const char set_bredr_settings_param_3[] = { 0x81, 0x02, 0x00, 0x00 };
+
+static const struct generic_data set_bredr_off_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_off_param,
+       .send_len = sizeof(set_bredr_off_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_bredr_settings_param_1,
+       .expect_len = sizeof(set_bredr_settings_param_1),
+       .expect_settings_unset = MGMT_SETTING_BREDR,
+};
+
+static const struct generic_data set_bredr_on_success_test_1 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_on_param,
+       .send_len = sizeof(set_bredr_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_bredr_settings_param_2,
+       .expect_len = sizeof(set_bredr_settings_param_2),
+       .expect_settings_set = MGMT_SETTING_BREDR,
+};
+
+static const struct generic_data set_bredr_on_success_test_2 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_on_param,
+       .send_len = sizeof(set_bredr_on_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_bredr_settings_param_3,
+       .expect_len = sizeof(set_bredr_settings_param_3),
+       .expect_settings_set = MGMT_SETTING_BREDR,
+};
+
+static const struct generic_data set_bredr_off_notsupp_test = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_off_param,
+       .send_len = sizeof(set_bredr_off_param),
+       .expect_status = MGMT_STATUS_NOT_SUPPORTED,
+};
+
+static const struct generic_data set_bredr_off_failure_test_1 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_off_param,
+       .send_len = sizeof(set_bredr_off_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data set_bredr_off_failure_test_2 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_off_param,
+       .send_len = sizeof(set_bredr_off_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data set_bredr_off_failure_test_3 = {
+       .send_opcode = MGMT_OP_SET_BREDR,
+       .send_param = set_bredr_invalid_param,
+       .send_len = sizeof(set_bredr_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const char set_local_name_param[260] = { 'T', 'e', 's', 't', ' ',
+                                               'n', 'a', 'm', 'e' };
+static const char write_local_name_hci[248] = { 'T', 'e', 's', 't', ' ',
+                                               'n', 'a', 'm', 'e' };
+static const char write_eir_local_name_hci_1[241] = { 0x00,
+               0x0a, 0x09, 'T', 'e', 's', 't', ' ', 'n', 'a', 'm', 'e',
+               0x02, 0x0a, 0x00, };
+
+static const struct generic_data set_local_name_test_1 = {
+       .send_opcode = MGMT_OP_SET_LOCAL_NAME,
+       .send_param = set_local_name_param,
+       .send_len = sizeof(set_local_name_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_local_name_param,
+       .expect_len = sizeof(set_local_name_param),
+       .expect_alt_ev = MGMT_EV_LOCAL_NAME_CHANGED,
+       .expect_alt_ev_param = set_local_name_param,
+       .expect_alt_ev_len = sizeof(set_local_name_param),
+};
+
+static const struct generic_data set_local_name_test_2 = {
+       .send_opcode = MGMT_OP_SET_LOCAL_NAME,
+       .send_param = set_local_name_param,
+       .send_len = sizeof(set_local_name_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_local_name_param,
+       .expect_len = sizeof(set_local_name_param),
+       .expect_hci_command = BT_HCI_CMD_WRITE_LOCAL_NAME,
+       .expect_hci_param = write_local_name_hci,
+       .expect_hci_len = sizeof(write_local_name_hci),
+       .expect_alt_ev = MGMT_EV_LOCAL_NAME_CHANGED,
+       .expect_alt_ev_param = set_local_name_param,
+       .expect_alt_ev_len = sizeof(set_local_name_param),
+};
+
+static const struct generic_data set_local_name_test_3 = {
+       .send_opcode = MGMT_OP_SET_LOCAL_NAME,
+       .send_param = set_local_name_param,
+       .send_len = sizeof(set_local_name_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_local_name_param,
+       .expect_len = sizeof(set_local_name_param),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_local_name_hci_1,
+       .expect_hci_len = sizeof(write_eir_local_name_hci_1),
+       .expect_alt_ev = MGMT_EV_LOCAL_NAME_CHANGED,
+       .expect_alt_ev_param = set_local_name_param,
+       .expect_alt_ev_len = sizeof(set_local_name_param),
+};
+
+static const char start_discovery_invalid_param[] = { 0x00 };
+static const char start_discovery_bredr_param[] = { 0x01 };
+static const char start_discovery_le_param[] = { 0x06 };
+static const char start_discovery_bredrle_param[] = { 0x07 };
+static const char start_discovery_valid_hci[] = { 0x01, 0x01 };
+static const char start_discovery_evt[] = { 0x07, 0x01 };
+static const char start_discovery_le_evt[] = { 0x06, 0x01 };
+
+static const struct generic_data start_discovery_not_powered_test_1 = {
+       .send_opcode = MGMT_OP_START_DISCOVERY,
+       .send_param = start_discovery_bredr_param,
+       .send_len = sizeof(start_discovery_bredr_param),
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+};
+
+static const struct generic_data start_discovery_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_START_DISCOVERY,
+       .send_param = start_discovery_invalid_param,
+       .send_len = sizeof(start_discovery_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data start_discovery_not_supported_test_1 = {
+       .send_opcode = MGMT_OP_START_DISCOVERY,
+       .send_param = start_discovery_le_param,
+       .send_len = sizeof(start_discovery_le_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const struct generic_data start_discovery_valid_param_test_1 = {
+       .send_opcode = MGMT_OP_START_DISCOVERY,
+       .send_param = start_discovery_bredrle_param,
+       .send_len = sizeof(start_discovery_bredrle_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = start_discovery_bredrle_param,
+       .expect_len = sizeof(start_discovery_bredrle_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+       .expect_hci_param = start_discovery_valid_hci,
+       .expect_hci_len = sizeof(start_discovery_valid_hci),
+       .expect_alt_ev = MGMT_EV_DISCOVERING,
+       .expect_alt_ev_param = start_discovery_evt,
+       .expect_alt_ev_len = sizeof(start_discovery_evt),
+};
+
+static const struct generic_data start_discovery_valid_param_test_2 = {
+       .send_opcode = MGMT_OP_START_DISCOVERY,
+       .send_param = start_discovery_le_param,
+       .send_len = sizeof(start_discovery_le_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = start_discovery_le_param,
+       .expect_len = sizeof(start_discovery_le_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+       .expect_hci_param = start_discovery_valid_hci,
+       .expect_hci_len = sizeof(start_discovery_valid_hci),
+       .expect_alt_ev = MGMT_EV_DISCOVERING,
+       .expect_alt_ev_param = start_discovery_le_evt,
+       .expect_alt_ev_len = sizeof(start_discovery_le_evt),
+};
+
+static const char stop_discovery_bredrle_param[] = { 0x07 };
+static const char stop_discovery_bredrle_invalid_param[] = { 0x06 };
+static const char stop_discovery_valid_hci[] = { 0x00, 0x00 };
+static const char stop_discovery_evt[] = { 0x07, 0x00 };
+static const char stop_discovery_bredr_param[] = { 0x01 };
+static const char stop_discovery_bredr_discovering[] = { 0x01, 0x00 };
+static const char stop_discovery_inq_param[] = { 0x33, 0x8b, 0x9e, 0x08, 0x00 };
+
+static const struct generic_data stop_discovery_success_test_1 = {
+       .send_opcode = MGMT_OP_STOP_DISCOVERY,
+       .send_param = stop_discovery_bredrle_param,
+       .send_len = sizeof(stop_discovery_bredrle_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = stop_discovery_bredrle_param,
+       .expect_len = sizeof(stop_discovery_bredrle_param),
+       .expect_hci_command = BT_HCI_CMD_LE_SET_SCAN_ENABLE,
+       .expect_hci_param = stop_discovery_valid_hci,
+       .expect_hci_len = sizeof(stop_discovery_valid_hci),
+       .expect_alt_ev = MGMT_EV_DISCOVERING,
+       .expect_alt_ev_param = stop_discovery_evt,
+       .expect_alt_ev_len = sizeof(stop_discovery_evt),
+};
+
+static const struct generic_data stop_discovery_bredr_success_test_1 = {
+       .setup_expect_hci_command = BT_HCI_CMD_INQUIRY,
+       .setup_expect_hci_param = stop_discovery_inq_param,
+       .setup_expect_hci_len = sizeof(stop_discovery_inq_param),
+       .send_opcode = MGMT_OP_STOP_DISCOVERY,
+       .send_param = stop_discovery_bredr_param,
+       .send_len = sizeof(stop_discovery_bredr_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = stop_discovery_bredr_param,
+       .expect_len = sizeof(stop_discovery_bredr_param),
+       .expect_hci_command = BT_HCI_CMD_INQUIRY_CANCEL,
+       .expect_alt_ev = MGMT_EV_DISCOVERING,
+       .expect_alt_ev_param = stop_discovery_bredr_discovering,
+       .expect_alt_ev_len = sizeof(stop_discovery_bredr_discovering),
+};
+
+static const struct generic_data stop_discovery_rejected_test_1 = {
+       .send_opcode = MGMT_OP_STOP_DISCOVERY,
+       .send_param = stop_discovery_bredrle_param,
+       .send_len = sizeof(stop_discovery_bredrle_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+       .expect_param = stop_discovery_bredrle_param,
+       .expect_len = sizeof(stop_discovery_bredrle_param),
+};
+
+static const struct generic_data stop_discovery_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_STOP_DISCOVERY,
+       .send_param = stop_discovery_bredrle_invalid_param,
+       .send_len = sizeof(stop_discovery_bredrle_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = stop_discovery_bredrle_invalid_param,
+       .expect_len = sizeof(stop_discovery_bredrle_invalid_param),
+};
+
+static const char set_dev_class_valid_param[] = { 0x01, 0x0c };
+static const char set_dev_class_zero_rsp[] = { 0x00, 0x00, 0x00 };
+static const char set_dev_class_valid_rsp[] = { 0x0c, 0x01, 0x00 };
+static const char set_dev_class_valid_hci[] = { 0x0c, 0x01, 0x00 };
+static const char set_dev_class_invalid_param[] = { 0x01, 0x01 };
+
+static const struct generic_data set_dev_class_valid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_DEV_CLASS,
+       .send_param = set_dev_class_valid_param,
+       .send_len = sizeof(set_dev_class_valid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+};
+
+static const struct generic_data set_dev_class_valid_param_test_2 = {
+       .send_opcode = MGMT_OP_SET_DEV_CLASS,
+       .send_param = set_dev_class_valid_param,
+       .send_len = sizeof(set_dev_class_valid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_valid_rsp,
+       .expect_len = sizeof(set_dev_class_valid_rsp),
+       .expect_alt_ev = MGMT_EV_CLASS_OF_DEV_CHANGED,
+       .expect_alt_ev_param = set_dev_class_valid_rsp,
+       .expect_alt_ev_len = sizeof(set_dev_class_valid_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_CLASS_OF_DEV,
+       .expect_hci_param = set_dev_class_valid_hci,
+       .expect_hci_len = sizeof(set_dev_class_valid_hci),
+};
+
+static const struct generic_data set_dev_class_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_SET_DEV_CLASS,
+       .send_param = set_dev_class_invalid_param,
+       .send_len = sizeof(set_dev_class_invalid_param),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const char add_spp_uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x01, 0x11, 0x00, 0x00,
+                       0x00 };
+static const char add_dun_uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x03, 0x11, 0x00, 0x00,
+                       0x00 };
+static const char add_sync_uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x04, 0x11, 0x00, 0x00,
+                       0x00 };
+static const char add_opp_uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x05, 0x11, 0x00, 0x00,
+                       0x00 };
+static const char write_eir_uuid16_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x03, 0x03, 0x01, 0x11 };
+static const char write_eir_multi_uuid16_hci_1[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x09, 0x03, 0x01, 0x11, 0x03,
+                       0x11, 0x04, 0x11, 0x05, 0x11 };
+static const char write_eir_multi_uuid16_hci_2[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0xeb, 0x02, 0x00, 0x20, 0x01,
+                       0x20, 0x02, 0x20, 0x03, 0x20, 0x04, 0x20, 0x05,
+                       0x20, 0x06, 0x20, 0x07, 0x20, 0x08, 0x20, 0x09,
+                       0x20, 0x0a, 0x20, 0x0b, 0x20, 0x0c, 0x20, 0x0d,
+                       0x20, 0x0e, 0x20, 0x0f, 0x20, 0x10, 0x20, 0x11,
+                       0x20, 0x12, 0x20, 0x13, 0x20, 0x14, 0x20, 0x15,
+                       0x20, 0x16, 0x20, 0x17, 0x20, 0x18, 0x20, 0x19,
+                       0x20, 0x1a, 0x20, 0x1b, 0x20, 0x1c, 0x20, 0x1d,
+                       0x20, 0x1e, 0x20, 0x1f, 0x20, 0x20, 0x20, 0x21,
+                       0x20, 0x22, 0x20, 0x23, 0x20, 0x24, 0x20, 0x25,
+                       0x20, 0x26, 0x20, 0x27, 0x20, 0x28, 0x20, 0x29,
+                       0x20, 0x2a, 0x20, 0x2b, 0x20, 0x2c, 0x20, 0x2d,
+                       0x20, 0x2e, 0x20, 0x2f, 0x20, 0x30, 0x20, 0x31,
+                       0x20, 0x32, 0x20, 0x33, 0x20, 0x34, 0x20, 0x35,
+                       0x20, 0x36, 0x20, 0x37, 0x20, 0x38, 0x20, 0x39,
+                       0x20, 0x3a, 0x20, 0x3b, 0x20, 0x3c, 0x20, 0x3d,
+                       0x20, 0x3e, 0x20, 0x3f, 0x20, 0x40, 0x20, 0x41,
+                       0x20, 0x42, 0x20, 0x43, 0x20, 0x44, 0x20, 0x45,
+                       0x20, 0x46, 0x20, 0x47, 0x20, 0x48, 0x20, 0x49,
+                       0x20, 0x4a, 0x20, 0x4b, 0x20, 0x4c, 0x20, 0x4d,
+                       0x20, 0x4e, 0x20, 0x4f, 0x20, 0x50, 0x20, 0x51,
+                       0x20, 0x52, 0x20, 0x53, 0x20, 0x54, 0x20, 0x55,
+                       0x20, 0x56, 0x20, 0x57, 0x20, 0x58, 0x20, 0x59,
+                       0x20, 0x5a, 0x20, 0x5b, 0x20, 0x5c, 0x20, 0x5d,
+                       0x20, 0x5e, 0x20, 0x5f, 0x20, 0x60, 0x20, 0x61,
+                       0x20, 0x62, 0x20, 0x63, 0x20, 0x64, 0x20, 0x65,
+                       0x20, 0x66, 0x20, 0x67, 0x20, 0x68, 0x20, 0x69,
+                       0x20, 0x6a, 0x20, 0x6b, 0x20, 0x6c, 0x20, 0x6d,
+                       0x20, 0x6e, 0x20, 0x6f, 0x20, 0x70, 0x20, 0x71,
+                       0x20, 0x72, 0x20, 0x73, 0x20, 0x74, 0x20, 0x00 };
+static const char add_uuid32_param_1[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x78, 0x56, 0x34, 0x12,
+                       0x00 };
+static const char add_uuid32_param_2[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0xef, 0xcd, 0xbc, 0x9a,
+                       0x00 };
+static const char add_uuid32_param_3[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0xff, 0xee, 0xdd, 0xcc,
+                       0x00 };
+static const char add_uuid32_param_4[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x11, 0x22, 0x33, 0x44,
+                       0x00 };
+static const char write_eir_uuid32_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x05, 0x05, 0x78, 0x56, 0x34,
+                       0x12 };
+static const char write_eir_uuid32_multi_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x11, 0x05, 0x78, 0x56, 0x34,
+                       0x12, 0xef, 0xcd, 0xbc, 0x9a, 0xff, 0xee, 0xdd,
+                       0xcc, 0x11, 0x22, 0x33, 0x44 };
+static const char write_eir_uuid32_multi_hci_2[] = { 0x00,
+                       0x02, 0x0a, 0x00, 0xe9, 0x04, 0xff, 0xff, 0xff,
+                       0xff, 0xfe, 0xff, 0xff, 0xff, 0xfd, 0xff, 0xff,
+                       0xff, 0xfc, 0xff, 0xff, 0xff, 0xfb, 0xff, 0xff,
+                       0xff, 0xfa, 0xff, 0xff, 0xff, 0xf9, 0xff, 0xff,
+                       0xff, 0xf8, 0xff, 0xff, 0xff, 0xf7, 0xff, 0xff,
+                       0xff, 0xf6, 0xff, 0xff, 0xff, 0xf5, 0xff, 0xff,
+                       0xff, 0xf4, 0xff, 0xff, 0xff, 0xf3, 0xff, 0xff,
+                       0xff, 0xf2, 0xff, 0xff, 0xff, 0xf1, 0xff, 0xff,
+                       0xff, 0xf0, 0xff, 0xff, 0xff, 0xef, 0xff, 0xff,
+                       0xff, 0xee, 0xff, 0xff, 0xff, 0xed, 0xff, 0xff,
+                       0xff, 0xec, 0xff, 0xff, 0xff, 0xeb, 0xff, 0xff,
+                       0xff, 0xea, 0xff, 0xff, 0xff, 0xe9, 0xff, 0xff,
+                       0xff, 0xe8, 0xff, 0xff, 0xff, 0xe7, 0xff, 0xff,
+                       0xff, 0xe6, 0xff, 0xff, 0xff, 0xe5, 0xff, 0xff,
+                       0xff, 0xe4, 0xff, 0xff, 0xff, 0xe3, 0xff, 0xff,
+                       0xff, 0xe2, 0xff, 0xff, 0xff, 0xe1, 0xff, 0xff,
+                       0xff, 0xe0, 0xff, 0xff, 0xff, 0xdf, 0xff, 0xff,
+                       0xff, 0xde, 0xff, 0xff, 0xff, 0xdd, 0xff, 0xff,
+                       0xff, 0xdc, 0xff, 0xff, 0xff, 0xdb, 0xff, 0xff,
+                       0xff, 0xda, 0xff, 0xff, 0xff, 0xd9, 0xff, 0xff,
+                       0xff, 0xd8, 0xff, 0xff, 0xff, 0xd7, 0xff, 0xff,
+                       0xff, 0xd6, 0xff, 0xff, 0xff, 0xd5, 0xff, 0xff,
+                       0xff, 0xd4, 0xff, 0xff, 0xff, 0xd3, 0xff, 0xff,
+                       0xff, 0xd2, 0xff, 0xff, 0xff, 0xd1, 0xff, 0xff,
+                       0xff, 0xd0, 0xff, 0xff, 0xff, 0xcf, 0xff, 0xff,
+                       0xff, 0xce, 0xff, 0xff, 0xff, 0xcd, 0xff, 0xff,
+                       0xff, 0xcc, 0xff, 0xff, 0xff, 0xcb, 0xff, 0xff,
+                       0xff, 0xca, 0xff, 0xff, 0xff, 0xc9, 0xff, 0xff,
+                       0xff, 0xc8, 0xff, 0xff, 0xff, 0xc7, 0xff, 0xff,
+                       0xff, 0xc6, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00 };
+static const char add_uuid128_param_1[] = {
+                       0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77,
+                       0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff,
+                       0x00 };
+static const char add_uuid128_param_2[] = {
+                       0xff, 0xee, 0xdd, 0xcc, 0xbb, 0xaa, 0x99, 0x88,
+                       0x77, 0x66, 0x55, 0x44, 0x33, 0x22, 0x11, 0x00,
+                       0x00 };
+static const char write_eir_uuid128_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x11, 0x07, 0x00, 0x11, 0x22,
+                       0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+                       0xbb, 0xcc, 0xdd, 0xee, 0xff };
+static const char write_eir_uuid128_multi_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x21, 0x07, 0x00, 0x11, 0x22,
+                       0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+                       0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xff, 0xee, 0xdd,
+                       0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55,
+                       0x44, 0x33, 0x22, 0x11 };
+static const char write_eir_uuid128_multi_hci_2[] = { 0x00,
+                       0x02, 0x0a, 0x00, 0xe1, 0x07, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x00, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x01, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x02, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x03, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x04, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x05, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x06, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x07, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x08, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x09, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x0a, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x0b, 0x11, 0x22, 0x33,
+                       0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb,
+                       0xcc, 0xdd, 0xee, 0xff, 0x0c, 0xff, 0xee, 0xdd,
+                       0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55,
+                       0x44, 0x33, 0x22, 0x11, 0x00, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 };
+static const char write_eir_uuid_mix_hci[241] = { 0x00,
+                       0x02, 0x0a, 0x00, 0x05, 0x03, 0x01, 0x11, 0x03,
+                       0x11, 0x09, 0x05, 0x78, 0x56, 0x34, 0x12, 0xef,
+                       0xcd, 0xbc, 0x9a, 0x21, 0x07, 0x00, 0x11, 0x22,
+                       0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa,
+                       0xbb, 0xcc, 0xdd, 0xee, 0xff, 0xff, 0xee, 0xdd,
+                       0xcc, 0xbb, 0xaa, 0x99, 0x88, 0x77, 0x66, 0x55,
+                       0x44, 0x33, 0x22, 0x11 };
+
+static const struct generic_data add_uuid16_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_spp_uuid_param,
+       .send_len = sizeof(add_spp_uuid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid16_hci,
+       .expect_hci_len = sizeof(write_eir_uuid16_hci),
+};
+
+static const struct generic_data add_multi_uuid16_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_opp_uuid_param,
+       .send_len = sizeof(add_opp_uuid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_multi_uuid16_hci_1,
+       .expect_hci_len = sizeof(write_eir_multi_uuid16_hci_1),
+};
+
+static const struct generic_data add_multi_uuid16_test_2 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_opp_uuid_param,
+       .send_len = sizeof(add_opp_uuid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_multi_uuid16_hci_2,
+       .expect_hci_len = sizeof(write_eir_multi_uuid16_hci_2),
+};
+
+static const struct generic_data add_uuid32_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid32_param_1,
+       .send_len = sizeof(add_uuid32_param_1),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid32_hci,
+       .expect_hci_len = sizeof(write_eir_uuid32_hci),
+};
+
+static const struct generic_data add_uuid32_multi_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid32_param_4,
+       .send_len = sizeof(add_uuid32_param_4),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid32_multi_hci,
+       .expect_hci_len = sizeof(write_eir_uuid32_multi_hci),
+};
+
+static const struct generic_data add_uuid32_multi_test_2 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid32_param_4,
+       .send_len = sizeof(add_uuid32_param_4),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid32_multi_hci_2,
+       .expect_hci_len = sizeof(write_eir_uuid32_multi_hci_2),
+};
+
+static const struct generic_data add_uuid128_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid128_param_1,
+       .send_len = sizeof(add_uuid128_param_1),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid128_hci,
+       .expect_hci_len = sizeof(write_eir_uuid128_hci),
+};
+
+static const struct generic_data add_uuid128_multi_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid128_param_2,
+       .send_len = sizeof(add_uuid32_param_2),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid128_multi_hci,
+       .expect_hci_len = sizeof(write_eir_uuid128_multi_hci),
+};
+
+static const struct generic_data add_uuid128_multi_test_2 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid128_param_2,
+       .send_len = sizeof(add_uuid128_param_2),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid128_multi_hci_2,
+       .expect_hci_len = sizeof(write_eir_uuid128_multi_hci_2),
+};
+
+static const struct generic_data add_uuid_mix_test_1 = {
+       .send_opcode = MGMT_OP_ADD_UUID,
+       .send_param = add_uuid128_param_2,
+       .send_len = sizeof(add_uuid128_param_2),
+       .expect_status = MGMT_STATUS_SUCCESS,
+       .expect_param = set_dev_class_zero_rsp,
+       .expect_len = sizeof(set_dev_class_zero_rsp),
+       .expect_hci_command = BT_HCI_CMD_WRITE_EXT_INQUIRY_RESPONSE,
+       .expect_hci_param = write_eir_uuid_mix_hci,
+       .expect_hci_len = sizeof(write_eir_uuid_mix_hci),
+};
+
+static const char load_link_keys_valid_param_1[] = { 0x00, 0x00, 0x00 };
+static const char load_link_keys_valid_param_2[] = { 0x01, 0x00, 0x00 };
+static const char load_link_keys_invalid_param_1[] = { 0x02, 0x00, 0x00 };
+static const char load_link_keys_invalid_param_2[] = { 0x00, 0x01, 0x00 };
+/* Invalid bdaddr type */
+static const char load_link_keys_invalid_param_3[] = { 0x00, 0x01, 0x00,
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,             /* addr */
+       0x01,                                           /* addr type */
+       0x00,                                           /* key type */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (1/2) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (2/2) */
+       0x04,                                           /* PIN length */
+};
+
+static const struct generic_data load_link_keys_success_test_1 = {
+       .send_opcode = MGMT_OP_LOAD_LINK_KEYS,
+       .send_param = load_link_keys_valid_param_1,
+       .send_len = sizeof(load_link_keys_valid_param_1),
+       .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+static const struct generic_data load_link_keys_success_test_2 = {
+       .send_opcode = MGMT_OP_LOAD_LINK_KEYS,
+       .send_param = load_link_keys_valid_param_2,
+       .send_len = sizeof(load_link_keys_valid_param_2),
+       .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+static const struct generic_data load_link_keys_invalid_params_test_1 = {
+       .send_opcode = MGMT_OP_LOAD_LINK_KEYS,
+       .send_param = load_link_keys_invalid_param_1,
+       .send_len = sizeof(load_link_keys_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data load_link_keys_invalid_params_test_2 = {
+       .send_opcode = MGMT_OP_LOAD_LINK_KEYS,
+       .send_param = load_link_keys_invalid_param_2,
+       .send_len = sizeof(load_link_keys_invalid_param_2),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data load_link_keys_invalid_params_test_3 = {
+       .send_opcode = MGMT_OP_LOAD_LINK_KEYS,
+       .send_param = load_link_keys_invalid_param_3,
+       .send_len = sizeof(load_link_keys_invalid_param_3),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const char load_ltks_valid_param_1[] = { 0x00, 0x00 };
+/* Invalid key count */
+static const char load_ltks_invalid_param_1[] = { 0x01, 0x00 };
+/* Invalid addr type */
+static const char load_ltks_invalid_param_2[] = {
+       0x01, 0x00,                                     /* count */
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,             /* bdaddr */
+       0x00,                                           /* addr type */
+       0x00,                                           /* authenticated */
+       0x00,                                           /* master */
+       0x00,                                           /* encryption size */
+       0x00, 0x00,                                     /* diversifier */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* rand */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (1/2) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (2/2 */
+};
+/* Invalid authenticated value */
+static const char load_ltks_invalid_param_3[] = {
+       0x01, 0x00,                                     /* count */
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,             /* bdaddr */
+       0x01,                                           /* addr type */
+       0x02,                                           /* authenticated */
+       0x00,                                           /* master */
+       0x00,                                           /* encryption size */
+       0x00, 0x00,                                     /* diversifier */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* rand */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (1/2) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (2/2 */
+};
+/* Invalid master value */
+static const char load_ltks_invalid_param_4[] = {
+       0x01, 0x00,                                     /* count */
+       0x00, 0x01, 0x02, 0x03, 0x04, 0x05,             /* bdaddr */
+       0x01,                                           /* addr type */
+       0x00,                                           /* authunticated */
+       0x02,                                           /* master */
+       0x00,                                           /* encryption size */
+       0x00, 0x00,                                     /* diversifier */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* rand */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (1/2) */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, /* value (2/2 */
+};
+
+static const struct generic_data load_ltks_success_test_1 = {
+       .send_opcode = MGMT_OP_LOAD_LONG_TERM_KEYS,
+       .send_param = load_ltks_valid_param_1,
+       .send_len = sizeof(load_ltks_valid_param_1),
+       .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+static const struct generic_data load_ltks_invalid_params_test_1 = {
+       .send_opcode = MGMT_OP_LOAD_LONG_TERM_KEYS,
+       .send_param = load_ltks_invalid_param_1,
+       .send_len = sizeof(load_ltks_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data load_ltks_invalid_params_test_2 = {
+       .send_opcode = MGMT_OP_LOAD_LONG_TERM_KEYS,
+       .send_param = load_ltks_invalid_param_2,
+       .send_len = sizeof(load_ltks_invalid_param_2),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data load_ltks_invalid_params_test_3 = {
+       .send_opcode = MGMT_OP_LOAD_LONG_TERM_KEYS,
+       .send_param = load_ltks_invalid_param_3,
+       .send_len = sizeof(load_ltks_invalid_param_3),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const struct generic_data load_ltks_invalid_params_test_4 = {
+       .send_opcode = MGMT_OP_LOAD_LONG_TERM_KEYS,
+       .send_param = load_ltks_invalid_param_4,
+       .send_len = sizeof(load_ltks_invalid_param_4),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+};
+
+static const char pair_device_param[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00 };
+static const char pair_device_rsp[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };
+static const char pair_device_invalid_param_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff, 0x00 };
+static const char pair_device_invalid_param_rsp_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+
+static const struct generic_data pair_device_not_powered_test_1 = {
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_param = pair_device_param,
+       .send_len = sizeof(pair_device_param),
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+       .expect_param = pair_device_rsp,
+       .expect_len = sizeof(pair_device_rsp),
+};
+
+static const struct generic_data pair_device_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_PAIR_DEVICE,
+       .send_param = pair_device_invalid_param_1,
+       .send_len = sizeof(pair_device_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = pair_device_invalid_param_rsp_1,
+       .expect_len = sizeof(pair_device_invalid_param_rsp_1),
+};
+
+static const char unpair_device_param[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x00 };
+static const char unpair_device_rsp[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };
+static const char unpair_device_invalid_param_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff, 0x00 };
+static const char unpair_device_invalid_param_rsp_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+static const char unpair_device_invalid_param_2[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00, 0x02 };
+static const char unpair_device_invalid_param_rsp_2[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x00 };
+
+static const struct generic_data unpair_device_not_powered_test_1 = {
+       .send_opcode = MGMT_OP_UNPAIR_DEVICE,
+       .send_param = unpair_device_param,
+       .send_len = sizeof(unpair_device_param),
+       .expect_status = MGMT_STATUS_NOT_POWERED,
+       .expect_param = unpair_device_rsp,
+       .expect_len = sizeof(unpair_device_rsp),
+};
+
+static const struct generic_data unpair_device_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_UNPAIR_DEVICE,
+       .send_param = unpair_device_invalid_param_1,
+       .send_len = sizeof(unpair_device_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = unpair_device_invalid_param_rsp_1,
+       .expect_len = sizeof(unpair_device_invalid_param_rsp_1),
+};
+
+static const struct generic_data unpair_device_invalid_param_test_2 = {
+       .send_opcode = MGMT_OP_UNPAIR_DEVICE,
+       .send_param = unpair_device_invalid_param_2,
+       .send_len = sizeof(unpair_device_invalid_param_2),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = unpair_device_invalid_param_rsp_2,
+       .expect_len = sizeof(unpair_device_invalid_param_rsp_2),
+};
+
+static const char disconnect_invalid_param_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+static const char disconnect_invalid_param_rsp_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+
+static const struct generic_data disconnect_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_DISCONNECT,
+       .send_param = disconnect_invalid_param_1,
+       .send_len = sizeof(disconnect_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = disconnect_invalid_param_rsp_1,
+       .expect_len = sizeof(disconnect_invalid_param_rsp_1),
+};
+
+static const char block_device_invalid_param_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+static const char block_device_invalid_param_rsp_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+
+static const struct generic_data block_device_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_BLOCK_DEVICE,
+       .send_param = block_device_invalid_param_1,
+       .send_len = sizeof(block_device_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = block_device_invalid_param_rsp_1,
+       .expect_len = sizeof(block_device_invalid_param_rsp_1),
+};
+
+static const char unblock_device_invalid_param_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+static const char unblock_device_invalid_param_rsp_1[] = {
+                       0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+
+static const struct generic_data unblock_device_invalid_param_test_1 = {
+       .send_opcode = MGMT_OP_UNBLOCK_DEVICE,
+       .send_param = unblock_device_invalid_param_1,
+       .send_len = sizeof(unblock_device_invalid_param_1),
+       .expect_status = MGMT_STATUS_INVALID_PARAMS,
+       .expect_param = unblock_device_invalid_param_rsp_1,
+       .expect_len = sizeof(unblock_device_invalid_param_rsp_1),
+};
+
+static const char set_static_addr_valid_param[] = {
+                       0x11, 0x22, 0x33, 0x44, 0x55, 0xc0 };
+
+static const struct generic_data set_static_addr_success_test = {
+       .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+       .send_param = set_static_addr_valid_param,
+       .send_len = sizeof(set_static_addr_valid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+static const struct generic_data set_static_addr_failure_test = {
+       .send_opcode = MGMT_OP_SET_STATIC_ADDRESS,
+       .send_param = set_static_addr_valid_param,
+       .send_len = sizeof(set_static_addr_valid_param),
+       .expect_status = MGMT_STATUS_REJECTED,
+};
+
+static const char set_scan_params_valid_param[] = { 0x60, 0x00, 0x30, 0x00 };
+
+static const struct generic_data set_scan_params_success_test = {
+       .send_opcode = MGMT_OP_SET_SCAN_PARAMS,
+       .send_param = set_scan_params_valid_param,
+       .send_len = sizeof(set_scan_params_valid_param),
+       .expect_status = MGMT_STATUS_SUCCESS,
+};
+
+static void powered_delay(void *user_data)
+{
+       tester_setup_complete();
+}
+
+static void setup_powered_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       if (option_wait_powered)
+               tester_wait(1, powered_delay, NULL);
+       else
+               tester_setup_complete();
+}
+
+static void setup_powered_discoverable(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+       unsigned char discov_param[] = { 0x01, 0x00, 0x00 };
+
+       tester_print("Enabling connectable, discoverable and powered");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                                       sizeof(param), param,
+                                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_DISCOVERABLE, data->mgmt_index,
+                                       sizeof(discov_param), discov_param,
+                                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_powered_connectable(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Enabling connectable and powered");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                                       sizeof(param), param,
+                                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_class(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+       unsigned char class_param[] = { 0x01, 0x0c };
+
+       tester_print("Setting device class and powering on");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_DEV_CLASS, data->mgmt_index,
+                               sizeof(class_param), class_param,
+                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_ssp_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with SSP enabled)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_le_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with LE enabled)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_le_nobr_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char on[] = { 0x01 };
+       unsigned char off[] = { 0x00 };
+
+       tester_print("Powering on controller (with LE enabled)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(on), on, NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_BREDR, data->mgmt_index,
+                               sizeof(off), off, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(on), on,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_discovery_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Discovery started");
+       tester_setup_complete();
+}
+
+static bool setup_command_hci_callback(const void *data, uint16_t len,
+                                                               void *user_data)
+{
+       struct test_data *tdata = tester_get_data();
+       const struct generic_data *test = tdata->test_data;
+
+       tester_print("HCI Command 0x%04x length %u (setup)",
+                                       test->setup_expect_hci_command, len);
+
+       if (len != test->setup_expect_hci_len) {
+               tester_warn("Invalid parameter size for HCI command (setup)");
+               tester_setup_failed();
+               goto done;
+       }
+
+       if (memcmp(data, test->setup_expect_hci_param, len) != 0) {
+               tester_warn("Unexpected HCI command parameter value (setup)");
+               tester_setup_failed();
+               goto done;
+       }
+
+       tester_setup_complete();
+
+done:
+       hciemu_del_hook(tdata->hciemu, HCIEMU_HOOK_PRE_EVT,
+                       test->setup_expect_hci_command);
+
+       return false;
+}
+
+static void setup_start_discovery_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       if (test->setup_expect_hci_command) {
+               tester_print("Registering HCI command callback (setup)");
+               hciemu_add_hook(data->hciemu, HCIEMU_HOOK_PRE_EVT,
+                               test->setup_expect_hci_command,
+                               setup_command_hci_callback,
+                               NULL);
+               mgmt_send(data->mgmt, MGMT_OP_START_DISCOVERY, data->mgmt_index,
+                               test->send_len, test->send_param,
+                               NULL, NULL, NULL);
+       } else {
+               unsigned char disc_param[] = { 0x07 };
+
+               mgmt_send(data->mgmt, MGMT_OP_START_DISCOVERY, data->mgmt_index,
+                                       sizeof(disc_param), disc_param,
+                                       setup_discovery_callback, NULL, NULL);
+       }
+
+       if (option_wait_powered)
+               tester_wait(1, NULL, NULL);
+}
+
+static void setup_start_discovery(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with LE enabled)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                               sizeof(param), param,
+                               setup_start_discovery_callback, NULL, NULL);
+}
+
+static void setup_ssp_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("SSP enabled");
+
+       tester_setup_complete();
+}
+
+static void setup_ssp(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Enabling SSP");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, setup_ssp_callback,
+                               NULL, NULL);
+}
+
+static void setup_le_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Low Energy enabled");
+
+       tester_setup_complete();
+}
+
+static void setup_le(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Enabling Low Energy");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, setup_le_callback,
+                               NULL, NULL);
+}
+
+static void setup_le_nobr(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char on[] = { 0x01 };
+       unsigned char off[] = { 0x00 };
+
+       tester_print("Enabling Low Energy");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(on), on, NULL,
+                               NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_SET_BREDR, data->mgmt_index,
+                               sizeof(off), off, setup_le_callback,
+                               NULL, NULL);
+}
+
+static void setup_multi_uuid32(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with 32-bit UUID)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_uuid32_param_1), add_uuid32_param_1,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_uuid32_param_2), add_uuid32_param_2,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_uuid32_param_3), add_uuid32_param_3,
+                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_multi_uuid32_2(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+       unsigned char uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00 };
+       int i;
+
+       tester_print("Powering on controller (with many 32-bit UUIDs)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       for (i = 0; i < 58; i++) {
+               uint32_t val = htobl(0xffffffff - i);
+               memcpy(&uuid_param[12], &val, sizeof(val));
+               mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(uuid_param), uuid_param,
+                               NULL, NULL, NULL);
+       }
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_multi_uuid128(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with 128-bit UUID)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                       sizeof(add_uuid128_param_1), add_uuid128_param_1,
+                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_multi_uuid128_2(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+       unsigned char uuid_param[] = {
+                       0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88,
+                       0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff, 0x00,
+                       0x00 };
+       int i;
+
+       tester_print("Powering on controller (with many 128-bit UUIDs)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       for (i = 0; i < 13; i++) {
+               uuid_param[15] = i;
+               mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(uuid_param), uuid_param,
+                               NULL, NULL, NULL);
+       }
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_multi_uuid16(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with SPP UUID)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_spp_uuid_param), add_spp_uuid_param,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_dun_uuid_param), add_dun_uuid_param,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                       sizeof(add_sync_uuid_param), add_sync_uuid_param,
+                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_multi_uuid16_2(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+       unsigned char uuid_param[] = {
+                       0xfb, 0x34, 0x9b, 0x5f, 0x80, 0x00, 0x00, 0x80,
+                       0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                       0x00 };
+       int i;
+
+       tester_print("Powering on controller (with many 16-bit UUIDs)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       for (i = 0; i < 117; i++) {
+               uint16_t val = htobs(i + 0x2000);
+               memcpy(&uuid_param[12], &val, sizeof(val));
+               mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(uuid_param), uuid_param,
+                               NULL, NULL, NULL);
+       }
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_uuid_mix(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller (with mixed UUIDs)");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_spp_uuid_param), add_spp_uuid_param,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_uuid32_param_1), add_uuid32_param_1,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                       sizeof(add_uuid128_param_1), add_uuid128_param_1,
+                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_dun_uuid_param), add_dun_uuid_param,
+                               NULL, NULL, NULL);
+       mgmt_send(data->mgmt, MGMT_OP_ADD_UUID, data->mgmt_index,
+                               sizeof(add_uuid32_param_2), add_uuid32_param_2,
+                               NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_connectable_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller connectable on");
+
+       tester_setup_complete();
+}
+
+static void setup_connectable(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Setting controller connectable");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_connectable_callback, NULL, NULL);
+}
+
+static void setup_connectable_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Setting controller powered and connectable");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                       sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void setup_link_sec_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Link security enabled");
+
+       tester_setup_complete();
+}
+
+static void setup_link_sec(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Enabling link security");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LINK_SECURITY, data->mgmt_index,
+                       sizeof(param), param, setup_link_sec_callback,
+                       NULL, NULL);
+}
+
+static void setup_link_sec_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Enabling link security and powering on");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LINK_SECURITY, data->mgmt_index,
+                       sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void command_generic_new_settings(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("New settings event received");
+
+       mgmt_unregister(data->mgmt, data->mgmt_settings_id);
+
+       tester_test_failed();
+}
+
+static void command_generic_new_settings_alt(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
+       uint32_t settings;
+
+       if (length != 4) {
+               tester_warn("Invalid parameter size for new settings event");
+               tester_test_failed();
+               return;
+       }
+
+       settings = bt_get_le32(param);
+
+       tester_print("New settings 0x%08x received", settings);
+
+       if (test->expect_settings_unset) {
+               if ((settings & test->expect_settings_unset) != 0)
+                       return;
+               goto done;
+       }
+
+       if (!test->expect_settings_set)
+               return;
+
+       if ((settings & test->expect_settings_set) != test->expect_settings_set)
+               return;
+
+done:
+       tester_print("Unregistering new settings notification");
+
+       mgmt_unregister(data->mgmt_alt, data->mgmt_alt_settings_id);
+
+       test_condition_complete(data);
+}
+
+static void command_generic_event_alt(uint16_t index, uint16_t length,
+                                                       const void *param,
+                                                       void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
+
+       if (length != test->expect_alt_ev_len) {
+               tester_warn("Invalid length %s event",
+                                       mgmt_evstr(test->expect_alt_ev));
+               tester_test_failed();
+               return;
+       }
+
+       tester_print("New %s event received", mgmt_evstr(test->expect_alt_ev));
+
+       if (memcmp(param, test->expect_alt_ev_param,
+                                               test->expect_alt_ev_len) != 0)
+               return;
+
+       tester_print("Unregistering %s notification",
+                                       mgmt_evstr(test->expect_alt_ev));
+
+       mgmt_unregister(data->mgmt_alt, data->mgmt_alt_ev_id);
+
+       test_condition_complete(data);
+}
+
+static void command_generic_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
+
+       tester_print("Command 0x%04x finished with status 0x%02x",
+                                               test->send_opcode, status);
+
+       if (status != test->expect_status) {
+               tester_test_failed();
+               return;
+       }
+
+       if (length != test->expect_len) {
+               tester_test_failed();
+               return;
+       }
+
+       if (test->expect_param && test->expect_len > 0 &&
+                               memcmp(param, test->expect_param, length)) {
+               tester_test_failed();
+               return;
+       }
+
+       test_condition_complete(data);
+}
+
+static void command_hci_callback(uint16_t opcode, const void *param,
+                                       uint8_t length, void *user_data)
+{
+       struct test_data *data = user_data;
+       const struct generic_data *test = data->test_data;
+
+       tester_print("HCI Command 0x%04x length %u", opcode, length);
+
+       if (opcode != test->expect_hci_command)
+               return;
+
+       if (length != test->expect_hci_len) {
+               tester_warn("Invalid parameter size for HCI command");
+               tester_test_failed();
+               return;
+       }
+
+       if (memcmp(param, test->expect_hci_param, length) != 0) {
+               tester_warn("Unexpected HCI command parameter value");
+               tester_test_failed();
+               return;
+       }
+
+       test_condition_complete(data);
+}
+
+static void test_command_generic(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct generic_data *test = data->test_data;
+       unsigned int id;
+       uint16_t index;
+
+       index = test->send_index_none ? MGMT_INDEX_NONE : data->mgmt_index;
+
+       if (test->expect_settings_set || test->expect_settings_unset) {
+               tester_print("Registering new settings notification");
+
+               id = mgmt_register(data->mgmt, MGMT_EV_NEW_SETTINGS, index,
+                               command_generic_new_settings, NULL, NULL);
+               data->mgmt_settings_id = id;
+
+               id = mgmt_register(data->mgmt_alt, MGMT_EV_NEW_SETTINGS, index,
+                               command_generic_new_settings_alt, NULL, NULL);
+               data->mgmt_alt_settings_id = id;
+               test_add_condition(data);
+       }
+
+       if (test->expect_alt_ev) {
+               tester_print("Registering %s notification",
+                                       mgmt_evstr(test->expect_alt_ev));
+               id = mgmt_register(data->mgmt_alt, test->expect_alt_ev, index,
+                                       command_generic_event_alt, NULL, NULL);
+               data->mgmt_alt_ev_id = id;
+               test_add_condition(data);
+       }
+
+       if (test->expect_hci_command) {
+               tester_print("Registering HCI command callback");
+               hciemu_add_master_post_command_hook(data->hciemu,
+                                               command_hci_callback, data);
+               test_add_condition(data);
+       }
+
+       tester_print("Sending command 0x%04x", test->send_opcode);
+
+       mgmt_send(data->mgmt, test->send_opcode, index,
+                                       test->send_len, test->send_param,
+                                       command_generic_callback, NULL, NULL);
+       test_add_condition(data);
+}
+
+static GOptionEntry options[] = {
+       { "wait-powered", 'P', 0, G_OPTION_ARG_NONE, &option_wait_powered,
+                                       "Add a delay after powering on" },
+       { NULL },
+};
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+       g_option_context_set_ignore_unknown_options(context, TRUE);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       tester_init(&argc, &argv);
+
+       test_bredrle("Controller setup",
+                               NULL, NULL, controller_setup);
+       test_bredr("Controller setup (BR/EDR-only)",
+                               NULL, NULL, controller_setup);
+       test_le("Controller setup (LE-only)",
+                               NULL, NULL, controller_setup);
+
+       test_bredrle("Invalid command",
+                               &invalid_command_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Read version - Success",
+                               &read_version_success_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read version - Invalid parameters",
+                               &read_version_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read version - Invalid index",
+                               &read_version_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read commands - Invalid parameters",
+                               &read_commands_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read commands - Invalid index",
+                               &read_commands_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read index list - Invalid parameters",
+                               &read_index_list_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read index list - Invalid index",
+                               &read_index_list_invalid_index_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read info - Invalid parameters",
+                               &read_info_invalid_param_test,
+                               NULL, test_command_generic);
+       test_bredrle("Read info - Invalid index",
+                               &read_info_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set powered on - Success",
+                               &set_powered_on_success_test,
+                               NULL, test_command_generic);
+       test_bredrle("Set powered on - Invalid parameters 1",
+                               &set_powered_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set powered on - Invalid parameters 2",
+                               &set_powered_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set powered on - Invalid parameters 3",
+                               &set_powered_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set powered on - Invalid index",
+                               &set_powered_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set powered off - Success",
+                               &set_powered_off_success_test,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set powered off - Class of Device",
+                               &set_powered_off_class_test,
+                               setup_class, test_command_generic);
+       test_bredrle("Set powered off - Invalid parameters 1",
+                               &set_powered_off_invalid_param_test_1,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set powered off - Invalid parameters 2",
+                               &set_powered_off_invalid_param_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set powered off - Invalid parameters 3",
+                               &set_powered_off_invalid_param_test_3,
+                               setup_powered, test_command_generic);
+
+       test_bredrle("Set connectable on - Success 1",
+                               &set_connectable_on_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set connectable on - Success 2",
+                               &set_connectable_on_success_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set connectable on - Invalid parameters 1",
+                               &set_connectable_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set connectable on - Invalid parameters 2",
+                               &set_connectable_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set connectable on - Invalid parameters 3",
+                               &set_connectable_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set connectable on - Invalid index",
+                               &set_connectable_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set connectable off - Success 1",
+                       &set_connectable_off_success_test_1,
+                       setup_connectable, test_command_generic);
+       test_bredrle("Set connectable off - Success 2",
+                       &set_connectable_off_success_test_2,
+                       setup_connectable_powered, test_command_generic);
+
+       test_bredrle("Set fast connectable on - Success 1",
+                       &set_fast_conn_on_success_test_1,
+                       setup_powered_connectable, test_command_generic);
+
+       test_bredrle("Set pairable on - Success",
+                               &set_pairable_on_success_test,
+                               NULL, test_command_generic);
+       test_bredrle("Set pairable on - Invalid parameters 1",
+                               &set_pairable_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set pairable on - Invalid parameters 2",
+                               &set_pairable_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set pairable on - Invalid parameters 3",
+                               &set_pairable_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set pairable on - Invalid index",
+                               &set_pairable_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set discoverable on - Invalid parameters 1",
+                               &set_discoverable_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Invalid parameters 2",
+                               &set_discoverable_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Invalid parameters 3",
+                               &set_discoverable_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Invalid parameters 4",
+                               &set_discoverable_on_invalid_param_test_4,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Not powered 1",
+                               &set_discoverable_on_not_powered_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Not powered 1",
+                               &set_discoverable_on_not_powered_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set discoverable on - Not powered 2",
+                               &set_discoverable_on_not_powered_test_1,
+                               setup_connectable, test_command_generic);
+       test_bredrle("Set discoverable on - Rejected 1",
+                               &set_discoverable_on_rejected_test_1,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set discoverable on - Rejected 2",
+                               &set_discoverable_on_rejected_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set discoverable on - Rejected 3",
+                               &set_discoverable_on_rejected_test_3,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set discoverable on - Success 1",
+                               &set_discoverable_on_success_test_1,
+                               setup_connectable, test_command_generic);
+       test_bredrle("Set discoverable on - Success 2",
+                               &set_discoverable_on_success_test_2,
+                               setup_powered_connectable, test_command_generic);
+       test_bredrle("Set discoverable off - Success 1",
+                               &set_discoverable_off_success_test_1,
+                               setup_connectable, test_command_generic);
+       test_bredrle("Set discoverable off - Success 2",
+                               &set_discoverable_off_success_test_2,
+                               setup_powered_discoverable,
+                               test_command_generic);
+
+       test_bredrle("Set link security on - Success 1",
+                               &set_link_sec_on_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set link security on - Success 2",
+                               &set_link_sec_on_success_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set link security on - Success 3",
+                               &set_link_sec_on_success_test_3,
+                               setup_link_sec, test_command_generic);
+       test_bredrle("Set link security on - Invalid parameters 1",
+                               &set_link_sec_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set link security on - Invalid parameters 2",
+                               &set_link_sec_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set link security on - Invalid parameters 3",
+                               &set_link_sec_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set link security on - Invalid index",
+                               &set_link_sec_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set link security off - Success 1",
+                               &set_link_sec_off_success_test_1,
+                               setup_link_sec, test_command_generic);
+       test_bredrle("Set link security off - Success 2",
+                               &set_link_sec_off_success_test_2,
+                               setup_link_sec_powered, test_command_generic);
+
+       test_bredrle("Set SSP on - Success 1",
+                               &set_ssp_on_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set SSP on - Success 2",
+                               &set_ssp_on_success_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set SSP on - Success 3",
+                               &set_ssp_on_success_test_3,
+                               setup_ssp, test_command_generic);
+       test_bredrle("Set SSP on - Invalid parameters 1",
+                               &set_ssp_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set SSP on - Invalid parameters 2",
+                               &set_ssp_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set SSP on - Invalid parameters 3",
+                               &set_ssp_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set SSP on - Invalid index",
+                               &set_ssp_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set High Speed on - Success",
+                               &set_hs_on_success_test,
+                               setup_ssp, test_command_generic);
+       test_bredrle("Set High Speed on - Invalid parameters 1",
+                               &set_hs_on_invalid_param_test_1,
+                               setup_ssp, test_command_generic);
+       test_bredrle("Set High Speed on - Invalid parameters 2",
+                               &set_hs_on_invalid_param_test_2,
+                               setup_ssp, test_command_generic);
+       test_bredrle("Set High Speed on - Invalid parameters 3",
+                               &set_hs_on_invalid_param_test_3,
+                               setup_ssp, test_command_generic);
+       test_bredrle("Set High Speed on - Invalid index",
+                               &set_hs_on_invalid_index_test,
+                               setup_ssp, test_command_generic);
+
+       test_bredrle("Set Low Energy on - Success 1",
+                               &set_le_on_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set Low Energy on - Success 2",
+                               &set_le_on_success_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set Low Energy on - Success 3",
+                               &set_le_on_success_test_3,
+                               setup_le, test_command_generic);
+       test_bredrle("Set Low Energy on - Invalid parameters 1",
+                               &set_le_on_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set Low Energy on - Invalid parameters 2",
+                               &set_le_on_invalid_param_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Set Low Energy on - Invalid parameters 3",
+                               &set_le_on_invalid_param_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Set Low Energy on - Invalid index",
+                               &set_le_on_invalid_index_test,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set Advertising on - Success 1",
+                               &set_adv_on_success_test_1,
+                               setup_le, test_command_generic);
+       test_bredrle("Set Advertising on - Success 2",
+                               &set_adv_on_success_test_2,
+                               setup_le_powered, test_command_generic);
+       test_bredrle("Set Advertising on - Rejected 1",
+                               &set_adv_on_rejected_test_1,
+                               setup_powered, test_command_generic);
+
+       test_bredrle("Set BR/EDR off - Success 1",
+                               &set_bredr_off_success_test_1,
+                               setup_le, test_command_generic);
+       test_bredrle("Set BR/EDR on - Success 1",
+                               &set_bredr_on_success_test_1,
+                               setup_le_nobr, test_command_generic);
+       test_bredrle("Set BR/EDR on - Success 2",
+                               &set_bredr_on_success_test_2,
+                               setup_le_nobr_powered, test_command_generic);
+       test_bredr("Set BR/EDR off - Not Supported 1",
+                               &set_bredr_off_notsupp_test,
+                               NULL, test_command_generic);
+       test_le("Set BR/EDR off - Not Supported 2",
+                               &set_bredr_off_notsupp_test,
+                               NULL, test_command_generic);
+       test_bredrle("Set BR/EDR off - Rejected 1",
+                               &set_bredr_off_failure_test_1,
+                               setup_le_powered, test_command_generic);
+       test_bredrle("Set BR/EDR off - Rejected 2",
+                               &set_bredr_off_failure_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set BR/EDR off - Invalid Parameters 1",
+                               &set_bredr_off_failure_test_3,
+                               setup_le, test_command_generic);
+
+       test_bredr("Set Local Name - Success 1",
+                               &set_local_name_test_1,
+                               NULL, test_command_generic);
+       test_bredr("Set Local Name - Success 2",
+                               &set_local_name_test_2,
+                               setup_powered, test_command_generic);
+       test_bredr("Set Local Name - Success 3",
+                               &set_local_name_test_3,
+                               setup_ssp_powered, test_command_generic);
+
+       test_bredrle("Start Discovery - Not powered 1",
+                               &start_discovery_not_powered_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Start Discovery - Invalid parameters 1",
+                               &start_discovery_invalid_param_test_1,
+                               setup_powered, test_command_generic);
+       test_bredrle("Start Discovery - Not supported 1",
+                               &start_discovery_not_supported_test_1,
+                               setup_powered, test_command_generic);
+       test_bredrle("Start Discovery - Success 1",
+                               &start_discovery_valid_param_test_1,
+                               setup_le_powered, test_command_generic);
+       test_le("Start Discovery - Success 2",
+                               &start_discovery_valid_param_test_2,
+                               setup_powered, test_command_generic);
+
+       test_bredrle("Stop Discovery - Success 1",
+                               &stop_discovery_success_test_1,
+                               setup_start_discovery, test_command_generic);
+       test_bredr("Stop Discovery - BR/EDR (Inquiry) Success 1",
+                               &stop_discovery_bredr_success_test_1,
+                               setup_start_discovery, test_command_generic);
+       test_bredrle("Stop Discovery - Rejected 1",
+                               &stop_discovery_rejected_test_1,
+                               setup_le_powered, test_command_generic);
+       test_bredrle("Stop Discovery - Invalid parameters 1",
+                               &stop_discovery_invalid_param_test_1,
+                               setup_start_discovery, test_command_generic);
+
+       test_bredrle("Set Device Class - Success 1",
+                               &set_dev_class_valid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Set Device Class - Success 2",
+                               &set_dev_class_valid_param_test_2,
+                               setup_powered, test_command_generic);
+       test_bredrle("Set Device Class - Invalid parameters 1",
+                               &set_dev_class_invalid_param_test_1,
+                               NULL, test_command_generic);
+
+       test_bredrle("Add UUID - UUID-16 1",
+                               &add_uuid16_test_1,
+                               setup_ssp_powered, test_command_generic);
+       test_bredrle("Add UUID - UUID-16 multiple 1",
+                               &add_multi_uuid16_test_1,
+                               setup_multi_uuid16, test_command_generic);
+       test_bredrle("Add UUID - UUID-16 partial 1",
+                               &add_multi_uuid16_test_2,
+                               setup_multi_uuid16_2, test_command_generic);
+       test_bredrle("Add UUID - UUID-32 1",
+                               &add_uuid32_test_1,
+                               setup_ssp_powered, test_command_generic);
+       test_bredrle("Add UUID - UUID-32 multiple 1",
+                               &add_uuid32_multi_test_1,
+                               setup_multi_uuid32, test_command_generic);
+       test_bredrle("Add UUID - UUID-32 partial 1",
+                               &add_uuid32_multi_test_2,
+                               setup_multi_uuid32_2, test_command_generic);
+       test_bredrle("Add UUID - UUID-128 1",
+                               &add_uuid128_test_1,
+                               setup_ssp_powered, test_command_generic);
+       test_bredrle("Add UUID - UUID-128 multiple 1",
+                               &add_uuid128_multi_test_1,
+                               setup_multi_uuid128, test_command_generic);
+       test_bredrle("Add UUID - UUID-128 partial 1",
+                               &add_uuid128_multi_test_2,
+                               setup_multi_uuid128_2, test_command_generic);
+       test_bredrle("Add UUID - UUID mix",
+                               &add_uuid_mix_test_1,
+                               setup_uuid_mix, test_command_generic);
+
+       test_bredrle("Load Link Keys - Empty List Success 1",
+                               &load_link_keys_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Load Link Keys - Empty List Success 2",
+                               &load_link_keys_success_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Load Link Keys - Invalid Parameters 1",
+                               &load_link_keys_invalid_params_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Load Link Keys - Invalid Parameters 2",
+                               &load_link_keys_invalid_params_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Load Link Keys - Invalid Parameters 3",
+                               &load_link_keys_invalid_params_test_3,
+                               NULL, test_command_generic);
+
+       test_bredrle("Load Long Term Keys - Success 1",
+                               &load_ltks_success_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Load Long Term Keys - Invalid Parameters 1",
+                               &load_ltks_invalid_params_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Load Long Term Keys - Invalid Parameters 2",
+                               &load_ltks_invalid_params_test_2,
+                               NULL, test_command_generic);
+       test_bredrle("Load Long Term Keys - Invalid Parameters 3",
+                               &load_ltks_invalid_params_test_3,
+                               NULL, test_command_generic);
+       test_bredrle("Load Long Term Keys - Invalid Parameters 4",
+                               &load_ltks_invalid_params_test_4,
+                               NULL, test_command_generic);
+
+       test_bredrle("Pair Device - Not Powered 1",
+                               &pair_device_not_powered_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Pair Device - Invalid Parameters 1",
+                               &pair_device_invalid_param_test_1,
+                               NULL, test_command_generic);
+
+       test_bredrle("Unpair Device - Not Powered 1",
+                               &unpair_device_not_powered_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Unpair Device - Invalid Parameters 1",
+                               &unpair_device_invalid_param_test_1,
+                               NULL, test_command_generic);
+       test_bredrle("Unpair Device - Invalid Parameters 2",
+                               &unpair_device_invalid_param_test_2,
+                               NULL, test_command_generic);
+
+       test_bredrle("Disconnect - Invalid Parameters 1",
+                               &disconnect_invalid_param_test_1,
+                               NULL, test_command_generic);
+
+       test_bredrle("Block Device - Invalid Parameters 1",
+                               &block_device_invalid_param_test_1,
+                               NULL, test_command_generic);
+
+       test_bredrle("Unblock Device - Invalid Parameters 1",
+                               &unblock_device_invalid_param_test_1,
+                               NULL, test_command_generic);
+
+       test_bredrle("Set Static Address - Success",
+                               &set_static_addr_success_test,
+                               NULL, test_command_generic);
+       test_bredrle("Set Static Address - Failure",
+                               &set_static_addr_failure_test,
+                               setup_powered, test_command_generic);
+
+       test_bredrle("Set Scan Parameters - Success",
+                               &set_scan_params_success_test,
+                               NULL, test_command_generic);
+
+       return tester_run();
+}
diff --git a/tools/mpris-player.c b/tools/mpris-player.c
new file mode 100644 (file)
index 0000000..c94330c
--- /dev/null
@@ -0,0 +1,2593 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <getopt.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include <dbus/dbus.h>
+#include <glib.h>
+#include <gdbus/gdbus.h>
+
+#define BLUEZ_BUS_NAME "org.bluez"
+#define BLUEZ_PATH "/org/bluez"
+#define BLUEZ_ADAPTER_INTERFACE "org.bluez.Adapter1"
+#define BLUEZ_MEDIA_INTERFACE "org.bluez.Media1"
+#define BLUEZ_MEDIA_PLAYER_INTERFACE "org.bluez.MediaPlayer1"
+#define BLUEZ_MEDIA_FOLDER_INTERFACE "org.bluez.MediaFolder1"
+#define BLUEZ_MEDIA_ITEM_INTERFACE "org.bluez.MediaItem1"
+#define BLUEZ_MEDIA_TRANSPORT_INTERFACE "org.bluez.MediaTransport1"
+#define MPRIS_BUS_NAME "org.mpris.MediaPlayer2."
+#define MPRIS_INTERFACE "org.mpris.MediaPlayer2"
+#define MPRIS_PLAYER_INTERFACE "org.mpris.MediaPlayer2.Player"
+#define MPRIS_TRACKLIST_INTERFACE "org.mpris.MediaPlayer2.TrackList"
+#define MPRIS_PLAYLISTS_INTERFACE "org.mpris.MediaPlayer2.Playlists"
+#define MPRIS_PLAYER_PATH "/org/mpris/MediaPlayer2"
+#define ERROR_INTERFACE "org.mpris.MediaPlayer2.Error"
+
+static GMainLoop *main_loop;
+static GDBusProxy *adapter = NULL;
+static DBusConnection *sys = NULL;
+static DBusConnection *session = NULL;
+static GDBusClient *client = NULL;
+static GSList *players = NULL;
+static GSList *transports = NULL;
+
+static gboolean option_version = FALSE;
+static gboolean option_export = FALSE;
+
+struct tracklist {
+       GDBusProxy *proxy;
+       GSList *items;
+};
+
+struct player {
+       char *bus_name;
+       DBusConnection *conn;
+       GDBusProxy *proxy;
+       GDBusProxy *folder;
+       GDBusProxy *device;
+       GDBusProxy *transport;
+       GDBusProxy *playlist;
+       struct tracklist *tracklist;
+};
+
+typedef int (* parse_metadata_func) (DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata);
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
+                                                               void *val);
+
+static void sig_term(int sig)
+{
+       g_main_loop_quit(main_loop);
+}
+
+static DBusMessage *get_all(DBusConnection *conn, const char *name)
+{
+       DBusMessage *msg, *reply;
+       DBusError err;
+       const char *iface = MPRIS_PLAYER_INTERFACE;
+
+       msg = dbus_message_new_method_call(name, MPRIS_PLAYER_PATH,
+                                       DBUS_INTERFACE_PROPERTIES, "GetAll");
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return NULL;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &iface,
+                                       DBUS_TYPE_INVALID);
+
+       dbus_error_init(&err);
+
+       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+       dbus_message_unref(msg);
+
+       if (!reply) {
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               return NULL;
+       }
+
+       return reply;
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+       DBusMessageIter value;
+       char sig[2] = { type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+       dbus_message_iter_append_basic(&value, type, val);
+
+       dbus_message_iter_close_container(iter, &value);
+}
+
+static void append_array_variant(DBusMessageIter *iter, int type, void *val,
+                                                       int n_elements)
+{
+       DBusMessageIter variant, array;
+       char type_sig[2] = { type, '\0' };
+       char array_sig[3] = { DBUS_TYPE_ARRAY, type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT,
+                                               array_sig, &variant);
+
+       dbus_message_iter_open_container(&variant, DBUS_TYPE_ARRAY,
+                                               type_sig, &array);
+
+       if (dbus_type_is_fixed(type) == TRUE) {
+               dbus_message_iter_append_fixed_array(&array, type, val,
+                                                       n_elements);
+       } else if (type == DBUS_TYPE_STRING || type == DBUS_TYPE_OBJECT_PATH) {
+               const char ***str_array = val;
+               int i;
+
+               for (i = 0; i < n_elements; i++)
+                       dbus_message_iter_append_basic(&array, type,
+                                                       &((*str_array)[i]));
+       }
+
+       dbus_message_iter_close_container(&variant, &array);
+
+       dbus_message_iter_close_container(iter, &variant);
+}
+
+static void dict_append_array(DBusMessageIter *dict, const char *key, int type,
+                       void *val, int n_elements)
+{
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                               NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_array_variant(&entry, type, val, n_elements);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static void append_basic(DBusMessageIter *base, DBusMessageIter *iter,
+                                                               int type)
+{
+       const void *value;
+
+       dbus_message_iter_get_basic(iter, &value);
+       dbus_message_iter_append_basic(base, type, &value);
+}
+
+static void append_iter(DBusMessageIter *base, DBusMessageIter *iter);
+static void append_container(DBusMessageIter *base, DBusMessageIter *iter,
+                                                               int type)
+{
+       DBusMessageIter iter_sub, base_sub;
+       char *sig;
+
+       dbus_message_iter_recurse(iter, &iter_sub);
+
+       switch (type) {
+       case DBUS_TYPE_ARRAY:
+       case DBUS_TYPE_VARIANT:
+               sig = dbus_message_iter_get_signature(&iter_sub);
+               break;
+       default:
+               sig = NULL;
+               break;
+       }
+
+       dbus_message_iter_open_container(base, type, sig, &base_sub);
+
+       if (sig != NULL)
+               dbus_free(sig);
+
+       append_iter(&base_sub, &iter_sub);
+
+       dbus_message_iter_close_container(base, &base_sub);
+}
+
+static void append_iter(DBusMessageIter *base, DBusMessageIter *iter)
+{
+       int type;
+
+       while ((type = dbus_message_iter_get_arg_type(iter)) !=
+                                                       DBUS_TYPE_INVALID) {
+               if (dbus_type_is_basic(type))
+                       append_basic(base, iter, type);
+               else if (dbus_type_is_container(type))
+                       append_container(base, iter, type);
+
+               dbus_message_iter_next(iter);
+       }
+}
+
+static void dict_append_iter(DBusMessageIter *dict, const char *key,
+                                               DBusMessageIter *iter)
+{
+       DBusMessageIter entry;
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                               NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_iter(&entry, iter);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static int parse_metadata_entry(DBusMessageIter *entry, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+               return -EINVAL;
+
+       dict_append_iter(metadata, key, entry);
+
+       return 0;
+}
+
+static int parse_metadata(DBusMessageIter *args, DBusMessageIter *metadata,
+                                               parse_metadata_func func)
+{
+       DBusMessageIter dict;
+       int ctype;
+
+       ctype = dbus_message_iter_get_arg_type(args);
+       if (ctype != DBUS_TYPE_ARRAY)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(args, &dict);
+
+       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+                                                       DBUS_TYPE_INVALID) {
+               DBusMessageIter entry;
+               const char *key;
+
+               if (ctype != DBUS_TYPE_DICT_ENTRY)
+                       return -EINVAL;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       return -EINVAL;
+
+               dbus_message_iter_get_basic(&entry, &key);
+               dbus_message_iter_next(&entry);
+
+               if (func(&entry, key, metadata) < 0)
+                       return -EINVAL;
+
+               dbus_message_iter_next(&dict);
+       }
+
+       return 0;
+}
+
+static void append_metadata(DBusMessageIter *iter, DBusMessageIter *dict,
+                                               parse_metadata_func func)
+{
+       DBusMessageIter value, metadata;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, "a{sv}",
+                                                               &value);
+
+       dbus_message_iter_open_container(&value, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+       parse_metadata(dict, &metadata, func);
+
+       dbus_message_iter_close_container(&value, &metadata);
+       dbus_message_iter_close_container(iter, &value);
+}
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
+                                                               void *val)
+{
+       DBusMessageIter entry;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) val);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       if (strcasecmp(key, "Metadata") == 0)
+               append_metadata(&entry, val, parse_metadata_entry);
+       else
+               append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static char *sender2path(const char *sender)
+{
+       char *path;
+
+       path = g_strconcat("/", sender, NULL);
+       return g_strdelimit(path, ":.", '_');
+}
+
+static void copy_reply(DBusPendingCall *call, void *user_data)
+{
+       DBusMessage *msg = user_data;
+       DBusMessage *reply = dbus_pending_call_steal_reply(call);
+       DBusMessage *copy;
+       DBusMessageIter args, iter;
+
+       copy = dbus_message_new_method_return(msg);
+       if (copy == NULL) {
+               dbus_message_unref(reply);
+               return;
+       }
+
+       dbus_message_iter_init_append(copy, &iter);
+
+       if (!dbus_message_iter_init(reply, &args))
+               goto done;
+
+       append_iter(&iter, &args);
+
+       dbus_connection_send(sys, copy, NULL);
+
+done:
+       dbus_message_unref(copy);
+       dbus_message_unref(reply);
+}
+
+static DBusHandlerResult player_message(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       char *owner = data;
+       DBusMessage *copy;
+       DBusMessageIter args, iter;
+       DBusPendingCall *call;
+
+       dbus_message_iter_init(msg, &args);
+
+       copy = dbus_message_new_method_call(owner,
+                                       MPRIS_PLAYER_PATH,
+                                       dbus_message_get_interface(msg),
+                                       dbus_message_get_member(msg));
+       if (copy == NULL)
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       dbus_message_iter_init_append(copy, &iter);
+       append_iter(&iter, &args);
+
+       if (!dbus_connection_send_with_reply(session, copy, &call, -1))
+               goto done;
+
+       dbus_message_ref(msg);
+       dbus_pending_call_set_notify(call, copy_reply, msg, NULL);
+       dbus_pending_call_unref(call);
+
+done:
+       dbus_message_unref(copy);
+
+       return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+}
+
+static struct player *find_player_by_bus_name(const char *name)
+{
+       GSList *l;
+
+       for (l = players; l; l = l->next) {
+               struct player *player = l->data;
+
+               if (strcmp(player->bus_name, name) == 0)
+                       return player;
+       }
+
+       return NULL;
+}
+
+static const DBusObjectPathVTable player_table = {
+       .message_function = player_message,
+};
+
+static void add_player(DBusConnection *conn, const char *name,
+                                                       const char *sender)
+{
+       DBusMessage *reply = NULL;
+       DBusMessage *msg;
+       DBusMessageIter iter, args;
+       DBusError err;
+       char *path, *owner;
+       struct player *player;
+
+       if (!adapter)
+               return;
+
+       player = find_player_by_bus_name(name);
+       if (player == NULL) {
+               reply = get_all(conn, name);
+               if (reply == NULL)
+                       return;
+               dbus_message_iter_init(reply, &args);
+       }
+
+       msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
+                                       g_dbus_proxy_get_path(adapter),
+                                       BLUEZ_MEDIA_INTERFACE,
+                                       "RegisterPlayer");
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return;
+       }
+
+       path = sender2path(sender);
+       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+       if (owner != NULL)
+               goto done;
+
+       dbus_message_iter_init_append(msg, &iter);
+
+       dbus_message_iter_append_basic(&iter, DBUS_TYPE_OBJECT_PATH, &path);
+
+       if (player != NULL) {
+               if (!g_dbus_get_properties(player->conn,
+                                               MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE,
+                                               &iter))
+                       goto done;
+       } else {
+               append_iter(&iter, &args);
+               dbus_message_unref(reply);
+       }
+
+       dbus_error_init(&err);
+
+       owner = strdup(sender);
+
+       if (!dbus_connection_register_object_path(sys, path, &player_table,
+                                                               owner)) {
+               fprintf(stderr, "Can't register object path for player\n");
+               free(owner);
+               goto done;
+       }
+
+       reply = dbus_connection_send_with_reply_and_block(sys, msg, -1, &err);
+       if (!reply) {
+               fprintf(stderr, "Can't register player\n");
+               free(owner);
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+       }
+
+done:
+       if (reply)
+               dbus_message_unref(reply);
+       dbus_message_unref(msg);
+       g_free(path);
+}
+
+static void remove_player(DBusConnection *conn, const char *sender)
+{
+       DBusMessage *msg;
+       char *path, *owner;
+
+       if (!adapter)
+               return;
+
+       path = sender2path(sender);
+       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+       if (owner == NULL) {
+               g_free(path);
+               return;
+       }
+
+       msg = dbus_message_new_method_call(BLUEZ_BUS_NAME,
+                                       g_dbus_proxy_get_path(adapter),
+                                       BLUEZ_MEDIA_INTERFACE,
+                                       "UnregisterPlayer");
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               g_free(path);
+               return;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID);
+
+       dbus_connection_send(sys, msg, NULL);
+
+       dbus_connection_unregister_object_path(sys, path);
+
+       dbus_message_unref(msg);
+       g_free(path);
+       g_free(owner);
+}
+
+static gboolean player_signal(DBusConnection *conn, DBusMessage *msg,
+                                                               void *user_data)
+{
+       DBusMessage *signal;
+       DBusMessageIter iter, args;
+       char *path, *owner;
+
+       dbus_message_iter_init(msg, &iter);
+
+       path = sender2path(dbus_message_get_sender(msg));
+       dbus_connection_get_object_path_data(sys, path, (void **) &owner);
+
+       if (owner == NULL)
+               goto done;
+
+       signal = dbus_message_new_signal(path, dbus_message_get_interface(msg),
+                                               dbus_message_get_member(msg));
+       if (signal == NULL) {
+               fprintf(stderr, "Unable to allocate new %s.%s signal",
+                                               dbus_message_get_interface(msg),
+                                               dbus_message_get_member(msg));
+               goto done;
+       }
+
+       dbus_message_iter_init_append(signal, &args);
+
+       append_iter(&args, &iter);
+
+       dbus_connection_send(sys, signal, NULL);
+       dbus_message_unref(signal);
+
+done:
+       g_free(path);
+
+       return TRUE;
+}
+
+static gboolean name_owner_changed(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       const char *name, *old, *new;
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_STRING, &name,
+                                       DBUS_TYPE_STRING, &old,
+                                       DBUS_TYPE_STRING, &new,
+                                       DBUS_TYPE_INVALID)) {
+               fprintf(stderr, "Invalid arguments for NameOwnerChanged signal");
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+       }
+
+       if (!g_str_has_prefix(name, "org.mpris"))
+               return DBUS_HANDLER_RESULT_NOT_YET_HANDLED;
+
+       if (*new == '\0') {
+               printf("player %s at %s disappear\n", name, old);
+               remove_player(conn, old);
+       } else if (option_export || find_player_by_bus_name(name) == NULL) {
+               printf("player %s at %s found\n", name, new);
+               add_player(conn, name, new);
+       }
+
+       return TRUE;
+}
+
+static char *get_name_owner(DBusConnection *conn, const char *name)
+{
+       DBusMessage *msg, *reply;
+       DBusError err;
+       char *owner;
+
+       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+                                       DBUS_INTERFACE_DBUS, "GetNameOwner");
+
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return NULL;
+       }
+
+       dbus_message_append_args(msg, DBUS_TYPE_STRING, &name,
+                                                       DBUS_TYPE_INVALID);
+
+       dbus_error_init(&err);
+
+       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+       dbus_message_unref(msg);
+
+       if (!reply) {
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               return NULL;
+       }
+
+       if (!dbus_message_get_args(reply, NULL,
+                                       DBUS_TYPE_STRING, &owner,
+                                       DBUS_TYPE_INVALID)) {
+               dbus_message_unref(reply);
+               return NULL;
+       }
+
+       owner = g_strdup(owner);
+
+       dbus_message_unref(reply);
+
+       dbus_connection_flush(conn);
+
+       return owner;
+}
+
+static void parse_list_names(DBusConnection *conn, DBusMessageIter *args)
+{
+       DBusMessageIter array;
+       int ctype;
+
+       ctype = dbus_message_iter_get_arg_type(args);
+       if (ctype != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(args, &array);
+
+       while ((ctype = dbus_message_iter_get_arg_type(&array)) !=
+                                                       DBUS_TYPE_INVALID) {
+               const char *name;
+               char *owner;
+
+               if (ctype != DBUS_TYPE_STRING)
+                       goto next;
+
+               dbus_message_iter_get_basic(&array, &name);
+
+               if (!g_str_has_prefix(name, "org.mpris"))
+                       goto next;
+
+               owner = get_name_owner(conn, name);
+
+               if (owner == NULL)
+                       goto next;
+
+               printf("player %s at %s found\n", name, owner);
+
+               add_player(conn, name, owner);
+
+               g_free(owner);
+next:
+               dbus_message_iter_next(&array);
+       }
+}
+
+static void list_names(DBusConnection *conn)
+{
+       DBusMessage *msg, *reply;
+       DBusMessageIter iter;
+       DBusError err;
+
+       msg = dbus_message_new_method_call(DBUS_SERVICE_DBUS, DBUS_PATH_DBUS,
+                                       DBUS_INTERFACE_DBUS, "ListNames");
+
+       if (!msg) {
+               fprintf(stderr, "Can't allocate new method call\n");
+               return;
+       }
+
+       dbus_error_init(&err);
+
+       reply = dbus_connection_send_with_reply_and_block(conn, msg, -1, &err);
+
+       dbus_message_unref(msg);
+
+       if (!reply) {
+               if (dbus_error_is_set(&err)) {
+                       fprintf(stderr, "%s\n", err.message);
+                       dbus_error_free(&err);
+               }
+               return;
+       }
+
+       dbus_message_iter_init(reply, &iter);
+
+       parse_list_names(conn, &iter);
+
+       dbus_message_unref(reply);
+
+       dbus_connection_flush(conn);
+}
+
+static void usage(void)
+{
+       printf("Bluetooth mpris-player ver %s\n\n", VERSION);
+
+       printf("Usage:\n");
+}
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { "export", 'e', 0, G_OPTION_ARG_NONE, &option_export,
+                               "Export remote players" },
+       { NULL },
+};
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       printf("org.bluez appeared\n");
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       printf("org.bluez disappeared\n");
+}
+
+static void unregister_tracklist(struct player *player)
+{
+       struct tracklist *tracklist = player->tracklist;
+
+       g_slist_free(tracklist->items);
+       g_dbus_proxy_unref(tracklist->proxy);
+       g_free(tracklist);
+       player->tracklist = NULL;
+}
+
+static void player_free(void *data)
+{
+       struct player *player = data;
+
+       if (player->tracklist != NULL)
+               unregister_tracklist(player);
+
+       if (player->conn) {
+               dbus_connection_close(player->conn);
+               dbus_connection_unref(player->conn);
+       }
+
+       g_dbus_proxy_unref(player->device);
+       g_dbus_proxy_unref(player->proxy);
+
+       if (player->transport)
+               g_dbus_proxy_unref(player->transport);
+
+       if (player->playlist)
+               g_dbus_proxy_unref(player->playlist);
+
+       g_free(player->bus_name);
+       g_free(player);
+}
+
+struct pending_call {
+       struct player *player;
+       DBusMessage *msg;
+};
+
+static void pending_call_free(void *data)
+{
+       struct pending_call *p = data;
+
+       if (p->msg)
+               dbus_message_unref(p->msg);
+
+       g_free(p);
+}
+
+static void player_reply(DBusMessage *message, void *user_data)
+{
+       struct pending_call *p = user_data;
+       struct player *player = p->player;
+       DBusMessage *msg = p->msg;
+       DBusMessage *reply;
+       DBusError err;
+
+       dbus_error_init(&err);
+       if (dbus_set_error_from_message(&err, message)) {
+               fprintf(stderr, "error: %s", err.name);
+               reply = g_dbus_create_error(msg, err.name, "%s", err.message);
+               dbus_error_free(&err);
+       } else
+               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+       g_dbus_send_message(player->conn, reply);
+}
+
+static void player_control(struct player *player, DBusMessage *msg,
+                                                       const char *name)
+{
+       struct pending_call *p;
+
+       p = g_new0(struct pending_call, 1);
+       p->player = player;
+       p->msg = dbus_message_ref(msg);
+
+       g_dbus_proxy_method_call(player->proxy, name, NULL, player_reply,
+                                               p, pending_call_free);
+}
+
+static const char *status_to_playback(const char *status)
+{
+       if (strcasecmp(status, "playing") == 0)
+               return "Playing";
+       else if (strcasecmp(status, "paused") == 0)
+               return "Paused";
+       else
+               return "Stopped";
+}
+
+static const char *player_get_status(struct player *player)
+{
+       const char *status;
+       DBusMessageIter value;
+
+       if (g_dbus_proxy_get_property(player->proxy, "Status", &value)) {
+               dbus_message_iter_get_basic(&value, &status);
+               return status_to_playback(status);
+       }
+
+       if (player->transport == NULL)
+               goto done;
+
+       if (!g_dbus_proxy_get_property(player->transport, "State", &value))
+               goto done;
+
+       dbus_message_iter_get_basic(&value, &status);
+
+       if (strcasecmp(status, "active") == 0)
+               return "Playing";
+
+done:
+       return "Stopped";
+}
+
+static DBusMessage *player_toggle(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+       const char *status;
+
+       status = player_get_status(player);
+
+       if (strcasecmp(status, "Playing") == 0)
+               player_control(player, msg, "Pause");
+       else
+               player_control(player, msg, "Play");
+
+       return NULL;
+}
+
+static DBusMessage *player_play(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+
+       player_control(player, msg, "Play");
+
+       return NULL;
+}
+
+static DBusMessage *player_pause(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+
+       player_control(player, msg, "Pause");
+
+       return NULL;
+}
+
+static DBusMessage *player_stop(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+
+       player_control(player, msg, "Stop");
+
+       return NULL;
+}
+
+static DBusMessage *player_next(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+
+       player_control(player, msg, "Next");
+
+       return NULL;
+}
+
+static DBusMessage *player_previous(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+
+       player_control(player, msg, "Previous");
+
+       return NULL;
+}
+
+static gboolean status_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct player *player = data;
+
+       return player_get_status(player) != NULL;
+}
+
+static gboolean get_status(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       const char *status;
+
+       status = player_get_status(player);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+       return TRUE;
+}
+
+static gboolean repeat_exists(const GDBusPropertyTable *property, void *data)
+{
+       DBusMessageIter iter;
+       struct player *player = data;
+
+       return g_dbus_proxy_get_property(player->proxy, "Repeat", &iter);
+}
+
+static const char *repeat_to_loopstatus(const char *value)
+{
+       if (strcasecmp(value, "off") == 0)
+               return "None";
+       else if (strcasecmp(value, "singletrack") == 0)
+               return "Track";
+       else if (strcasecmp(value, "alltracks") == 0)
+               return "Playlist";
+
+       return NULL;
+}
+
+static gboolean get_repeat(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter value;
+       const char *status;
+
+       if (!g_dbus_proxy_get_property(player->proxy, "Repeat", &value))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&value, &status);
+
+       status = repeat_to_loopstatus(status);
+       if (status == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &status);
+
+       return TRUE;
+}
+
+static const char *loopstatus_to_repeat(const char *value)
+{
+       if (strcasecmp(value, "None") == 0)
+               return "off";
+       else if (strcasecmp(value, "Track") == 0)
+               return "singletrack";
+       else if (strcasecmp(value, "Playlist") == 0)
+               return "alltracks";
+
+       return NULL;
+}
+
+static void property_result(const DBusError *err, void *user_data)
+{
+       GDBusPendingPropertySet id = GPOINTER_TO_UINT(user_data);
+
+       if (!dbus_error_is_set(err))
+               return g_dbus_pending_property_success(id);
+
+       g_dbus_pending_property_error(id, err->name, err->message);
+}
+
+static void set_repeat(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       struct player *player = data;
+       const char *value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       value = loopstatus_to_repeat(value);
+       if (value == NULL) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       g_dbus_proxy_set_property_basic(player->proxy, "Repeat",
+                                       DBUS_TYPE_STRING, &value,
+                                       property_result, GUINT_TO_POINTER(id),
+                                       NULL);
+}
+
+static gboolean get_double(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       double value = 1.0;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+       return TRUE;
+}
+
+static gboolean shuffle_exists(const GDBusPropertyTable *property, void *data)
+{
+       DBusMessageIter iter;
+       struct player *player = data;
+
+       return g_dbus_proxy_get_property(player->proxy, "Shuffle", &iter);
+}
+
+static gboolean get_shuffle(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter value;
+       const char *string;
+       dbus_bool_t shuffle;
+
+       if (!g_dbus_proxy_get_property(player->proxy, "Shuffle", &value))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&value, &string);
+
+       shuffle = strcmp(string, "off") != 0;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &shuffle);
+
+       return TRUE;
+}
+
+static void set_shuffle(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       struct player *player = data;
+       dbus_bool_t shuffle;
+       const char *value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_BOOLEAN) {
+               g_dbus_pending_property_error(id,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments in method call");
+               return;
+       }
+
+       dbus_message_iter_get_basic(iter, &shuffle);
+       value = shuffle ? "alltracks" : "off";
+
+       g_dbus_proxy_set_property_basic(player->proxy, "Shuffle",
+                                       DBUS_TYPE_STRING, &value,
+                                       property_result, GUINT_TO_POINTER(id),
+                                       NULL);
+}
+
+static gboolean position_exists(const GDBusPropertyTable *property, void *data)
+{
+       DBusMessageIter iter;
+       struct player *player = data;
+
+       return g_dbus_proxy_get_property(player->proxy, "Position", &iter);
+}
+
+static gboolean get_position(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter var;
+       uint32_t position;
+       int64_t value;
+
+       if (!g_dbus_proxy_get_property(player->proxy, "Position", &var))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&var, &position);
+
+       value = position * 1000;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_INT64, &value);
+
+       return TRUE;
+}
+
+static gboolean track_exists(const GDBusPropertyTable *property, void *data)
+{
+       DBusMessageIter iter;
+       struct player *player = data;
+
+       return g_dbus_proxy_get_property(player->proxy, "Track", &iter);
+}
+
+static gboolean parse_string_metadata(DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       const char *value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       dict_append_entry(metadata, key, DBUS_TYPE_STRING, &value);
+
+       return TRUE;
+}
+
+static gboolean parse_array_metadata(DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       char **value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_STRING)
+               return FALSE;
+
+       value = dbus_malloc0(sizeof(char *));
+
+       dbus_message_iter_get_basic(iter, &(value[0]));
+
+       dict_append_array(metadata, key, DBUS_TYPE_STRING, &value, 1);
+
+       dbus_free(value);
+
+       return TRUE;
+}
+
+static gboolean parse_int64_metadata(DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       uint32_t duration;
+       int64_t value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &duration);
+
+       value = duration * 1000;
+
+       dict_append_entry(metadata, key, DBUS_TYPE_INT64, &value);
+
+       return TRUE;
+}
+
+static gboolean parse_int32_metadata(DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       uint32_t value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_UINT32)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       dict_append_entry(metadata, key, DBUS_TYPE_INT32, &value);
+
+       return TRUE;
+}
+
+static gboolean parse_path_metadata(DBusMessageIter *iter, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       const char *value;
+
+       if (dbus_message_iter_get_arg_type(iter) != DBUS_TYPE_OBJECT_PATH)
+               return FALSE;
+
+       dbus_message_iter_get_basic(iter, &value);
+
+       dict_append_entry(metadata, key, DBUS_TYPE_OBJECT_PATH, &value);
+
+       return TRUE;
+}
+
+static int parse_track_entry(DBusMessageIter *entry, const char *key,
+                                               DBusMessageIter *metadata)
+{
+       DBusMessageIter var;
+
+       if (dbus_message_iter_get_arg_type(entry) != DBUS_TYPE_VARIANT)
+               return -EINVAL;
+
+       dbus_message_iter_recurse(entry, &var);
+
+       if (strcasecmp(key, "Title") == 0) {
+               if (!parse_string_metadata(&var, "xesam:title", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "Artist") == 0) {
+               if (!parse_array_metadata(&var, "xesam:artist", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "Album") == 0) {
+               if (!parse_string_metadata(&var, "xesam:album", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "Genre") == 0) {
+               if (!parse_array_metadata(&var, "xesam:genre", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "Duration") == 0) {
+               if (!parse_int64_metadata(&var, "mpris:length", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "TrackNumber") == 0) {
+               if (!parse_int32_metadata(&var, "xesam:trackNumber", metadata))
+                       return -EINVAL;
+       } else if (strcasecmp(key, "Item") == 0) {
+               if (!parse_path_metadata(&var, "mpris:trackid", metadata))
+                       return -EINVAL;
+       }
+
+       return 0;
+}
+
+static gboolean get_track(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter var, metadata;
+
+       if (!g_dbus_proxy_get_property(player->proxy, "Track", &var))
+               return FALSE;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+       parse_metadata(&var, &metadata, parse_track_entry);
+
+       dbus_message_iter_close_container(iter, &metadata);
+
+       return TRUE;
+}
+
+static gboolean get_enable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       dbus_bool_t value = TRUE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+
+static gboolean get_volume(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       double value = 0.0;
+       uint16_t volume;
+       DBusMessageIter var;
+
+       if (player->transport == NULL)
+               goto done;
+
+       if (!g_dbus_proxy_get_property(player->transport, "Volume", &var))
+               goto done;
+
+       dbus_message_iter_get_basic(&var, &volume);
+
+       value = (double) volume / 127;
+
+done:
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_DOUBLE, &value);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable player_methods[] = {
+       { GDBUS_ASYNC_METHOD("PlayPause", NULL, NULL, player_toggle) },
+       { GDBUS_ASYNC_METHOD("Play", NULL, NULL, player_play) },
+       { GDBUS_ASYNC_METHOD("Pause", NULL, NULL, player_pause) },
+       { GDBUS_ASYNC_METHOD("Stop", NULL, NULL, player_stop) },
+       { GDBUS_ASYNC_METHOD("Next", NULL, NULL, player_next) },
+       { GDBUS_ASYNC_METHOD("Previous", NULL, NULL, player_previous) },
+       { }
+};
+
+static const GDBusSignalTable player_signals[] = {
+       { GDBUS_SIGNAL("Seeked", GDBUS_ARGS({"Position", "x"})) },
+       { }
+};
+
+static const GDBusPropertyTable player_properties[] = {
+       { "PlaybackStatus", "s", get_status, NULL, status_exists },
+       { "LoopStatus", "s", get_repeat, set_repeat, repeat_exists },
+       { "Rate", "d", get_double, NULL, NULL },
+       { "MinimumRate", "d", get_double, NULL, NULL },
+       { "MaximumRate", "d", get_double, NULL, NULL },
+       { "Shuffle", "b", get_shuffle, set_shuffle, shuffle_exists },
+       { "Position", "x", get_position, NULL, position_exists },
+       { "Metadata", "a{sv}", get_track, NULL, track_exists },
+       { "Volume", "d", get_volume, NULL, NULL },
+       { "CanGoNext", "b", get_enable, NULL, NULL },
+       { "CanGoPrevious", "b", get_enable, NULL, NULL },
+       { "CanPlay", "b", get_enable, NULL, NULL },
+       { "CanPause", "b", get_enable, NULL, NULL },
+       { "CanSeek", "b", get_enable, NULL, NULL },
+       { "CanControl", "b", get_enable, NULL, NULL },
+       { }
+};
+
+static gboolean get_disable(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       dbus_bool_t value = FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static gboolean get_name(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter var;
+       const char *alias;
+       char *name;
+
+       if (!g_dbus_proxy_get_property(player->device, "Alias", &var))
+               return FALSE;
+
+       dbus_message_iter_get_basic(&var, &alias);
+
+       if (g_dbus_proxy_get_property(player->proxy, "Name", &var)) {
+               dbus_message_iter_get_basic(&var, &name);
+               name = g_strconcat(alias, " ", name, NULL);
+       } else
+               name = g_strdup(alias);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &name);
+
+       g_free(name);
+
+       return TRUE;
+}
+
+static const GDBusMethodTable mpris_methods[] = {
+       { }
+};
+
+static gboolean get_tracklist(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       dbus_bool_t value;
+
+       value = player->tracklist != NULL ? TRUE : FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable mpris_properties[] = {
+       { "CanQuit", "b", get_disable, NULL, NULL },
+       { "Fullscreen", "b", get_disable, NULL, NULL },
+       { "CanSetFullscreen", "b", get_disable, NULL, NULL },
+       { "CanRaise", "b", get_disable, NULL, NULL },
+       { "HasTrackList", "b", get_tracklist, NULL, NULL },
+       { "Identity", "s", get_name, NULL, NULL },
+       { }
+};
+
+static GDBusProxy *find_item(struct player *player, const char *path)
+{
+       struct tracklist *tracklist = player->tracklist;
+       GSList *l;
+
+       for (l = tracklist->items; l; l = l->next) {
+               GDBusProxy *proxy = l->data;
+               const char *p = g_dbus_proxy_get_path(proxy);
+
+               if (g_str_equal(path, p))
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void append_item_metadata(void *data, void *user_data)
+{
+       GDBusProxy *item = data;
+       DBusMessageIter *iter = user_data;
+       DBusMessageIter var, metadata;
+       const char *path = g_dbus_proxy_get_path(item);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+       dict_append_entry(&metadata, "mpris:trackid", DBUS_TYPE_OBJECT_PATH,
+                                                                       &path);
+
+       if (g_dbus_proxy_get_property(item, "Metadata", &var))
+               parse_metadata(&var, &metadata, parse_track_entry);
+
+       dbus_message_iter_close_container(iter, &metadata);
+
+       return;
+}
+
+static DBusMessage *tracklist_get_metadata(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct player *player = data;
+       DBusMessage *reply;
+       DBusMessageIter args, array;
+       GSList *l = NULL;
+
+       dbus_message_iter_init(msg, &args);
+
+       if (dbus_message_iter_get_arg_type(&args) != DBUS_TYPE_ARRAY)
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       dbus_message_iter_recurse(&args, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) ==
+                                               DBUS_TYPE_OBJECT_PATH) {
+               const char *path;
+               GDBusProxy *item;
+
+               dbus_message_iter_get_basic(&array, &path);
+
+               item = find_item(player, path);
+               if (item == NULL)
+                       return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+               l = g_slist_append(l, item);
+
+               dbus_message_iter_next(&array);
+       }
+
+       reply = dbus_message_new_method_return(msg);
+
+       dbus_message_iter_init_append(reply, &args);
+
+       dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_ARRAY_AS_STRING
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &array);
+
+       g_slist_foreach(l, append_item_metadata, &array);
+
+       dbus_message_iter_close_container(&args, &array);
+
+       return reply;
+}
+
+static void item_play_reply(DBusMessage *message, void *user_data)
+{
+       struct pending_call *p = user_data;
+       struct player *player = p->player;
+       DBusMessage *msg = p->msg;
+       DBusMessage *reply;
+       DBusError err;
+
+       dbus_error_init(&err);
+       if (dbus_set_error_from_message(&err, message)) {
+               fprintf(stderr, "error: %s", err.name);
+               reply = g_dbus_create_error(msg, err.name, "%s", err.message);
+               dbus_error_free(&err);
+       } else
+               reply = g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+
+       g_dbus_send_message(player->conn, reply);
+}
+
+static void item_play(struct player *player, DBusMessage *msg,
+                                                       GDBusProxy *item)
+{
+       struct pending_call *p;
+
+       p = g_new0(struct pending_call, 1);
+       p->player = player;
+       p->msg = dbus_message_ref(msg);
+
+       g_dbus_proxy_method_call(item, "Play", NULL, item_play_reply,
+                                               p, pending_call_free);
+}
+
+static DBusMessage *tracklist_goto(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct player *player = data;
+       GDBusProxy *item;
+       const char *path;
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID))
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments");
+
+       item = find_item(player, path);
+       if (item == NULL)
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid arguments");
+
+       item_play(player, msg, item);
+
+       return NULL;
+}
+
+static DBusMessage *tracklist_add_track(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
+                                       "Not implemented");
+}
+
+static DBusMessage *tracklist_remove_track(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       return g_dbus_create_error(msg, ERROR_INTERFACE ".NotImplemented",
+                                       "Not implemented");
+}
+
+static const GDBusMethodTable tracklist_methods[] = {
+       { GDBUS_METHOD("GetTracksMetadata",
+                       GDBUS_ARGS({ "tracks", "ao" }),
+                       GDBUS_ARGS({ "metadata", "aa{sv}" }),
+                       tracklist_get_metadata) },
+       { GDBUS_METHOD("AddTrack",
+                       GDBUS_ARGS({ "uri", "s" }, { "after", "o" },
+                                               { "current", "b" }),
+                       NULL,
+                       tracklist_add_track) },
+       { GDBUS_METHOD("RemoveTrack",
+                       GDBUS_ARGS({ "track", "o" }), NULL,
+                       tracklist_remove_track) },
+       { GDBUS_ASYNC_METHOD("GoTo",
+                       GDBUS_ARGS({ "track", "o" }), NULL,
+                       tracklist_goto) },
+       { },
+};
+
+static const GDBusSignalTable tracklist_signals[] = {
+       { GDBUS_SIGNAL("TrackAdded", GDBUS_ARGS({"metadata", "a{sv}"},
+                                               {"after", "o"})) },
+       { GDBUS_SIGNAL("TrackRemoved", GDBUS_ARGS({"track", "o"})) },
+       { GDBUS_SIGNAL("TrackMetadataChanged", GDBUS_ARGS({"track", "o"},
+                                               {"metadata", "a{sv}"})) },
+       { }
+};
+
+static gboolean tracklist_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct player *player = data;
+
+       return player->tracklist != NULL;
+}
+
+static void append_path(gpointer data, gpointer user_data)
+{
+       GDBusProxy *proxy = data;
+       DBusMessageIter *iter = user_data;
+       const char *path = g_dbus_proxy_get_path(proxy);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static gboolean get_tracks(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       struct tracklist *tracklist = player->tracklist;
+       DBusMessageIter value;
+
+       if (tracklist == NULL)
+               return FALSE;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING,
+                                       &value);
+       g_slist_foreach(player->tracklist->items, append_path, &value);
+       dbus_message_iter_close_container(iter, &value);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable tracklist_properties[] = {
+       { "Tracks", "ao", get_tracks, NULL, tracklist_exists },
+       { "CanEditTracks", "b", get_disable, NULL, NULL },
+       { }
+};
+
+static void list_items_setup(DBusMessageIter *iter, void *user_data)
+{
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void change_folder_reply(DBusMessage *message, void *user_data)
+{
+       struct player *player = user_data;
+       struct tracklist *tracklist = player->tracklist;
+       DBusError err;
+
+       dbus_error_init(&err);
+       if (dbus_set_error_from_message(&err, message)) {
+               fprintf(stderr, "error: %s", err.name);
+               return;
+       }
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYLISTS_INTERFACE,
+                                               "ActivePlaylist");
+
+       g_dbus_proxy_method_call(tracklist->proxy, "ListItems",
+                                       list_items_setup, NULL, NULL, NULL);
+}
+
+static void change_folder_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct player *player = user_data;
+       const char *path;
+
+       path = g_dbus_proxy_get_path(player->playlist);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static DBusMessage *playlist_activate(DBusConnection *conn,
+                                               DBusMessage *msg, void *data)
+{
+       struct player *player = data;
+       struct tracklist *tracklist = player->tracklist;
+       const char *path;
+
+       if (player->playlist == NULL || tracklist == NULL)
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_OBJECT_PATH, &path,
+                                       DBUS_TYPE_INVALID))
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       if (!g_str_equal(path, g_dbus_proxy_get_path(player->playlist)))
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       g_dbus_proxy_method_call(tracklist->proxy, "ChangeFolder",
+                               change_folder_setup, change_folder_reply,
+                               player, NULL);
+
+       return g_dbus_create_reply(msg, DBUS_TYPE_INVALID);
+}
+
+static DBusMessage *playlist_get(DBusConnection *conn, DBusMessage *msg,
+                                                               void *data)
+{
+       struct player *player = data;
+       uint32_t index, count;
+       const char *order;
+       dbus_bool_t reverse;
+       DBusMessage *reply;
+       DBusMessageIter iter, entry, value, name;
+       const char *string, *path;
+       const char *empty = "";
+
+       if (player->playlist == NULL)
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       if (!dbus_message_get_args(msg, NULL,
+                                       DBUS_TYPE_UINT32, &index,
+                                       DBUS_TYPE_UINT32, &count,
+                                       DBUS_TYPE_STRING, &order,
+                                       DBUS_TYPE_BOOLEAN, &reverse,
+                                       DBUS_TYPE_INVALID))
+               return g_dbus_create_error(msg,
+                                       ERROR_INTERFACE ".InvalidArguments",
+                                       "Invalid Arguments");
+
+       path = g_dbus_proxy_get_path(player->playlist);
+
+       reply = dbus_message_new_method_return(msg);
+
+       dbus_message_iter_init_append(reply, &iter);
+
+       dbus_message_iter_open_container(&iter, DBUS_TYPE_ARRAY, "(oss)",
+                                                               &entry);
+       dbus_message_iter_open_container(&entry, DBUS_TYPE_STRUCT, NULL,
+                                                               &value);
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_OBJECT_PATH, &path);
+       if (g_dbus_proxy_get_property(player->playlist, "Name", &name)) {
+               dbus_message_iter_get_basic(&name, &string);
+               dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
+                                                               &string);
+       } else {
+               dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING,
+                                                               &path);
+       }
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &empty);
+       dbus_message_iter_close_container(&entry, &value);
+       dbus_message_iter_close_container(&iter, &entry);
+
+       return reply;
+}
+
+static const GDBusMethodTable playlist_methods[] = {
+       { GDBUS_METHOD("ActivatePlaylist",
+                       GDBUS_ARGS({ "playlist", "o" }), NULL,
+                       playlist_activate) },
+       { GDBUS_METHOD("GetPlaylists",
+                       GDBUS_ARGS({ "index", "u" }, { "maxcount", "u"},
+                                       { "order", "s" }, { "reverse", "b" }),
+                       GDBUS_ARGS({ "playlists", "a(oss)"}),
+                       playlist_get) },
+       { },
+};
+
+static gboolean playlist_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct player *player = data;
+
+       return player->playlist != NULL;
+}
+
+static gboolean get_playlist_count(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       uint32_t count = 1;
+
+       if (player->playlist == NULL)
+               return FALSE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT32, &count);
+
+       return TRUE;
+}
+
+static gboolean get_orderings(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       DBusMessageIter value;
+       const char *order = "User";
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_TYPE_OBJECT_PATH_AS_STRING,
+                                       &value);
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_STRING, &order);
+       dbus_message_iter_close_container(iter, &value);
+
+       return TRUE;
+}
+
+static gboolean get_active_playlist(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct player *player = data;
+       DBusMessageIter value, entry;
+       dbus_bool_t enabled = TRUE;
+       const char *path, *empty = "";
+
+       if (player->playlist == NULL)
+               return FALSE;
+
+       path = g_dbus_proxy_get_path(player->playlist);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_STRUCT,
+                                                       NULL, &value);
+       dbus_message_iter_append_basic(&value, DBUS_TYPE_BOOLEAN, &enabled);
+       dbus_message_iter_open_container(&value, DBUS_TYPE_STRUCT, NULL,
+                                                               &entry);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_OBJECT_PATH, &path);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &path);
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &empty);
+       dbus_message_iter_close_container(&value, &entry);
+       dbus_message_iter_close_container(iter, &value);
+
+       return TRUE;
+}
+
+static const GDBusPropertyTable playlist_properties[] = {
+       { "PlaylistCount", "u", get_playlist_count, NULL, playlist_exists },
+       { "Orderings", "as", get_orderings, NULL, NULL },
+       { "ActivePlaylist", "(b(oss))", get_active_playlist, NULL,
+                                                       playlist_exists },
+       { }
+};
+
+#define a_z "abcdefghijklmnopqrstuvwxyz"
+#define A_Z "ABCDEFGHIJKLMNOPQRSTUVWXYZ"
+#define _0_9 "_0123456789"
+
+static char *mpris_busname(char *name)
+{
+       if (g_ascii_isdigit(name[0]))
+               return g_strconcat(MPRIS_BUS_NAME, "bt_",
+                               g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
+       else
+               return g_strconcat(MPRIS_BUS_NAME,
+                               g_strcanon(name, A_Z a_z _0_9, '_'), NULL);
+}
+
+static GDBusProxy *find_transport_by_path(const char *path)
+{
+       GSList *l;
+
+       for (l = transports; l; l = l->next) {
+               GDBusProxy *transport = l->data;
+               DBusMessageIter iter;
+               const char *value;
+
+               if (!g_dbus_proxy_get_property(transport, "Device", &iter))
+                       continue;
+
+               dbus_message_iter_get_basic(&iter, &value);
+
+               if (strcmp(path, value) == 0)
+                       return transport;
+       }
+
+       return NULL;
+}
+
+static struct player *find_player(GDBusProxy *proxy)
+{
+       GSList *l;
+
+       for (l = players; l; l = l->next) {
+               struct player *player = l->data;
+               const char *path, *p;
+
+               if (player->proxy == proxy)
+                       return player;
+
+               path = g_dbus_proxy_get_path(proxy);
+               p = g_dbus_proxy_get_path(player->proxy);
+               if (g_str_equal(path, p))
+                       return player;
+       }
+
+       return NULL;
+}
+
+static void register_tracklist(GDBusProxy *proxy)
+{
+       struct player *player;
+       struct tracklist *tracklist;
+
+       player = find_player(proxy);
+       if (player == NULL)
+               return;
+
+       if (player->tracklist != NULL)
+               return;
+
+       tracklist = g_new0(struct tracklist, 1);
+       tracklist->proxy = g_dbus_proxy_ref(proxy);
+
+       player->tracklist = tracklist;
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_INTERFACE,
+                                               "HasTrackList");
+
+       if (player->playlist == NULL)
+               return;
+
+       g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
+                               change_folder_setup, change_folder_reply,
+                               player, NULL);
+}
+
+static void register_player(GDBusProxy *proxy)
+{
+       struct player *player;
+       DBusMessageIter iter;
+       const char *path, *alias, *name;
+       char *busname;
+       GDBusProxy *device, *transport;
+
+       if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+               return;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       device = g_dbus_proxy_new(client, path, "org.bluez.Device1");
+       if (device == NULL)
+               return;
+
+       if (!g_dbus_proxy_get_property(device, "Alias", &iter))
+               return;
+
+       dbus_message_iter_get_basic(&iter, &alias);
+
+       if (g_dbus_proxy_get_property(proxy, "Name", &iter)) {
+               dbus_message_iter_get_basic(&iter, &name);
+               busname = g_strconcat(alias, " ", name, NULL);
+       } else
+               busname = g_strdup(alias);
+
+       player = g_new0(struct player, 1);
+       player->bus_name = mpris_busname(busname);
+       player->proxy = g_dbus_proxy_ref(proxy);
+       player->device = device;
+
+       g_free(busname);
+
+       players = g_slist_prepend(players, player);
+
+       printf("Player %s created\n", player->bus_name);
+
+       player->conn = g_dbus_setup_private(DBUS_BUS_SESSION, player->bus_name,
+                                                                       NULL);
+       if (!session) {
+               fprintf(stderr, "Could not register bus name %s",
+                                                       player->bus_name);
+               goto fail;
+       }
+
+       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_INTERFACE,
+                                               mpris_methods,
+                                               NULL,
+                                               mpris_properties,
+                                               player, NULL)) {
+               fprintf(stderr, "Could not register interface %s",
+                                               MPRIS_INTERFACE);
+               goto fail;
+       }
+
+       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE,
+                                               player_methods,
+                                               player_signals,
+                                               player_properties,
+                                               player, player_free)) {
+               fprintf(stderr, "Could not register interface %s",
+                                               MPRIS_PLAYER_INTERFACE);
+               goto fail;
+       }
+
+       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_TRACKLIST_INTERFACE,
+                                               tracklist_methods,
+                                               tracklist_signals,
+                                               tracklist_properties,
+                                               player, NULL)) {
+               fprintf(stderr, "Could not register interface %s",
+                                               MPRIS_TRACKLIST_INTERFACE);
+               goto fail;
+       }
+
+       if (!g_dbus_register_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYLISTS_INTERFACE,
+                                               playlist_methods,
+                                               NULL,
+                                               playlist_properties,
+                                               player, NULL)) {
+               fprintf(stderr, "Could not register interface %s",
+                                               MPRIS_PLAYLISTS_INTERFACE);
+               goto fail;
+       }
+
+       transport = find_transport_by_path(path);
+       if (transport)
+               player->transport = g_dbus_proxy_ref(transport);
+
+       return;
+
+fail:
+       players = g_slist_remove(players, player);
+       player_free(player);
+}
+
+static struct player *find_player_by_device(const char *device)
+{
+       GSList *l;
+
+       for (l = players; l; l = l->next) {
+               struct player *player = l->data;
+               const char *path = g_dbus_proxy_get_path(player->device);
+
+               if (g_strcmp0(device, path) == 0)
+                       return player;
+       }
+
+       return NULL;
+}
+
+static void register_transport(GDBusProxy *proxy)
+{
+       struct player *player;
+       DBusMessageIter iter;
+       const char *path;
+
+       if (g_slist_find(transports, proxy) != NULL)
+               return;
+
+       if (!g_dbus_proxy_get_property(proxy, "Volume", &iter))
+               return;
+
+       if (!g_dbus_proxy_get_property(proxy, "Device", &iter))
+               return;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       transports = g_slist_append(transports, proxy);
+
+       player = find_player_by_device(path);
+       if (player == NULL || player->transport != NULL)
+               return;
+
+       player->transport = g_dbus_proxy_ref(proxy);
+}
+
+static struct player *find_player_by_item(const char *item)
+{
+       GSList *l;
+
+       for (l = players; l; l = l->next) {
+               struct player *player = l->data;
+               const char *path = g_dbus_proxy_get_path(player->proxy);
+
+               if (g_str_has_prefix(item, path))
+                       return player;
+       }
+
+       return NULL;
+}
+
+static void register_playlist(struct player *player, GDBusProxy *proxy)
+{
+       const char *path;
+       DBusMessageIter iter;
+
+       if (!g_dbus_proxy_get_property(player->proxy, "Playlist", &iter))
+               return;
+
+       dbus_message_iter_get_basic(&iter, &path);
+
+       if (!g_str_equal(path, g_dbus_proxy_get_path(proxy)))
+               return;
+
+       player->playlist = g_dbus_proxy_ref(proxy);
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYLISTS_INTERFACE,
+                                               "PlaylistCount");
+
+       if (player->tracklist == NULL)
+               return;
+
+       g_dbus_proxy_method_call(player->tracklist->proxy, "ChangeFolder",
+                               change_folder_setup, change_folder_reply,
+                               player, NULL);
+}
+
+static void register_item(struct player *player, GDBusProxy *proxy)
+{
+       struct tracklist *tracklist;
+       const char *path, *playlist;
+       DBusMessage *signal;
+       DBusMessageIter iter, args, metadata;
+       GSList *l;
+       GDBusProxy *after;
+
+       if (player->playlist == NULL) {
+               register_playlist(player, proxy);
+               return;
+       }
+
+       tracklist = player->tracklist;
+       if (tracklist == NULL)
+               return;
+
+       path = g_dbus_proxy_get_path(proxy);
+       playlist = g_dbus_proxy_get_path(player->playlist);
+       if (!g_str_has_prefix(path, playlist))
+               return;
+
+       l = g_slist_last(tracklist->items);
+       tracklist->items = g_slist_append(tracklist->items, proxy);
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_TRACKLIST_INTERFACE,
+                                               "Tracks");
+
+       if (l == NULL)
+               return;
+
+       signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
+                                       MPRIS_TRACKLIST_INTERFACE,
+                                       "TrackAdded");
+       if (!signal) {
+               fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
+                                               MPRIS_TRACKLIST_INTERFACE);
+               return;
+       }
+
+       dbus_message_iter_init_append(signal, &args);
+
+       if (!g_dbus_proxy_get_property(proxy, "Metadata", &iter)) {
+               dbus_message_unref(signal);
+               return;
+       }
+
+       dbus_message_iter_open_container(&args, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &metadata);
+
+       parse_metadata(&iter, &metadata, parse_track_entry);
+
+       dbus_message_iter_close_container(&args, &metadata);
+
+       after = l->data;
+       path = g_dbus_proxy_get_path(after);
+       dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
+
+       g_dbus_send_message(player->conn, signal);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+       const char *path;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+       path = g_dbus_proxy_get_path(proxy);
+
+       if (!strcmp(interface, BLUEZ_ADAPTER_INTERFACE)) {
+               if (adapter != NULL)
+                       return;
+
+               printf("Bluetooth Adapter %s found\n", path);
+               adapter = proxy;
+               list_names(session);
+       } else if (!strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE)) {
+               printf("Bluetooth Player %s found\n", path);
+               register_player(proxy);
+       } else if (!strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE)) {
+               printf("Bluetooth Transport %s found\n", path);
+               register_transport(proxy);
+       } else if (!strcmp(interface, BLUEZ_MEDIA_FOLDER_INTERFACE)) {
+               printf("Bluetooth Folder %s found\n", path);
+               register_tracklist(proxy);
+       } else if (!strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE)) {
+               struct player *player;
+
+               player = find_player_by_item(path);
+               if (player == NULL)
+                       return;
+
+               printf("Bluetooth Item %s found\n", path);
+               register_item(player, proxy);
+       }
+}
+
+static void unregister_player(struct player *player)
+{
+       players = g_slist_remove(players, player);
+
+       if (player->tracklist != NULL) {
+               g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYLISTS_INTERFACE);
+               g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_TRACKLIST_INTERFACE);
+       }
+
+       g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_INTERFACE);
+
+       g_dbus_unregister_interface(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE);
+}
+
+static struct player *find_player_by_transport(GDBusProxy *proxy)
+{
+       GSList *l;
+
+       for (l = players; l; l = l->next) {
+               struct player *player = l->data;
+
+               if (player->transport == proxy)
+                       return player;
+       }
+
+       return NULL;
+}
+
+static void unregister_transport(GDBusProxy *proxy)
+{
+       struct player *player;
+
+       if (g_slist_find(transports, proxy) == NULL)
+               return;
+
+       transports = g_slist_remove(transports, proxy);
+
+       player = find_player_by_transport(proxy);
+       if (player == NULL)
+               return;
+
+       g_dbus_proxy_unref(player->transport);
+       player->transport = NULL;
+}
+
+static void unregister_item(struct player *player, GDBusProxy *proxy)
+{
+       struct tracklist *tracklist = player->tracklist;
+       const char *path;
+
+       if (tracklist == NULL)
+               return;
+
+       if (g_slist_find(tracklist->items, proxy) == NULL)
+               return;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       tracklist->items = g_slist_remove(tracklist->items, proxy);
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_TRACKLIST_INTERFACE,
+                                               "Tracks");
+
+       g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
+                               MPRIS_TRACKLIST_INTERFACE, "TrackRemoved",
+                               DBUS_TYPE_OBJECT_PATH, &path,
+                               DBUS_TYPE_INVALID);
+}
+
+static void remove_players(DBusConnection *conn)
+{
+       char **paths;
+       int i;
+
+       dbus_connection_list_registered(conn, "/", &paths);
+
+       for (i = 0; paths[i]; i++) {
+               char *path;
+               void *data;
+
+               path = g_strdup_printf("/%s", paths[i]);
+               dbus_connection_get_object_path_data(sys, path, &data);
+               dbus_connection_unregister_object_path(sys, path);
+
+               g_free(path);
+               g_free(data);
+       }
+
+       dbus_free_string_array(paths);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+       const char *path;
+
+       if (adapter == NULL)
+               return;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+       path = g_dbus_proxy_get_path(proxy);
+
+       if (strcmp(interface, BLUEZ_ADAPTER_INTERFACE) == 0) {
+               if (adapter != proxy)
+                       return;
+               printf("Bluetooth Adapter %s removed\n", path);
+               adapter = NULL;
+               remove_players(sys);
+       } else if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0) {
+               struct player *player;
+
+               player = find_player(proxy);
+               if (player == NULL)
+                       return;
+
+               printf("Bluetooth Player %s removed\n", path);
+               unregister_player(player);
+       } else if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0) {
+               printf("Bluetooth Transport %s removed\n", path);
+               unregister_transport(proxy);
+       } else if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0) {
+               struct player *player;
+
+               player = find_player_by_item(path);
+               if (player == NULL)
+                       return;
+
+               printf("Bluetooth Item %s removed\n", path);
+               unregister_item(player, proxy);
+       }
+}
+
+static const char *property_to_mpris(const char *property)
+{
+       if (strcasecmp(property, "Repeat") == 0)
+               return "LoopStatus";
+       else if (strcasecmp(property, "Shuffle") == 0)
+               return "Shuffle";
+       else if (strcasecmp(property, "Status") == 0)
+               return "PlaybackStatus";
+       else if (strcasecmp(property, "Position") == 0)
+               return "Position";
+       else if (strcasecmp(property, "Track") == 0)
+               return "Metadata";
+
+       return NULL;
+}
+
+static void player_property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct player *player;
+       const char *property;
+       uint32_t position;
+       uint64_t value;
+
+       player = find_player(proxy);
+       if (player == NULL)
+               return;
+
+       property = property_to_mpris(name);
+       if (property == NULL)
+               return;
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE,
+                                               property);
+
+       if (strcasecmp(name, "Position") != 0)
+               return;
+
+       dbus_message_iter_get_basic(iter, &position);
+
+       value = position * 1000;
+
+       g_dbus_emit_signal(player->conn, MPRIS_PLAYER_PATH,
+                                       MPRIS_PLAYER_INTERFACE, "Seeked",
+                                       DBUS_TYPE_INT64, &value,
+                                       DBUS_TYPE_INVALID);
+}
+
+static void transport_property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct player *player;
+       DBusMessageIter var;
+       const char *path;
+
+       if (strcasecmp(name, "Volume") != 0 && strcasecmp(name, "State") != 0)
+               return;
+
+       if (!g_dbus_proxy_get_property(proxy, "Device", &var))
+               return;
+
+       dbus_message_iter_get_basic(&var, &path);
+
+       player = find_player_by_device(path);
+       if (player == NULL)
+               return;
+
+       if (strcasecmp(name, "State") == 0) {
+               if (!g_dbus_proxy_get_property(player->proxy, "Status", &var))
+                       g_dbus_emit_property_changed(player->conn,
+                                               MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE,
+                                               "PlaybackStatus");
+               return;
+       }
+
+       g_dbus_emit_property_changed(player->conn, MPRIS_PLAYER_PATH,
+                                               MPRIS_PLAYER_INTERFACE,
+                                               name);
+}
+
+static void item_property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct player *player;
+       DBusMessage *signal;
+       DBusMessageIter args;
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       player = find_player_by_item(path);
+       if (player == NULL)
+               return;
+
+       if (strcasecmp(name, "Metadata") != 0)
+               return;
+
+       signal = dbus_message_new_signal(MPRIS_PLAYER_PATH,
+                                       MPRIS_TRACKLIST_INTERFACE,
+                                       "TrackMetadataChanged");
+       if (!signal) {
+               fprintf(stderr, "Unable to allocate new %s.TrackAdded signal",
+                                               MPRIS_TRACKLIST_INTERFACE);
+               return;
+       }
+
+       dbus_message_iter_init_append(signal, &args);
+
+       dbus_message_iter_append_basic(&args, DBUS_TYPE_OBJECT_PATH, &path);
+
+       append_iter(&args, iter);
+
+       g_dbus_send_message(player->conn, signal);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (strcmp(interface, BLUEZ_MEDIA_PLAYER_INTERFACE) == 0)
+               return player_property_changed(proxy, name, iter, user_data);
+
+       if (strcmp(interface, BLUEZ_MEDIA_TRANSPORT_INTERFACE) == 0)
+               return transport_property_changed(proxy, name, iter,
+                                                               user_data);
+
+       if (strcmp(interface, BLUEZ_MEDIA_ITEM_INTERFACE) == 0)
+               return item_property_changed(proxy, name, iter, user_data);
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       guint owner_watch, properties_watch, signal_watch;
+       struct sigaction sa;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               usage();
+               exit(0);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       sys = g_dbus_setup_bus(DBUS_BUS_SYSTEM, NULL, NULL);
+       if (!sys) {
+               fprintf(stderr, "Can't get on system bus");
+               exit(1);
+       }
+
+       session = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
+       if (!session) {
+               fprintf(stderr, "Can't get on session bus");
+               exit(1);
+       }
+
+       owner_watch = g_dbus_add_signal_watch(session, NULL, NULL,
+                                               DBUS_INTERFACE_DBUS,
+                                               "NameOwnerChanged",
+                                               name_owner_changed,
+                                               NULL, NULL);
+
+       properties_watch = g_dbus_add_properties_watch(session, NULL, NULL,
+                                                       MPRIS_PLAYER_INTERFACE,
+                                                       player_signal,
+                                                       NULL, NULL);
+
+       signal_watch = g_dbus_add_signal_watch(session, NULL, NULL,
+                                                       MPRIS_PLAYER_INTERFACE,
+                                                       NULL, player_signal,
+                                                       NULL, NULL);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_flags   = SA_NOCLDSTOP;
+       sa.sa_handler = sig_term;
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGINT,  &sa, NULL);
+
+       client = g_dbus_client_new(sys, BLUEZ_BUS_NAME, BLUEZ_PATH);
+
+       g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+
+       g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+                                               property_changed, NULL);
+
+       g_main_loop_run(main_loop);
+
+       g_dbus_remove_watch(session, owner_watch);
+       g_dbus_remove_watch(session, properties_watch);
+       g_dbus_remove_watch(session, signal_watch);
+
+       g_dbus_client_unref(client);
+
+       dbus_connection_unref(session);
+       dbus_connection_unref(sys);
+
+       g_main_loop_unref(main_loop);
+
+       return 0;
+}
diff --git a/tools/obex-client-tool.c b/tools/obex-client-tool.c
new file mode 100644 (file)
index 0000000..54dbcbb
--- /dev/null
@@ -0,0 +1,467 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <stdio.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+
+#include <gobex/gobex.h>
+#include <btio/btio.h>
+
+static GMainLoop *main_loop = NULL;
+static GObex *obex = NULL;
+
+static gboolean option_packet = FALSE;
+static gboolean option_bluetooth = FALSE;
+static char *option_source = NULL;
+static char *option_dest = NULL;
+static int option_channel = -1;
+static int option_imtu = -1;
+static int option_omtu = -1;
+
+static void sig_term(int sig)
+{
+       g_print("Terminating due to signal %d\n", sig);
+       g_main_loop_quit(main_loop);
+}
+
+static GOptionEntry options[] = {
+       { "unix", 'u', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+                       &option_bluetooth, "Use a UNIX socket" },
+       { "bluetooth", 'b', 0, G_OPTION_ARG_NONE,
+                       &option_bluetooth, "Use Bluetooth" },
+       { "source", 's', 0, G_OPTION_ARG_STRING,
+                       &option_source, "Bluetooth adapter address",
+                       "00:..." },
+       { "destination", 'd', 0, G_OPTION_ARG_STRING,
+                       &option_dest, "Remote bluetooth address",
+                       "00:..." },
+       { "channel", 'c', 0, G_OPTION_ARG_INT,
+                       &option_channel, "Transport channel", "CHANNEL" },
+       { "packet", 'p', 0, G_OPTION_ARG_NONE,
+                       &option_packet, "Packet based transport" },
+       { "stream", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+                       &option_packet, "Stream based transport" },
+       { "input-mtu", 'i', 0, G_OPTION_ARG_INT,
+                       &option_imtu, "Transport input MTU", "MTU" },
+       { "output-mtu", 'o', 0, G_OPTION_ARG_INT,
+                       &option_omtu, "Transport output MTU", "MTU" },
+       { NULL },
+};
+
+static void conn_complete(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       if (err != NULL)
+               g_print("Connect failed: %s\n", err->message);
+       else
+               g_print("Connect succeeded\n");
+}
+
+static void cmd_connect(int argc, char **argv)
+{
+       g_obex_connect(obex, conn_complete, NULL, NULL, G_OBEX_HDR_INVALID);
+}
+
+struct transfer_data {
+       int fd;
+};
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+
+       if (err != NULL)
+               g_printerr("failed: %s\n", err->message);
+       else
+               g_print("transfer succeeded\n");
+
+       close(data->fd);
+       g_free(data);
+}
+
+static gssize put_data_cb(void *buf, gsize len, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+
+       return read(data->fd, buf, len);
+}
+
+static void cmd_put(int argc, char **argv)
+{
+       struct transfer_data *data;
+       GError *err = NULL;
+       int fd;
+
+       if (argc < 2) {
+               g_printerr("Filename required\n");
+               return;
+       }
+
+       fd = open(argv[1], O_RDONLY | O_NOCTTY, 0);
+       if (fd < 0) {
+               g_printerr("open: %s\n", strerror(errno));
+               return;
+       }
+
+       data = g_new0(struct transfer_data, 1);
+       data->fd = fd;
+
+       g_obex_put_req(obex, put_data_cb, transfer_complete, data, &err,
+                                               G_OBEX_HDR_NAME, argv[1],
+                                               G_OBEX_HDR_INVALID);
+       if (err != NULL) {
+               g_printerr("put failed: %s\n", err->message);
+               g_error_free(err);
+               close(data->fd);
+               g_free(data);
+       }
+}
+
+static gboolean get_data_cb(const void *buf, gsize len, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+
+       if (write(data->fd, buf, len) < 0) {
+               g_printerr("write: %s\n", strerror(errno));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void cmd_get(int argc, char **argv)
+{
+       struct transfer_data *data;
+       GError *err = NULL;
+       int fd;
+
+       if (argc < 2) {
+               g_printerr("Filename required\n");
+               return;
+       }
+
+       fd = open(argv[1], O_WRONLY | O_CREAT | O_NOCTTY, 0600);
+       if (fd < 0) {
+               g_printerr("open: %s\n", strerror(errno));
+               return;
+       }
+
+       data = g_new0(struct transfer_data, 1);
+       data->fd = fd;
+
+       g_obex_get_req(obex, get_data_cb, transfer_complete, data, &err,
+                                               G_OBEX_HDR_NAME, argv[1],
+                                               G_OBEX_HDR_INVALID);
+       if (err != NULL) {
+               g_printerr("get failed: %s\n", err->message);
+               g_error_free(err);
+               close(data->fd);
+               g_free(data);
+       }
+}
+
+static void cmd_help(int argc, char **argv);
+
+static void cmd_exit(int argc, char **argv)
+{
+       g_main_loop_quit(main_loop);
+}
+
+static struct {
+       const char *cmd;
+       void (*func)(int argc, char **argv);
+       const char *params;
+       const char *desc;
+} commands[] = {
+       { "help",       cmd_help,       "",             "Show this help"},
+       { "exit",       cmd_exit,       "",             "Exit application" },
+       { "quit",       cmd_exit,       "",             "Exit application" },
+       { "connect",    cmd_connect,    "[target]",     "OBEX Connect" },
+       { "put",        cmd_put,        "<file>",       "Send a file" },
+       { "get",        cmd_get,        "<file>",       "Receive a file" },
+       { NULL },
+};
+
+static void cmd_help(int argc, char **argv)
+{
+       int i;
+
+       for (i = 0; commands[i].cmd; i++)
+               printf("%-15s %-30s %s\n", commands[i].cmd,
+                               commands[i].params, commands[i].desc);
+}
+
+static void parse_line(char *line_read)
+{
+       char **argvp;
+       int argcp;
+       int i;
+
+       if (line_read == NULL) {
+               g_print("\n");
+               g_main_loop_quit(main_loop);
+               return;
+       }
+
+       line_read = g_strstrip(line_read);
+
+       if (*line_read == '\0') {
+               free(line_read);
+               return;
+       }
+
+       add_history(line_read);
+
+       g_shell_parse_argv(line_read, &argcp, &argvp, NULL);
+
+       free(line_read);
+
+       for (i = 0; commands[i].cmd; i++)
+               if (strcasecmp(commands[i].cmd, argvp[0]) == 0)
+                       break;
+
+       if (commands[i].cmd)
+               commands[i].func(argcp, argvp);
+       else
+               g_print("%s: command not found\n", argvp[0]);
+
+       g_strfreev(argvp);
+}
+
+static gboolean prompt_read(GIOChannel *chan, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       rl_callback_read_char();
+
+       return TRUE;
+}
+
+static void disconn_func(GObex *obex, GError *err, gpointer user_data)
+{
+       g_printerr("Disconnected: %s\n", err ? err->message : "(no error)");
+       g_main_loop_quit(main_loop);
+}
+
+static void transport_connect(GIOChannel *io, GObexTransportType transport)
+{
+       GIOChannel *input;
+       GIOCondition events;
+
+       g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       obex = g_obex_new(io, transport, option_imtu, option_omtu);
+       g_obex_set_disconnect_function(obex, disconn_func, NULL);
+
+       input = g_io_channel_unix_new(STDIN_FILENO);
+       g_io_channel_set_close_on_unref(input, TRUE);
+       events = G_IO_IN | G_IO_ERR | G_IO_HUP | G_IO_NVAL;
+       g_io_add_watch(input, events, prompt_read, NULL);
+       g_io_channel_unref(input);
+       rl_callback_handler_install("client> ", parse_line);
+}
+
+static GIOChannel *unix_connect(GObexTransportType transport)
+{
+       GIOChannel *io;
+       struct sockaddr_un addr = {
+               AF_UNIX, "\0/gobex/server"
+       };
+       int sk, err, sock_type;
+
+       if (option_packet)
+               sock_type = SOCK_SEQPACKET;
+       else
+               sock_type = SOCK_STREAM;
+
+       sk = socket(PF_LOCAL, sock_type, 0);
+       if (sk < 0) {
+               err = errno;
+               g_printerr("Can't create unix socket: %s (%d)\n",
+                                               strerror(err), err);
+               return NULL;
+       }
+
+       if (connect(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               err = errno;
+               g_printerr("connect: %s (%d)\n", strerror(err), err);
+               return NULL;
+       }
+
+       io = g_io_channel_unix_new(sk);
+
+       g_print("Unix socket created: %d\n", sk);
+
+       transport_connect(io, transport);
+
+       return io;
+}
+
+static void conn_callback(GIOChannel *io, GError *err, gpointer user_data)
+{
+       GObexTransportType transport = GPOINTER_TO_UINT(user_data);
+
+       if (err != NULL) {
+               g_printerr("%s\n", err->message);
+               return;
+       }
+
+       g_print("Bluetooth socket connected\n");
+
+       transport_connect(io, transport);
+}
+
+static GIOChannel *l2cap_connect(GObexTransportType transport, GError **err)
+{
+       if (option_source)
+               return bt_io_connect(conn_callback,
+                                       GUINT_TO_POINTER(transport),
+                                       NULL, err,
+                                       BT_IO_OPT_SOURCE, option_source,
+                                       BT_IO_OPT_DEST, option_dest,
+                                       BT_IO_OPT_PSM, option_channel,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                                       BT_IO_OPT_OMTU, option_omtu,
+                                       BT_IO_OPT_IMTU, option_imtu,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+
+       return bt_io_connect(conn_callback,
+                                       GUINT_TO_POINTER(transport),
+                                       NULL, err,
+                                       BT_IO_OPT_DEST, option_dest,
+                                       BT_IO_OPT_PSM, option_channel,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                                       BT_IO_OPT_OMTU, option_omtu,
+                                       BT_IO_OPT_IMTU, option_imtu,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+}
+
+static GIOChannel *rfcomm_connect(GObexTransportType transport, GError **err)
+{
+       if (option_source)
+               return bt_io_connect(conn_callback,
+                                       GUINT_TO_POINTER(transport),
+                                       NULL, err,
+                                       BT_IO_OPT_SOURCE, option_source,
+                                       BT_IO_OPT_DEST, option_dest,
+                                       BT_IO_OPT_CHANNEL, option_channel,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+
+       return bt_io_connect(conn_callback,
+                                       GUINT_TO_POINTER(transport),
+                                       NULL, err,
+                                       BT_IO_OPT_DEST, option_dest,
+                                       BT_IO_OPT_CHANNEL, option_channel,
+                                       BT_IO_OPT_SEC_LEVEL, BT_IO_SEC_LOW,
+                                       BT_IO_OPT_INVALID);
+}
+
+static GIOChannel *bluetooth_connect(GObexTransportType transport)
+{
+       GIOChannel *io;
+       GError *err = NULL;
+
+       if (option_dest == NULL || option_channel < 0)
+               return NULL;
+
+       if (option_channel > 31)
+               io = l2cap_connect(transport, &err);
+       else
+               io = rfcomm_connect(transport, &err);
+
+       if (io != NULL)
+               return io;
+
+       g_printerr("%s\n", err->message);
+       g_error_free(err);
+       return NULL;
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *err = NULL;
+       struct sigaction sa;
+       GIOChannel *io;
+       GObexTransportType transport;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       g_option_context_parse(context, &argc, &argv, &err);
+       if (err != NULL) {
+               g_printerr("%s\n", err->message);
+               g_error_free(err);
+               exit(EXIT_FAILURE);
+       }
+
+       if (option_packet)
+               transport = G_OBEX_TRANSPORT_PACKET;
+       else
+               transport = G_OBEX_TRANSPORT_STREAM;
+
+       if (option_bluetooth)
+               io = bluetooth_connect(transport);
+       else
+               io = unix_connect(transport);
+
+       if (io == NULL)
+               exit(EXIT_FAILURE);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = sig_term;
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       g_main_loop_run(main_loop);
+
+       rl_callback_handler_remove();
+       clear_history();
+       g_obex_unref(obex);
+       g_option_context_free(context);
+       g_main_loop_unref(main_loop);
+
+       exit(EXIT_SUCCESS);
+}
diff --git a/tools/obex-server-tool.c b/tools/obex-server-tool.c
new file mode 100644 (file)
index 0000000..e37c56f
--- /dev/null
@@ -0,0 +1,458 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 <sys/types.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <sys/un.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <errno.h>
+
+#include <gobex/gobex.h>
+#include <btio/btio.h>
+
+static GMainLoop *main_loop = NULL;
+
+static GSList *clients = NULL;
+
+static gboolean option_packet = FALSE;
+static gboolean option_bluetooth = FALSE;
+static int option_channel = -1;
+static int option_imtu = -1;
+static int option_omtu = -1;
+static char *option_root = NULL;
+
+static void sig_term(int sig)
+{
+       g_print("Terminating due to signal %d\n", sig);
+       g_main_loop_quit(main_loop);
+}
+
+static GOptionEntry options[] = {
+       { "unix", 'u', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+                       &option_bluetooth, "Use a UNIX socket" },
+       { "bluetooth", 'b', 0, G_OPTION_ARG_NONE,
+                       &option_bluetooth, "Use Bluetooth" },
+       { "channel", 'c', 0, G_OPTION_ARG_INT,
+                       &option_channel, "Transport channel", "CHANNEL" },
+       { "packet", 'p', 0, G_OPTION_ARG_NONE,
+                       &option_packet, "Packet based transport" },
+       { "stream", 's', G_OPTION_FLAG_REVERSE, G_OPTION_ARG_NONE,
+                       &option_packet, "Stream based transport" },
+       { "root", 'r', 0, G_OPTION_ARG_STRING,
+                       &option_root, "Root dir", "/..." },
+       { "input-mtu", 'i', 0, G_OPTION_ARG_INT,
+                       &option_imtu, "Transport input MTU", "MTU" },
+       { "output-mtu", 'o', 0, G_OPTION_ARG_INT,
+                       &option_omtu, "Transport output MTU", "MTU" },
+       { NULL },
+};
+
+static void disconn_func(GObex *obex, GError *err, gpointer user_data)
+{
+       g_print("Client disconnected: %s\n", err ? err->message : "<no err>");
+       clients = g_slist_remove(clients, obex);
+       g_obex_unref(obex);
+}
+
+struct transfer_data {
+       int fd;
+};
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+
+       if (err != NULL)
+               g_printerr("transfer failed: %s\n", err->message);
+       else
+               g_print("transfer succeeded\n");
+
+       close(data->fd);
+       g_free(data);
+}
+
+static gboolean recv_data(const void *buf, gsize len, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+
+       g_print("received %zu bytes of data\n", len);
+
+       if (write(data->fd, buf, len) < 0) {
+               g_printerr("write: %s\n", strerror(errno));
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void handle_put(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       GError *err = NULL;
+       GObexHeader *hdr;
+       const char *type, *name;
+       struct transfer_data *data;
+       gsize type_len;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TYPE);
+       if (hdr != NULL) {
+               g_obex_header_get_bytes(hdr, (const guint8 **) &type,
+                                                               &type_len);
+               if (type[type_len - 1] != '\0') {
+                       g_printerr("non-nul terminated type header\n");
+                       type = NULL;
+               }
+       } else
+               type = NULL;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_NAME);
+       if (hdr != NULL)
+               g_obex_header_get_unicode(hdr, &name);
+       else
+               name = NULL;
+
+       g_print("put type \"%s\" name \"%s\"\n", type ? type : "",
+                                                       name ? name : "");
+
+       data = g_new0(struct transfer_data, 1);
+
+       data->fd = open(name, O_WRONLY | O_CREAT | O_NOCTTY, 0600);
+       if (data->fd < 0) {
+               g_printerr("open(%s): %s\n", name, strerror(errno));
+               g_free(data);
+               g_obex_send_rsp(obex, G_OBEX_RSP_FORBIDDEN, NULL,
+                                                       G_OBEX_HDR_INVALID);
+               return;
+       }
+
+       g_obex_put_rsp(obex, req, recv_data, transfer_complete, data, &err,
+                                                       G_OBEX_HDR_INVALID);
+       if (err != NULL) {
+               g_printerr("Unable to send response: %s\n", err->message);
+               g_error_free(err);
+               g_free(data);
+       }
+}
+
+static gssize send_data(void *buf, gsize len, gpointer user_data)
+{
+       struct transfer_data *data = user_data;
+       gssize ret;
+
+       ret = read(data->fd, buf, len);
+       g_print("sending %zu bytes of data\n", ret);
+
+       return ret;
+}
+
+static void handle_get(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       GError *err = NULL;
+       struct transfer_data *data;
+       const char *type, *name;
+       GObexHeader *hdr;
+       gsize type_len;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_TYPE);
+       if (hdr != NULL) {
+               g_obex_header_get_bytes(hdr, (const guint8 **) &type,
+                                                               &type_len);
+               if (type[type_len - 1] != '\0') {
+                       g_printerr("non-nul terminated type header\n");
+                       type = NULL;
+               }
+       } else
+               type = NULL;
+
+       hdr = g_obex_packet_get_header(req, G_OBEX_HDR_NAME);
+       if (hdr != NULL)
+               g_obex_header_get_unicode(hdr, &name);
+       else
+               name = NULL;
+
+       g_print("get type \"%s\" name \"%s\"\n", type ? type : "",
+                                                       name ? name : "");
+
+       data = g_new0(struct transfer_data, 1);
+
+       data->fd = open(name, O_RDONLY | O_NOCTTY, 0);
+       if (data->fd < 0) {
+               g_printerr("open(%s): %s\n", name, strerror(errno));
+               g_free(data);
+               g_obex_send_rsp(obex, G_OBEX_RSP_FORBIDDEN, NULL,
+                                                       G_OBEX_HDR_INVALID);
+               return;
+       }
+
+       g_obex_get_rsp(obex, send_data, transfer_complete, data, &err,
+                                                       G_OBEX_HDR_INVALID);
+       if (err != NULL) {
+               g_printerr("Unable to send response: %s\n", err->message);
+               g_error_free(err);
+               g_free(data);
+       }
+}
+
+static void handle_connect(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       GObexPacket *rsp;
+
+       g_print("connect\n");
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE, G_OBEX_HDR_INVALID);
+       g_obex_send(obex, rsp, NULL);
+}
+
+static void transport_accept(GIOChannel *io)
+{
+       GObex *obex;
+       GObexTransportType transport;
+
+       g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       if (option_packet)
+               transport = G_OBEX_TRANSPORT_PACKET;
+       else
+               transport = G_OBEX_TRANSPORT_STREAM;
+
+       obex = g_obex_new(io, transport, option_imtu, option_omtu);
+       g_obex_set_disconnect_function(obex, disconn_func, NULL);
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put, NULL);
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get, NULL);
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT, handle_connect,
+                                                                       NULL);
+       clients = g_slist_append(clients, obex);
+}
+
+static gboolean unix_accept(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+       struct sockaddr_un addr;
+       socklen_t addrlen;
+       int sk, cli_sk;
+       GIOChannel *io;
+
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       if (cond & (G_IO_HUP | G_IO_ERR)) {
+               g_io_channel_shutdown(chan, TRUE, NULL);
+               return FALSE;
+       }
+
+       sk = g_io_channel_unix_get_fd(chan);
+
+       memset(&addr, 0, sizeof(addr));
+       addrlen = sizeof(addr);
+
+       cli_sk = accept(sk, (struct sockaddr *) &addr, &addrlen);
+       if (cli_sk < 0) {
+               g_printerr("accept: %s (%d)\n", strerror(errno), errno);
+               return TRUE;
+       }
+
+       g_print("Accepted new client connection on unix socket (fd=%d)\n",
+                                                               cli_sk);
+
+       io = g_io_channel_unix_new(cli_sk);
+
+       transport_accept(io);
+       g_io_channel_unref(io);
+
+       return TRUE;
+}
+
+static void bluetooth_accept(GIOChannel *io, GError *err, gpointer data)
+{
+       if (err) {
+               g_printerr("accept: %s\n", err->message);
+               return;
+       }
+
+       g_print("Accepted new client connection on bluetooth socket\n");
+
+       transport_accept(io);
+}
+
+static gboolean bluetooth_watch(GIOChannel *chan, GIOCondition cond, gpointer data)
+{
+       if (cond & G_IO_NVAL)
+               return FALSE;
+
+       g_io_channel_shutdown(chan, TRUE, NULL);
+       return FALSE;
+}
+
+static GIOChannel *l2cap_listen(GError **err)
+{
+       return bt_io_listen(bluetooth_accept, NULL, NULL,
+                                       NULL, err,
+                                       BT_IO_OPT_PSM, option_channel,
+                                       BT_IO_OPT_MODE, BT_IO_MODE_ERTM,
+                                       BT_IO_OPT_OMTU, option_omtu,
+                                       BT_IO_OPT_IMTU, option_imtu,
+                                       BT_IO_OPT_INVALID);
+}
+
+static GIOChannel *rfcomm_listen(GError **err)
+{
+       return bt_io_listen(bluetooth_accept, NULL, NULL,
+                                       NULL, err,
+                                       BT_IO_OPT_CHANNEL, option_channel,
+                                       BT_IO_OPT_INVALID);
+}
+
+static guint bluetooth_listen(void)
+{
+       GIOChannel *io;
+       guint id;
+       GError *err = NULL;
+
+       if (option_channel == -1) {
+               g_printerr("Bluetooth channel not set\n");
+               return 0;
+       }
+
+       if (option_packet || option_channel > 31)
+               io = l2cap_listen(&err);
+       else
+               io = rfcomm_listen(&err);
+
+       if (io == NULL) {
+               g_printerr("%s\n", err->message);
+               g_error_free(err);
+               return 0;
+       }
+
+       g_print("Bluetooth socket created\n");
+
+       id = g_io_add_watch(io, G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                                       bluetooth_watch, NULL);
+
+       g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_close_on_unref(io, TRUE);
+       g_io_channel_unref(io);
+
+       return id;
+}
+
+static guint unix_listen(void)
+{
+       GIOChannel *io;
+       struct sockaddr_un addr = {
+               AF_UNIX, "\0/gobex/server"
+       };
+       int sk, err, sock_type;
+       guint id;
+
+       if (option_packet)
+               sock_type = SOCK_SEQPACKET;
+       else
+               sock_type = SOCK_STREAM;
+
+       sk = socket(PF_LOCAL, sock_type, 0);
+       if (sk < 0) {
+               err = errno;
+               g_printerr("Can't create unix socket: %s (%d)\n",
+                                               strerror(err), err);
+               return 0;
+       }
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               g_printerr("Can't bind unix socket: %s (%d)\n",
+                                               strerror(errno), errno);
+               close(sk);
+               return 0;
+       }
+
+       if (listen(sk, 1) < 0) {
+               g_printerr("Can't listen on unix socket: %s (%d)\n",
+                                               strerror(errno), errno);
+               close(sk);
+               return 0;
+       }
+
+       g_print("Unix socket created: %d\n", sk);
+
+       io = g_io_channel_unix_new(sk);
+       id = g_io_add_watch(io, G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                                                       unix_accept, NULL);
+
+       g_io_channel_set_flags(io, G_IO_FLAG_NONBLOCK, NULL);
+       g_io_channel_set_close_on_unref(io, TRUE);
+       g_io_channel_unref(io);
+
+       return id;
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *err = NULL;
+       struct sigaction sa;
+       guint server_id;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       g_option_context_parse(context, &argc, &argv, &err);
+       if (err != NULL) {
+               g_printerr("%s\n", err->message);
+               g_error_free(err);
+               exit(EXIT_FAILURE);
+       }
+
+       if (option_root && chdir(option_root) > 0) {
+               perror("chdir:");
+               exit(EXIT_FAILURE);
+       }
+
+       if (option_bluetooth)
+               server_id = bluetooth_listen();
+       else
+               server_id = unix_listen();
+
+       if (server_id == 0)
+               exit(EXIT_FAILURE);
+
+       memset(&sa, 0, sizeof(sa));
+       sa.sa_handler = sig_term;
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+
+       g_main_loop_run(main_loop);
+
+       g_source_remove(server_id);
+       g_slist_free_full(clients, (GDestroyNotify) g_obex_unref);
+       g_option_context_free(context);
+       g_main_loop_unref(main_loop);
+
+       exit(EXIT_SUCCESS);
+}
diff --git a/tools/obexctl.c b/tools/obexctl.c
new file mode 100644 (file)
index 0000000..0491b51
--- /dev/null
@@ -0,0 +1,2400 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  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 <stdbool.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <signal.h>
+#include <sys/signalfd.h>
+#include <inttypes.h>
+
+#include <readline/readline.h>
+#include <readline/history.h>
+#include <glib.h>
+#include <gdbus.h>
+
+#include <client/display.h>
+
+/* String display constants */
+#define COLORED_NEW    COLOR_GREEN "NEW" COLOR_OFF
+#define COLORED_CHG    COLOR_YELLOW "CHG" COLOR_OFF
+#define COLORED_DEL    COLOR_RED "DEL" COLOR_OFF
+
+#define PROMPT_ON      COLOR_BLUE "[obex]" COLOR_OFF "# "
+#define PROMPT_OFF     "[obex]# "
+
+#define OBEX_SESSION_INTERFACE "org.bluez.obex.Session1"
+#define OBEX_TRANSFER_INTERFACE "org.bluez.obex.Transfer1"
+#define OBEX_CLIENT_INTERFACE "org.bluez.obex.Client1"
+#define OBEX_OPP_INTERFACE "org.bluez.obex.ObjectPush1"
+#define OBEX_FTP_INTERFACE "org.bluez.obex.FileTransfer1"
+#define OBEX_PBAP_INTERFACE "org.bluez.obex.PhonebookAccess1"
+#define OBEX_MAP_INTERFACE "org.bluez.obex.MessageAccess1"
+#define OBEX_MSG_INTERFACE "org.bluez.obex.Message1"
+
+static GMainLoop *main_loop;
+static DBusConnection *dbus_conn;
+static GDBusProxy *default_session;
+static GSList *sessions = NULL;
+static GSList *opps = NULL;
+static GSList *ftps = NULL;
+static GSList *pbaps = NULL;
+static GSList *maps = NULL;
+static GSList *msgs = NULL;
+static GSList *transfers = NULL;
+static GDBusProxy *client = NULL;
+
+struct transfer_data {
+       uint64_t transferred;
+       uint64_t size;
+};
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_ON);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       rl_set_prompt(PROMPT_OFF);
+       printf("\r");
+       rl_on_new_line();
+       rl_redisplay();
+}
+
+static void cmd_quit(int argc, char *argv[])
+{
+       g_main_loop_quit(main_loop);
+}
+
+static void connect_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to connect: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Connection successful\n");
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+       DBusMessageIter value;
+       char sig[2] = { type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+       dbus_message_iter_append_basic(&value, type, val);
+
+       dbus_message_iter_close_container(iter, &value);
+}
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key,
+                                                       int type, void *val)
+{
+       DBusMessageIter entry;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) val);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+struct connect_args {
+       char *dev;
+       char *target;
+};
+
+static void connect_args_free(void *data)
+{
+       struct connect_args *args = data;
+
+       g_free(args->dev);
+       g_free(args->target);
+       g_free(args);
+}
+
+static void connect_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct connect_args *args = user_data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->dev);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       if (args->target == NULL)
+               goto done;
+
+       dict_append_entry(&dict, "Target", DBUS_TYPE_STRING, &args->target);
+
+done:
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void cmd_connect(int argc, char *argv[])
+{
+       struct connect_args *args;
+       const char *target = "opp";
+
+       if (argc < 2) {
+               rl_printf("Missing device address argument\n");
+               return;
+       }
+
+       if (!client) {
+               rl_printf("Client proxy not available\n");
+               return;
+       }
+
+       if (argc > 2)
+               target = argv[2];
+
+       args = g_new0(struct connect_args, 1);
+       args->dev = g_strdup(argv[1]);
+       args->target = g_strdup(target);
+
+       if (g_dbus_proxy_method_call(client, "CreateSession", connect_setup,
+                       connect_reply, args, connect_args_free) == FALSE) {
+               rl_printf("Failed to connect\n");
+               return;
+       }
+
+       rl_printf("Attempting to connect to %s\n", argv[1]);
+}
+
+static void disconnect_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to disconnect: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Disconnection successful\n");
+}
+
+static void disconnect_setup(DBusMessageIter *iter, void *user_data)
+{
+       GDBusProxy *proxy = user_data;
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_OBJECT_PATH, &path);
+}
+
+static GDBusProxy *find_session(const char *path)
+{
+       GSList *l;
+
+       for (l = sessions; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void cmd_disconnect(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc > 1)
+               proxy = find_session(argv[1]);
+       else
+               proxy = default_session;
+
+       if (proxy == NULL) {
+               rl_printf("Session not available\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(client, "RemoveSession", disconnect_setup,
+                               disconnect_reply, proxy, NULL) == FALSE) {
+               rl_printf("Failed to disconnect\n");
+               return;
+       }
+
+       rl_printf("Attempting to disconnect to %s\n",
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static char *proxy_description(GDBusProxy *proxy, const char *title,
+                                               const char *description)
+{
+       const char *path;
+
+       path = g_dbus_proxy_get_path(proxy);
+
+       return g_strdup_printf("%s%s%s%s %s ",
+                                       description ? "[" : "",
+                                       description ? : "",
+                                       description ? "] " : "",
+                                       title, path);
+}
+
+static void print_proxy(GDBusProxy *proxy, const char *title,
+                                                       const char *description)
+{
+       char *str;
+
+       str = proxy_description(proxy, title, description);
+
+       rl_printf("%s%s\n", str, default_session == proxy ? "[default]" : "");
+
+       g_free(str);
+}
+
+static void cmd_list(int argc, char *arg[])
+{
+       GSList *l;
+
+       for (l = sessions; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+               print_proxy(proxy, "Session", NULL);
+       }
+}
+
+static bool check_default_session(void)
+{
+       if (!default_session) {
+               rl_printf("No default session available\n");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static void print_iter(const char *label, const char *name,
+                                               DBusMessageIter *iter)
+{
+       dbus_bool_t valbool;
+       dbus_uint64_t valu64;
+       dbus_uint32_t valu32;
+       dbus_uint16_t valu16;
+       dbus_int16_t vals16;
+       const char *valstr;
+       DBusMessageIter subiter;
+
+       if (iter == NULL) {
+               rl_printf("%s%s is nil\n", label, name);
+               return;
+       }
+
+       switch (dbus_message_iter_get_arg_type(iter)) {
+       case DBUS_TYPE_INVALID:
+               rl_printf("%s%s is invalid\n", label, name);
+               break;
+       case DBUS_TYPE_STRING:
+       case DBUS_TYPE_OBJECT_PATH:
+               dbus_message_iter_get_basic(iter, &valstr);
+               rl_printf("%s%s: %s\n", label, name, valstr);
+               break;
+       case DBUS_TYPE_BOOLEAN:
+               dbus_message_iter_get_basic(iter, &valbool);
+               rl_printf("%s%s: %s\n", label, name,
+                                       valbool == TRUE ? "yes" : "no");
+               break;
+       case DBUS_TYPE_UINT64:
+               dbus_message_iter_get_basic(iter, &valu64);
+               rl_printf("%s%s: %" PRIu64 "\n", label, name, valu64);
+               break;
+       case DBUS_TYPE_UINT32:
+               dbus_message_iter_get_basic(iter, &valu32);
+               rl_printf("%s%s: 0x%08x\n", label, name, valu32);
+               break;
+       case DBUS_TYPE_UINT16:
+               dbus_message_iter_get_basic(iter, &valu16);
+               rl_printf("%s%s: 0x%04x\n", label, name, valu16);
+               break;
+       case DBUS_TYPE_INT16:
+               dbus_message_iter_get_basic(iter, &vals16);
+               rl_printf("%s%s: %d\n", label, name, vals16);
+               break;
+       case DBUS_TYPE_VARIANT:
+               dbus_message_iter_recurse(iter, &subiter);
+               print_iter(label, name, &subiter);
+               break;
+       case DBUS_TYPE_ARRAY:
+               dbus_message_iter_recurse(iter, &subiter);
+               while (dbus_message_iter_get_arg_type(&subiter) !=
+                                                       DBUS_TYPE_INVALID) {
+                       print_iter(label, name, &subiter);
+                       dbus_message_iter_next(&subiter);
+               }
+               break;
+       case DBUS_TYPE_DICT_ENTRY:
+               dbus_message_iter_recurse(iter, &subiter);
+               dbus_message_iter_get_basic(&subiter, &valstr);
+               dbus_message_iter_next(&subiter);
+               print_iter(label, valstr, &subiter);
+               break;
+       default:
+               rl_printf("%s%s has unsupported type\n", label, name);
+               break;
+       }
+}
+
+static void print_property(GDBusProxy *proxy, const char *name)
+{
+       DBusMessageIter iter;
+
+       if (g_dbus_proxy_get_property(proxy, name, &iter) == FALSE)
+               return;
+
+       print_iter("\t", name, &iter);
+}
+
+static void cmd_show(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               if (check_default_session() == FALSE)
+                       return;
+
+               proxy = default_session;
+       } else {
+               proxy = find_session(argv[1]);
+               if (!proxy) {
+                       rl_printf("Session %s not available\n", argv[1]);
+                       return;
+               }
+       }
+
+       rl_printf("Session %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(proxy, "Destination");
+       print_property(proxy, "Target");
+}
+
+static void set_default_session(GDBusProxy *proxy)
+{
+       char *desc;
+       DBusMessageIter iter;
+
+       default_session = proxy;
+
+       if (proxy == NULL) {
+               desc = g_strdup(PROMPT_ON);
+               goto done;
+       }
+
+       if (g_dbus_proxy_get_property(proxy, "Destination", &iter))
+               dbus_message_iter_get_basic(&iter, &desc);
+
+       desc = g_strdup_printf(COLOR_BLUE "[%s]" COLOR_OFF "# ", desc);
+
+done:
+       rl_set_prompt(desc);
+       rl_redisplay();
+       g_free(desc);
+}
+
+static void cmd_select(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing session address argument\n");
+               return;
+       }
+
+       proxy = find_session(argv[1]);
+       if (proxy == NULL) {
+               rl_printf("Session %s not available\n", argv[1]);
+               return;
+       }
+
+       if (default_session == proxy)
+               return;
+
+       set_default_session(proxy);
+
+       print_proxy(proxy, "Session", NULL);
+}
+
+static GDBusProxy *find_transfer(const char *path)
+{
+       GSList *l;
+
+       for (l = transfers; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static GDBusProxy *find_message(const char *path)
+{
+       GSList *l;
+
+       for (l = msgs; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void transfer_info(GDBusProxy *proxy, int argc, char *argv[])
+{
+       rl_printf("Transfer %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(proxy, "Session");
+       print_property(proxy, "Name");
+       print_property(proxy, "Type");
+       print_property(proxy, "Status");
+       print_property(proxy, "Time");
+       print_property(proxy, "Size");
+       print_property(proxy, "Transferred");
+       print_property(proxy, "Filename");
+}
+
+static void message_info(GDBusProxy *proxy, int argc, char *argv[])
+{
+       rl_printf("Message %s\n", g_dbus_proxy_get_path(proxy));
+
+       print_property(proxy, "Folder");
+       print_property(proxy, "Subject");
+       print_property(proxy, "Timestamp");
+       print_property(proxy, "Sender");
+       print_property(proxy, "SenderAddress");
+       print_property(proxy, "ReplyTo");
+       print_property(proxy, "Recipient");
+       print_property(proxy, "RecipientAddress");
+       print_property(proxy, "Type");
+       print_property(proxy, "Size");
+       print_property(proxy, "Status");
+       print_property(proxy, "Priority");
+       print_property(proxy, "Read");
+       print_property(proxy, "Deleted");
+       print_property(proxy, "Sent");
+       print_property(proxy, "Protected");
+}
+
+static void cmd_info(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing object path argument\n");
+               return;
+       }
+
+       proxy = find_transfer(argv[1]);
+       if (proxy) {
+               transfer_info(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_message(argv[1]);
+       if (proxy) {
+               message_info(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Object %s not available\n", argv[1]);
+}
+
+static void cancel_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to cancel: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Cancel successful\n");
+}
+
+static void cmd_cancel(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (argc < 2) {
+               rl_printf("Missing transfer address argument\n");
+               return;
+       }
+
+       proxy = find_transfer(argv[1]);
+       if (!proxy) {
+               rl_printf("Transfer %s not available\n", argv[1]);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Cancel", NULL, cancel_reply, NULL,
+                                                       NULL) == FALSE) {
+               rl_printf("Failed to cancel transfer\n");
+               return;
+       }
+
+       rl_printf("Attempting to cancel transfer %s\n",
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static GDBusProxy *find_opp(const char *path)
+{
+       GSList *l;
+
+       for (l = opps; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static GDBusProxy *find_map(const char *path)
+{
+       GSList *l;
+
+       for (l = maps; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void print_dict_iter(DBusMessageIter *iter)
+{
+       DBusMessageIter dict;
+       int ctype;
+
+       ctype = dbus_message_iter_get_arg_type(iter);
+       if (ctype != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(iter, &dict);
+
+       while ((ctype = dbus_message_iter_get_arg_type(&dict)) !=
+                                                       DBUS_TYPE_INVALID) {
+               DBusMessageIter entry;
+               const char *key;
+
+               if (ctype != DBUS_TYPE_DICT_ENTRY)
+                       return;
+
+               dbus_message_iter_recurse(&dict, &entry);
+               if (dbus_message_iter_get_arg_type(&entry) != DBUS_TYPE_STRING)
+                       return;
+
+               dbus_message_iter_get_basic(&entry, &key);
+               dbus_message_iter_next(&entry);
+
+               print_iter("\t", key, &entry);
+
+               dbus_message_iter_next(&dict);
+       }
+}
+
+static void print_transfer_iter(DBusMessageIter *iter)
+{
+       const char *path;
+
+       dbus_message_iter_get_basic(iter, &path);
+
+       rl_printf("Transfer %s\n", path);
+
+       dbus_message_iter_next(iter);
+
+       print_dict_iter(iter);
+}
+
+static void send_reply(DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to send: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       print_transfer_iter(&iter);
+}
+
+static void send_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *file = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
+}
+
+static void opp_send(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing file argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "SendFile", send_setup, send_reply,
+                                       g_strdup(argv[1]), g_free) == FALSE) {
+               rl_printf("Failed to send\n");
+               return;
+       }
+
+       rl_printf("Attempting to send %s to %s\n", argv[1],
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static void push_reply(DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to PushMessage: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       print_transfer_iter(&iter);
+}
+
+static void push_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *file = user_data;
+       const char *folder = "";
+       DBusMessageIter dict;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void map_send(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing file argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "PushMessage", push_setup,
+                                       push_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to send\n");
+               return;
+       }
+
+       rl_printf("Attempting to send %s to %s\n", argv[1],
+                                               g_dbus_proxy_get_path(proxy));
+}
+
+static void cmd_send(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       proxy = find_opp(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               opp_send(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_map(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               map_send(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Command not supported\n");
+}
+
+static void change_folder_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to ChangeFolder: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("ChangeFolder successful\n");
+}
+
+static void change_folder_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *folder = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+}
+
+static void select_reply(DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to Select: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       rl_printf("Select successful\n");
+}
+
+static void select_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *folder = user_data;
+       const char *location = "int";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &location);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+}
+
+static void setfolder_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to SetFolder: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("SetFolder successful\n");
+}
+
+static void setfolder_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *folder = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+}
+
+static GDBusProxy *find_ftp(const char *path)
+{
+       GSList *l;
+
+       for (l = ftps; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static GDBusProxy *find_pbap(const char *path)
+{
+       GSList *l;
+
+       for (l = pbaps; l; l = g_slist_next(l)) {
+               GDBusProxy *proxy = l->data;
+
+               if (strcmp(path, g_dbus_proxy_get_path(proxy)) == 0)
+                       return proxy;
+       }
+
+       return NULL;
+}
+
+static void ftp_cd(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing path argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "ChangeFolder", change_folder_setup,
+                                       change_folder_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to ChangeFolder\n");
+               return;
+       }
+
+       rl_printf("Attempting to ChangeFolder to %s\n", argv[1]);
+}
+
+static void pbap_cd(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing path argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Select", select_setup,
+                                       select_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to Select\n");
+               return;
+       }
+
+       rl_printf("Attempting to Select to %s\n", argv[1]);
+}
+
+static void map_cd(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing path argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "SetFolder", setfolder_setup,
+                                       setfolder_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to SetFolder\n");
+               return;
+       }
+
+       rl_printf("Attempting to SetFolder to %s\n", argv[1]);
+}
+
+static void cmd_cd(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               ftp_cd(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_pbap(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               pbap_cd(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_map(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               map_cd(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Command not supported\n");
+}
+
+static void list_folder_reply(DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter, array;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to ListFolder: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
+               print_dict_iter(&array);
+               dbus_message_iter_next(&array);
+       }
+}
+
+static void ftp_ls(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (g_dbus_proxy_method_call(proxy, "ListFolder", NULL,
+                                               list_folder_reply, NULL,
+                                               NULL) == FALSE) {
+               rl_printf("Failed to ls\n");
+               return;
+       }
+
+       rl_printf("Attempting to ListFolder\n");
+}
+
+static void parse_list_reply(DBusMessage *message)
+{
+       DBusMessageIter iter, array;
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
+               DBusMessageIter entry;
+               const char *vcard;
+
+               if (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_STRUCT)
+                       return;
+
+               dbus_message_iter_recurse(&array, &entry);
+
+               dbus_message_iter_get_basic(&entry, &vcard);
+               dbus_message_iter_next(&entry);
+               print_iter("\t", vcard, &entry);
+               dbus_message_iter_next(&array);
+       }
+}
+
+static void list_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to List: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       parse_list_reply(message);
+}
+
+static void list_setup(DBusMessageIter *iter, void *user_data)
+{
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void search_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to Search: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       parse_list_reply(message);
+}
+
+static void search_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *value = user_data;
+       const char *field;
+       DBusMessageIter dict;
+
+       field = isalpha(value[0]) ? "name" : "number";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &field);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &value);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void pbap_search(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (g_dbus_proxy_method_call(proxy, "Search", search_setup,
+                                       search_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to Search\n");
+               return;
+       }
+
+       rl_printf("Attempting to Search\n");
+}
+
+static void list_folders_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+       DBusMessageIter iter, array;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to ListFolders: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       while (dbus_message_iter_get_arg_type(&array) != DBUS_TYPE_INVALID) {
+               print_dict_iter(&array);
+               dbus_message_iter_next(&array);
+       }
+}
+
+static void list_folders_setup(DBusMessageIter *iter, void *user_data)
+{
+       DBusMessageIter dict;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void list_messages_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+       DBusMessageIter iter, array;
+       int ctype;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to ListFolders: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       if (dbus_message_iter_get_arg_type(&iter) != DBUS_TYPE_ARRAY)
+               return;
+
+       dbus_message_iter_recurse(&iter, &array);
+
+       while ((ctype = dbus_message_iter_get_arg_type(&array)) ==
+                                                       DBUS_TYPE_DICT_ENTRY) {
+               DBusMessageIter entry;
+               const char *obj;
+
+               dbus_message_iter_recurse(&array, &entry);
+               dbus_message_iter_get_basic(&entry, &obj);
+               rl_printf("\t%s\n", obj);
+               dbus_message_iter_next(&array);
+       }
+}
+
+static void list_messages_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *folder = user_data;
+       DBusMessageIter dict;
+
+       if (strcmp(folder, "*") == 0)
+               folder = "";
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void pbap_ls(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc > 1) {
+               pbap_search(proxy, argc, argv);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "List", list_setup, list_reply,
+                                               NULL, NULL) == FALSE) {
+               rl_printf("Failed to List\n");
+               return;
+       }
+
+       rl_printf("Attempting to List\n");
+}
+
+static void map_ls_messages(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (g_dbus_proxy_method_call(proxy, "ListMessages", list_messages_setup,
+                                       list_messages_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to ListMessages\n");
+               return;
+       }
+
+       rl_printf("Attempting to ListMessages\n");
+}
+
+static void map_ls(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc > 1) {
+               map_ls_messages(proxy, argc, argv);
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "ListFolders", list_folders_setup,
+                                               list_folders_reply, NULL,
+                                               NULL) == FALSE) {
+               rl_printf("Failed to ListFolders\n");
+               return;
+       }
+
+       rl_printf("Attempting to ListFolders\n");
+}
+
+static void cmd_ls(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               ftp_ls(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_pbap(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               pbap_ls(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_map(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               map_ls(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Command not supported\n");
+}
+
+struct cp_args {
+       char *source;
+       char *target;
+};
+
+static void cp_free(void *data)
+{
+       struct cp_args *args = data;
+
+       g_free(args->source);
+       g_free(args->target);
+       g_free(args);
+}
+
+static struct cp_args *cp_new(char *argv[])
+{
+       struct cp_args *args;
+       const char *source;
+       const char *target;
+
+       source = rindex(argv[1], ':');
+       if (source == NULL)
+               source = argv[1];
+       else
+               source++;
+
+       target = rindex(argv[2], ':');
+       if (target == NULL)
+               target = argv[2];
+       else
+               target++;
+
+       args = g_new0(struct cp_args, 1);
+       args->source = g_strdup(source);
+       args->target = g_strdup(target);
+
+       return args;
+}
+
+static void cp_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct cp_args *args = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
+}
+
+static void copy_file_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to CopyFile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("CopyFile successful\n");
+}
+
+static void ftp_copy(GDBusProxy *proxy, int argc, char *argv[])
+{
+       struct cp_args *args;
+
+       args = cp_new(argv);
+
+       if (g_dbus_proxy_method_call(proxy, "CopyFile", cp_setup,
+                               copy_file_reply, args, cp_free) == FALSE) {
+               rl_printf("Failed to CopyFile\n");
+               return;
+       }
+
+       rl_printf("Attempting to CopyFile\n");
+}
+
+static void get_file_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+       DBusMessageIter iter;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to GetFile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       print_transfer_iter(&iter);
+}
+
+static void get_file_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct cp_args *args = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
+}
+
+static void ftp_get(GDBusProxy *proxy, int argc, char *argv[])
+{
+       struct cp_args *args;
+
+       if (rindex(argv[2], ':') == NULL)
+               return ftp_copy(proxy, argc, argv);
+
+       args = cp_new(argv);
+
+       if (g_dbus_proxy_method_call(proxy, "GetFile", get_file_setup,
+                               get_file_reply, args, cp_free) == FALSE) {
+               rl_printf("Failed to GetFile\n");
+               return;
+       }
+
+       rl_printf("Attempting to GetFile\n");
+}
+
+static void put_file_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+       DBusMessageIter iter;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to PutFile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       print_transfer_iter(&iter);
+}
+
+static void ftp_put(GDBusProxy *proxy, int argc, char *argv[])
+{
+       struct cp_args *args;
+
+       if (rindex(argv[2], ':') != NULL) {
+               rl_printf("Invalid target file argument\n");
+               return;
+       }
+
+       args = cp_new(argv);
+
+       if (g_dbus_proxy_method_call(proxy, "PutFile", cp_setup, put_file_reply,
+                                               args, cp_free) == FALSE) {
+               rl_printf("Failed to PutFile\n");
+               return;
+       }
+
+       rl_printf("Attempting to PutFile\n");
+}
+
+static void ftp_cp(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing source file argument\n");
+               return;
+       }
+
+       if (argc < 3) {
+               rl_printf("Missing target file argument\n");
+               return;
+       }
+
+       if (rindex(argv[1], ':') == NULL)
+               return ftp_get(proxy, argc, argv);
+
+       return ftp_put(proxy, argc, argv);
+}
+
+static void pull_all_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to PullAll: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+
+       rl_printf("PullAll successful\n");
+}
+
+static void pull_all_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *file = user_data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void pbap_pull_all(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (g_dbus_proxy_method_call(proxy, "PullAll", pull_all_setup,
+                                       pull_all_reply, g_strdup(argv[2]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to PullAll\n");
+               return;
+       }
+
+       rl_printf("Attempting to PullAll\n");
+}
+
+static void pull_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to Pull: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+
+       rl_printf("Pull successful\n");
+}
+
+static void pull_setup(DBusMessageIter *iter, void *user_data)
+{
+       struct cp_args *args = user_data;
+       DBusMessageIter dict;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->source);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &args->target);
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                                       DBUS_TYPE_STRING_AS_STRING
+                                       DBUS_TYPE_VARIANT_AS_STRING
+                                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING,
+                                       &dict);
+
+       dbus_message_iter_close_container(iter, &dict);
+}
+
+static void pbap_pull(GDBusProxy *proxy, int argc, char *argv[])
+{
+       struct cp_args *args;
+
+       args = cp_new(argv);
+
+       if (g_dbus_proxy_method_call(proxy, "Pull", pull_setup, pull_reply,
+                                               args, cp_free) == FALSE) {
+               rl_printf("Failed to Pull\n");
+               return;
+       }
+
+       rl_printf("Attempting to Pull\n");
+}
+
+static void pbap_cp(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing source file argument\n");
+               return;
+       }
+
+       if (argc < 3) {
+               rl_printf("Missing target file argument\n");
+               return;
+       }
+
+       if (strcmp(argv[1], "*") == 0)
+               return pbap_pull_all(proxy, argc, argv);
+
+       return pbap_pull(proxy, argc, argv);
+}
+
+static void get_reply(DBusMessage *message, void *user_data)
+{
+       DBusMessageIter iter;
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to Get: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       dbus_message_iter_init(message, &iter);
+
+       print_transfer_iter(&iter);
+}
+
+static void get_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *file = user_data;
+       dbus_bool_t attachment = TRUE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &attachment);
+}
+
+static void map_cp(GDBusProxy *proxy, int argc, char *argv[])
+{
+       GDBusProxy *obj;
+
+       if (argc < 2) {
+               rl_printf("Missing message argument\n");
+               return;
+       }
+
+       obj = find_message(argv[1]);
+       if (obj == NULL) {
+               rl_printf("Invalid message argument\n");
+               return;
+       }
+
+       if (argc < 3) {
+               rl_printf("Missing target file argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(obj, "Get", get_setup, get_reply,
+                                       g_strdup(argv[2]), g_free) == FALSE) {
+               rl_printf("Failed to Get\n");
+               return;
+       }
+
+       rl_printf("Attempting to Get\n");
+}
+
+static void cmd_cp(int argc, char *argv[])
+{
+
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               ftp_cp(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_pbap(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               pbap_cp(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_map(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               map_cp(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Command not supported\n");
+}
+
+static void move_file_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to MoveFile: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("MoveFile successful\n");
+}
+
+static void cmd_mv(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+       struct cp_args *args;
+
+       if (!check_default_session())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing source file argument\n");
+               return;
+       }
+
+       if (argc < 3) {
+               rl_printf("Missing target file argument\n");
+               return;
+       }
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy == NULL) {
+               rl_printf("Command not supported\n");
+               return;
+       }
+
+       args = cp_new(argv);
+
+       if (g_dbus_proxy_method_call(proxy, "MoveFile", cp_setup,
+                               move_file_reply, args, cp_free) == FALSE) {
+               rl_printf("Failed to MoveFile\n");
+               return;
+       }
+
+       rl_printf("Attempting to MoveFile\n");
+}
+
+static void delete_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to Delete: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("Delete successful\n");
+}
+
+static void delete_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *file = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &file);
+}
+
+static void ftp_rm(GDBusProxy *proxy, int argc, char *argv[])
+{
+       if (argc < 2) {
+               rl_printf("Missing file argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "Delete", delete_setup,
+                                       delete_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to Delete\n");
+               return;
+       }
+
+       rl_printf("Attempting to Delete\n");
+}
+
+static void set_delete_reply(const DBusError *error, void *user_data)
+{
+       if (dbus_error_is_set(error))
+               rl_printf("Failed to set Deleted: %s\n", error->name);
+       else
+               rl_printf("Set Deleted successful\n");
+}
+
+static void map_rm(GDBusProxy *proxy, int argc, char *argv[])
+{
+       GDBusProxy *msg;
+       dbus_bool_t value = TRUE;
+
+       if (argc < 2) {
+               rl_printf("Missing message argument\n");
+               return;
+       }
+
+       msg = find_message(argv[1]);
+       if (msg == NULL) {
+               rl_printf("Invalid message argument\n");
+               return;
+       }
+
+       if (g_dbus_proxy_set_property_basic(msg, "Deleted", DBUS_TYPE_BOOLEAN,
+                                               &value, set_delete_reply,
+                                               NULL, NULL) == FALSE) {
+               rl_printf("Failed to set Deleted\n");
+               return;
+       }
+
+       rl_printf("Attempting to set Deleted\n");
+}
+
+static void cmd_rm(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               ftp_rm(proxy, argc, argv);
+               return;
+       }
+
+       proxy = find_map(g_dbus_proxy_get_path(default_session));
+       if (proxy) {
+               map_rm(proxy, argc, argv);
+               return;
+       }
+
+       rl_printf("Command not supported\n");
+}
+
+static void create_folder_reply(DBusMessage *message, void *user_data)
+{
+       DBusError error;
+
+       dbus_error_init(&error);
+
+       if (dbus_set_error_from_message(&error, message) == TRUE) {
+               rl_printf("Failed to CreateFolder: %s\n", error.name);
+               dbus_error_free(&error);
+               return;
+       }
+
+       rl_printf("CreateFolder successful\n");
+}
+
+static void create_folder_setup(DBusMessageIter *iter, void *user_data)
+{
+       const char *folder = user_data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &folder);
+}
+
+static void cmd_mkdir(int argc, char *argv[])
+{
+       GDBusProxy *proxy;
+
+       if (!check_default_session())
+               return;
+
+       if (argc < 2) {
+               rl_printf("Missing folder argument\n");
+               return;
+       }
+
+       proxy = find_ftp(g_dbus_proxy_get_path(default_session));
+       if (proxy == NULL) {
+               rl_printf("Command not supported\n");
+               return;
+       }
+
+       if (g_dbus_proxy_method_call(proxy, "CreateFolder", create_folder_setup,
+                                       create_folder_reply, g_strdup(argv[1]),
+                                       g_free) == FALSE) {
+               rl_printf("Failed to CreateFolder\n");
+               return;
+       }
+
+       rl_printf("Attempting to CreateFolder\n");
+}
+
+static const struct {
+       const char *cmd;
+       const char *arg;
+       void (*func) (int argc, char *argv[]);
+       const char *desc;
+} cmd_table[] = {
+       { "connect",      "<dev> [uuid]", cmd_connect, "Connect session" },
+       { "disconnect",   "[session]", cmd_disconnect, "Disconnect session" },
+       { "list",         NULL,       cmd_list, "List available sessions" },
+       { "show",         "[session]", cmd_show, "Session information" },
+       { "select",       "<session>", cmd_select, "Select default session" },
+       { "info",         "<object>", cmd_info, "Object information" },
+       { "cancel",       "<transfer>", cmd_cancel, "Cancel transfer" },
+       { "send",         "<file>",   cmd_send, "Send file" },
+       { "cd",           "<path>",   cmd_cd, "Change current folder" },
+       { "ls",           NULL,       cmd_ls, "List current folder" },
+       { "cp",          "<source file> <destination file>",   cmd_cp,
+                               "Copy source file to destination file" },
+       { "mv",          "<source file> <destination file>",   cmd_mv,
+                               "Move source file to destination file" },
+       { "rm",          "<file>",    cmd_rm, "Delete file" },
+       { "mkdir",       "<folder>",    cmd_mkdir, "Create folder" },
+       { "quit",         NULL,       cmd_quit, "Quit program" },
+       { "exit",         NULL,       cmd_quit },
+       { "help" },
+       {}
+};
+
+static char *cmd_generator(const char *text, int state)
+{
+       static int index, len;
+       const char *cmd;
+
+       if (!state) {
+               index = 0;
+               len = strlen(text);
+       }
+
+       while ((cmd = cmd_table[index].cmd)) {
+               index++;
+
+               if (!strncmp(cmd, text, len))
+                       return strdup(cmd);
+       }
+
+       return NULL;
+}
+
+static char **cmd_completion(const char *text, int start, int end)
+{
+       char **matches = NULL;
+
+       if (start == 0) {
+               rl_completion_display_matches_hook = NULL;
+               matches = rl_completion_matches(text, cmd_generator);
+       }
+
+       if (!matches)
+               rl_attempted_completion_over = 1;
+
+       return matches;
+}
+
+static void rl_handler(char *input)
+{
+       int argc;
+       char **argv = NULL;
+       int i;
+
+       if (!input) {
+               rl_insert_text("quit");
+               rl_redisplay();
+               rl_crlf();
+               g_main_loop_quit(main_loop);
+               return;
+       }
+
+       if (!strlen(input))
+               goto done;
+
+       add_history(input);
+
+       argv = g_strsplit(input, " ", -1);
+       if (argv == NULL)
+               goto done;
+
+       for (argc = 0; argv[argc];)
+               argc++;
+
+       if (argc == 0)
+               goto done;
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (strcmp(argv[0], cmd_table[i].cmd))
+                       continue;
+
+               if (cmd_table[i].func) {
+                       cmd_table[i].func(argc, argv);
+                       goto done;
+               }
+       }
+
+       if (strcmp(argv[0], "help")) {
+               printf("Invalid command\n");
+               goto done;
+       }
+
+       printf("Available commands:\n");
+
+       for (i = 0; cmd_table[i].cmd; i++) {
+               if (cmd_table[i].desc)
+                       printf("  %s %-*s %s\n", cmd_table[i].cmd,
+                                       (int)(25 - strlen(cmd_table[i].cmd)),
+                                       cmd_table[i].arg ? : "",
+                                       cmd_table[i].desc ? : "");
+       }
+
+done:
+       g_strfreev(argv);
+       free(input);
+}
+
+static gboolean option_version = FALSE;
+
+static GOptionEntry options[] = {
+       { "version", 'v', 0, G_OPTION_ARG_NONE, &option_version,
+                               "Show version information and exit" },
+       { NULL },
+};
+
+static gboolean signal_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       static unsigned int __terminated = 0;
+       struct signalfd_siginfo si;
+       ssize_t result;
+       int fd;
+
+       if (condition & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, &si, sizeof(si));
+       if (result != sizeof(si))
+               return FALSE;
+
+       switch (si.ssi_signo) {
+       case SIGINT:
+               rl_replace_line("", 0);
+               rl_crlf();
+               rl_on_new_line();
+               rl_redisplay();
+               break;
+       case SIGTERM:
+               if (__terminated == 0) {
+                       rl_replace_line("", 0);
+                       rl_crlf();
+                       g_main_loop_quit(main_loop);
+               }
+
+               __terminated = 1;
+               break;
+       }
+
+       return TRUE;
+}
+
+static guint setup_signalfd(void)
+{
+       GIOChannel *channel;
+       guint source;
+       sigset_t mask;
+       int fd;
+
+       sigemptyset(&mask);
+       sigaddset(&mask, SIGINT);
+       sigaddset(&mask, SIGTERM);
+
+       if (sigprocmask(SIG_BLOCK, &mask, NULL) < 0) {
+               perror("Failed to set signal mask");
+               return 0;
+       }
+
+       fd = signalfd(-1, &mask, 0);
+       if (fd < 0) {
+               perror("Failed to create signal descriptor");
+               return 0;
+       }
+
+       channel = g_io_channel_unix_new(fd);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               signal_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static gboolean input_handler(GIOChannel *channel, GIOCondition condition,
+                                                       gpointer user_data)
+{
+       if (condition & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+               g_main_loop_quit(main_loop);
+               return FALSE;
+       }
+
+       rl_callback_read_char();
+       return TRUE;
+}
+
+static guint setup_standard_input(void)
+{
+       GIOChannel *channel;
+       guint source;
+
+       channel = g_io_channel_unix_new(fileno(stdin));
+
+       source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               input_handler, NULL);
+
+       g_io_channel_unref(channel);
+
+       return source;
+}
+
+static void client_added(GDBusProxy *proxy)
+{
+       if (client == NULL)
+               client = proxy;
+
+       print_proxy(proxy, "Client", COLORED_NEW);
+}
+
+static void session_added(GDBusProxy *proxy)
+{
+       sessions = g_slist_append(sessions, proxy);
+
+       if (default_session == NULL)
+               set_default_session(proxy);
+
+       print_proxy(proxy, "Session", COLORED_NEW);
+}
+
+static void print_transferred(struct transfer_data *data, const char *str,
+                                                       DBusMessageIter *iter)
+{
+       dbus_uint64_t valu64;
+       uint64_t speed;
+       int seconds, minutes;
+
+       dbus_message_iter_get_basic(iter, &valu64);
+       speed = valu64 - data->transferred;
+       data->transferred = valu64;
+
+       if (data->size == 0) {
+               rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s)\n",
+                                               str, valu64, speed / 1000);
+               return;
+       }
+
+       seconds = (data->size - data->transferred) / speed;
+       minutes = seconds / 60;
+       seconds %= 60;
+       rl_printf("%sTransferred: %" PRIu64 " (@%" PRIu64 "KB/s %02u:%02u)\n",
+                               str, valu64, speed / 1000, minutes, seconds);
+}
+
+static void transfer_property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct transfer_data *data = user_data;
+       char *str;
+
+       str = proxy_description(proxy, "Transfer", COLORED_CHG);
+
+       if (strcmp(name, "Transferred") == 0) {
+               print_transferred(data, str, iter);
+               goto done;
+       }
+
+       if (strcmp(name, "Size") == 0)
+               dbus_message_iter_get_basic(iter, &data->size);
+
+       print_iter(str, name, iter);
+
+done:
+       g_free(str);
+}
+
+static void transfer_destroy(GDBusProxy *proxy, void *user_data)
+{
+       struct transfer_data *data = user_data;
+
+       g_free(data);
+}
+
+static void transfer_added(GDBusProxy *proxy)
+{
+       struct transfer_data *data;
+       DBusMessageIter iter;
+
+       transfers = g_slist_append(transfers, proxy);
+
+       print_proxy(proxy, "Transfer", COLORED_NEW);
+
+       data = g_new0(struct transfer_data, 1);
+
+       if (g_dbus_proxy_get_property(proxy, "Transfered", &iter))
+               dbus_message_iter_get_basic(&iter, &data->transferred);
+
+       if (g_dbus_proxy_get_property(proxy, "Size", &iter))
+               dbus_message_iter_get_basic(&iter, &data->size);
+
+       g_dbus_proxy_set_property_watch(proxy, transfer_property_changed, data);
+       g_dbus_proxy_set_removed_watch(proxy, transfer_destroy, data);
+}
+
+static void opp_added(GDBusProxy *proxy)
+{
+       opps = g_slist_append(opps, proxy);
+
+       print_proxy(proxy, "ObjectPush", COLORED_NEW);
+}
+
+static void ftp_added(GDBusProxy *proxy)
+{
+       ftps = g_slist_append(ftps, proxy);
+
+       print_proxy(proxy, "FileTransfer", COLORED_NEW);
+}
+
+static void pbap_added(GDBusProxy *proxy)
+{
+       pbaps = g_slist_append(pbaps, proxy);
+
+       print_proxy(proxy, "PhonebookAccess", COLORED_NEW);
+}
+
+static void map_added(GDBusProxy *proxy)
+{
+       maps = g_slist_append(maps, proxy);
+
+       print_proxy(proxy, "MessageAccess", COLORED_NEW);
+}
+
+static void msg_added(GDBusProxy *proxy)
+{
+       msgs = g_slist_append(msgs, proxy);
+
+       print_proxy(proxy, "Message", COLORED_NEW);
+}
+
+static void proxy_added(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
+               client_added(proxy);
+       else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
+               session_added(proxy);
+       else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
+               transfer_added(proxy);
+       else if (!strcmp(interface, OBEX_OPP_INTERFACE))
+               opp_added(proxy);
+       else if (!strcmp(interface, OBEX_FTP_INTERFACE))
+               ftp_added(proxy);
+       else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
+               pbap_added(proxy);
+       else if (!strcmp(interface, OBEX_MAP_INTERFACE))
+               map_added(proxy);
+       else if (!strcmp(interface, OBEX_MSG_INTERFACE))
+               msg_added(proxy);
+}
+
+static void client_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "Client", COLORED_DEL);
+
+       if (client == proxy)
+               client = NULL;
+}
+
+static void session_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "Session", COLORED_DEL);
+
+       if (default_session == proxy)
+               set_default_session(NULL);
+
+       sessions = g_slist_remove(sessions, proxy);
+}
+
+static void transfer_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "Transfer", COLORED_DEL);
+
+       transfers = g_slist_remove(transfers, proxy);
+}
+
+static void opp_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "ObjectPush", COLORED_DEL);
+
+       opps = g_slist_remove(opps, proxy);
+}
+
+static void ftp_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "FileTransfer", COLORED_DEL);
+
+       ftps = g_slist_remove(ftps, proxy);
+}
+
+static void pbap_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "PhonebookAccess", COLORED_DEL);
+
+       pbaps = g_slist_remove(pbaps, proxy);
+}
+
+static void map_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "MessageAccess", COLORED_DEL);
+
+       maps = g_slist_remove(maps, proxy);
+}
+
+static void msg_removed(GDBusProxy *proxy)
+{
+       print_proxy(proxy, "Message", COLORED_DEL);
+
+       msgs = g_slist_remove(msgs, proxy);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, OBEX_CLIENT_INTERFACE))
+               client_removed(proxy);
+       else if (!strcmp(interface, OBEX_SESSION_INTERFACE))
+               session_removed(proxy);
+       else if (!strcmp(interface, OBEX_TRANSFER_INTERFACE))
+               transfer_removed(proxy);
+       else if (!strcmp(interface, OBEX_OPP_INTERFACE))
+               opp_removed(proxy);
+       else if (!strcmp(interface, OBEX_FTP_INTERFACE))
+               ftp_removed(proxy);
+       else if (!strcmp(interface, OBEX_PBAP_INTERFACE))
+               pbap_removed(proxy);
+       else if (!strcmp(interface, OBEX_MAP_INTERFACE))
+               map_removed(proxy);
+       else if (!strcmp(interface, OBEX_MSG_INTERFACE))
+               msg_removed(proxy);
+}
+
+static void session_property_changed(GDBusProxy *proxy, const char *name,
+                                               DBusMessageIter *iter)
+{
+       char *str;
+
+       str = proxy_description(proxy, "Session", COLORED_CHG);
+       print_iter(str, name, iter);
+       g_free(str);
+}
+
+static void property_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       const char *interface;
+
+       interface = g_dbus_proxy_get_interface(proxy);
+
+       if (!strcmp(interface, OBEX_SESSION_INTERFACE))
+               session_property_changed(proxy, name, iter);
+}
+
+int main(int argc, char *argv[])
+{
+       GOptionContext *context;
+       GError *error = NULL;
+       GDBusClient *client;
+       guint signal, input;
+
+       context = g_option_context_new(NULL);
+       g_option_context_add_main_entries(context, options, NULL);
+
+       if (g_option_context_parse(context, &argc, &argv, &error) == FALSE) {
+               if (error != NULL) {
+                       g_printerr("%s\n", error->message);
+                       g_error_free(error);
+               } else
+                       g_printerr("An unknown error occurred\n");
+               exit(1);
+       }
+
+       g_option_context_free(context);
+
+       if (option_version == TRUE) {
+               printf("%s\n", VERSION);
+               exit(0);
+       }
+
+       main_loop = g_main_loop_new(NULL, FALSE);
+       dbus_conn = g_dbus_setup_bus(DBUS_BUS_SESSION, NULL, NULL);
+
+       rl_attempted_completion_function = cmd_completion;
+
+       rl_erase_empty_line = 1;
+       rl_callback_handler_install(NULL, rl_handler);
+
+       rl_set_prompt(PROMPT_OFF);
+       rl_redisplay();
+
+       input = setup_standard_input();
+       signal = setup_signalfd();
+       client = g_dbus_client_new(dbus_conn, "org.bluez.obex",
+                                                       "/org/bluez/obex");
+
+       g_dbus_client_set_connect_watch(client, connect_handler, NULL);
+       g_dbus_client_set_disconnect_watch(client, disconnect_handler, NULL);
+
+       g_dbus_client_set_proxy_handlers(client, proxy_added, proxy_removed,
+                                                       property_changed, NULL);
+
+       g_main_loop_run(main_loop);
+
+       g_dbus_client_unref(client);
+       g_source_remove(signal);
+       g_source_remove(input);
+
+       rl_message("");
+       rl_callback_handler_remove();
+
+       dbus_connection_unref(dbus_conn);
+       g_main_loop_unref(main_loop);
+
+       return 0;
+}
diff --git a/tools/parser.c b/tools/parser.c
deleted file mode 100644 (file)
index 5733ab7..0000000
+++ /dev/null
@@ -1,1817 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
-
-/* Bison implementation for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-   
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-   
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-/* C LALR(1) parser skeleton written by Richard Stallman, by
-   simplifying the original so-called "semantic" parser.  */
-
-/* All symbols defined below should begin with yy or YY, to avoid
-   infringing on user name space.  This should be done even for local
-   variables, as they might otherwise be expanded by user macros.
-   There are some unavoidable exceptions within include files to
-   define necessary library symbols; they are noted "INFRINGES ON
-   USER NAME SPACE" below.  */
-
-/* Identify Bison output.  */
-#define YYBISON 1
-
-/* Bison version.  */
-#define YYBISON_VERSION "2.5"
-
-/* Skeleton name.  */
-#define YYSKELETON_NAME "yacc.c"
-
-/* Pure parsers.  */
-#define YYPURE 0
-
-/* Push parsers.  */
-#define YYPUSH 0
-
-/* Pull parsers.  */
-#define YYPULL 1
-
-/* Using locations.  */
-#define YYLSP_NEEDED 0
-
-
-
-/* Copy the first part of user declarations.  */
-
-/* Line 268 of yacc.c  */
-#line 1 "parser.y"
-
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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 <sys/param.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "kword.h"
-
-int yylex(void);
-int yyerror(char *s); 
-
-struct rfcomm_opts *opts;
-
-
-
-/* Line 268 of yacc.c  */
-#line 120 "tools/parser.c"
-
-/* Enabling traces.  */
-#ifndef YYDEBUG
-# define YYDEBUG 0
-#endif
-
-/* Enabling verbose error messages.  */
-#ifdef YYERROR_VERBOSE
-# undef YYERROR_VERBOSE
-# define YYERROR_VERBOSE 1
-#else
-# define YYERROR_VERBOSE 0
-#endif
-
-/* Enabling the token table.  */
-#ifndef YYTOKEN_TABLE
-# define YYTOKEN_TABLE 0
-#endif
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     K_BIND = 258,
-     K_DEVICE = 259,
-     K_CHANNEL = 260,
-     K_COMMENT = 261,
-     K_YES = 262,
-     K_NO = 263,
-     NUMBER = 264,
-     RFCOMM = 265,
-     STRING = 266,
-     WORD = 267,
-     BDADDR = 268
-   };
-#endif
-/* Tokens.  */
-#define K_BIND 258
-#define K_DEVICE 259
-#define K_CHANNEL 260
-#define K_COMMENT 261
-#define K_YES 262
-#define K_NO 263
-#define NUMBER 264
-#define RFCOMM 265
-#define STRING 266
-#define WORD 267
-#define BDADDR 268
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-
-/* Line 293 of yacc.c  */
-#line 49 "parser.y"
-
-       int number;
-       char *string;
-       bdaddr_t *bdaddr;
-
-
-
-/* Line 293 of yacc.c  */
-#line 190 "tools/parser.c"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-
-/* Copy the second part of user declarations.  */
-
-
-/* Line 343 of yacc.c  */
-#line 202 "tools/parser.c"
-
-#ifdef short
-# undef short
-#endif
-
-#ifdef YYTYPE_UINT8
-typedef YYTYPE_UINT8 yytype_uint8;
-#else
-typedef unsigned char yytype_uint8;
-#endif
-
-#ifdef YYTYPE_INT8
-typedef YYTYPE_INT8 yytype_int8;
-#elif (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-typedef signed char yytype_int8;
-#else
-typedef short int yytype_int8;
-#endif
-
-#ifdef YYTYPE_UINT16
-typedef YYTYPE_UINT16 yytype_uint16;
-#else
-typedef unsigned short int yytype_uint16;
-#endif
-
-#ifdef YYTYPE_INT16
-typedef YYTYPE_INT16 yytype_int16;
-#else
-typedef short int yytype_int16;
-#endif
-
-#ifndef YYSIZE_T
-# ifdef __SIZE_TYPE__
-#  define YYSIZE_T __SIZE_TYPE__
-# elif defined size_t
-#  define YYSIZE_T size_t
-# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#  include <stddef.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYSIZE_T size_t
-# else
-#  define YYSIZE_T unsigned int
-# endif
-#endif
-
-#define YYSIZE_MAXIMUM ((YYSIZE_T) -1)
-
-#ifndef YY_
-# if defined YYENABLE_NLS && YYENABLE_NLS
-#  if ENABLE_NLS
-#   include <libintl.h> /* INFRINGES ON USER NAME SPACE */
-#   define YY_(msgid) dgettext ("bison-runtime", msgid)
-#  endif
-# endif
-# ifndef YY_
-#  define YY_(msgid) msgid
-# endif
-#endif
-
-/* Suppress unused-variable warnings by "using" E.  */
-#if ! defined lint || defined __GNUC__
-# define YYUSE(e) ((void) (e))
-#else
-# define YYUSE(e) /* empty */
-#endif
-
-/* Identity function, used to suppress warnings about constant conditions.  */
-#ifndef lint
-# define YYID(n) (n)
-#else
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static int
-YYID (int yyi)
-#else
-static int
-YYID (yyi)
-    int yyi;
-#endif
-{
-  return yyi;
-}
-#endif
-
-#if ! defined yyoverflow || YYERROR_VERBOSE
-
-/* The parser invokes alloca or malloc; define the necessary symbols.  */
-
-# ifdef YYSTACK_USE_ALLOCA
-#  if YYSTACK_USE_ALLOCA
-#   ifdef __GNUC__
-#    define YYSTACK_ALLOC __builtin_alloca
-#   elif defined __BUILTIN_VA_ARG_INCR
-#    include <alloca.h> /* INFRINGES ON USER NAME SPACE */
-#   elif defined _AIX
-#    define YYSTACK_ALLOC __alloca
-#   elif defined _MSC_VER
-#    include <malloc.h> /* INFRINGES ON USER NAME SPACE */
-#    define alloca _alloca
-#   else
-#    define YYSTACK_ALLOC alloca
-#    if ! defined _ALLOCA_H && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-#     include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#     ifndef EXIT_SUCCESS
-#      define EXIT_SUCCESS 0
-#     endif
-#    endif
-#   endif
-#  endif
-# endif
-
-# ifdef YYSTACK_ALLOC
-   /* Pacify GCC's `empty if-body' warning.  */
-#  define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0))
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-    /* The OS might guarantee only one guard page at the bottom of the stack,
-       and a page size can be as small as 4096 bytes.  So we cannot safely
-       invoke alloca (N) if N exceeds 4096.  Use a slightly smaller number
-       to allow for a few compiler-allocated temporary stack slots.  */
-#   define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */
-#  endif
-# else
-#  define YYSTACK_ALLOC YYMALLOC
-#  define YYSTACK_FREE YYFREE
-#  ifndef YYSTACK_ALLOC_MAXIMUM
-#   define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM
-#  endif
-#  if (defined __cplusplus && ! defined EXIT_SUCCESS \
-       && ! ((defined YYMALLOC || defined malloc) \
-            && (defined YYFREE || defined free)))
-#   include <stdlib.h> /* INFRINGES ON USER NAME SPACE */
-#   ifndef EXIT_SUCCESS
-#    define EXIT_SUCCESS 0
-#   endif
-#  endif
-#  ifndef YYMALLOC
-#   define YYMALLOC malloc
-#   if ! defined malloc && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-#  ifndef YYFREE
-#   define YYFREE free
-#   if ! defined free && ! defined EXIT_SUCCESS && (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-void free (void *); /* INFRINGES ON USER NAME SPACE */
-#   endif
-#  endif
-# endif
-#endif /* ! defined yyoverflow || YYERROR_VERBOSE */
-
-
-#if (! defined yyoverflow \
-     && (! defined __cplusplus \
-        || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL)))
-
-/* A type that is properly aligned for any stack member.  */
-union yyalloc
-{
-  yytype_int16 yyss_alloc;
-  YYSTYPE yyvs_alloc;
-};
-
-/* The size of the maximum gap between one aligned stack and the next.  */
-# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1)
-
-/* The size of an array large to enough to hold all stacks, each with
-   N elements.  */
-# define YYSTACK_BYTES(N) \
-     ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \
-      + YYSTACK_GAP_MAXIMUM)
-
-# define YYCOPY_NEEDED 1
-
-/* Relocate STACK from its old location to the new one.  The
-   local variables YYSIZE and YYSTACKSIZE give the old and new number of
-   elements in the stack, and YYPTR gives the new location of the
-   stack.  Advance YYPTR to a properly aligned location for the next
-   stack.  */
-# define YYSTACK_RELOCATE(Stack_alloc, Stack)                          \
-    do                                                                 \
-      {                                                                        \
-       YYSIZE_T yynewbytes;                                            \
-       YYCOPY (&yyptr->Stack_alloc, Stack, yysize);                    \
-       Stack = &yyptr->Stack_alloc;                                    \
-       yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \
-       yyptr += yynewbytes / sizeof (*yyptr);                          \
-      }                                                                        \
-    while (YYID (0))
-
-#endif
-
-#if defined YYCOPY_NEEDED && YYCOPY_NEEDED
-/* Copy COUNT objects from FROM to TO.  The source and destination do
-   not overlap.  */
-# ifndef YYCOPY
-#  if defined __GNUC__ && 1 < __GNUC__
-#   define YYCOPY(To, From, Count) \
-      __builtin_memcpy (To, From, (Count) * sizeof (*(From)))
-#  else
-#   define YYCOPY(To, From, Count)             \
-      do                                       \
-       {                                       \
-         YYSIZE_T yyi;                         \
-         for (yyi = 0; yyi < (Count); yyi++)   \
-           (To)[yyi] = (From)[yyi];            \
-       }                                       \
-      while (YYID (0))
-#  endif
-# endif
-#endif /* !YYCOPY_NEEDED */
-
-/* YYFINAL -- State number of the termination state.  */
-#define YYFINAL  8
-/* YYLAST -- Last index in YYTABLE.  */
-#define YYLAST   40
-
-/* YYNTOKENS -- Number of terminals.  */
-#define YYNTOKENS  17
-/* YYNNTS -- Number of nonterminals.  */
-#define YYNNTS  8
-/* YYNRULES -- Number of rules.  */
-#define YYNRULES  20
-/* YYNRULES -- Number of states.  */
-#define YYNSTATES  33
-
-/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX.  */
-#define YYUNDEFTOK  2
-#define YYMAXUTOK   268
-
-#define YYTRANSLATE(YYX)                                               \
-  ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK)
-
-/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX.  */
-static const yytype_uint8 yytranslate[] =
-{
-       0,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,    16,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,    14,     2,    15,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     2,     2,     2,     2,
-       2,     2,     2,     2,     2,     2,     1,     2,     3,     4,
-       5,     6,     7,     8,     9,    10,    11,    12,    13
-};
-
-#if YYDEBUG
-/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in
-   YYRHS.  */
-static const yytype_uint8 yyprhs[] =
-{
-       0,     0,     3,     4,     6,     9,    14,    19,    21,    23,
-      25,    27,    30,    33,    37,    40,    43,    46,    49,    51,
-      53
-};
-
-/* YYRHS -- A `-1'-separated list of the rules' RHS.  */
-static const yytype_int8 yyrhs[] =
-{
-      18,     0,    -1,    -1,    19,    -1,    18,    19,    -1,    20,
-      14,    22,    15,    -1,    21,    14,    22,    15,    -1,    12,
-      -1,     1,    -1,    12,    -1,    10,    -1,    23,    16,    -1,
-       1,    16,    -1,    22,    23,    16,    -1,     3,    24,    -1,
-       4,    13,    -1,     5,     9,    -1,     6,    11,    -1,    12,
-      -1,     7,    -1,     8,    -1
-};
-
-/* YYRLINE[YYN] -- source line where rule number YYN was defined.  */
-static const yytype_uint8 yyrline[] =
-{
-       0,    66,    66,    67,    68,    71,    72,    73,    76,    83,
-      89,    98,    99,   100,   103,   108,   113,   118,   123,   129,
-     130
-};
-#endif
-
-#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE
-/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM.
-   First, the terminals, then, starting at YYNTOKENS, nonterminals.  */
-static const char *const yytname[] =
-{
-  "$end", "error", "$undefined", "K_BIND", "K_DEVICE", "K_CHANNEL",
-  "K_COMMENT", "K_YES", "K_NO", "NUMBER", "RFCOMM", "STRING", "WORD",
-  "BDADDR", "'{'", "'}'", "';'", "$accept", "config", "statement",
-  "section", "rfcomm", "rfcomm_options", "rfcomm_option", "bool", 0
-};
-#endif
-
-# ifdef YYPRINT
-/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to
-   token YYLEX-NUM.  */
-static const yytype_uint16 yytoknum[] =
-{
-       0,   256,   257,   258,   259,   260,   261,   262,   263,   264,
-     265,   266,   267,   268,   123,   125,    59
-};
-# endif
-
-/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives.  */
-static const yytype_uint8 yyr1[] =
-{
-       0,    17,    18,    18,    18,    19,    19,    19,    19,    20,
-      21,    22,    22,    22,    23,    23,    23,    23,    23,    24,
-      24
-};
-
-/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN.  */
-static const yytype_uint8 yyr2[] =
-{
-       0,     2,     0,     1,     2,     4,     4,     1,     1,     1,
-       1,     2,     2,     3,     2,     2,     2,     2,     1,     1,
-       1
-};
-
-/* YYDEFACT[STATE-NAME] -- Default reduction number in state STATE-NUM.
-   Performed when YYTABLE doesn't specify something else to do.  Zero
-   means the default is an error.  */
-static const yytype_uint8 yydefact[] =
-{
-       0,     8,    10,     7,     0,     3,     0,     0,     1,     4,
-       0,     0,     0,     0,     0,     0,     0,    18,     0,     0,
-       0,    12,    19,    20,    14,    15,    16,    17,     5,     0,
-      11,     6,    13
-};
-
-/* YYDEFGOTO[NTERM-NUM].  */
-static const yytype_int8 yydefgoto[] =
-{
-      -1,     4,     5,     6,     7,    18,    19,    24
-};
-
-/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing
-   STATE-NUM.  */
-#define YYPACT_NINF -7
-static const yytype_int8 yypact[] =
-{
-      10,    -7,    -7,    -6,    14,    -7,     4,     7,    -7,    -7,
-      24,    24,    15,    25,    21,    26,    12,    -7,    -3,    22,
-       1,    -7,    -7,    -7,    -7,    -7,    -7,    -7,    -7,    23,
-      -7,    -7,    -7
-};
-
-/* YYPGOTO[NTERM-NUM].  */
-static const yytype_int8 yypgoto[] =
-{
-      -7,    -7,    33,    -7,    -7,    29,    -1,    -7
-};
-
-/* YYTABLE[YYPACT[STATE-NUM]].  What to do in state STATE-NUM.  If
-   positive, shift that token.  If negative, reduce the rule which
-   number is the opposite.  If YYTABLE_NINF, syntax error.  */
-#define YYTABLE_NINF -10
-static const yytype_int8 yytable[] =
-{
-      13,    14,    15,    16,    13,    14,    15,    16,    -9,    17,
-      -2,     1,    28,    17,     8,     1,    31,    29,    10,    29,
-       2,    11,     3,    27,     2,    12,     3,    13,    14,    15,
-      16,    21,    22,    23,    25,    26,    17,     9,    30,    32,
-      20
-};
-
-#define yypact_value_is_default(yystate) \
-  ((yystate) == (-7))
-
-#define yytable_value_is_error(yytable_value) \
-  YYID (0)
-
-static const yytype_uint8 yycheck[] =
-{
-       3,     4,     5,     6,     3,     4,     5,     6,    14,    12,
-       0,     1,    15,    12,     0,     1,    15,    18,    14,    20,
-      10,    14,    12,    11,    10,     1,    12,     3,     4,     5,
-       6,    16,     7,     8,    13,     9,    12,     4,    16,    16,
-      11
-};
-
-/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing
-   symbol of state STATE-NUM.  */
-static const yytype_uint8 yystos[] =
-{
-       0,     1,    10,    12,    18,    19,    20,    21,     0,    19,
-      14,    14,     1,     3,     4,     5,     6,    12,    22,    23,
-      22,    16,     7,     8,    24,    13,     9,    11,    15,    23,
-      16,    15,    16
-};
-
-#define yyerrok                (yyerrstatus = 0)
-#define yyclearin      (yychar = YYEMPTY)
-#define YYEMPTY                (-2)
-#define YYEOF          0
-
-#define YYACCEPT       goto yyacceptlab
-#define YYABORT                goto yyabortlab
-#define YYERROR                goto yyerrorlab
-
-
-/* Like YYERROR except do call yyerror.  This remains here temporarily
-   to ease the transition to the new meaning of YYERROR, for GCC.
-   Once GCC version 2 has supplanted version 1, this can go.  However,
-   YYFAIL appears to be in use.  Nevertheless, it is formally deprecated
-   in Bison 2.4.2's NEWS entry, where a plan to phase it out is
-   discussed.  */
-
-#define YYFAIL         goto yyerrlab
-#if defined YYFAIL
-  /* This is here to suppress warnings from the GCC cpp's
-     -Wunused-macros.  Normally we don't worry about that warning, but
-     some users do, and we want to make it easy for users to remove
-     YYFAIL uses, which will produce warnings from Bison 2.5.  */
-#endif
-
-#define YYRECOVERING()  (!!yyerrstatus)
-
-#define YYBACKUP(Token, Value)                                 \
-do                                                             \
-  if (yychar == YYEMPTY && yylen == 1)                         \
-    {                                                          \
-      yychar = (Token);                                                \
-      yylval = (Value);                                                \
-      YYPOPSTACK (1);                                          \
-      goto yybackup;                                           \
-    }                                                          \
-  else                                                         \
-    {                                                          \
-      yyerror (YY_("syntax error: cannot back up")); \
-      YYERROR;                                                 \
-    }                                                          \
-while (YYID (0))
-
-
-#define YYTERROR       1
-#define YYERRCODE      256
-
-
-/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N].
-   If N is 0, then set CURRENT to the empty location which ends
-   the previous symbol: RHS[0] (always defined).  */
-
-#define YYRHSLOC(Rhs, K) ((Rhs)[K])
-#ifndef YYLLOC_DEFAULT
-# define YYLLOC_DEFAULT(Current, Rhs, N)                               \
-    do                                                                 \
-      if (YYID (N))                                                    \
-       {                                                               \
-         (Current).first_line   = YYRHSLOC (Rhs, 1).first_line;        \
-         (Current).first_column = YYRHSLOC (Rhs, 1).first_column;      \
-         (Current).last_line    = YYRHSLOC (Rhs, N).last_line;         \
-         (Current).last_column  = YYRHSLOC (Rhs, N).last_column;       \
-       }                                                               \
-      else                                                             \
-       {                                                               \
-         (Current).first_line   = (Current).last_line   =              \
-           YYRHSLOC (Rhs, 0).last_line;                                \
-         (Current).first_column = (Current).last_column =              \
-           YYRHSLOC (Rhs, 0).last_column;                              \
-       }                                                               \
-    while (YYID (0))
-#endif
-
-
-/* This macro is provided for backward compatibility. */
-
-#ifndef YY_LOCATION_PRINT
-# define YY_LOCATION_PRINT(File, Loc) ((void) 0)
-#endif
-
-
-/* YYLEX -- calling `yylex' with the right arguments.  */
-
-#ifdef YYLEX_PARAM
-# define YYLEX yylex (YYLEX_PARAM)
-#else
-# define YYLEX yylex ()
-#endif
-
-/* Enable debugging if requested.  */
-#if YYDEBUG
-
-# ifndef YYFPRINTF
-#  include <stdio.h> /* INFRINGES ON USER NAME SPACE */
-#  define YYFPRINTF fprintf
-# endif
-
-# define YYDPRINTF(Args)                       \
-do {                                           \
-  if (yydebug)                                 \
-    YYFPRINTF Args;                            \
-} while (YYID (0))
-
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)                   \
-do {                                                                     \
-  if (yydebug)                                                           \
-    {                                                                    \
-      YYFPRINTF (stderr, "%s ", Title);                                          \
-      yy_symbol_print (stderr,                                           \
-                 Type, Value); \
-      YYFPRINTF (stderr, "\n");                                                  \
-    }                                                                    \
-} while (YYID (0))
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_value_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (!yyvaluep)
-    return;
-# ifdef YYPRINT
-  if (yytype < YYNTOKENS)
-    YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep);
-# else
-  YYUSE (yyoutput);
-# endif
-  switch (yytype)
-    {
-      default:
-       break;
-    }
-}
-
-
-/*--------------------------------.
-| Print this symbol on YYOUTPUT.  |
-`--------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep)
-#else
-static void
-yy_symbol_print (yyoutput, yytype, yyvaluep)
-    FILE *yyoutput;
-    int yytype;
-    YYSTYPE const * const yyvaluep;
-#endif
-{
-  if (yytype < YYNTOKENS)
-    YYFPRINTF (yyoutput, "token %s (", yytname[yytype]);
-  else
-    YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]);
-
-  yy_symbol_value_print (yyoutput, yytype, yyvaluep);
-  YYFPRINTF (yyoutput, ")");
-}
-
-/*------------------------------------------------------------------.
-| yy_stack_print -- Print the state stack from its BOTTOM up to its |
-| TOP (included).                                                   |
-`------------------------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop)
-#else
-static void
-yy_stack_print (yybottom, yytop)
-    yytype_int16 *yybottom;
-    yytype_int16 *yytop;
-#endif
-{
-  YYFPRINTF (stderr, "Stack now");
-  for (; yybottom <= yytop; yybottom++)
-    {
-      int yybot = *yybottom;
-      YYFPRINTF (stderr, " %d", yybot);
-    }
-  YYFPRINTF (stderr, "\n");
-}
-
-# define YY_STACK_PRINT(Bottom, Top)                           \
-do {                                                           \
-  if (yydebug)                                                 \
-    yy_stack_print ((Bottom), (Top));                          \
-} while (YYID (0))
-
-
-/*------------------------------------------------.
-| Report that the YYRULE is going to be reduced.  |
-`------------------------------------------------*/
-
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yy_reduce_print (YYSTYPE *yyvsp, int yyrule)
-#else
-static void
-yy_reduce_print (yyvsp, yyrule)
-    YYSTYPE *yyvsp;
-    int yyrule;
-#endif
-{
-  int yynrhs = yyr2[yyrule];
-  int yyi;
-  unsigned long int yylno = yyrline[yyrule];
-  YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n",
-            yyrule - 1, yylno);
-  /* The symbols being reduced.  */
-  for (yyi = 0; yyi < yynrhs; yyi++)
-    {
-      YYFPRINTF (stderr, "   $%d = ", yyi + 1);
-      yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi],
-                      &(yyvsp[(yyi + 1) - (yynrhs)])
-                                      );
-      YYFPRINTF (stderr, "\n");
-    }
-}
-
-# define YY_REDUCE_PRINT(Rule)         \
-do {                                   \
-  if (yydebug)                         \
-    yy_reduce_print (yyvsp, Rule); \
-} while (YYID (0))
-
-/* Nonzero means print parse trace.  It is left uninitialized so that
-   multiple parsers can coexist.  */
-int yydebug;
-#else /* !YYDEBUG */
-# define YYDPRINTF(Args)
-# define YY_SYMBOL_PRINT(Title, Type, Value, Location)
-# define YY_STACK_PRINT(Bottom, Top)
-# define YY_REDUCE_PRINT(Rule)
-#endif /* !YYDEBUG */
-
-
-/* YYINITDEPTH -- initial size of the parser's stacks.  */
-#ifndef        YYINITDEPTH
-# define YYINITDEPTH 200
-#endif
-
-/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only
-   if the built-in stack extension method is used).
-
-   Do not make this value too large; the results are undefined if
-   YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH)
-   evaluated with infinite-precision integer arithmetic.  */
-
-#ifndef YYMAXDEPTH
-# define YYMAXDEPTH 10000
-#endif
-
-
-#if YYERROR_VERBOSE
-
-# ifndef yystrlen
-#  if defined __GLIBC__ && defined _STRING_H
-#   define yystrlen strlen
-#  else
-/* Return the length of YYSTR.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static YYSIZE_T
-yystrlen (const char *yystr)
-#else
-static YYSIZE_T
-yystrlen (yystr)
-    const char *yystr;
-#endif
-{
-  YYSIZE_T yylen;
-  for (yylen = 0; yystr[yylen]; yylen++)
-    continue;
-  return yylen;
-}
-#  endif
-# endif
-
-# ifndef yystpcpy
-#  if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE
-#   define yystpcpy stpcpy
-#  else
-/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in
-   YYDEST.  */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static char *
-yystpcpy (char *yydest, const char *yysrc)
-#else
-static char *
-yystpcpy (yydest, yysrc)
-    char *yydest;
-    const char *yysrc;
-#endif
-{
-  char *yyd = yydest;
-  const char *yys = yysrc;
-
-  while ((*yyd++ = *yys++) != '\0')
-    continue;
-
-  return yyd - 1;
-}
-#  endif
-# endif
-
-# ifndef yytnamerr
-/* Copy to YYRES the contents of YYSTR after stripping away unnecessary
-   quotes and backslashes, so that it's suitable for yyerror.  The
-   heuristic is that double-quoting is unnecessary unless the string
-   contains an apostrophe, a comma, or backslash (other than
-   backslash-backslash).  YYSTR is taken from yytname.  If YYRES is
-   null, do not copy; instead, return the length of what the result
-   would have been.  */
-static YYSIZE_T
-yytnamerr (char *yyres, const char *yystr)
-{
-  if (*yystr == '"')
-    {
-      YYSIZE_T yyn = 0;
-      char const *yyp = yystr;
-
-      for (;;)
-       switch (*++yyp)
-         {
-         case '\'':
-         case ',':
-           goto do_not_strip_quotes;
-
-         case '\\':
-           if (*++yyp != '\\')
-             goto do_not_strip_quotes;
-           /* Fall through.  */
-         default:
-           if (yyres)
-             yyres[yyn] = *yyp;
-           yyn++;
-           break;
-
-         case '"':
-           if (yyres)
-             yyres[yyn] = '\0';
-           return yyn;
-         }
-    do_not_strip_quotes: ;
-    }
-
-  if (! yyres)
-    return yystrlen (yystr);
-
-  return yystpcpy (yyres, yystr) - yyres;
-}
-# endif
-
-/* Copy into *YYMSG, which is of size *YYMSG_ALLOC, an error message
-   about the unexpected token YYTOKEN for the state stack whose top is
-   YYSSP.
-
-   Return 0 if *YYMSG was successfully written.  Return 1 if *YYMSG is
-   not large enough to hold the message.  In that case, also set
-   *YYMSG_ALLOC to the required number of bytes.  Return 2 if the
-   required number of bytes is too large to store.  */
-static int
-yysyntax_error (YYSIZE_T *yymsg_alloc, char **yymsg,
-                yytype_int16 *yyssp, int yytoken)
-{
-  YYSIZE_T yysize0 = yytnamerr (0, yytname[yytoken]);
-  YYSIZE_T yysize = yysize0;
-  YYSIZE_T yysize1;
-  enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 };
-  /* Internationalized format string. */
-  const char *yyformat = 0;
-  /* Arguments of yyformat. */
-  char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM];
-  /* Number of reported tokens (one for the "unexpected", one per
-     "expected"). */
-  int yycount = 0;
-
-  /* There are many possibilities here to consider:
-     - Assume YYFAIL is not used.  It's too flawed to consider.  See
-       <http://lists.gnu.org/archive/html/bison-patches/2009-12/msg00024.html>
-       for details.  YYERROR is fine as it does not invoke this
-       function.
-     - If this state is a consistent state with a default action, then
-       the only way this function was invoked is if the default action
-       is an error action.  In that case, don't check for expected
-       tokens because there are none.
-     - The only way there can be no lookahead present (in yychar) is if
-       this state is a consistent state with a default action.  Thus,
-       detecting the absence of a lookahead is sufficient to determine
-       that there is no unexpected or expected token to report.  In that
-       case, just report a simple "syntax error".
-     - Don't assume there isn't a lookahead just because this state is a
-       consistent state with a default action.  There might have been a
-       previous inconsistent state, consistent state with a non-default
-       action, or user semantic action that manipulated yychar.
-     - Of course, the expected token list depends on states to have
-       correct lookahead information, and it depends on the parser not
-       to perform extra reductions after fetching a lookahead from the
-       scanner and before detecting a syntax error.  Thus, state merging
-       (from LALR or IELR) and default reductions corrupt the expected
-       token list.  However, the list is correct for canonical LR with
-       one exception: it will still contain any token that will not be
-       accepted due to an error action in a later state.
-  */
-  if (yytoken != YYEMPTY)
-    {
-      int yyn = yypact[*yyssp];
-      yyarg[yycount++] = yytname[yytoken];
-      if (!yypact_value_is_default (yyn))
-        {
-          /* Start YYX at -YYN if negative to avoid negative indexes in
-             YYCHECK.  In other words, skip the first -YYN actions for
-             this state because they are default actions.  */
-          int yyxbegin = yyn < 0 ? -yyn : 0;
-          /* Stay within bounds of both yycheck and yytname.  */
-          int yychecklim = YYLAST - yyn + 1;
-          int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS;
-          int yyx;
-
-          for (yyx = yyxbegin; yyx < yyxend; ++yyx)
-            if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR
-                && !yytable_value_is_error (yytable[yyx + yyn]))
-              {
-                if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM)
-                  {
-                    yycount = 1;
-                    yysize = yysize0;
-                    break;
-                  }
-                yyarg[yycount++] = yytname[yyx];
-                yysize1 = yysize + yytnamerr (0, yytname[yyx]);
-                if (! (yysize <= yysize1
-                       && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-                  return 2;
-                yysize = yysize1;
-              }
-        }
-    }
-
-  switch (yycount)
-    {
-# define YYCASE_(N, S)                      \
-      case N:                               \
-        yyformat = S;                       \
-      break
-      YYCASE_(0, YY_("syntax error"));
-      YYCASE_(1, YY_("syntax error, unexpected %s"));
-      YYCASE_(2, YY_("syntax error, unexpected %s, expecting %s"));
-      YYCASE_(3, YY_("syntax error, unexpected %s, expecting %s or %s"));
-      YYCASE_(4, YY_("syntax error, unexpected %s, expecting %s or %s or %s"));
-      YYCASE_(5, YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"));
-# undef YYCASE_
-    }
-
-  yysize1 = yysize + yystrlen (yyformat);
-  if (! (yysize <= yysize1 && yysize1 <= YYSTACK_ALLOC_MAXIMUM))
-    return 2;
-  yysize = yysize1;
-
-  if (*yymsg_alloc < yysize)
-    {
-      *yymsg_alloc = 2 * yysize;
-      if (! (yysize <= *yymsg_alloc
-             && *yymsg_alloc <= YYSTACK_ALLOC_MAXIMUM))
-        *yymsg_alloc = YYSTACK_ALLOC_MAXIMUM;
-      return 1;
-    }
-
-  /* Avoid sprintf, as that infringes on the user's name space.
-     Don't have undefined behavior even if the translation
-     produced a string with the wrong number of "%s"s.  */
-  {
-    char *yyp = *yymsg;
-    int yyi = 0;
-    while ((*yyp = *yyformat) != '\0')
-      if (*yyp == '%' && yyformat[1] == 's' && yyi < yycount)
-        {
-          yyp += yytnamerr (yyp, yyarg[yyi++]);
-          yyformat += 2;
-        }
-      else
-        {
-          yyp++;
-          yyformat++;
-        }
-  }
-  return 0;
-}
-#endif /* YYERROR_VERBOSE */
-
-/*-----------------------------------------------.
-| Release the memory associated to this symbol.  |
-`-----------------------------------------------*/
-
-/*ARGSUSED*/
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-static void
-yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep)
-#else
-static void
-yydestruct (yymsg, yytype, yyvaluep)
-    const char *yymsg;
-    int yytype;
-    YYSTYPE *yyvaluep;
-#endif
-{
-  YYUSE (yyvaluep);
-
-  if (!yymsg)
-    yymsg = "Deleting";
-  YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp);
-
-  switch (yytype)
-    {
-
-      default:
-       break;
-    }
-}
-
-
-/* Prevent warnings from -Wmissing-prototypes.  */
-#ifdef YYPARSE_PARAM
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void *YYPARSE_PARAM);
-#else
-int yyparse ();
-#endif
-#else /* ! YYPARSE_PARAM */
-#if defined __STDC__ || defined __cplusplus
-int yyparse (void);
-#else
-int yyparse ();
-#endif
-#endif /* ! YYPARSE_PARAM */
-
-
-/* The lookahead symbol.  */
-int yychar;
-
-/* The semantic value of the lookahead symbol.  */
-YYSTYPE yylval;
-
-/* Number of syntax errors so far.  */
-int yynerrs;
-
-
-/*----------.
-| yyparse.  |
-`----------*/
-
-#ifdef YYPARSE_PARAM
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void *YYPARSE_PARAM)
-#else
-int
-yyparse (YYPARSE_PARAM)
-    void *YYPARSE_PARAM;
-#endif
-#else /* ! YYPARSE_PARAM */
-#if (defined __STDC__ || defined __C99__FUNC__ \
-     || defined __cplusplus || defined _MSC_VER)
-int
-yyparse (void)
-#else
-int
-yyparse ()
-
-#endif
-#endif
-{
-    int yystate;
-    /* Number of tokens to shift before error messages enabled.  */
-    int yyerrstatus;
-
-    /* The stacks and their tools:
-       `yyss': related to states.
-       `yyvs': related to semantic values.
-
-       Refer to the stacks thru separate pointers, to allow yyoverflow
-       to reallocate them elsewhere.  */
-
-    /* The state stack.  */
-    yytype_int16 yyssa[YYINITDEPTH];
-    yytype_int16 *yyss;
-    yytype_int16 *yyssp;
-
-    /* The semantic value stack.  */
-    YYSTYPE yyvsa[YYINITDEPTH];
-    YYSTYPE *yyvs;
-    YYSTYPE *yyvsp;
-
-    YYSIZE_T yystacksize;
-
-  int yyn;
-  int yyresult;
-  /* Lookahead token as an internal (translated) token number.  */
-  int yytoken;
-  /* The variables used to return semantic value and location from the
-     action routines.  */
-  YYSTYPE yyval;
-
-#if YYERROR_VERBOSE
-  /* Buffer for error messages, and its allocated size.  */
-  char yymsgbuf[128];
-  char *yymsg = yymsgbuf;
-  YYSIZE_T yymsg_alloc = sizeof yymsgbuf;
-#endif
-
-#define YYPOPSTACK(N)   (yyvsp -= (N), yyssp -= (N))
-
-  /* The number of symbols on the RHS of the reduced rule.
-     Keep to zero when no symbol should be popped.  */
-  int yylen = 0;
-
-  yytoken = 0;
-  yyss = yyssa;
-  yyvs = yyvsa;
-  yystacksize = YYINITDEPTH;
-
-  YYDPRINTF ((stderr, "Starting parse\n"));
-
-  yystate = 0;
-  yyerrstatus = 0;
-  yynerrs = 0;
-  yychar = YYEMPTY; /* Cause a token to be read.  */
-
-  /* Initialize stack pointers.
-     Waste one element of value and location stack
-     so that they stay on the same level as the state stack.
-     The wasted elements are never initialized.  */
-  yyssp = yyss;
-  yyvsp = yyvs;
-
-  goto yysetstate;
-
-/*------------------------------------------------------------.
-| yynewstate -- Push a new state, which is found in yystate.  |
-`------------------------------------------------------------*/
- yynewstate:
-  /* In all cases, when you get here, the value and location stacks
-     have just been pushed.  So pushing a state here evens the stacks.  */
-  yyssp++;
-
- yysetstate:
-  *yyssp = yystate;
-
-  if (yyss + yystacksize - 1 <= yyssp)
-    {
-      /* Get the current used size of the three stacks, in elements.  */
-      YYSIZE_T yysize = yyssp - yyss + 1;
-
-#ifdef yyoverflow
-      {
-       /* Give user a chance to reallocate the stack.  Use copies of
-          these so that the &'s don't force the real ones into
-          memory.  */
-       YYSTYPE *yyvs1 = yyvs;
-       yytype_int16 *yyss1 = yyss;
-
-       /* Each stack pointer address is followed by the size of the
-          data in use in that stack, in bytes.  This used to be a
-          conditional around just the two extra args, but that might
-          be undefined if yyoverflow is a macro.  */
-       yyoverflow (YY_("memory exhausted"),
-                   &yyss1, yysize * sizeof (*yyssp),
-                   &yyvs1, yysize * sizeof (*yyvsp),
-                   &yystacksize);
-
-       yyss = yyss1;
-       yyvs = yyvs1;
-      }
-#else /* no yyoverflow */
-# ifndef YYSTACK_RELOCATE
-      goto yyexhaustedlab;
-# else
-      /* Extend the stack our own way.  */
-      if (YYMAXDEPTH <= yystacksize)
-       goto yyexhaustedlab;
-      yystacksize *= 2;
-      if (YYMAXDEPTH < yystacksize)
-       yystacksize = YYMAXDEPTH;
-
-      {
-       yytype_int16 *yyss1 = yyss;
-       union yyalloc *yyptr =
-         (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize));
-       if (! yyptr)
-         goto yyexhaustedlab;
-       YYSTACK_RELOCATE (yyss_alloc, yyss);
-       YYSTACK_RELOCATE (yyvs_alloc, yyvs);
-#  undef YYSTACK_RELOCATE
-       if (yyss1 != yyssa)
-         YYSTACK_FREE (yyss1);
-      }
-# endif
-#endif /* no yyoverflow */
-
-      yyssp = yyss + yysize - 1;
-      yyvsp = yyvs + yysize - 1;
-
-      YYDPRINTF ((stderr, "Stack size increased to %lu\n",
-                 (unsigned long int) yystacksize));
-
-      if (yyss + yystacksize - 1 <= yyssp)
-       YYABORT;
-    }
-
-  YYDPRINTF ((stderr, "Entering state %d\n", yystate));
-
-  if (yystate == YYFINAL)
-    YYACCEPT;
-
-  goto yybackup;
-
-/*-----------.
-| yybackup.  |
-`-----------*/
-yybackup:
-
-  /* Do appropriate processing given the current state.  Read a
-     lookahead token if we need one and don't already have one.  */
-
-  /* First try to decide what to do without reference to lookahead token.  */
-  yyn = yypact[yystate];
-  if (yypact_value_is_default (yyn))
-    goto yydefault;
-
-  /* Not known => get a lookahead token if don't already have one.  */
-
-  /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol.  */
-  if (yychar == YYEMPTY)
-    {
-      YYDPRINTF ((stderr, "Reading a token: "));
-      yychar = YYLEX;
-    }
-
-  if (yychar <= YYEOF)
-    {
-      yychar = yytoken = YYEOF;
-      YYDPRINTF ((stderr, "Now at end of input.\n"));
-    }
-  else
-    {
-      yytoken = YYTRANSLATE (yychar);
-      YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc);
-    }
-
-  /* If the proper action on seeing token YYTOKEN is to reduce or to
-     detect an error, take that action.  */
-  yyn += yytoken;
-  if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken)
-    goto yydefault;
-  yyn = yytable[yyn];
-  if (yyn <= 0)
-    {
-      if (yytable_value_is_error (yyn))
-        goto yyerrlab;
-      yyn = -yyn;
-      goto yyreduce;
-    }
-
-  /* Count tokens shifted since error; after three, turn off error
-     status.  */
-  if (yyerrstatus)
-    yyerrstatus--;
-
-  /* Shift the lookahead token.  */
-  YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc);
-
-  /* Discard the shifted token.  */
-  yychar = YYEMPTY;
-
-  yystate = yyn;
-  *++yyvsp = yylval;
-
-  goto yynewstate;
-
-
-/*-----------------------------------------------------------.
-| yydefault -- do the default action for the current state.  |
-`-----------------------------------------------------------*/
-yydefault:
-  yyn = yydefact[yystate];
-  if (yyn == 0)
-    goto yyerrlab;
-  goto yyreduce;
-
-
-/*-----------------------------.
-| yyreduce -- Do a reduction.  |
-`-----------------------------*/
-yyreduce:
-  /* yyn is the number of a rule to reduce with.  */
-  yylen = yyr2[yyn];
-
-  /* If YYLEN is nonzero, implement the default value of the action:
-     `$$ = $1'.
-
-     Otherwise, the following line sets YYVAL to garbage.
-     This behavior is undocumented and Bison
-     users should not rely upon it.  Assigning to YYVAL
-     unconditionally makes the parser a bit smaller, and it avoids a
-     GCC warning that YYVAL may be used uninitialized.  */
-  yyval = yyvsp[1-yylen];
-
-
-  YY_REDUCE_PRINT (yyn);
-  switch (yyn)
-    {
-        case 7:
-
-/* Line 1806 of yacc.c  */
-#line 74 "parser.y"
-    {
-                       }
-    break;
-
-  case 8:
-
-/* Line 1806 of yacc.c  */
-#line 77 "parser.y"
-    {
-                               yyclearin;
-                               yyerrok;
-                       }
-    break;
-
-  case 9:
-
-/* Line 1806 of yacc.c  */
-#line 84 "parser.y"
-    {
-                               opts = NULL;
-                       }
-    break;
-
-  case 10:
-
-/* Line 1806 of yacc.c  */
-#line 90 "parser.y"
-    {
-                               if (((yyvsp[(1) - (1)].number) >= 0) && ((yyvsp[(1) - (1)].number) < RFCOMM_MAX_DEV))
-                                       opts = &rfcomm_opts[(yyvsp[(1) - (1)].number)];
-                               else
-                                       opts = NULL;
-                       }
-    break;
-
-  case 14:
-
-/* Line 1806 of yacc.c  */
-#line 104 "parser.y"
-    {
-                               if (opts)
-                                       opts->bind = (yyvsp[(2) - (2)].number);
-                       }
-    break;
-
-  case 15:
-
-/* Line 1806 of yacc.c  */
-#line 109 "parser.y"
-    {
-                               if (opts)
-                                       bacpy(&opts->bdaddr, (yyvsp[(2) - (2)].bdaddr));
-                       }
-    break;
-
-  case 16:
-
-/* Line 1806 of yacc.c  */
-#line 114 "parser.y"
-    {
-                               if (opts)
-                                       opts->channel = (yyvsp[(2) - (2)].number);
-                       }
-    break;
-
-  case 17:
-
-/* Line 1806 of yacc.c  */
-#line 119 "parser.y"
-    {
-                               if (opts)
-                                       snprintf(opts->comment, MAXCOMMENTLEN, "%s", (yyvsp[(2) - (2)].string));
-                       }
-    break;
-
-  case 18:
-
-/* Line 1806 of yacc.c  */
-#line 124 "parser.y"
-    {
-                               // Unknown option
-                       }
-    break;
-
-  case 19:
-
-/* Line 1806 of yacc.c  */
-#line 129 "parser.y"
-    { (yyval.number) = 1; }
-    break;
-
-  case 20:
-
-/* Line 1806 of yacc.c  */
-#line 130 "parser.y"
-    { (yyval.number) = 0; }
-    break;
-
-
-
-/* Line 1806 of yacc.c  */
-#line 1547 "tools/parser.c"
-      default: break;
-    }
-  /* User semantic actions sometimes alter yychar, and that requires
-     that yytoken be updated with the new translation.  We take the
-     approach of translating immediately before every use of yytoken.
-     One alternative is translating here after every semantic action,
-     but that translation would be missed if the semantic action invokes
-     YYABORT, YYACCEPT, or YYERROR immediately after altering yychar or
-     if it invokes YYBACKUP.  In the case of YYABORT or YYACCEPT, an
-     incorrect destructor might then be invoked immediately.  In the
-     case of YYERROR or YYBACKUP, subsequent parser actions might lead
-     to an incorrect destructor call or verbose syntax error message
-     before the lookahead is translated.  */
-  YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc);
-
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-
-  *++yyvsp = yyval;
-
-  /* Now `shift' the result of the reduction.  Determine what state
-     that goes to, based on the state we popped back to and the rule
-     number reduced by.  */
-
-  yyn = yyr1[yyn];
-
-  yystate = yypgoto[yyn - YYNTOKENS] + *yyssp;
-  if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp)
-    yystate = yytable[yystate];
-  else
-    yystate = yydefgoto[yyn - YYNTOKENS];
-
-  goto yynewstate;
-
-
-/*------------------------------------.
-| yyerrlab -- here on detecting error |
-`------------------------------------*/
-yyerrlab:
-  /* Make sure we have latest lookahead translation.  See comments at
-     user semantic actions for why this is necessary.  */
-  yytoken = yychar == YYEMPTY ? YYEMPTY : YYTRANSLATE (yychar);
-
-  /* If not already recovering from an error, report this error.  */
-  if (!yyerrstatus)
-    {
-      ++yynerrs;
-#if ! YYERROR_VERBOSE
-      yyerror (YY_("syntax error"));
-#else
-# define YYSYNTAX_ERROR yysyntax_error (&yymsg_alloc, &yymsg, \
-                                        yyssp, yytoken)
-      {
-        char const *yymsgp = YY_("syntax error");
-        int yysyntax_error_status;
-        yysyntax_error_status = YYSYNTAX_ERROR;
-        if (yysyntax_error_status == 0)
-          yymsgp = yymsg;
-        else if (yysyntax_error_status == 1)
-          {
-            if (yymsg != yymsgbuf)
-              YYSTACK_FREE (yymsg);
-            yymsg = (char *) YYSTACK_ALLOC (yymsg_alloc);
-            if (!yymsg)
-              {
-                yymsg = yymsgbuf;
-                yymsg_alloc = sizeof yymsgbuf;
-                yysyntax_error_status = 2;
-              }
-            else
-              {
-                yysyntax_error_status = YYSYNTAX_ERROR;
-                yymsgp = yymsg;
-              }
-          }
-        yyerror (yymsgp);
-        if (yysyntax_error_status == 2)
-          goto yyexhaustedlab;
-      }
-# undef YYSYNTAX_ERROR
-#endif
-    }
-
-
-
-  if (yyerrstatus == 3)
-    {
-      /* If just tried and failed to reuse lookahead token after an
-        error, discard it.  */
-
-      if (yychar <= YYEOF)
-       {
-         /* Return failure if at end of input.  */
-         if (yychar == YYEOF)
-           YYABORT;
-       }
-      else
-       {
-         yydestruct ("Error: discarding",
-                     yytoken, &yylval);
-         yychar = YYEMPTY;
-       }
-    }
-
-  /* Else will try to reuse lookahead token after shifting the error
-     token.  */
-  goto yyerrlab1;
-
-
-/*---------------------------------------------------.
-| yyerrorlab -- error raised explicitly by YYERROR.  |
-`---------------------------------------------------*/
-yyerrorlab:
-
-  /* Pacify compilers like GCC when the user code never invokes
-     YYERROR and the label yyerrorlab therefore never appears in user
-     code.  */
-  if (/*CONSTCOND*/ 0)
-     goto yyerrorlab;
-
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYERROR.  */
-  YYPOPSTACK (yylen);
-  yylen = 0;
-  YY_STACK_PRINT (yyss, yyssp);
-  yystate = *yyssp;
-  goto yyerrlab1;
-
-
-/*-------------------------------------------------------------.
-| yyerrlab1 -- common code for both syntax error and YYERROR.  |
-`-------------------------------------------------------------*/
-yyerrlab1:
-  yyerrstatus = 3;     /* Each real token shifted decrements this.  */
-
-  for (;;)
-    {
-      yyn = yypact[yystate];
-      if (!yypact_value_is_default (yyn))
-       {
-         yyn += YYTERROR;
-         if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR)
-           {
-             yyn = yytable[yyn];
-             if (0 < yyn)
-               break;
-           }
-       }
-
-      /* Pop the current state because it cannot handle the error token.  */
-      if (yyssp == yyss)
-       YYABORT;
-
-
-      yydestruct ("Error: popping",
-                 yystos[yystate], yyvsp);
-      YYPOPSTACK (1);
-      yystate = *yyssp;
-      YY_STACK_PRINT (yyss, yyssp);
-    }
-
-  *++yyvsp = yylval;
-
-
-  /* Shift the error token.  */
-  YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp);
-
-  yystate = yyn;
-  goto yynewstate;
-
-
-/*-------------------------------------.
-| yyacceptlab -- YYACCEPT comes here.  |
-`-------------------------------------*/
-yyacceptlab:
-  yyresult = 0;
-  goto yyreturn;
-
-/*-----------------------------------.
-| yyabortlab -- YYABORT comes here.  |
-`-----------------------------------*/
-yyabortlab:
-  yyresult = 1;
-  goto yyreturn;
-
-#if !defined(yyoverflow) || YYERROR_VERBOSE
-/*-------------------------------------------------.
-| yyexhaustedlab -- memory exhaustion comes here.  |
-`-------------------------------------------------*/
-yyexhaustedlab:
-  yyerror (YY_("memory exhausted"));
-  yyresult = 2;
-  /* Fall through.  */
-#endif
-
-yyreturn:
-  if (yychar != YYEMPTY)
-    {
-      /* Make sure we have latest lookahead translation.  See comments at
-         user semantic actions for why this is necessary.  */
-      yytoken = YYTRANSLATE (yychar);
-      yydestruct ("Cleanup: discarding lookahead",
-                  yytoken, &yylval);
-    }
-  /* Do not reclaim the symbols of the rule which action triggered
-     this YYABORT or YYACCEPT.  */
-  YYPOPSTACK (yylen);
-  YY_STACK_PRINT (yyss, yyssp);
-  while (yyssp != yyss)
-    {
-      yydestruct ("Cleanup: popping",
-                 yystos[*yyssp], yyvsp);
-      YYPOPSTACK (1);
-    }
-#ifndef yyoverflow
-  if (yyss != yyssa)
-    YYSTACK_FREE (yyss);
-#endif
-#if YYERROR_VERBOSE
-  if (yymsg != yymsgbuf)
-    YYSTACK_FREE (yymsg);
-#endif
-  /* Make sure YYID is used.  */
-  return YYID (yyresult);
-}
-
-
-
-/* Line 2067 of yacc.c  */
-#line 133 "parser.y"
-
-
-int yyerror(char *s) 
-{
-       fprintf(stderr, "%s line %d\n", s, lineno);
-       return 0;
-}
-
-int rfcomm_read_config(char *filename)
-{
-       extern FILE *yyin;
-       char file[MAXPATHLEN + 1];
-       int i;
-
-       for (i = 0; i < RFCOMM_MAX_DEV; i++) {
-               rfcomm_opts[i].bind = 0;
-               bacpy(&rfcomm_opts[i].bdaddr, BDADDR_ANY);
-               rfcomm_opts[i].channel = 1;
-       }
-
-       if (filename) {
-               snprintf(file, MAXPATHLEN,  "%s", filename);
-       } else {
-               snprintf(file, MAXPATHLEN, "%s/.bluetooth/rfcomm.conf", getenv("HOME"));
-
-               if ((getuid() == 0) || (access(file, R_OK) < 0))
-                       snprintf(file, MAXPATHLEN, "%s/rfcomm.conf", CONFIGDIR);
-       }
-
-       if (!(yyin = fopen(file, "r")))
-               return -1;
-
-       lineno = 1;
-       yyparse();
-
-       fclose(yyin);
-
-       return 0;
-}
-
diff --git a/tools/parser.h b/tools/parser.h
deleted file mode 100644 (file)
index 20149b2..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-/* A Bison parser, made by GNU Bison 2.5.  */
-
-/* Bison interface for Yacc-like parsers in C
-   
-      Copyright (C) 1984, 1989-1990, 2000-2011 Free Software Foundation, Inc.
-   
-   This program is free software: you can redistribute it and/or modify
-   it under the terms of the GNU General Public License as published by
-   the Free Software Foundation, either version 3 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, see <http://www.gnu.org/licenses/>.  */
-
-/* As a special exception, you may create a larger work that contains
-   part or all of the Bison parser skeleton and distribute that work
-   under terms of your choice, so long as that work isn't itself a
-   parser generator using the skeleton or a modified version thereof
-   as a parser skeleton.  Alternatively, if you modify or redistribute
-   the parser skeleton itself, you may (at your option) remove this
-   special exception, which will cause the skeleton and the resulting
-   Bison output files to be licensed under the GNU General Public
-   License without this special exception.
-   
-   This special exception was added by the Free Software Foundation in
-   version 2.2 of Bison.  */
-
-
-/* Tokens.  */
-#ifndef YYTOKENTYPE
-# define YYTOKENTYPE
-   /* Put the tokens into the symbol table, so that GDB and other debuggers
-      know about them.  */
-   enum yytokentype {
-     K_BIND = 258,
-     K_DEVICE = 259,
-     K_CHANNEL = 260,
-     K_COMMENT = 261,
-     K_YES = 262,
-     K_NO = 263,
-     NUMBER = 264,
-     RFCOMM = 265,
-     STRING = 266,
-     WORD = 267,
-     BDADDR = 268
-   };
-#endif
-/* Tokens.  */
-#define K_BIND 258
-#define K_DEVICE 259
-#define K_CHANNEL 260
-#define K_COMMENT 261
-#define K_YES 262
-#define K_NO 263
-#define NUMBER 264
-#define RFCOMM 265
-#define STRING 266
-#define WORD 267
-#define BDADDR 268
-
-
-
-
-#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED
-typedef union YYSTYPE
-{
-
-/* Line 2068 of yacc.c  */
-#line 49 "parser.y"
-
-       int number;
-       char *string;
-       bdaddr_t *bdaddr;
-
-
-
-/* Line 2068 of yacc.c  */
-#line 84 "tools/parser.h"
-} YYSTYPE;
-# define YYSTYPE_IS_TRIVIAL 1
-# define yystype YYSTYPE /* obsolescent; will be withdrawn */
-# define YYSTYPE_IS_DECLARED 1
-#endif
-
-extern YYSTYPE yylval;
-
-
diff --git a/tools/parser.y b/tools/parser.y
deleted file mode 100644 (file)
index 96e6a56..0000000
+++ /dev/null
@@ -1,171 +0,0 @@
-%{
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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 <sys/param.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "kword.h"
-
-int yylex(void);
-int yyerror(char *s); 
-
-struct rfcomm_opts *opts;
-
-%}
-
-%union {
-       int number;
-       char *string;
-       bdaddr_t *bdaddr;
-}
-
-%token K_BIND K_DEVICE K_CHANNEL K_COMMENT
-%token K_YES K_NO
-
-%token <number> NUMBER RFCOMM
-%token <string> STRING WORD
-%token <bdaddr> BDADDR
-
-%type <number> bool
-
-%%
-
-config         :
-               | statement
-               | config statement
-               ;
-
-statement      : section '{' rfcomm_options '}'
-               | rfcomm  '{' rfcomm_options '}'
-               | WORD
-                       {
-                       }
-               | error
-                       {
-                               yyclearin;
-                               yyerrok;
-                       }
-               ;
-
-section                : WORD
-                       {
-                               opts = NULL;
-                       }
-               ;
-
-rfcomm         : RFCOMM
-                       {
-                               if (($1 >= 0) && ($1 < RFCOMM_MAX_DEV))
-                                       opts = &rfcomm_opts[$1];
-                               else
-                                       opts = NULL;
-                       }
-               ;
-
-rfcomm_options : rfcomm_option ';'
-               | error ';'
-               | rfcomm_options rfcomm_option ';'
-               ;
-
-rfcomm_option  : K_BIND bool
-                       {
-                               if (opts)
-                                       opts->bind = $2;
-                       }
-               | K_DEVICE BDADDR
-                       {
-                               if (opts)
-                                       bacpy(&opts->bdaddr, $2);
-                       }
-               | K_CHANNEL NUMBER
-                       {
-                               if (opts)
-                                       opts->channel = $2;
-                       }
-               | K_COMMENT STRING
-                       {
-                               if (opts)
-                                       snprintf(opts->comment, MAXCOMMENTLEN, "%s", $2);
-                       }
-               | WORD
-                       {
-                               // Unknown option
-                       }
-               ;
-
-bool           : K_YES { $$ = 1; }
-               | K_NO  { $$ = 0; }
-               ;
-
-%%
-
-int yyerror(char *s) 
-{
-       fprintf(stderr, "%s line %d\n", s, lineno);
-       return 0;
-}
-
-int rfcomm_read_config(char *filename)
-{
-       extern FILE *yyin;
-       char file[MAXPATHLEN + 1];
-       int i;
-
-       for (i = 0; i < RFCOMM_MAX_DEV; i++) {
-               rfcomm_opts[i].bind = 0;
-               bacpy(&rfcomm_opts[i].bdaddr, BDADDR_ANY);
-               rfcomm_opts[i].channel = 1;
-       }
-
-       if (filename) {
-               snprintf(file, MAXPATHLEN,  "%s", filename);
-       } else {
-               snprintf(file, MAXPATHLEN, "%s/.bluetooth/rfcomm.conf", getenv("HOME"));
-
-               if ((getuid() == 0) || (access(file, R_OK) < 0))
-                       snprintf(file, MAXPATHLEN, "%s/rfcomm.conf", CONFIGDIR);
-       }
-
-       if (!(yyin = fopen(file, "r")))
-               return -1;
-
-       lineno = 1;
-       yyparse();
-
-       fclose(yyin);
-
-       return 0;
-}
diff --git a/tools/parser/amp.c b/tools/parser/amp.c
new file mode 100644 (file)
index 0000000..158ca4a
--- /dev/null
@@ -0,0 +1,126 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "parser.h"
+#include "lib/amp.h"
+
+static void amp_dump_chanlist(int level, struct amp_tlv *tlv, char *prefix)
+{
+       struct amp_chan_list *chan_list = (void *) tlv->val;
+       struct amp_country_triplet *triplet;
+       int i, num;
+
+       num = (tlv->len - sizeof(*chan_list)) / sizeof(*triplet);
+
+       printf("%s (number of triplets %d)\n", prefix, num);
+
+       p_indent(level+2, 0);
+
+       printf("Country code: %c%c%c\n", chan_list->country_code[0],
+               chan_list->country_code[1], chan_list->country_code[2]);
+
+       for (i = 0; i < num; i++) {
+               triplet = &chan_list->triplets[i];
+
+               p_indent(level+2, 0);
+
+               if (triplet->chans.first_channel >= 201) {
+                       printf("Reg ext id %d reg class %d coverage class %d\n",
+                                               triplet->ext.reg_extension_id,
+                                               triplet->ext.reg_class,
+                                               triplet->ext.coverage_class);
+               } else {
+                       if (triplet->chans.num_channels == 1)
+                               printf("Channel %d max power %d\n",
+                                               triplet->chans.first_channel,
+                                               triplet->chans.max_power);
+                       else
+                               printf("Channels %d - %d max power %d\n",
+                                               triplet->chans.first_channel,
+                                               triplet->chans.first_channel +
+                                               triplet->chans.num_channels,
+                                               triplet->chans.max_power);
+               }
+       }
+}
+
+void amp_assoc_dump(int level, uint8_t *assoc, uint16_t len)
+{
+       struct amp_tlv *tlv = (void *) assoc;
+
+       p_indent(level, 0);
+       printf("Assoc data [len %d]:\n", len);
+
+       while (len > sizeof(*tlv)) {
+               uint16_t tlvlen = btohs(tlv->len);
+               struct amp_pal_ver *ver;
+
+               p_indent(level+1, 0);
+
+               switch (tlv->type) {
+               case A2MP_MAC_ADDR_TYPE:
+                       if (tlvlen != 6)
+                               break;
+                       printf("MAC: %2.2X:%2.2X:%2.2X:%2.2X:%2.2X:%2.2X\n",
+                                       tlv->val[0], tlv->val[1], tlv->val[2],
+                                       tlv->val[3], tlv->val[4], tlv->val[5]);
+                       break;
+
+               case A2MP_PREF_CHANLIST_TYPE:
+                       amp_dump_chanlist(level, tlv, "Preferred Chan List");
+                       break;
+
+               case A2MP_CONNECTED_CHAN:
+                       amp_dump_chanlist(level, tlv, "Connected Chan List");
+                       break;
+
+               case A2MP_PAL_CAP_TYPE:
+                       if (tlvlen != 4)
+                               break;
+                       printf("PAL CAP: %2.2x %2.2x %2.2x %2.2x\n",
+                                       tlv->val[0], tlv->val[1], tlv->val[2],
+                                       tlv->val[3]);
+                       break;
+
+               case A2MP_PAL_VER_INFO:
+                       if (tlvlen != 5)
+                               break;
+                       ver = (struct amp_pal_ver *) tlv->val;
+                       printf("PAL VER: %2.2x Comp ID: %4.4x SubVer: %4.4x\n",
+                                       ver->ver, btohs(ver->company_id),
+                                       btohs(ver->sub_ver));
+                       break;
+
+               default:
+                       printf("Unrecognized type %d\n", tlv->type);
+                       break;
+               }
+
+               len -= tlvlen + sizeof(*tlv);
+               assoc += tlvlen + sizeof(*tlv);
+               tlv = (struct amp_tlv *) assoc;
+       }
+}
diff --git a/tools/parser/att.c b/tools/parser/att.c
new file mode 100644 (file)
index 0000000..5d9bea4
--- /dev/null
@@ -0,0 +1,636 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  André Dieb Martins <andre.dieb@gmail.com>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (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 "parser.h"
+
+#define GATT_PRIM_SVC_UUID             0x2800
+#define GATT_SND_SVC_UUID              0x2801
+#define GATT_INCLUDE_UUID              0x2802
+#define GATT_CHARAC_UUID               0x2803
+
+#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
+
+#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
+
+
+
+/* Attribute Protocol Opcodes */
+#define ATT_OP_ERROR                   0x01
+#define ATT_OP_MTU_REQ                 0x02
+#define ATT_OP_MTU_RESP                        0x03
+#define ATT_OP_FIND_INFO_REQ           0x04
+#define ATT_OP_FIND_INFO_RESP          0x05
+#define ATT_OP_FIND_BY_TYPE_REQ                0x06
+#define ATT_OP_FIND_BY_TYPE_RESP       0x07
+#define ATT_OP_READ_BY_TYPE_REQ                0x08
+#define ATT_OP_READ_BY_TYPE_RESP       0x09
+#define ATT_OP_READ_REQ                        0x0A
+#define ATT_OP_READ_RESP               0x0B
+#define ATT_OP_READ_BLOB_REQ           0x0C
+#define ATT_OP_READ_BLOB_RESP          0x0D
+#define ATT_OP_READ_MULTI_REQ          0x0E
+#define ATT_OP_READ_MULTI_RESP         0x0F
+#define ATT_OP_READ_BY_GROUP_REQ       0x10
+#define ATT_OP_READ_BY_GROUP_RESP      0x11
+#define ATT_OP_WRITE_REQ               0x12
+#define ATT_OP_WRITE_RESP              0x13
+#define ATT_OP_WRITE_CMD               0x52
+#define ATT_OP_PREP_WRITE_REQ          0x16
+#define ATT_OP_PREP_WRITE_RESP         0x17
+#define ATT_OP_EXEC_WRITE_REQ          0x18
+#define ATT_OP_EXEC_WRITE_RESP         0x19
+#define ATT_OP_HANDLE_NOTIFY           0x1B
+#define ATT_OP_HANDLE_IND              0x1D
+#define ATT_OP_HANDLE_CNF              0x1E
+#define ATT_OP_SIGNED_WRITE_CMD                0xD2
+
+/* Error codes for Error response PDU */
+#define ATT_ECODE_INVALID_HANDLE               0x01
+#define ATT_ECODE_READ_NOT_PERM                        0x02
+#define ATT_ECODE_WRITE_NOT_PERM               0x03
+#define ATT_ECODE_INVALID_PDU                  0x04
+#define ATT_ECODE_INSUFF_AUTHEN                        0x05
+#define ATT_ECODE_REQ_NOT_SUPP                 0x06
+#define ATT_ECODE_INVALID_OFFSET               0x07
+#define ATT_ECODE_INSUFF_AUTHO                 0x08
+#define ATT_ECODE_PREP_QUEUE_FULL              0x09
+#define ATT_ECODE_ATTR_NOT_FOUND               0x0A
+#define ATT_ECODE_ATTR_NOT_LONG                        0x0B
+#define ATT_ECODE_INSUFF_ENCR_KEY_SIZE         0x0C
+#define ATT_ECODE_INVAL_ATTR_VALUE_LEN         0x0D
+#define ATT_ECODE_UNLIKELY                     0x0E
+#define ATT_ECODE_INSUFF_ENC                   0x0F
+#define ATT_ECODE_UNSUPP_GRP_TYPE              0x10
+#define ATT_ECODE_INSUFF_RESOURCES             0x11
+#define ATT_ECODE_IO                           0xFF
+
+
+/* Attribute Protocol Opcodes */
+static const char *attop2str(uint8_t op)
+{
+       switch (op) {
+       case ATT_OP_ERROR:
+               return "Error";
+       case ATT_OP_MTU_REQ:
+               return "MTU req";
+       case ATT_OP_MTU_RESP:
+               return "MTU resp";
+       case ATT_OP_FIND_INFO_REQ:
+               return "Find Information req";
+       case ATT_OP_FIND_INFO_RESP:
+               return "Find Information resp";
+       case ATT_OP_FIND_BY_TYPE_REQ:
+               return "Find By Type req";
+       case ATT_OP_FIND_BY_TYPE_RESP:
+               return "Find By Type resp";
+       case ATT_OP_READ_BY_TYPE_REQ:
+               return "Read By Type req";
+       case ATT_OP_READ_BY_TYPE_RESP:
+               return "Read By Type resp";
+       case ATT_OP_READ_REQ:
+               return "Read req";
+       case ATT_OP_READ_RESP:
+               return "Read resp";
+       case ATT_OP_READ_BLOB_REQ:
+               return "Read Blob req";
+       case ATT_OP_READ_BLOB_RESP:
+               return "Read Blob resp";
+       case ATT_OP_READ_MULTI_REQ:
+               return "Read Multi req";
+       case ATT_OP_READ_MULTI_RESP:
+               return "Read Multi resp";
+       case ATT_OP_READ_BY_GROUP_REQ:
+               return "Read By Group req";
+       case ATT_OP_READ_BY_GROUP_RESP:
+               return "Read By Group resp";
+       case ATT_OP_WRITE_REQ:
+               return "Write req";
+       case ATT_OP_WRITE_RESP:
+               return "Write resp";
+       case ATT_OP_WRITE_CMD:
+               return "Write cmd";
+       case ATT_OP_PREP_WRITE_REQ:
+               return "Prepare Write req";
+       case ATT_OP_PREP_WRITE_RESP:
+               return "Prepare Write resp";
+       case ATT_OP_EXEC_WRITE_REQ:
+               return "Exec Write req";
+       case ATT_OP_EXEC_WRITE_RESP:
+               return "Exec Write resp";
+       case ATT_OP_HANDLE_NOTIFY:
+               return "Handle notify";
+       case ATT_OP_HANDLE_IND:
+               return "Handle indicate";
+       case ATT_OP_HANDLE_CNF:
+               return "Handle CNF";
+       case ATT_OP_SIGNED_WRITE_CMD:
+               return "Signed Write Cmd";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char * atterror2str(uint8_t err)
+{
+       switch (err) {
+       case ATT_ECODE_INVALID_HANDLE:
+               return "Invalid handle";
+       case ATT_ECODE_READ_NOT_PERM:
+               return "Read not permitted";
+       case ATT_ECODE_WRITE_NOT_PERM:
+               return "Write not permitted";
+       case ATT_ECODE_INVALID_PDU:
+               return "Invalid PDU";
+       case ATT_ECODE_INSUFF_AUTHEN:
+               return "Insufficient authentication";
+       case ATT_ECODE_REQ_NOT_SUPP:
+               return "Request not supported";
+       case ATT_ECODE_INVALID_OFFSET:
+               return "Invalid offset";
+       case ATT_ECODE_INSUFF_AUTHO:
+               return "Insufficient authorization";
+       case ATT_ECODE_PREP_QUEUE_FULL:
+               return "Prepare queue full";
+       case ATT_ECODE_ATTR_NOT_FOUND:
+               return "Attribute not found";
+       case ATT_ECODE_ATTR_NOT_LONG:
+               return "Attribute not long";
+       case ATT_ECODE_INSUFF_ENCR_KEY_SIZE:
+               return "Insufficient encryption key size";
+       case ATT_ECODE_INVAL_ATTR_VALUE_LEN:
+               return "Invalid attribute value length";
+       case ATT_ECODE_UNLIKELY:
+               return "Unlikely error";
+       case ATT_ECODE_INSUFF_ENC:
+               return "Insufficient encryption";
+       case ATT_ECODE_UNSUPP_GRP_TYPE:
+               return "Unsupported group type";
+       case ATT_ECODE_INSUFF_RESOURCES:
+               return "Insufficient resources";
+       case ATT_ECODE_IO:
+               return "Application Error";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *uuid2str(uint16_t uuid)
+{
+       switch (uuid) {
+       case GATT_PRIM_SVC_UUID:
+               return "GATT Primary Service";
+       case GATT_SND_SVC_UUID:
+               return "GATT Secondary Service";
+       case GATT_INCLUDE_UUID:
+               return "GATT Include";
+       case GATT_CHARAC_UUID:
+               return "GATT Characteristic";
+       case GATT_CHARAC_DEVICE_NAME:
+               return "GATT(type) Device Name";
+       case GATT_CHARAC_APPEARANCE:
+               return "GATT(type) Appearance";
+       case GATT_CHARAC_PERIPHERAL_PRIV_FLAG:
+               return "GATT(type) Peripheral Privacy Flag";
+       case GATT_CHARAC_RECONNECTION_ADDRESS:
+               return "GATT(type) Characteristic Reconnection Address";
+       case GATT_CHARAC_PERIPHERAL_PREF_CONN:
+               return "GATT(type) Characteristic Preferred Connection Parameters";
+       case GATT_CHARAC_SERVICE_CHANGED:
+               return "GATT(type) Characteristic Service Changed";
+       case GATT_CHARAC_EXT_PROPER_UUID:
+               return "GATT(desc) Characteristic Extended Properties";
+       case GATT_CHARAC_USER_DESC_UUID:
+               return "GATT(desc) User Description";
+       case GATT_CLIENT_CHARAC_CFG_UUID:
+               return "GATT(desc) Client Characteristic Configuration";
+       case GATT_SERVER_CHARAC_CFG_UUID:
+               return "GATT(desc) Server Characteristic Configuration";
+       case GATT_CHARAC_FMT_UUID:
+               return "GATT(desc) Format";
+       case GATT_CHARAC_AGREG_FMT_UUID:
+               return "GATT(desc) Aggregate Format";
+       default:
+               return "Unknown";
+       }
+}
+
+static void att_error_dump(int level, struct frame *frm)
+{
+       uint8_t op = get_u8(frm);
+       uint16_t handle = btohs(htons(get_u16(frm)));
+       uint8_t err = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("Error: %s (%d)\n", atterror2str(err), err);
+
+       p_indent(level, frm);
+       printf("%s (0x%.2x) on handle 0x%4.4x\n", attop2str(op), op, handle);
+}
+
+static void att_mtu_req_dump(int level, struct frame *frm)
+{
+       uint16_t client_rx_mtu = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("client rx mtu %d\n", client_rx_mtu);
+}
+
+static void att_mtu_resp_dump(int level, struct frame *frm)
+{
+       uint16_t server_rx_mtu = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("server rx mtu %d\n", server_rx_mtu);
+}
+
+static void att_find_info_req_dump(int level, struct frame *frm)
+{
+       uint16_t start = btohs(htons(get_u16(frm)));
+       uint16_t end = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("start 0x%4.4x, end 0x%4.4x\n", start, end);
+}
+
+static void print_uuid128(struct frame *frm)
+{
+       uint8_t uuid[16];
+       int i;
+
+       for (i = 0; i < 16; i++)
+               uuid[15 - i] = get_u8(frm);
+
+       for (i = 0; i < 16; i++) {
+               printf("%02x", uuid[i]);
+               if (i == 3 || i == 5 || i == 7 || i == 9)
+                       printf("-");
+       }
+}
+
+static void att_find_info_resp_dump(int level, struct frame *frm)
+{
+       uint8_t fmt = get_u8(frm);
+
+       p_indent(level, frm);
+
+       if (fmt == 0x01) {
+               printf("format: uuid-16\n");
+
+               while (frm->len > 0) {
+                       uint16_t handle = btohs(htons(get_u16(frm)));
+                       uint16_t uuid = btohs(htons(get_u16(frm)));
+                       p_indent(level + 1, frm);
+                       printf("handle 0x%4.4x, uuid 0x%4.4x (%s)\n", handle, uuid,
+                                       uuid2str(uuid));
+               }
+       } else {
+               printf("format: uuid-128\n");
+
+               while (frm->len > 0) {
+                       uint16_t handle = btohs(htons(get_u16(frm)));
+
+                       p_indent(level + 1, frm);
+                       printf("handle 0x%4.4x, uuid ", handle);
+                       print_uuid128(frm);
+                       printf("\n");
+               }
+       }
+}
+
+static void att_find_by_type_req_dump(int level, struct frame *frm)
+{
+       uint16_t start = btohs(htons(get_u16(frm)));
+       uint16_t end = btohs(htons(get_u16(frm)));
+       uint16_t uuid = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("start 0x%4.4x, end 0x%4.4x, uuid 0x%4.4x\n", start, end, uuid);
+
+       p_indent(level, frm);
+       printf("value");
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_find_by_type_resp_dump(int level, struct frame *frm)
+{
+       while (frm->len > 0) {
+               uint16_t uuid = btohs(htons(get_u16(frm)));
+               uint16_t end = btohs(htons(get_u16(frm)));
+
+               p_indent(level, frm);
+               printf("Found attr 0x%4.4x, group end handle 0x%4.4x\n",
+                                                               uuid, end);
+       }
+}
+
+static void att_read_by_type_req_dump(int level, struct frame *frm)
+{
+       uint16_t start = btohs(htons(get_u16(frm)));
+       uint16_t end = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("start 0x%4.4x, end 0x%4.4x\n", start, end);
+
+       p_indent(level, frm);
+       if (frm->len == 2) {
+               printf("type-uuid 0x%4.4x\n", btohs(htons(get_u16(frm))));
+       } else if (frm->len == 16) {
+               printf("type-uuid ");
+               print_uuid128(frm);
+               printf("\n");
+       } else {
+               printf("malformed uuid (expected 2 or 16 octets)\n");
+               p_indent(level, frm);
+               raw_dump(level, frm);
+       }
+}
+
+static void att_read_by_type_resp_dump(int level, struct frame *frm)
+{
+       uint8_t length = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("length: %d\n", length);
+
+       while (frm->len > 0) {
+               uint16_t handle = btohs(htons(get_u16(frm)));
+               int val_len = length - 2;
+               int i;
+
+               p_indent(level + 1, frm);
+               printf("handle 0x%4.4x, value ", handle);
+               for (i = 0; i < val_len; i++) {
+                       printf("0x%.2x ", get_u8(frm));
+               }
+               printf("\n");
+       }
+}
+
+static void att_read_req_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle 0x%4.4x\n", handle);
+}
+
+static void att_read_blob_req_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+       uint16_t offset = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle 0x%4.4x offset 0x%4.4x\n", handle, offset);
+}
+
+static void att_read_blob_resp_dump(int level, struct frame *frm)
+{
+       p_indent(level, frm);
+       printf("value");
+
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_read_multi_req_dump(int level, struct frame *frm)
+{
+       p_indent(level, frm);
+       printf("Handles\n");
+
+       while (frm->len > 0) {
+               p_indent(level, frm);
+               printf("handle 0x%4.4x\n", btohs(htons(get_u16(frm))));
+       }
+}
+
+static void att_read_multi_resp_dump(int level, struct frame *frm)
+{
+       p_indent(level, frm);
+       printf("values");
+
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_read_by_group_resp_dump(int level, struct frame *frm)
+{
+       uint8_t length = get_u8(frm);
+
+       while (frm->len > 0) {
+               uint16_t attr_handle = btohs(htons(get_u16(frm)));
+               uint16_t end_grp_handle = btohs(htons(get_u16(frm)));
+               uint8_t remaining = length - 4;
+
+               p_indent(level, frm);
+               printf("attr handle 0x%4.4x, end group handle 0x%4.4x\n",
+                                               attr_handle, end_grp_handle);
+
+               p_indent(level, frm);
+               printf("value");
+               while (remaining > 0) {
+                       printf(" 0x%2.2x", get_u8(frm));
+                       remaining--;
+               }
+               printf("\n");
+       }
+}
+
+static void att_write_req_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle 0x%4.4x value ", handle);
+
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_signed_write_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+       int value_len = frm->len - 12; /* handle:2 already accounted, sig: 12 */
+
+       p_indent(level, frm);
+       printf("handle 0x%4.4x value ", handle);
+
+       while (value_len--)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+
+       p_indent(level, frm);
+       printf("auth signature ");
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_prep_write_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+       uint16_t val_offset = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("attr handle 0x%4.4x, value offset 0x%4.4x\n", handle,
+                                                               val_offset);
+
+       p_indent(level, frm);
+       printf("part attr value ");
+       while (frm->len > 0)
+               printf(" 0x%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void att_exec_write_req_dump(int level, struct frame *frm)
+{
+       uint8_t flags = get_u8(frm);
+
+       p_indent(level, frm);
+       if (flags == 0x00)
+               printf("cancel all prepared writes ");
+       else
+               printf("immediatelly write all pending prepared values ");
+
+       printf("(0x%2.2x)\n", flags);
+}
+
+static void att_handle_notify_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle 0x%4.4x\n", handle);
+
+       p_indent(level, frm);
+       printf("value ");
+       while (frm->len > 0)
+               printf("0x%.2x ", get_u8(frm));
+       printf("\n");
+}
+
+void att_dump(int level, struct frame *frm)
+{
+       uint8_t op;
+
+       op = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("ATT: %s (0x%.2x)\n", attop2str(op), op);
+
+       switch (op) {
+               case ATT_OP_ERROR:
+                       att_error_dump(level + 1, frm);
+                       break;
+               case ATT_OP_MTU_REQ:
+                       att_mtu_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_MTU_RESP:
+                       att_mtu_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_FIND_INFO_REQ:
+                       att_find_info_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_FIND_INFO_RESP:
+                       att_find_info_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_FIND_BY_TYPE_REQ:
+                       att_find_by_type_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_FIND_BY_TYPE_RESP:
+                       att_find_by_type_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_BY_TYPE_REQ:
+               case ATT_OP_READ_BY_GROUP_REQ: /* exact same parsing */
+                       att_read_by_type_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_BY_TYPE_RESP:
+                       att_read_by_type_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_REQ:
+                       att_read_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_RESP:
+                       raw_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_BLOB_REQ:
+                       att_read_blob_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_BLOB_RESP:
+                       att_read_blob_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_MULTI_REQ:
+                       att_read_multi_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_MULTI_RESP:
+                       att_read_multi_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_READ_BY_GROUP_RESP:
+                       att_read_by_group_resp_dump(level + 1, frm);
+                       break;
+               case ATT_OP_WRITE_REQ:
+               case ATT_OP_WRITE_CMD:
+                       att_write_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_SIGNED_WRITE_CMD:
+                       att_signed_write_dump(level + 1, frm);
+                       break;
+               case ATT_OP_PREP_WRITE_REQ:
+               case ATT_OP_PREP_WRITE_RESP:
+                       att_prep_write_dump(level + 1, frm);
+                       break;
+               case ATT_OP_EXEC_WRITE_REQ:
+                       att_exec_write_req_dump(level + 1, frm);
+                       break;
+               case ATT_OP_HANDLE_NOTIFY:
+                       att_handle_notify_dump(level + 1, frm);
+                       break;
+               default:
+                       raw_dump(level, frm);
+                       break;
+       }
+}
similarity index 50%
rename from serial/main.c
rename to tools/parser/avctp.c
index 38ded03..58b181d 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2004-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
 #include <config.h>
 #endif
 
+#include <stdio.h>
 #include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include <gdbus.h>
+#include "parser.h"
+#include "sdp.h"
 
-#include "plugin.h"
-#include "manager.h"
-
-static DBusConnection *connection;
-
-static int serial_init(void)
+static char *pt2str(uint8_t hdr)
 {
-       connection = dbus_bus_get(DBUS_BUS_SYSTEM, NULL);
-       if (connection == NULL)
-               return -EIO;
-
-       if (serial_manager_init(connection) < 0) {
-               dbus_connection_unref(connection);
-               return -EIO;
+       switch (hdr & 0x0c) {
+       case 0x00:
+               return "";
+       case 0x04:
+               return "Start";
+       case 0x08:
+               return "Cont";
+       case 0x0c:
+               return "End";
+       default:
+               return "Unk";
        }
-
-       return 0;
 }
 
-static void serial_exit(void)
+void avctp_dump(int level, struct frame *frm, uint16_t psm)
 {
-       serial_manager_exit();
+       uint8_t hdr;
+       uint16_t pid;
 
-       dbus_connection_unref(connection);
-}
+       p_indent(level, frm);
+
+       hdr = get_u8(frm);
+       pid = get_u16(frm);
 
-BLUETOOTH_PLUGIN_DEFINE(serial, VERSION,
-                       BLUETOOTH_PLUGIN_PRIORITY_DEFAULT, serial_init, serial_exit)
+       printf("AVCTP %s: %s %s: pt 0x%02x transaction %d pid 0x%04x\n",
+                               psm == 23 ? "Control" : "Browsing",
+                               hdr & 0x02 ? "Response" : "Command",
+                               pt2str(hdr), hdr & 0x0c, hdr >> 4, pid);
+
+       if (pid == SDP_UUID_AV_REMOTE || pid == SDP_UUID_AV_REMOTE_TARGET)
+               avrcp_dump(level + 1, frm, hdr, psm);
+       else
+               raw_dump(level + 1, frm);
+}
diff --git a/tools/parser/avdtp.c b/tools/parser/avdtp.c
new file mode 100644 (file)
index 0000000..5a2ee55
--- /dev/null
@@ -0,0 +1,520 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+static char *si2str(uint8_t si)
+{
+       switch (si & 0x7f) {
+       case 0x01:
+               return "Discover";
+       case 0x02:
+               return "Capabilities";
+       case 0x03:
+               return "Set config";
+       case 0x04:
+               return "Get config";
+       case 0x05:
+               return "Reconfigure";
+       case 0x06:
+               return "Open";
+       case 0x07:
+               return "Start";
+       case 0x08:
+               return "Close";
+       case 0x09:
+               return "Suspend";
+       case 0x0a:
+               return "Abort";
+       case 0x0b:
+               return "Security";
+       case 0x0c:
+               return "All Capabilities";
+       case 0x0d:
+               return "Delay Report";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *pt2str(uint8_t hdr)
+{
+       switch (hdr & 0x0c) {
+       case 0x00:
+               return "Single";
+       case 0x04:
+               return "Start";
+       case 0x08:
+               return "Cont";
+       case 0x0c:
+               return "End";
+       default:
+               return "Unk";
+       }
+}
+
+static char *mt2str(uint8_t hdr)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               return "cmd";
+       case 0x02:
+               return "rsp";
+       case 0x03:
+               return "rej";
+       default:
+               return "rfd";
+       }
+}
+
+static char *media2str(uint8_t type)
+{
+       switch (type) {
+       case 0:
+               return "Audio";
+       case 1:
+               return "Video";
+       case 2:
+               return "Multimedia";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *codec2str(uint8_t type, uint8_t codec)
+{
+       switch (type) {
+       case 0:
+               switch (codec) {
+               case 0:
+                       return "SBC";
+               case 1:
+                       return "MPEG-1,2 Audio";
+               case 2:
+                       return "MPEG-2,4 AAC";
+               case 4:
+                       return "ATRAC family";
+               case 255:
+                       return "non-A2DP";
+               default:
+                       return "Reserved";
+               }
+               break;
+       case 1:
+               switch (codec) {
+               case 1:
+                       return "H.263 baseline";
+               case 2:
+                       return "MPEG-4 Visual Simple Profile";
+               case 3:
+                       return "H.263 profile 3";
+               case 4:
+                       return "H.263 profile 8";
+               case 255:
+                       return "Non-VDP";
+               default:
+                       return "Reserved";
+               }
+               break;
+       }
+       return "Unknown";
+}
+
+static char *cat2str(uint8_t cat)
+{
+       switch (cat) {
+       case 1:
+               return "Media Transport";
+       case 2:
+               return "Reporting";
+       case 3:
+               return "Recovery";
+       case 4:
+               return "Content Protection";
+       case 5:
+               return "Header Compression";
+       case 6:
+               return "Multiplexing";
+       case 7:
+               return "Media Codec";
+       case 8:
+               return "Delay Reporting";
+       default:
+               return "Reserved";
+       }
+}
+
+static void errorcode(int level, struct frame *frm)
+{
+       uint8_t code;
+
+       p_indent(level, frm);
+       code = get_u8(frm);
+       printf("Error code %d\n", code);
+}
+
+static void acp_seid(int level, struct frame *frm)
+{
+       uint8_t seid;
+
+       p_indent(level, frm);
+       seid = get_u8(frm);
+       printf("ACP SEID %d\n", seid >> 2);
+}
+
+static void acp_int_seid(int level, struct frame *frm)
+{
+       uint8_t acp_seid, int_seid;
+
+       p_indent(level, frm);
+       acp_seid = get_u8(frm);
+       int_seid = get_u8(frm);
+       printf("ACP SEID %d - INT SEID %d\n", acp_seid >> 2, int_seid >> 2);
+}
+
+static void capabilities(int level, struct frame *frm)
+{
+       uint8_t cat, len;
+
+       while (frm->len > 1) {
+               p_indent(level, frm);
+               cat = get_u8(frm);
+               len = get_u8(frm);
+
+               if (cat == 7) {
+                       uint8_t type, codec, tmp;
+
+                       type  = get_u8(frm);
+                       codec = get_u8(frm);
+
+                       printf("%s - %s\n", cat2str(cat), codec2str(type, codec));
+
+                       switch (codec) {
+                       case 0:
+                               tmp = get_u8(frm);
+                               p_indent(level + 1, frm);
+                               if (tmp & 0x80)
+                                       printf("16kHz ");
+                               if (tmp & 0x40)
+                                       printf("32kHz ");
+                               if (tmp & 0x20)
+                                       printf("44.1kHz ");
+                               if (tmp & 0x10)
+                                       printf("48kHz ");
+                               printf("\n");
+                               p_indent(level + 1, frm);
+                               if (tmp & 0x08)
+                                       printf("Mono ");
+                               if (tmp & 0x04)
+                                       printf("DualChannel ");
+                               if (tmp & 0x02)
+                                       printf("Stereo ");
+                               if (tmp & 0x01)
+                                       printf("JointStereo ");
+                               printf("\n");
+                               tmp = get_u8(frm);
+                               p_indent(level + 1, frm);
+                               if (tmp & 0x80)
+                                       printf("4 ");
+                               if (tmp & 0x40)
+                                       printf("8 ");
+                               if (tmp & 0x20)
+                                       printf("12 ");
+                               if (tmp & 0x10)
+                                       printf("16 ");
+                               printf("Blocks\n");
+                               p_indent(level + 1, frm);
+                               if (tmp & 0x08)
+                                       printf("4 ");
+                               if (tmp & 0x04)
+                                       printf("8 ");
+                               printf("Subbands\n");
+                               p_indent(level + 1, frm);
+                               if (tmp & 0x02)
+                                       printf("SNR ");
+                               if (tmp & 0x01)
+                                       printf("Loudness ");
+                               printf("\n");
+                               tmp = get_u8(frm);
+                               p_indent(level + 1, frm);
+                               printf("Bitpool Range %d-%d\n", tmp, get_u8(frm));
+                               break;
+                       default:
+                               hex_dump(level + 1, frm, len - 2);
+                               frm->ptr += (len - 2);
+                               frm->len -= (len - 2);
+                               break;
+                       }
+               } else {
+                       printf("%s\n", cat2str(cat));
+                       hex_dump(level + 1, frm, len);
+
+                       frm->ptr += len;
+                       frm->len -= len;
+               }
+       }
+}
+
+static inline void discover(int level, uint8_t hdr, struct frame *frm)
+{
+       uint8_t seid, type;
+
+       switch (hdr & 0x03) {
+       case 0x02:
+               while (frm->len > 1) {
+                       p_indent(level, frm);
+                       seid = get_u8(frm);
+                       type = get_u8(frm);
+                       printf("ACP SEID %d - %s %s%s\n",
+                               seid >> 2, media2str(type >> 4),
+                               type & 0x08 ? "Sink" : "Source",
+                               seid & 0x02 ? " (InUse)" : "");
+               }
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void get_capabilities(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+               break;
+       case 0x02:
+               capabilities(level, frm);
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void set_configuration(int level, uint8_t hdr, struct frame *frm)
+{
+       uint8_t cat;
+
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_int_seid(level, frm);
+               capabilities(level, frm);
+               break;
+       case 0x03:
+               p_indent(level, frm);
+               cat = get_u8(frm);
+               printf("%s\n", cat2str(cat));
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void get_configuration(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+       case 0x02:
+               capabilities(level, frm);
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void reconfigure(int level, uint8_t hdr, struct frame *frm)
+{
+       uint8_t cat;
+
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+               capabilities(level, frm);
+               break;
+       case 0x03:
+               p_indent(level, frm);
+               cat = get_u8(frm);
+               printf("%s\n", cat2str(cat));
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void open_close_stream(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void start_suspend_stream(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               while (frm->len > 0)
+                       acp_seid(level, frm);
+               break;
+       case 0x03:
+               acp_seid(level, frm);
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void abort_streaming(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+               break;
+       }
+}
+
+static inline void security(int level, uint8_t hdr, struct frame *frm)
+{
+       switch (hdr & 0x03) {
+       case 0x00:
+               acp_seid(level, frm);
+       case 0x02:
+               hex_dump(level + 1, frm, frm->len);
+               frm->ptr += frm->len;
+               frm->len = 0;
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+static inline void delay_report(int level, uint8_t hdr, struct frame *frm)
+{
+       uint8_t seid;
+       uint16_t delay;
+
+       switch (hdr & 0x03) {
+       case 0x00:
+               p_indent(level, frm);
+               seid = get_u8(frm);
+               delay = get_u16(frm);
+               printf("ACP SEID %d delay %u.%ums\n", seid >> 2,
+                                               delay / 10, delay % 10);
+               break;
+       case 0x03:
+               errorcode(level, frm);
+               break;
+       }
+}
+
+void avdtp_dump(int level, struct frame *frm)
+{
+       uint8_t hdr, sid, nsp, type;
+       uint16_t seqn;
+       uint32_t time, ssrc;
+
+       switch (frm->num) {
+       case 1:
+               p_indent(level, frm);
+               hdr = get_u8(frm);
+
+               nsp = (hdr & 0x0c) == 0x04 ? get_u8(frm) : 0;
+               sid = hdr & 0x08 ? 0x00 : get_u8(frm);
+
+               printf("AVDTP(s): %s %s: transaction %d nsp 0x%02x\n",
+                       hdr & 0x08 ? pt2str(hdr) : si2str(sid),
+                       mt2str(hdr), hdr >> 4, nsp);
+
+               switch (sid & 0x7f) {
+               case 0x01:
+                       discover(level + 1, hdr, frm);
+                       break;
+               case 0x02:
+               case 0x0c:
+                       get_capabilities(level + 1, hdr, frm);
+                       break;
+               case 0x03:
+                       set_configuration(level + 1, hdr, frm);
+                       break;
+               case 0x04:
+                       get_configuration(level + 1, hdr, frm);
+                       break;
+               case 0x05:
+                       reconfigure(level + 1, hdr, frm);
+                       break;
+               case 0x06:
+                       open_close_stream(level + 1, hdr, frm);
+                       break;
+               case 0x07:
+                       start_suspend_stream(level + 1, hdr, frm);
+                       break;
+               case 0x08:
+                       open_close_stream(level + 1, hdr, frm);
+                       break;
+               case 0x09:
+                       start_suspend_stream(level + 1, hdr, frm);
+                       break;
+               case 0x0a:
+                       abort_streaming(level + 1, hdr, frm);
+                       break;
+               case 0x0b:
+                       security(level + 1, hdr, frm);
+                       break;
+               case 0x0d:
+                       delay_report(level + 1, hdr, frm);
+                       break;
+               }
+
+               break;
+
+       case 2:
+               p_indent(level, frm);
+               hdr  = get_u8(frm);
+               type = get_u8(frm);
+               seqn = get_u16(frm);
+               time = get_u32(frm);
+               ssrc = get_u32(frm);
+
+               printf("AVDTP(m): ver %d %s%scc %d %spt %d seqn %d time %d ssrc %d\n",
+                       hdr >> 6, hdr & 0x20 ? "pad " : "", hdr & 0x10 ? "ext " : "",
+                       hdr & 0xf, type & 0x80 ? "mark " : "", type & 0x7f, seqn, time, ssrc);
+               break;
+       }
+
+       raw_dump(level, frm);
+}
diff --git a/tools/parser/avrcp.c b/tools/parser/avrcp.c
new file mode 100644 (file)
index 0000000..b523533
--- /dev/null
@@ -0,0 +1,2290 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011 Intel Corporation.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <inttypes.h>
+
+#include "parser.h"
+
+/* ctype entries */
+#define AVC_CTYPE_CONTROL              0x0
+#define AVC_CTYPE_STATUS               0x1
+#define AVC_CTYPE_SPECIFIC_INQUIRY     0x2
+#define AVC_CTYPE_NOTIFY               0x3
+#define AVC_CTYPE_GENERAL_INQUIRY      0x4
+#define AVC_CTYPE_NOT_IMPLEMENTED      0x8
+#define AVC_CTYPE_ACCEPTED             0x9
+#define AVC_CTYPE_REJECTED             0xA
+#define AVC_CTYPE_IN_TRANSITION                0xB
+#define AVC_CTYPE_STABLE               0xC
+#define AVC_CTYPE_CHANGED              0xD
+#define AVC_CTYPE_INTERIM              0xF
+
+/* subunit type */
+#define AVC_SUBUNIT_MONITOR            0x00
+#define AVC_SUBUNIT_AUDIO              0x01
+#define AVC_SUBUNIT_PRINTER            0x02
+#define AVC_SUBUNIT_DISC               0x03
+#define AVC_SUBUNIT_TAPE               0x04
+#define AVC_SUBUNIT_TURNER             0x05
+#define AVC_SUBUNIT_CA                 0x06
+#define AVC_SUBUNIT_CAMERA             0x07
+#define AVC_SUBUNIT_PANEL              0x09
+#define AVC_SUBUNIT_BULLETIN_BOARD     0x0a
+#define AVC_SUBUNIT_CAMERA_STORAGE     0x0b
+#define AVC_SUBUNIT_VENDOR_UNIQUE      0x0c
+#define AVC_SUBUNIT_EXTENDED           0x1e
+#define AVC_SUBUNIT_UNIT               0x1f
+
+/* opcodes */
+#define AVC_OP_VENDORDEP               0x00
+#define AVC_OP_UNITINFO                        0x30
+#define AVC_OP_SUBUNITINFO             0x31
+#define AVC_OP_PASSTHROUGH             0x7c
+
+/* operands in passthrough commands */
+#define AVC_PANEL_VOLUME_UP            0x41
+#define AVC_PANEL_VOLUME_DOWN          0x42
+#define AVC_PANEL_MUTE                 0x43
+#define AVC_PANEL_PLAY                 0x44
+#define AVC_PANEL_STOP                 0x45
+#define AVC_PANEL_PAUSE                        0x46
+#define AVC_PANEL_RECORD               0x47
+#define AVC_PANEL_REWIND               0x48
+#define AVC_PANEL_FAST_FORWARD         0x49
+#define AVC_PANEL_EJECT                        0x4a
+#define AVC_PANEL_FORWARD              0x4b
+#define AVC_PANEL_BACKWARD             0x4c
+
+/* Packet types */
+#define AVRCP_PACKET_TYPE_SINGLE       0x00
+#define AVRCP_PACKET_TYPE_START                0x01
+#define AVRCP_PACKET_TYPE_CONTINUING   0x02
+#define AVRCP_PACKET_TYPE_END          0x03
+
+/* pdu ids */
+#define AVRCP_GET_CAPABILITIES         0x10
+#define AVRCP_LIST_PLAYER_ATTRIBUTES   0x11
+#define AVRCP_LIST_PLAYER_VALUES       0x12
+#define AVRCP_GET_CURRENT_PLAYER_VALUE 0x13
+#define AVRCP_SET_PLAYER_VALUE         0x14
+#define AVRCP_GET_PLAYER_ATTRIBUTE_TEXT        0x15
+#define AVRCP_GET_PLAYER_VALUE_TEXT    0x16
+#define AVRCP_DISPLAYABLE_CHARSET      0x17
+#define AVRCP_CT_BATTERY_STATUS                0x18
+#define AVRCP_GET_ELEMENT_ATTRIBUTES   0x20
+#define AVRCP_GET_PLAY_STATUS          0x30
+#define AVRCP_REGISTER_NOTIFICATION    0x31
+#define AVRCP_REQUEST_CONTINUING       0x40
+#define AVRCP_ABORT_CONTINUING         0x41
+#define AVRCP_SET_ABSOLUTE_VOLUME      0x50
+#define AVRCP_SET_ADDRESSED_PLAYER     0x60
+#define AVRCP_SET_BROWSED_PLAYER       0x70
+#define AVRCP_GET_FOLDER_ITEMS         0x71
+#define AVRCP_CHANGE_PATH              0x72
+#define AVRCP_GET_ITEM_ATTRIBUTES      0x73
+#define AVRCP_PLAY_ITEM                        0x74
+#define AVRCP_SEARCH                   0x80
+#define AVRCP_ADD_TO_NOW_PLAYING       0x90
+#define AVRCP_GENERAL_REJECT           0xA0
+
+/* notification events */
+#define AVRCP_EVENT_PLAYBACK_STATUS_CHANGED            0x01
+#define AVRCP_EVENT_TRACK_CHANGED                      0x02
+#define AVRCP_EVENT_TRACK_REACHED_END                  0x03
+#define AVRCP_EVENT_TRACK_REACHED_START                        0x04
+#define AVRCP_EVENT_PLAYBACK_POS_CHANGED               0x05
+#define AVRCP_EVENT_BATT_STATUS_CHANGED                        0x06
+#define AVRCP_EVENT_SYSTEM_STATUS_CHANGED              0x07
+#define AVRCP_EVENT_PLAYER_APPLICATION_SETTING_CHANGED 0x08
+#define AVRCP_EVENT_NOW_PLAYING_CONTENT_CHANGED                0x09
+#define AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED          0x0a
+#define AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED           0x0b
+#define AVRCP_EVENT_UIDS_CHANGED                       0x0c
+#define AVRCP_EVENT_VOLUME_CHANGED                     0x0d
+
+/* error statuses */
+#define AVRCP_STATUS_INVALID_COMMAND                   0x00
+#define AVRCP_STATUS_INVALID_PARAMETER                 0x01
+#define AVRCP_STATUS_NOT_FOUND                         0x02
+#define AVRCP_STATUS_INTERNAL_ERROR                    0x03
+#define AVRCP_STATUS_SUCCESS                           0x04
+#define AVRCP_STATUS_UID_CHANGED                       0x05
+#define AVRCP_STATUS_INVALID_DIRECTION                 0x07
+#define AVRCP_STATUS_NOT_DIRECTORY                     0x08
+#define AVRCP_STATUS_DOES_NOT_EXIST                    0x09
+#define AVRCP_STATUS_INVALID_SCOPE                     0x0a
+#define AVRCP_STATUS_OUT_OF_BOUNDS                     0x0b
+#define AVRCP_STATUS_IS_DIRECTORY                      0x0c
+#define AVRCP_STATUS_MEDIA_IN_USE                      0x0d
+#define AVRCP_STATUS_NOW_PLAYING_LIST_FULL             0x0e
+#define AVRCP_STATUS_SEARCH_NOT_SUPPORTED              0x0f
+#define AVRCP_STATUS_SEARCH_IN_PROGRESS                        0x10
+#define AVRCP_STATUS_INVALID_PLAYER_ID                 0x11
+#define AVRCP_STATUS_PLAYER_NOT_BROWSABLE              0x12
+#define AVRCP_STATUS_PLAYER_NOT_ADDRESSED              0x13
+#define AVRCP_STATUS_NO_VALID_SEARCH_RESULTS           0x14
+#define AVRCP_STATUS_NO_AVAILABLE_PLAYERS              0x15
+#define AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED          0x16
+
+/* player attributes */
+#define AVRCP_ATTRIBUTE_ILEGAL         0x00
+#define AVRCP_ATTRIBUTE_EQUALIZER      0x01
+#define AVRCP_ATTRIBUTE_REPEAT_MODE    0x02
+#define AVRCP_ATTRIBUTE_SHUFFLE                0x03
+#define AVRCP_ATTRIBUTE_SCAN           0x04
+
+/* media attributes */
+#define AVRCP_MEDIA_ATTRIBUTE_ILLEGAL  0x0
+#define AVRCP_MEDIA_ATTRIBUTE_TITLE    0x1
+#define AVRCP_MEDIA_ATTRIBUTE_ARTIST   0x2
+#define AVRCP_MEDIA_ATTRIBUTE_ALBUM    0x3
+#define AVRCP_MEDIA_ATTRIBUTE_TRACK    0x4
+#define AVRCP_MEDIA_ATTRIBUTE_TOTAL    0x5
+#define AVRCP_MEDIA_ATTRIBUTE_GENRE    0x6
+#define AVRCP_MEDIA_ATTRIBUTE_DURATION 0x7
+
+/* play status */
+#define AVRCP_PLAY_STATUS_STOPPED      0x00
+#define AVRCP_PLAY_STATUS_PLAYING      0x01
+#define AVRCP_PLAY_STATUS_PAUSED       0x02
+#define AVRCP_PLAY_STATUS_FWD_SEEK     0x03
+#define AVRCP_PLAY_STATUS_REV_SEEK     0x04
+#define AVRCP_PLAY_STATUS_ERROR                0xFF
+
+/* media scope */
+#define AVRCP_MEDIA_PLAYER_LIST                0x00
+#define AVRCP_MEDIA_PLAYER_VFS         0x01
+#define AVRCP_MEDIA_SEARCH             0x02
+#define AVRCP_MEDIA_NOW_PLAYING                0x03
+
+static struct avrcp_continuing {
+       uint16_t num;
+       uint16_t size;
+} avrcp_continuing;
+
+static const char *ctype2str(uint8_t ctype)
+{
+       switch (ctype & 0x0f) {
+       case AVC_CTYPE_CONTROL:
+               return "Control";
+       case AVC_CTYPE_STATUS:
+               return "Status";
+       case AVC_CTYPE_SPECIFIC_INQUIRY:
+               return "Specific Inquiry";
+       case AVC_CTYPE_NOTIFY:
+               return "Notify";
+       case AVC_CTYPE_GENERAL_INQUIRY:
+               return "General Inquiry";
+       case AVC_CTYPE_NOT_IMPLEMENTED:
+               return "Not Implemented";
+       case AVC_CTYPE_ACCEPTED:
+               return "Accepted";
+       case AVC_CTYPE_REJECTED:
+               return "Rejected";
+       case AVC_CTYPE_IN_TRANSITION:
+               return "In Transition";
+       case AVC_CTYPE_STABLE:
+               return "Stable";
+       case AVC_CTYPE_CHANGED:
+               return "Changed";
+       case AVC_CTYPE_INTERIM:
+               return "Interim";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char *opcode2str(uint8_t opcode)
+{
+       switch (opcode) {
+       case AVC_OP_VENDORDEP:
+               return "Vendor Dependent";
+       case AVC_OP_UNITINFO:
+               return "Unit Info";
+       case AVC_OP_SUBUNITINFO:
+               return "Subunit Info";
+       case AVC_OP_PASSTHROUGH:
+               return "Passthrough";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char *pt2str(uint8_t pt)
+{
+       switch (pt) {
+       case AVRCP_PACKET_TYPE_SINGLE:
+               return "Single";
+       case AVRCP_PACKET_TYPE_START:
+               return "Start";
+       case AVRCP_PACKET_TYPE_CONTINUING:
+               return "Continuing";
+       case AVRCP_PACKET_TYPE_END:
+               return "End";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char *pdu2str(uint8_t pduid)
+{
+       switch (pduid) {
+       case AVRCP_GET_CAPABILITIES:
+               return "GetCapabilities";
+       case AVRCP_LIST_PLAYER_ATTRIBUTES:
+               return "ListPlayerApplicationSettingAttributes";
+       case AVRCP_LIST_PLAYER_VALUES:
+               return "ListPlayerApplicationSettingValues";
+       case AVRCP_GET_CURRENT_PLAYER_VALUE:
+               return "GetCurrentPlayerApplicationSettingValue";
+       case AVRCP_SET_PLAYER_VALUE:
+               return "SetPlayerApplicationSettingValue";
+       case AVRCP_GET_PLAYER_ATTRIBUTE_TEXT:
+               return "GetPlayerApplicationSettingAttributeText";
+       case AVRCP_GET_PLAYER_VALUE_TEXT:
+               return "GetPlayerApplicationSettingValueText";
+       case AVRCP_DISPLAYABLE_CHARSET:
+               return "InformDisplayableCharacterSet";
+       case AVRCP_CT_BATTERY_STATUS:
+               return "InformBatteryStatusOfCT";
+       case AVRCP_GET_ELEMENT_ATTRIBUTES:
+               return "GetElementAttributes";
+       case AVRCP_GET_PLAY_STATUS:
+               return "GetPlayStatus";
+       case AVRCP_REGISTER_NOTIFICATION:
+               return "RegisterNotification";
+       case AVRCP_REQUEST_CONTINUING:
+               return "RequestContinuingResponse";
+       case AVRCP_ABORT_CONTINUING:
+               return "AbortContinuingResponse";
+       case AVRCP_SET_ABSOLUTE_VOLUME:
+               return "SetAbsoluteVolume";
+       case AVRCP_SET_ADDRESSED_PLAYER:
+               return "SetAddressedPlayer";
+       case AVRCP_SET_BROWSED_PLAYER:
+               return "SetBrowsedPlayer";
+       case AVRCP_GET_FOLDER_ITEMS:
+               return "GetFolderItems";
+       case AVRCP_CHANGE_PATH:
+               return "ChangePath";
+       case AVRCP_GET_ITEM_ATTRIBUTES:
+               return "GetItemAttributes";
+       case AVRCP_PLAY_ITEM:
+               return "PlayItem";
+       case AVRCP_SEARCH:
+               return "Search";
+       case AVRCP_ADD_TO_NOW_PLAYING:
+               return "AddToNowPlaying";
+       case AVRCP_GENERAL_REJECT:
+               return "GeneralReject";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *cap2str(uint8_t cap)
+{
+       switch (cap) {
+       case 0x2:
+               return "CompanyID";
+       case 0x3:
+               return "EventsID";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *event2str(uint8_t event)
+{
+       switch (event) {
+       case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
+               return "EVENT_PLAYBACK_STATUS_CHANGED";
+       case AVRCP_EVENT_TRACK_CHANGED:
+               return "EVENT_TRACK_CHANGED";
+       case AVRCP_EVENT_TRACK_REACHED_END:
+               return "EVENT_TRACK_REACHED_END";
+       case AVRCP_EVENT_TRACK_REACHED_START:
+               return "EVENT_TRACK_REACHED_START";
+       case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
+               return "EVENT_PLAYBACK_POS_CHANGED";
+       case AVRCP_EVENT_BATT_STATUS_CHANGED:
+               return "EVENT_BATT_STATUS_CHANGED";
+       case AVRCP_EVENT_SYSTEM_STATUS_CHANGED:
+               return "EVENT_SYSTEM_STATUS_CHANGED";
+       case AVRCP_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:
+               return "EVENT_PLAYER_APPLICATION_SETTING_CHANGED";
+       case AVRCP_EVENT_NOW_PLAYING_CONTENT_CHANGED:
+               return "EVENT_NOW_PLAYING_CONTENT_CHANGED";
+       case AVRCP_EVENT_AVAILABLE_PLAYERS_CHANGED:
+               return "EVENT_AVAILABLE_PLAYERS_CHANGED";
+       case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+               return "EVENT_ADDRESSED_PLAYER_CHANGED";
+       case AVRCP_EVENT_UIDS_CHANGED:
+               return "EVENT_UIDS_CHANGED";
+       case AVRCP_EVENT_VOLUME_CHANGED:
+               return "EVENT_VOLUME_CHANGED";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *error2str(uint8_t status)
+{
+       switch (status) {
+       case AVRCP_STATUS_INVALID_COMMAND:
+               return "Invalid Command";
+       case AVRCP_STATUS_INVALID_PARAMETER:
+               return "Invalid Parameter";
+       case AVRCP_STATUS_NOT_FOUND:
+               return "Not Found";
+       case AVRCP_STATUS_INTERNAL_ERROR:
+               return "Internal Error";
+       case AVRCP_STATUS_SUCCESS:
+               return "Success";
+       case AVRCP_STATUS_UID_CHANGED:
+               return "UID Changed";
+       case AVRCP_STATUS_INVALID_DIRECTION:
+               return "Invalid Direction";
+       case AVRCP_STATUS_NOT_DIRECTORY:
+               return "Not a Directory";
+       case AVRCP_STATUS_DOES_NOT_EXIST:
+               return "Does Not Exist";
+       case AVRCP_STATUS_INVALID_SCOPE:
+               return "Invalid Scope";
+       case AVRCP_STATUS_OUT_OF_BOUNDS:
+               return "Range Out of Bonds";
+       case AVRCP_STATUS_MEDIA_IN_USE:
+               return "Media in Use";
+       case AVRCP_STATUS_IS_DIRECTORY:
+               return "UID is a Directory";
+       case AVRCP_STATUS_NOW_PLAYING_LIST_FULL:
+               return "Now Playing List Full";
+       case AVRCP_STATUS_SEARCH_NOT_SUPPORTED:
+               return "Seach Not Supported";
+       case AVRCP_STATUS_SEARCH_IN_PROGRESS:
+               return "Search in Progress";
+       case AVRCP_STATUS_INVALID_PLAYER_ID:
+               return "Invalid Player ID";
+       case AVRCP_STATUS_PLAYER_NOT_BROWSABLE:
+               return "Player Not Browsable";
+       case AVRCP_STATUS_PLAYER_NOT_ADDRESSED:
+               return "Player Not Addressed";
+       case AVRCP_STATUS_NO_VALID_SEARCH_RESULTS:
+               return "No Valid Search Result";
+       case AVRCP_STATUS_NO_AVAILABLE_PLAYERS:
+               return "No Available Players";
+       case AVRCP_STATUS_ADDRESSED_PLAYER_CHANGED:
+               return "Addressed Player Changed";
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_rejected_dump(int level, struct frame *frm, uint16_t len)
+{
+       uint8_t status;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       status = get_u8(frm);
+       printf("Error: 0x%02x (%s)\n", status, error2str(status));
+}
+
+static void avrcp_get_capabilities_dump(int level, struct frame *frm, uint16_t len)
+{
+       uint8_t cap;
+       uint8_t count;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       cap = get_u8(frm);
+       printf("CapabilityID: 0x%02x (%s)\n", cap, cap2str(cap));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       count = get_u8(frm);
+       printf("CapabilityCount: 0x%02x\n", count);
+
+       switch (cap) {
+       case 0x2:
+               for (; count > 0; count--) {
+                       int i;
+
+                       p_indent(level, frm);
+
+                       printf("%s: 0x", cap2str(cap));
+                       for (i = 0; i < 3; i++)
+                               printf("%02x", get_u8(frm));
+                       printf("\n");
+               }
+               break;
+       case 0x3:
+               for (; count > 0; count--) {
+                       uint8_t event;
+
+                       p_indent(level, frm);
+
+                       event = get_u8(frm);
+                       printf("%s: 0x%02x (%s)\n", cap2str(cap), event,
+                                                       event2str(event));
+               }
+               break;
+       default:
+               raw_dump(level, frm);
+       }
+}
+
+static const char *attr2str(uint8_t attr)
+{
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_ILEGAL:
+               return "Illegal";
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               return "Equalizer ON/OFF Status";
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               return "Repeat Mode Status";
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+               return "Shuffle ON/OFF Status";
+       case AVRCP_ATTRIBUTE_SCAN:
+               return "Scan ON/OFF Status";
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_list_player_attributes_dump(int level, struct frame *frm,
+                                                               uint16_t len)
+{
+       uint8_t num;
+
+       if (len == 0)
+               return;
+
+       p_indent(level, frm);
+
+       num = get_u8(frm);
+       printf("AttributeCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+       }
+}
+
+static const char *value2str(uint8_t attr, uint8_t value)
+{
+       switch (attr) {
+       case AVRCP_ATTRIBUTE_ILEGAL:
+               return "Illegal";
+       case AVRCP_ATTRIBUTE_EQUALIZER:
+               switch (value) {
+               case 0x01:
+                       return "OFF";
+               case 0x02:
+                       return "ON";
+               default:
+                       return "Reserved";
+               }
+       case AVRCP_ATTRIBUTE_REPEAT_MODE:
+               switch (value) {
+               case 0x01:
+                       return "OFF";
+               case 0x02:
+                       return "Single Track Repeat";
+               case 0x03:
+                       return "All Track Repeat";
+               case 0x04:
+                       return "Group Repeat";
+               default:
+                       return "Reserved";
+               }
+       case AVRCP_ATTRIBUTE_SHUFFLE:
+               switch (value) {
+               case 0x01:
+                       return "OFF";
+               case 0x02:
+                       return "All Track Suffle";
+               case 0x03:
+                       return "Group Suffle";
+               default:
+                       return "Reserved";
+               }
+       case AVRCP_ATTRIBUTE_SCAN:
+               switch (value) {
+               case 0x01:
+                       return "OFF";
+               case 0x02:
+                       return "All Track Scan";
+               case 0x03:
+                       return "Group Scan";
+               default:
+                       return "Reserved";
+               }
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_list_player_values_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       static uint8_t attr = 0; /* Remember attribute */
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       attr = get_u8(frm);
+       printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+
+       return;
+
+response:
+       num = get_u8(frm);
+       printf("ValueCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t value;
+
+               p_indent(level, frm);
+
+               value = get_u8(frm);
+               printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+       }
+}
+
+static void avrcp_get_current_player_value_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       num = get_u8(frm);
+       printf("AttributeCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+       }
+
+       return;
+
+response:
+       num = get_u8(frm);
+       printf("ValueCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t attr, value;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+
+               p_indent(level, frm);
+
+               value = get_u8(frm);
+               printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+       }
+}
+
+static void avrcp_set_player_value_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               return;
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       num = get_u8(frm);
+       printf("AttributeCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t attr, value;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+
+               p_indent(level, frm);
+
+               value = get_u8(frm);
+               printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+       }
+}
+
+static const char *charset2str(uint16_t charset)
+{
+       switch (charset) {
+       case 1:
+       case 2:
+               return "Reserved";
+       case 3:
+               return "ASCII";
+       case 4:
+               return "ISO_8859-1";
+       case 5:
+               return "ISO_8859-2";
+       case 6:
+               return "ISO_8859-3";
+       case 7:
+               return "ISO_8859-4";
+       case 8:
+               return "ISO_8859-5";
+       case 9:
+               return "ISO_8859-6";
+       case 10:
+               return "ISO_8859-7";
+       case 11:
+               return "ISO_8859-8";
+       case 12:
+               return "ISO_8859-9";
+       case 106:
+               return "UTF-8";
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_get_player_attribute_text_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       num = get_u8(frm);
+       printf("AttributeCount: 0x%02x\n", num);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       for (; num > 0; num--) {
+               uint8_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+       }
+
+       return;
+
+response:
+       for (; num > 0; num--) {
+               uint8_t attr, len;
+               uint16_t charset;
+
+               p_indent(level, frm);
+
+               attr = get_u8(frm);
+               printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+
+               p_indent(level, frm);
+
+               charset = get_u16(frm);
+               printf("CharsetID: 0x%04x (%s)\n", charset,
+                                                       charset2str(charset));
+
+               p_indent(level, frm);
+
+               len = get_u8(frm);
+               printf("StringLength: 0x%02x\n", len);
+
+               p_indent(level, frm);
+
+               printf("String: ");
+               for (; len > 0; len--) {
+                       uint8_t c = get_u8(frm);
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+       }
+}
+
+static void avrcp_get_player_value_text_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       static uint8_t attr = 0; /* Remember attribute */
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       attr = get_u8(frm);
+       printf("AttributeID: 0x%02x (%s)\n", attr, attr2str(attr));
+
+       p_indent(level, frm);
+
+       num = get_u8(frm);
+       printf("ValueCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t value;
+
+               p_indent(level, frm);
+
+               value = get_u8(frm);
+               printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+       }
+
+       return;
+
+response:
+       num = get_u8(frm);
+       printf("ValueCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint8_t value, len;
+               uint16_t charset;
+
+               p_indent(level, frm);
+
+               value = get_u8(frm);
+               printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+
+               p_indent(level, frm);
+
+               charset = get_u16(frm);
+               printf("CharsetID: 0x%04x (%s)\n", charset,
+                                                       charset2str(charset));
+
+               p_indent(level, frm);
+
+               len = get_u8(frm);
+               printf("StringLength: 0x%02x\n", len);
+
+               p_indent(level, frm);
+
+               printf("String: ");
+               for (; len > 0; len--) {
+                       uint8_t c = get_u8(frm);
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+       }
+}
+
+static void avrcp_displayable_charset(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t num;
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               return;
+
+       p_indent(level, frm);
+
+       if (len < 2) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       num = get_u8(frm);
+       printf("CharsetCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint16_t charset;
+
+               p_indent(level, frm);
+
+               charset = get_u16(frm);
+               printf("CharsetID: 0x%04x (%s)\n", charset,
+                                                       charset2str(charset));
+       }
+}
+
+static const char *status2str(uint8_t status)
+{
+       switch (status) {
+       case 0x0:
+               return "NORMAL";
+       case 0x1:
+               return "WARNING";
+       case 0x2:
+               return "CRITICAL";
+       case 0x3:
+               return "EXTERNAL";
+       case 0x4:
+               return "FULL_CHARGE";
+       default:
+               return "Reserved";
+       }
+}
+
+static void avrcp_ct_battery_status_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t status;
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               return;
+
+       p_indent(level, frm);
+
+       status = get_u8(frm);
+       printf("BatteryStatus: 0x%02x (%s)\n", status, status2str(status));
+}
+
+static const char *mediattr2str(uint32_t attr)
+{
+       switch (attr) {
+       case AVRCP_MEDIA_ATTRIBUTE_ILLEGAL:
+               return "Illegal";
+       case AVRCP_MEDIA_ATTRIBUTE_TITLE:
+               return "Title";
+       case AVRCP_MEDIA_ATTRIBUTE_ARTIST:
+               return "Artist";
+       case AVRCP_MEDIA_ATTRIBUTE_ALBUM:
+               return "Album";
+       case AVRCP_MEDIA_ATTRIBUTE_TRACK:
+               return "Track";
+       case AVRCP_MEDIA_ATTRIBUTE_TOTAL:
+               return "Track Total";
+       case AVRCP_MEDIA_ATTRIBUTE_GENRE:
+               return "Genre";
+       case AVRCP_MEDIA_ATTRIBUTE_DURATION:
+               return "Track duration";
+       default:
+               return "Reserved";
+       }
+}
+
+static void avrcp_get_element_attributes_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len,
+                                               uint8_t pt)
+{
+       uint64_t id;
+       uint8_t num;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (len < 9) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       id = get_u64(frm);
+       printf("Identifier: 0x%jx (%s)\n", id, id ? "Reserved" : "PLAYING");
+
+       p_indent(level, frm);
+
+       num = get_u8(frm);
+       printf("AttributeCount: 0x%02x\n", num);
+
+       for (; num > 0; num--) {
+               uint32_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u32(frm);
+               printf("Attribute: 0x%08x (%s)\n", attr, mediattr2str(attr));
+       }
+
+       return;
+
+response:
+       if (pt == AVRCP_PACKET_TYPE_SINGLE || pt == AVRCP_PACKET_TYPE_START) {
+               if (len < 1) {
+                       printf("PDU Malformed\n");
+                       raw_dump(level, frm);
+                       return;
+               }
+
+               num = get_u8(frm);
+               avrcp_continuing.num = num;
+               printf("AttributeCount: 0x%02x\n", num);
+               len--;
+       } else {
+               num = avrcp_continuing.num;
+
+               if (avrcp_continuing.size > 0) {
+                       uint16_t size;
+
+                       if (avrcp_continuing.size > len) {
+                               size = len;
+                               avrcp_continuing.size -= len;
+                       } else {
+                               size = avrcp_continuing.size;
+                               avrcp_continuing.size = 0;
+                       }
+
+                       printf("ContinuingAttributeValue: ");
+                       for (; size > 0; size--) {
+                               uint8_t c = get_u8(frm);
+                               printf("%1c", isprint(c) ? c : '.');
+                       }
+                       printf("\n");
+
+                       len -= size;
+               }
+       }
+
+       while (num > 0 && len > 0) {
+               uint32_t attr;
+               uint16_t charset, attrlen;
+
+               p_indent(level, frm);
+
+               attr = get_u32(frm);
+               printf("Attribute: 0x%08x (%s)\n", attr, mediattr2str(attr));
+
+               p_indent(level, frm);
+
+               charset = get_u16(frm);
+               printf("CharsetID: 0x%04x (%s)\n", charset,
+                                                       charset2str(charset));
+
+               p_indent(level, frm);
+               attrlen = get_u16(frm);
+               printf("AttributeValueLength: 0x%04x\n", attrlen);
+
+               len -= sizeof(attr) + sizeof(charset) + sizeof(attrlen);
+               num--;
+
+               p_indent(level, frm);
+
+               printf("AttributeValue: ");
+               for (; attrlen > 0 && len > 0; attrlen--, len--) {
+                       uint8_t c = get_u8(frm);
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+
+               if (attrlen > 0)
+                       avrcp_continuing.size = attrlen;
+       }
+
+       avrcp_continuing.num = num;
+}
+
+static const char *playstatus2str(uint8_t status)
+{
+       switch (status) {
+       case AVRCP_PLAY_STATUS_STOPPED:
+               return "STOPPED";
+       case AVRCP_PLAY_STATUS_PLAYING:
+               return "PLAYING";
+       case AVRCP_PLAY_STATUS_PAUSED:
+               return "PAUSED";
+       case AVRCP_PLAY_STATUS_FWD_SEEK:
+               return "FWD_SEEK";
+       case AVRCP_PLAY_STATUS_REV_SEEK:
+               return "REV_SEEK";
+       case AVRCP_PLAY_STATUS_ERROR:
+               return "ERROR";
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_get_play_status_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint32_t interval;
+       uint8_t status;
+
+       if (ctype <= AVC_CTYPE_GENERAL_INQUIRY)
+               return;
+
+       p_indent(level, frm);
+
+       if (len < 9) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       interval = get_u32(frm);
+       printf("SongLength: 0x%08x (%u miliseconds)\n", interval, interval);
+
+       p_indent(level, frm);
+
+       interval = get_u32(frm);
+       printf("SongPosition: 0x%08x (%u miliconds)\n", interval, interval);
+
+       p_indent(level, frm);
+
+       status = get_u8(frm);
+       printf("PlayStatus: 0x%02x (%s)\n", status, playstatus2str(status));
+}
+
+static void avrcp_register_notification_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t event, status;
+       uint16_t uid;
+       uint32_t interval;
+       uint64_t id;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (len < 5) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       event = get_u8(frm);
+       printf("EventID: 0x%02x (%s)\n", event, event2str(event));
+
+       p_indent(level, frm);
+
+       interval = get_u32(frm);
+       printf("Interval: 0x%08x (%u seconds)\n", interval, interval);
+
+       return;
+
+response:
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       event = get_u8(frm);
+       printf("EventID: 0x%02x (%s)\n", event, event2str(event));
+
+       p_indent(level, frm);
+
+       switch (event) {
+       case AVRCP_EVENT_PLAYBACK_STATUS_CHANGED:
+               status = get_u8(frm);
+               printf("PlayStatus: 0x%02x (%s)\n", status,
+                                               playstatus2str(status));
+               break;
+       case AVRCP_EVENT_TRACK_CHANGED:
+               id = get_u64(frm);
+               printf("Identifier: 0x%16" PRIx64 " (%" PRIu64 ")\n", id, id);
+               break;
+       case AVRCP_EVENT_PLAYBACK_POS_CHANGED:
+               interval = get_u32(frm);
+               printf("Position: 0x%08x (%u miliseconds)\n", interval,
+                                                               interval);
+               break;
+       case AVRCP_EVENT_BATT_STATUS_CHANGED:
+               status = get_u8(frm);
+               printf("BatteryStatus: 0x%02x (%s)\n", status,
+                                                       status2str(status));
+               break;
+       case AVRCP_EVENT_SYSTEM_STATUS_CHANGED:
+               status = get_u8(frm);
+               printf("SystemStatus: 0x%02x ", status);
+               switch (status) {
+               case 0x00:
+                       printf("(POWER_ON)\n");
+               case 0x01:
+                       printf("(POWER_OFF)\n");
+               case 0x02:
+                       printf("(UNPLUGGED)\n");
+               default:
+                       printf("(UNKOWN)\n");
+               }
+               break;
+       case AVRCP_EVENT_PLAYER_APPLICATION_SETTING_CHANGED:
+               status = get_u8(frm);
+               printf("AttributeCount: 0x%02x\n", status);
+
+               for (; status > 0; status--) {
+                       uint8_t attr, value;
+
+                       p_indent(level, frm);
+
+                       attr = get_u8(frm);
+                       printf("AttributeID: 0x%02x (%s)\n", attr,
+                                                       attr2str(attr));
+
+                       p_indent(level, frm);
+
+                       value = get_u8(frm);
+                       printf("ValueID: 0x%02x (%s)\n", value,
+                                               value2str(attr, value));
+               }
+               break;
+       case AVRCP_EVENT_VOLUME_CHANGED:
+               status = get_u8(frm) & 0x7F;
+               printf("Volume: %.2f%% (%d/127)\n", status/1.27, status);
+               break;
+       case AVRCP_EVENT_ADDRESSED_PLAYER_CHANGED:
+               uid = get_u16(frm);
+               printf("PlayerID: 0x%04x (%u)\n", uid, uid);
+
+
+               p_indent(level, frm);
+
+               uid = get_u16(frm);
+               printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
+               break;
+       case AVRCP_EVENT_UIDS_CHANGED:
+               uid = get_u16(frm);
+               printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
+               break;
+       }
+}
+
+static void avrcp_set_absolute_volume_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint8_t value;
+
+       p_indent(level, frm);
+
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       value = get_u8(frm) & 0x7F;
+       printf("Volume: %.2f%% (%d/127)\n", value/1.27, value);
+}
+
+static void avrcp_set_addressed_player(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint16_t id;
+       uint8_t status;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (len < 2) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       id = get_u16(frm);
+       printf("PlayerID: 0x%04x (%u)\n", id, id);
+       return;
+
+response:
+       if (len < 1) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+}
+
+static void avrcp_set_browsed_player_dump(int level, struct frame *frm,
+                                               uint8_t hdr, uint16_t len)
+{
+       uint32_t items;
+       uint16_t id, uids, charset;
+       uint8_t status, folders;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       if (len < 2) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       id = get_u16(frm);
+       printf("PlayerID: 0x%04x (%u)\n", id, id);
+       return;
+
+response:
+       if (len != 1 && len < 10) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       uids = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uids, uids);
+
+       p_indent(level, frm);
+
+       items = get_u32(frm);
+       printf("Number of Items: 0x%08x (%u)\n", items, items);
+
+       p_indent(level, frm);
+
+       charset = get_u16(frm);
+       printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
+
+       p_indent(level, frm);
+
+       folders = get_u8(frm);
+       printf("Folder Depth: 0x%02x (%u)\n", folders, folders);
+
+       for (; folders > 0; folders--) {
+               uint16_t len;
+
+               p_indent(level, frm);
+
+               len = get_u8(frm);
+               printf("Folder: ");
+               for (; len > 0; len--) {
+                       uint8_t c = get_u8(frm);
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+       }
+}
+
+static const char *scope2str(uint8_t scope)
+{
+       switch (scope) {
+       case AVRCP_MEDIA_PLAYER_LIST:
+               return "Media Player List";
+       case AVRCP_MEDIA_PLAYER_VFS:
+               return "Media Player Virtual Filesystem";
+       case AVRCP_MEDIA_SEARCH:
+               return "Search";
+       case AVRCP_MEDIA_NOW_PLAYING:
+               return "Now Playing";
+       default:
+               return "Unknown";
+       }
+}
+
+static void avrcp_play_item_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint64_t uid;
+       uint32_t uidcounter;
+       uint8_t scope, status;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (len < 11) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       scope = get_u8(frm);
+       printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
+
+       p_indent(level, frm);
+
+       uid = get_u64(frm);
+       printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       p_indent(level, frm);
+
+       uidcounter = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+}
+
+static void avrcp_add_to_now_playing_dump(int level, struct frame *frm,
+                                               uint8_t ctype, uint16_t len)
+{
+       uint64_t uid;
+       uint32_t uidcounter;
+       uint8_t scope, status;
+
+       p_indent(level, frm);
+
+       if (ctype > AVC_CTYPE_GENERAL_INQUIRY)
+               goto response;
+
+       if (len < 11) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       scope = get_u8(frm);
+       printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
+
+       p_indent(level, frm);
+
+       uid = get_u64(frm);
+       printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       p_indent(level, frm);
+
+       uidcounter = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+}
+
+static void avrcp_pdu_dump(int level, struct frame *frm, uint8_t ctype)
+{
+       uint8_t pduid, pt;
+       uint16_t len;
+
+       p_indent(level, frm);
+
+       pduid = get_u8(frm);
+       pt = get_u8(frm);
+       len = get_u16(frm);
+
+       printf("AVRCP: %s: pt %s len 0x%04x\n", pdu2str(pduid),
+                                                       pt2str(pt), len);
+
+       if (len != frm->len) {
+               p_indent(level, frm);
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       if (ctype == AVC_CTYPE_REJECTED) {
+               avrcp_rejected_dump(level + 1, frm, len);
+               return;
+       }
+
+       switch (pduid) {
+       case AVRCP_GET_CAPABILITIES:
+               avrcp_get_capabilities_dump(level + 1, frm, len);
+               break;
+       case AVRCP_LIST_PLAYER_ATTRIBUTES:
+               avrcp_list_player_attributes_dump(level + 1, frm, len);
+               break;
+       case AVRCP_LIST_PLAYER_VALUES:
+               avrcp_list_player_values_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_GET_CURRENT_PLAYER_VALUE:
+               avrcp_get_current_player_value_dump(level + 1, frm, ctype,
+                                                                       len);
+               break;
+       case AVRCP_SET_PLAYER_VALUE:
+               avrcp_set_player_value_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_GET_PLAYER_ATTRIBUTE_TEXT:
+               avrcp_get_player_attribute_text_dump(level + 1, frm, ctype,
+                                                                       len);
+               break;
+       case AVRCP_GET_PLAYER_VALUE_TEXT:
+               avrcp_get_player_value_text_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_DISPLAYABLE_CHARSET:
+               avrcp_displayable_charset(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_CT_BATTERY_STATUS:
+               avrcp_ct_battery_status_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_GET_ELEMENT_ATTRIBUTES:
+               avrcp_get_element_attributes_dump(level + 1, frm, ctype, len,
+                                                                       pt);
+               break;
+       case AVRCP_GET_PLAY_STATUS:
+               avrcp_get_play_status_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_REGISTER_NOTIFICATION:
+               avrcp_register_notification_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_SET_ABSOLUTE_VOLUME:
+               avrcp_set_absolute_volume_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_SET_ADDRESSED_PLAYER:
+               avrcp_set_addressed_player(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_PLAY_ITEM:
+               avrcp_play_item_dump(level + 1, frm, ctype, len);
+               break;
+       case AVRCP_ADD_TO_NOW_PLAYING:
+               avrcp_add_to_now_playing_dump(level + 1, frm, ctype, len);
+               break;
+       default:
+               raw_dump(level, frm);
+       }
+}
+
+static char *op2str(uint8_t op)
+{
+       switch (op & 0x7f) {
+       case AVC_PANEL_VOLUME_UP:
+               return "VOLUME UP";
+       case AVC_PANEL_VOLUME_DOWN:
+               return "VOLUME DOWN";
+       case AVC_PANEL_MUTE:
+               return "MUTE";
+       case AVC_PANEL_PLAY:
+               return "PLAY";
+       case AVC_PANEL_STOP:
+               return "STOP";
+       case AVC_PANEL_PAUSE:
+               return "PAUSE";
+       case AVC_PANEL_RECORD:
+               return "RECORD";
+       case AVC_PANEL_REWIND:
+               return "REWIND";
+       case AVC_PANEL_FAST_FORWARD:
+               return "FAST FORWARD";
+       case AVC_PANEL_EJECT:
+               return "EJECT";
+       case AVC_PANEL_FORWARD:
+               return "FORWARD";
+       case AVC_PANEL_BACKWARD:
+               return "BACKWARD";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+
+static void avrcp_passthrough_dump(int level, struct frame *frm)
+{
+       uint8_t op, len;
+
+       p_indent(level, frm);
+
+       op = get_u8(frm);
+       printf("Operation: 0x%02x (%s %s)\n", op, op2str(op),
+                                       op & 0x80 ? "Released" : "Pressed");
+
+       p_indent(level, frm);
+
+       len = get_u8(frm);
+
+       printf("Lenght: 0x%02x\n", len);
+
+       raw_dump(level, frm);
+}
+
+static const char *subunit2str(uint8_t subunit)
+{
+       switch (subunit) {
+       case AVC_SUBUNIT_MONITOR:
+               return "Monitor";
+       case AVC_SUBUNIT_AUDIO:
+               return "Audio";
+       case AVC_SUBUNIT_PRINTER:
+               return "Printer";
+       case AVC_SUBUNIT_DISC:
+               return "Disc";
+       case AVC_SUBUNIT_TAPE:
+               return "Tape";
+       case AVC_SUBUNIT_TURNER:
+               return "Turner";
+       case AVC_SUBUNIT_CA:
+               return "CA";
+       case AVC_SUBUNIT_CAMERA:
+               return "Camera";
+       case AVC_SUBUNIT_PANEL:
+               return "Panel";
+       case AVC_SUBUNIT_BULLETIN_BOARD:
+               return "Bulleting Board";
+       case AVC_SUBUNIT_CAMERA_STORAGE:
+               return "Camera Storage";
+       case AVC_SUBUNIT_VENDOR_UNIQUE:
+               return "Vendor Unique";
+       case AVC_SUBUNIT_EXTENDED:
+               return "Extended to next byte";
+       case AVC_SUBUNIT_UNIT:
+               return "Unit";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *playertype2str(uint8_t type)
+{
+       switch (type & 0x0F) {
+       case 0x01:
+               return "Audio";
+       case 0x02:
+               return "Video";
+       case 0x03:
+               return "Audio, Video";
+       case 0x04:
+               return "Audio Broadcasting";
+       case 0x05:
+               return "Audio, Audio Broadcasting";
+       case 0x06:
+               return "Video, Audio Broadcasting";
+       case 0x07:
+               return "Audio, Video, Audio Broadcasting";
+       case 0x08:
+               return "Video Broadcasting";
+       case 0x09:
+               return "Audio, Video Broadcasting";
+       case 0x0A:
+               return "Video, Video Broadcasting";
+       case 0x0B:
+               return "Audio, Video, Video Broadcasting";
+       case 0x0C:
+               return "Audio Broadcasting, Video Broadcasting";
+       case 0x0D:
+               return "Audio, Audio Broadcasting, Video Broadcasting";
+       case 0x0E:
+               return "Video, Audio Broadcasting, Video Broadcasting";
+       case 0x0F:
+               return "Audio, Video, Audio Broadcasting, Video Broadcasting";
+       }
+
+       return "None";
+}
+
+static const char *playersubtype2str(uint32_t subtype)
+{
+       switch (subtype & 0x03) {
+       case 0x01:
+               return "Audio Book";
+       case 0x02:
+               return "Podcast";
+       case 0x03:
+               return "Audio Book, Podcast";
+       }
+
+       return "None";
+}
+
+static void avrcp_media_player_item_dump(int level, struct frame *frm,
+                                                               uint16_t len)
+{
+       uint16_t id, charset, namelen;
+       uint8_t type, status;
+       uint32_t subtype;
+       uint64_t features[2];
+
+       p_indent(level, frm);
+
+       if (len < 28) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       id = get_u16(frm);
+       printf("PlayerID: 0x%04x (%u)\n", id, id);
+
+       p_indent(level, frm);
+
+       type = get_u8(frm);
+       printf("PlayerType: 0x%04x (%s)\n", type, playertype2str(type));
+
+       p_indent(level, frm);
+
+       subtype = get_u32(frm);
+       printf("PlayerSubtype: 0x%08x (%s)\n", subtype,
+                                               playersubtype2str(subtype));
+
+       p_indent(level, frm);
+
+       status = get_u8(frm);
+       printf("PlayStatus: 0x%02x (%s)\n", status, playstatus2str(status));
+
+       p_indent(level, frm);
+
+       get_u128(frm, &features[0], &features[1]);
+       printf("Features: 0x%16" PRIx64 "%16" PRIx64 "\n", features[1],
+                                                               features[0]);
+
+       p_indent(level, frm);
+
+       charset = get_u16(frm);
+       printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
+
+       p_indent(level, frm);
+
+       namelen = get_u16(frm);
+       printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
+
+       p_indent(level, frm);
+
+       printf("Name: ");
+       for (; namelen > 0; namelen--) {
+               uint8_t c = get_u8(frm);
+               printf("%1c", isprint(c) ? c : '.');
+       }
+       printf("\n");
+}
+
+static const char *foldertype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "Mixed";
+       case 0x01:
+               return "Titles";
+       case 0x02:
+               return "Albuns";
+       case 0x03:
+               return "Artists";
+       case 0x04:
+               return "Genres";
+       case 0x05:
+               return "Playlists";
+       case 0x06:
+               return "Years";
+       }
+
+       return "Reserved";
+}
+
+static void avrcp_folder_item_dump(int level, struct frame *frm, uint16_t len)
+{
+       uint8_t type, playable;
+       uint16_t charset, namelen;
+       uint64_t uid;
+
+       p_indent(level, frm);
+
+       if (len < 14) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       uid = get_u64(frm);
+       printf("FolderUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       p_indent(level, frm);
+
+       type = get_u8(frm);
+       printf("FolderType: 0x%02x (%s)\n", type, foldertype2str(type));
+
+       p_indent(level, frm);
+
+       playable = get_u8(frm);
+       printf("IsPlayable: 0x%02x (%s)\n", playable,
+                                       playable & 0x01 ? "True" : "False");
+
+       p_indent(level, frm);
+
+       charset = get_u16(frm);
+       printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
+
+       p_indent(level, frm);
+
+       namelen = get_u16(frm);
+       printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
+
+       p_indent(level, frm);
+
+       printf("Name: ");
+       for (; namelen > 0; namelen--) {
+               uint8_t c = get_u8(frm);
+               printf("%1c", isprint(c) ? c : '.');
+       }
+       printf("\n");
+}
+
+static const char *elementtype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "Audio";
+       case 0x01:
+               return "Video";
+       }
+
+       return "Reserved";
+}
+
+static void avrcp_attribute_entry_list_dump(int level, struct frame *frm,
+                                                               uint8_t count)
+{
+       for (; count > 0; count--) {
+               uint32_t attr;
+               uint16_t charset;
+               uint8_t len;
+
+               p_indent(level, frm);
+
+               attr = get_u32(frm);
+               printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
+
+               p_indent(level, frm);
+
+               charset = get_u16(frm);
+               printf("CharsetID: 0x%04x (%s)\n", charset,
+                                                       charset2str(charset));
+
+               p_indent(level, frm);
+
+               len = get_u16(frm);
+               printf("AttributeLength: 0x%04x (%u)\n", len, len);
+
+               p_indent(level, frm);
+
+               printf("AttributeValue: ");
+               for (; len > 0; len--) {
+                       uint8_t c = get_u8(frm);
+                       printf("%1c", isprint(c) ? c : '.');
+               }
+               printf("\n");
+       }
+}
+
+static void avrcp_media_element_item_dump(int level, struct frame *frm,
+                                                               uint16_t len)
+{
+       uint64_t uid;
+       uint16_t charset, namelen;
+       uint8_t type, count;
+
+       p_indent(level, frm);
+
+       if (len < 14) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       uid = get_u64(frm);
+       printf("ElementUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       p_indent(level, frm);
+
+       type = get_u8(frm);
+       printf("ElementType: 0x%02x (%s)\n", type, elementtype2str(type));
+
+       p_indent(level, frm);
+
+       charset = get_u16(frm);
+       printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
+
+       p_indent(level, frm);
+
+       namelen = get_u16(frm);
+       printf("NameLength: 0x%04x (%u)\n", namelen, namelen);
+
+       p_indent(level, frm);
+
+       printf("Name: ");
+       for (; namelen > 0; namelen--) {
+               uint8_t c = get_u8(frm);
+               printf("%1c", isprint(c) ? c : '.');
+       }
+       printf("\n");
+
+       p_indent(level, frm);
+
+       count = get_u8(frm);
+       printf("AttributeCount: 0x%02x (%u)\n", count, count);
+
+       avrcp_attribute_entry_list_dump(level, frm, count);
+}
+
+static void avrcp_get_folder_items_dump(int level, struct frame *frm,
+                                               uint8_t hdr, uint16_t len)
+{
+       uint8_t scope, count, status;
+       uint32_t start, end;
+       uint16_t uid, num;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       if (len < 10) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       scope = get_u8(frm);
+       printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
+
+       p_indent(level, frm);
+
+       start = get_u32(frm);
+       printf("StartItem: 0x%08x (%u)\n", start, start);
+
+       p_indent(level, frm);
+
+       end = get_u32(frm);
+       printf("EndItem: 0x%08x (%u)\n", end, end);
+
+       p_indent(level, frm);
+
+       count = get_u8(frm);
+       printf("AttributeCount: 0x%02x (%u)\n", count, count);
+
+       for (; count > 0; count--) {
+               uint32_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u32(frm);
+               printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
+       }
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       uid = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uid, uid);
+
+       p_indent(level, frm);
+
+       num = get_u16(frm);
+       printf("Number of Items: 0x%04x (%u)\n", num, num);
+
+       for (; num > 0; num--) {
+               uint8_t type;
+               uint16_t len;
+
+               p_indent(level, frm);
+
+               type = get_u8(frm);
+               len = get_u16(frm);
+               switch (type) {
+               case 0x01:
+                       printf("Item: 0x01 (Media Player)) ");
+                       printf("Length: 0x%04x (%u)\n", len, len);
+                       avrcp_media_player_item_dump(level, frm, len);
+                       break;
+               case 0x02:
+                       printf("Item: 0x02 (Folder) ");
+                       printf("Length: 0x%04x (%u)\n", len, len);
+                       avrcp_folder_item_dump(level, frm, len);
+                       break;
+               case 0x03:
+                       printf("Item: 0x03 (Media Element) ");
+                       printf("Length: 0x%04x (%u)\n", len, len);
+                       avrcp_media_element_item_dump(level, frm, len);
+                       break;
+               }
+       }
+}
+
+static const char *dir2str(uint8_t dir)
+{
+       switch (dir) {
+       case 0x00:
+               return "Folder Up";
+       case 0x01:
+               return "Folder Down";
+       }
+
+       return "Reserved";
+}
+
+static void avrcp_change_path_dump(int level, struct frame *frm, uint8_t hdr,
+                                                               uint16_t len)
+{
+       uint64_t uid;
+       uint32_t items;
+       uint16_t uidcounter;
+       uint8_t dir, status;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       if (len < 11) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       uidcounter = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
+
+       p_indent(level, frm);
+
+       dir = get_u8(frm);
+       printf("Direction: 0x%02x (%s)\n", dir, dir2str(dir));
+
+       p_indent(level, frm);
+
+       uid = get_u64(frm);
+       printf("FolderUID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       items = get_u32(frm);
+       printf("Number of Items: 0x%04x (%u)", items, items);
+}
+
+static void avrcp_get_item_attributes_dump(int level, struct frame *frm,
+                                               uint8_t hdr, uint16_t len)
+{
+       uint64_t uid;
+       uint32_t uidcounter;
+       uint8_t scope, count, status;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       if (len < 12) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       scope = get_u8(frm);
+       printf("Scope: 0x%02x (%s)\n", scope, scope2str(scope));
+
+       p_indent(level, frm);
+
+       uid = get_u64(frm);
+       printf("UID: 0x%16" PRIx64 " (%" PRIu64 ")\n", uid, uid);
+
+       p_indent(level, frm);
+
+       uidcounter = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
+
+       p_indent(level, frm);
+
+       count = get_u8(frm);
+       printf("AttributeCount: 0x%02x (%u)\n", count, count);
+
+       for (; count > 0; count--) {
+               uint32_t attr;
+
+               p_indent(level, frm);
+
+               attr = get_u32(frm);
+               printf("AttributeID: 0x%08x (%s)\n", attr, mediattr2str(attr));
+       }
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       count = get_u8(frm);
+       printf("AttributeCount: 0x%02x (%u)\n", count, count);
+
+       avrcp_attribute_entry_list_dump(level, frm, count);
+}
+
+static void avrcp_search_dump(int level, struct frame *frm, uint8_t hdr,
+                                                               uint16_t len)
+{
+       uint32_t uidcounter, items;
+       uint16_t charset, namelen;
+       uint8_t status;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       if (len < 4) {
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       charset = get_u16(frm);
+       printf("CharsetID: 0x%04x (%s)\n", charset, charset2str(charset));
+
+       p_indent(level, frm);
+
+       namelen = get_u16(frm);
+       printf("Length: 0x%04x (%u)\n", namelen, namelen);
+
+       p_indent(level, frm);
+
+       printf("String: ");
+       for (; namelen > 0; namelen--) {
+               uint8_t c = get_u8(frm);
+               printf("%1c", isprint(c) ? c : '.');
+       }
+       printf("\n");
+
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+
+       if (len == 1)
+               return;
+
+       p_indent(level, frm);
+
+       uidcounter = get_u16(frm);
+       printf("UIDCounter: 0x%04x (%u)\n", uidcounter, uidcounter);
+
+       p_indent(level, frm);
+
+       items = get_u32(frm);
+       printf("Number of Items: 0x%04x (%u)", items, items);
+}
+
+static void avrcp_general_reject_dump(int level, struct frame *frm,
+                                               uint8_t hdr, uint16_t len)
+{
+       uint8_t status;
+
+       p_indent(level, frm);
+
+       if (hdr & 0x02)
+               goto response;
+
+       printf("PDU Malformed\n");
+       raw_dump(level, frm);
+       return;
+
+response:
+       status = get_u8(frm);
+       printf("Status: 0x%02x (%s)\n", status, error2str(status));
+}
+
+static void avrcp_browsing_dump(int level, struct frame *frm, uint8_t hdr)
+{
+       uint8_t pduid;
+       uint16_t len;
+
+       pduid = get_u8(frm);
+       len = get_u16(frm);
+
+       printf("AVRCP: %s: len 0x%04x\n", pdu2str(pduid), len);
+
+       if (len != frm->len) {
+               p_indent(level, frm);
+               printf("PDU Malformed\n");
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (pduid) {
+       case AVRCP_SET_BROWSED_PLAYER:
+               avrcp_set_browsed_player_dump(level + 1, frm, hdr, len);
+               break;
+       case AVRCP_GET_FOLDER_ITEMS:
+               avrcp_get_folder_items_dump(level + 1, frm, hdr, len);
+               break;
+       case AVRCP_CHANGE_PATH:
+               avrcp_change_path_dump(level + 1, frm, hdr, len);
+               break;
+       case AVRCP_GET_ITEM_ATTRIBUTES:
+               avrcp_get_item_attributes_dump(level + 1, frm, hdr, len);
+               break;
+       case AVRCP_SEARCH:
+               avrcp_search_dump(level + 1, frm, hdr, len);
+               break;
+       case AVRCP_GENERAL_REJECT:
+               avrcp_general_reject_dump(level + 1, frm, hdr, len);
+               break;
+       default:
+               raw_dump(level, frm);
+       }
+}
+
+static void avrcp_control_dump(int level, struct frame *frm)
+{
+       uint8_t ctype, address, subunit, opcode, company[3];
+       int i;
+
+       ctype = get_u8(frm);
+       address = get_u8(frm);
+       opcode = get_u8(frm);
+
+       printf("AV/C: %s: address 0x%02x opcode 0x%02x\n", ctype2str(ctype),
+                                                       address, opcode);
+
+       p_indent(level + 1, frm);
+
+       subunit = address >> 3;
+       printf("Subunit: %s\n", subunit2str(subunit));
+
+       p_indent(level + 1, frm);
+
+       printf("Opcode: %s\n", opcode2str(opcode));
+
+       /* Skip non-panel subunit packets */
+       if (subunit != AVC_SUBUNIT_PANEL) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       /* Not implemented should not contain any operand */
+       if (ctype == AVC_CTYPE_NOT_IMPLEMENTED) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (opcode) {
+       case AVC_OP_PASSTHROUGH:
+               avrcp_passthrough_dump(level + 1, frm);
+               break;
+       case AVC_OP_VENDORDEP:
+               p_indent(level + 1, frm);
+
+               printf("Company ID: 0x");
+               for (i = 0; i < 3; i++) {
+                       company[i] = get_u8(frm);
+                       printf("%02x", company[i]);
+               }
+               printf("\n");
+
+               avrcp_pdu_dump(level + 1, frm, ctype);
+               break;
+       default:
+               raw_dump(level, frm);
+       }
+}
+
+void avrcp_dump(int level, struct frame *frm, uint8_t hdr, uint16_t psm)
+{
+       p_indent(level, frm);
+
+       switch (psm) {
+               case 0x17:
+                       avrcp_control_dump(level, frm);
+                       break;
+               case 0x1B:
+                       avrcp_browsing_dump(level, frm, hdr);
+                       break;
+               default:
+                       raw_dump(level, frm);
+       }
+}
diff --git a/tools/parser/bnep.c b/tools/parser/bnep.c
new file mode 100644 (file)
index 0000000..d9e958d
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2002-2003  Takashi Sasai <sasai@sm.sony.co.jp>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/ethernet.h>
+
+#include "parser.h"
+
+/* BNEP Type */
+#define BNEP_GENERAL_ETHERNET                  0x00
+#define BNEP_CONTROL                           0x01
+#define BNEP_COMPRESSED_ETHERNET               0x02
+#define BNEP_COMPRESSED_ETHERNET_SOURCE_ONLY   0x03
+#define BNEP_COMPRESSED_ETHERNET_DEST_ONLY     0x04
+
+/* BNEP Control Packet Type */
+#define BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD    0x00
+#define BNEP_SETUP_CONNECTION_REQUEST_MSG      0x01
+#define BNEP_SETUP_CONNECTION_RESPONSE_MSG     0x02
+#define BNEP_FILTER_NET_TYPE_SET_MSG           0x03
+#define BNEP_FILTER_NET_TYPE_RESPONSE_MSG      0x04
+#define BNEP_FILTER_MULT_ADDR_SET_MSG          0x05
+#define BNEP_FILTER_MULT_ADDR_RESPONSE_MSG     0x06
+
+/* BNEP Extension Type */
+#define BNEP_EXTENSION_CONTROL                 0x00
+
+#ifndef ETHERTYPE_IPV6
+#define ETHERTYPE_IPV6 ETH_P_IPV6
+#endif
+
+static char *get_macaddr(struct frame *frm)
+{
+       static char str[20];
+       unsigned char *buf = frm->ptr;
+
+       sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+               buf[0], buf[1], buf[2], buf[3], buf[4], buf[5]);
+
+       frm->ptr += 6;
+       frm->len -= 6;
+
+       return str;
+}
+
+static void bnep_control(int level, struct frame *frm, int header_length)
+{
+       uint8_t uuid_size;
+       int i, length;
+       char *s;
+       uint32_t uuid = 0;
+       uint8_t type = get_u8(frm);
+
+       p_indent(++level, frm);
+       switch (type) {
+       case BNEP_CONTROL_COMMAND_NOT_UNDERSTOOD:
+               printf("Not Understood(0x%02x) type 0x%02x\n", type, get_u8(frm));
+               break;
+
+       case BNEP_SETUP_CONNECTION_REQUEST_MSG:
+               uuid_size = get_u8(frm);
+               printf("Setup Req(0x%02x) size 0x%02x ", type, uuid_size);
+               switch (uuid_size) {
+               case 2:
+                       uuid = get_u16(frm);
+                       printf("dst 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       uuid = get_u16(frm);
+                       printf(" src 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       printf("\n");
+                       break;
+               case 4:
+                       uuid = get_u32(frm);
+                       printf("dst 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       uuid = get_u32(frm);
+                       printf(" src 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       printf("\n");
+                       break;
+               case 16:
+                       uuid = get_u32(frm);
+                       printf("dst 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       frm->ptr += 12;
+                       frm->len -= 12;
+                       uuid = get_u32(frm);
+                       printf(" src 0x%x", uuid);
+                       if ((s = get_uuid_name(uuid)) != 0)
+                               printf("(%s)", s);
+                       printf("\n");
+                       frm->ptr += 12;
+                       frm->len -= 12;
+                       break;
+               default:
+                       frm->ptr += (uuid_size * 2);
+                       frm->len -= (uuid_size * 2);
+                       break;
+               }
+               break;
+
+       case BNEP_SETUP_CONNECTION_RESPONSE_MSG:
+               printf("Setup Rsp(0x%02x) res 0x%04x\n",
+                                               type, get_u16(frm));
+               break;
+
+       case BNEP_FILTER_NET_TYPE_SET_MSG:
+               length = get_u16(frm);
+               printf("Filter NetType Set(0x%02x) len 0x%04x\n",
+                                                       type, length);
+               for (i = 0; i < length / 4; i++) {
+                       p_indent(level + 1, frm);
+                       printf("0x%04x - ", get_u16(frm));
+                       printf("0x%04x\n", get_u16(frm));
+               }
+               break;
+
+       case BNEP_FILTER_NET_TYPE_RESPONSE_MSG:
+               printf("Filter NetType Rsp(0x%02x) res 0x%04x\n",
+                                                       type, get_u16(frm));
+               break;
+
+       case BNEP_FILTER_MULT_ADDR_SET_MSG:
+               length = get_u16(frm);
+               printf("Filter MultAddr Set(0x%02x) len 0x%04x\n",
+                                                       type, length);
+               for (i = 0; i < length / 12; i++) {
+                       p_indent(level + 1, frm);
+                       printf("%s - ", get_macaddr(frm));
+                       printf("%s\n", get_macaddr(frm));
+               }
+               break;
+
+       case BNEP_FILTER_MULT_ADDR_RESPONSE_MSG:
+               printf("Filter MultAddr Rsp(0x%02x) res 0x%04x\n",
+                                                       type, get_u16(frm));
+               break;
+
+       default:
+               printf("Unknown control type(0x%02x)\n", type);
+               raw_ndump(level + 1, frm, header_length - 1);
+               frm->ptr += header_length - 1;
+               frm->len -= header_length - 1;
+               return;
+       }
+}
+
+static void bnep_eval_extension(int level, struct frame *frm)
+{
+       uint8_t type = get_u8(frm);
+       uint8_t length = get_u8(frm);
+       int extension = type & 0x80;
+
+       p_indent(level, frm);
+
+       switch (type & 0x7f) {
+       case BNEP_EXTENSION_CONTROL:
+               printf("Ext Control(0x%02x|%s) len 0x%02x\n",
+                               type & 0x7f, extension ? "1" : "0", length);
+               bnep_control(level, frm, length);
+               break;
+
+       default:
+               printf("Ext Unknown(0x%02x|%s) len 0x%02x\n",
+                               type & 0x7f, extension ? "1" : "0", length);
+               raw_ndump(level + 1, frm, length);
+               frm->ptr += length;
+               frm->len -= length;
+       }
+
+       if (extension)
+               bnep_eval_extension(level, frm);
+}
+
+void bnep_dump(int level, struct frame *frm)
+{
+       uint8_t type = get_u8(frm);
+       uint16_t proto = 0x0000;
+       int extension = type & 0x80;
+
+       p_indent(level, frm);
+
+       switch (type & 0x7f) {
+       case BNEP_CONTROL:
+               printf("BNEP: Control(0x%02x|%s)\n",
+                                       type & 0x7f, extension ? "1" : "0");
+               bnep_control(level, frm, -1);
+               break;
+
+       case BNEP_COMPRESSED_ETHERNET:
+               printf("BNEP: Compressed(0x%02x|%s)\n",
+                                       type & 0x7f, extension ? "1" : "0");
+               p_indent(++level, frm);
+               proto = get_u16(frm);
+               printf("[proto 0x%04x]\n", proto);
+               break;
+
+       case BNEP_GENERAL_ETHERNET:
+               printf("BNEP: General ethernet(0x%02x|%s)\n",
+                                       type & 0x7f, extension ? "1" : "0");
+               p_indent(++level, frm);
+               printf("dst %s ", get_macaddr(frm));
+               printf("src %s ", get_macaddr(frm));
+               proto = get_u16(frm);
+               printf("[proto 0x%04x]\n", proto);
+               break;
+
+       case BNEP_COMPRESSED_ETHERNET_DEST_ONLY:
+               printf("BNEP: Compressed DestOnly(0x%02x|%s)\n",
+                                       type & 0x7f, extension ? "1" : "0");
+               p_indent(++level, frm);
+               printf("dst %s ", get_macaddr(frm));
+               proto = get_u16(frm);
+               printf("[proto 0x%04x]\n", proto);
+               break;
+
+       case BNEP_COMPRESSED_ETHERNET_SOURCE_ONLY:
+               printf("BNEP: Compressed SrcOnly(0x%02x|%s)\n",
+                                       type & 0x7f, extension ? "1" : "0");
+               p_indent(++level, frm);
+               printf("src %s ", get_macaddr(frm));
+               proto = get_u16(frm);
+               printf("[proto 0x%04x]\n", proto);
+               break;
+
+       default:
+               printf("(Unknown packet type)\n");
+               return;
+       }
+
+       /* Extension info */
+       if (extension)
+               bnep_eval_extension(++level, frm);
+
+       /* Control packet => No payload info */
+       if ((type & 0x7f) == BNEP_CONTROL)
+               return;
+
+       /* 802.1p header */
+       if (proto == 0x8100) {
+               p_indent(level, frm);
+               printf("802.1p Header: 0x%04x ", get_u16(frm));
+               proto = get_u16(frm);
+               printf("[proto 0x%04x]\n", proto);
+       }
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (proto) {
+       case ETHERTYPE_ARP:
+               p_indent(++level, frm);
+               printf("ARP: ");
+               arp_dump(level, frm);
+               break;
+
+       case ETHERTYPE_REVARP:
+               p_indent(++level, frm);
+               printf("RARP: ");
+               arp_dump(level, frm);
+               break;
+
+       case ETHERTYPE_IP:
+               p_indent(++level, frm);
+               printf("IP: ");
+               ip_dump(level, frm);
+               break;
+
+       case ETHERTYPE_IPV6:
+               p_indent(++level, frm);
+               printf("IPV6: ");
+               ip_dump(level, frm);
+               break;
+
+       default:
+               raw_dump(level, frm);
+               break;
+       }
+}
similarity index 58%
rename from tools/kword.c
rename to tools/parser/bpa.c
index 62e24fe..207397f 100644 (file)
@@ -2,7 +2,7 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2002-2010  Marcel Holtmann <marcel@holtmann.org>
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
  *
  *
  *  This program is free software; you can redistribute it and/or modify
 
 #include <stdio.h>
 #include <errno.h>
-#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
 
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-#include "kword.h"
 #include "parser.h"
 
-int lineno;
+#define BPA_U8(frm)  (get_u8(frm))
+#define BPA_U16(frm) (btohs(htons(get_u16(frm))))
+#define BPA_U32(frm) (btohl(htonl(get_u32(frm))))
 
-struct keyword_t rfcomm_keyword[] = {
-       { "bind",       K_BIND          },
-       { "device",     K_DEVICE        },
-       { "channel",    K_CHANNEL       },
-       { "comment",    K_COMMENT       },
+void bpa_dump(int level, struct frame *frm)
+{
+       uint8_t id, status, channel;
+       uint16_t num, len;
+       uint32_t time;
 
-       { "yes",        K_YES           },
-       { "no",         K_NO            },
-       { "enable",     K_YES           },
-       { "disable",    K_NO            },
+       id = get_u8(frm);
+       num = get_u16(frm);
+       len = BPA_U16(frm);
 
-       { NULL , 0 }
-};
+       status  = get_u8(frm);
+       time    = get_u32(frm);
+       channel = get_u8(frm);
 
-int rfcomm_find_keyword(struct keyword_t *keyword, char *string)
-{
-       while (keyword->string) {
-               if (!strcmp(string, keyword->string))
-                       return keyword->type;
-               keyword++;
-       }
+       p_indent(level, frm);
+       printf("BPA: id %d num %d len %u status 0x%02x time %d channel %d\n",
+               id, num, len, status, time, channel);
 
-       return -1;
+       raw_dump(level, frm);
 }
-
-struct rfcomm_opts rfcomm_opts[RFCOMM_MAX_DEV];
diff --git a/tools/parser/capi.c b/tools/parser/capi.c
new file mode 100644 (file)
index 0000000..97abc4c
--- /dev/null
@@ -0,0 +1,843 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+#define CAPI_U8(frm)  (get_u8(frm))
+#define CAPI_U16(frm) (btohs(htons(get_u16(frm))))
+#define CAPI_U32(frm) (btohl(htonl(get_u32(frm))))
+
+static char *cmd2str(uint8_t cmd)
+{
+       switch (cmd) {
+       case 0x01:
+               return "ALERT";
+       case 0x02:
+               return "CONNECT";
+       case 0x03:
+               return "CONNECT_ACTIVE";
+       case 0x04:
+               return "DISCONNECT";
+       case 0x05:
+               return "LISTEN";
+       case 0x08:
+               return "INFO";
+       case 0x20:
+               return "INTEROPERABILITY";
+       case 0x41:
+               return "SELECT_B_PROTOCOL";
+       case 0x80:
+               return "FACILITY";
+       case 0x82:
+               return "CONNECT_B3";
+       case 0x83:
+               return "CONNECT_B3_ACTIVE";
+       case 0x84:
+               return "DISCONNECT_B3";
+       case 0x86:
+               return "DATA_B3";
+       case 0x87:
+               return "RESET_B3";
+       case 0x88:
+               return "CONNECT_B3_T90_ACTIVE";
+       case 0xff:
+               return "MANUFACTURER";
+       default:
+               return "UNKNOWN";
+       }
+}
+
+static char *subcmd2str(uint8_t subcmd)
+{
+       switch (subcmd) {
+       case 0x80:
+               return "REQ";
+       case 0x81:
+               return "CONF";
+       case 0x82:
+               return "IND";
+       case 0x83:
+               return "RESP";
+       default:
+               return "UNKN";
+       }
+}
+
+static char *interopsel2str(uint16_t sel)
+{
+       switch (sel) {
+       case 0x0000:
+               return "USB Device Management";
+       case 0x0001:
+               return "Bluetooth Device Management";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *func2str(uint16_t func)
+{
+       switch (func) {
+       case 0:
+               return "Register";
+       case 1:
+               return "Release";
+       case 2:
+               return "Get_Profile";
+       case 3:
+               return "Get_Manufacturer";
+       case 4:
+               return "Get_Version";
+       case 5:
+               return "Get_Serial_Number";
+       case 6:
+               return "Manufacturer";
+       case 7:
+               return "Echo_Loopback";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *facilitysel2str(uint16_t sel)
+{
+       switch (sel) {
+       case 0x0000:
+               return "Handset";
+       case 0x0001:
+               return "DTMF";
+       case 0x0002:
+               return "V.42 bis";
+       case 0x0003:
+               return "Supplementary Services";
+       case 0x0004:
+               return "Power management wakeup";
+       case 0x0005:
+               return "Line Interconnect";
+       case 0x0006:
+               return "DTMF";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *info2str(uint16_t info)
+{
+       switch (info) {
+       case 0x0000:
+               return "No error";
+       case 0x0001:
+               return "NCPI not supported by current protocol, NCPI ignored";
+       case 0x0002:
+               return "Flags not supported by current protocol, flags ignored";
+       case 0x2001:
+               return "Message not supported in current state";
+       case 0x2002:
+               return "Incorrect Controller/PLCI/NCCI";
+       case 0x2003:
+               return "No PLCI available";
+       case 0x2004:
+               return "No NCCI available";
+       case 0x2005:
+               return "No Listen resources available";
+       case 0x2007:
+               return "Illegal message parameter coding";
+       case 0x2008:
+               return "No interconnection resources available";
+       case 0x3001:
+               return "B1 protocol not supported";
+       case 0x3002:
+               return "B2 protocol not supported";
+       case 0x3003:
+               return "B3 protocol not supported";
+       case 0x3004:
+               return "B1 protocol parameter not supported";
+       case 0x3005:
+               return "B2 protocol parameter not supported";
+       case 0x3006:
+               return "B3 protocol parameter not supported";
+       case 0x3007:
+               return "B protocol combination not supported";
+       case 0x3008:
+               return "NCPI not supported";
+       case 0x3009:
+               return "CIP Value unknown";
+       case 0x300A:
+               return "Flags not supported (reserved bits)";
+       case 0x300B:
+               return "Facility not supported";
+       case 0x300C:
+               return "Data length not supported by current protocol";
+       case 0x300D:
+               return "Reset procedure not supported by current protocol";
+       case 0x300F:
+               return "Unsupported interoperability";
+       case 0x3011:
+               return "Facility specific function not supported";
+       case 0x3301:
+               return "Protocol error, Layer 1";
+       case 0x3302:
+               return "Protocol error, Layer 2";
+       case 0x3303:
+               return "Protocol error, Layer 3";
+       case 0x3304:
+               return "Another application got that call";
+       case 0x3305:
+               return "Cleared by Call Control Supervision";
+       case 0x3400:
+               /* The cause value received from the network in a cause
+                * information element (Octet 4) is indicated in the field 00 */
+               return "Disconnect cause from the network in accordance with Q.850/ETS 300 102-1";
+       default:
+               return "Unknown";
+       }
+}
+
+static void profile(int level, struct frame *frm)
+{
+       uint16_t nctr, nchn;
+       uint32_t value;
+
+       nctr = CAPI_U16(frm);
+       nchn = CAPI_U16(frm);
+
+       if (nchn > 0) {
+               p_indent(level, frm);
+               printf("Controller: %d\n", nctr);
+               p_indent(level, frm);
+               printf("Number of B-channels: %d\n", nchn);
+
+               value = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("Global options: 0x%04x\n", value);
+               value = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("B1 protocol support: 0x%08x\n", value);
+               value = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("B2 protocol support: 0x%08x\n", value);
+               value = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("B3 protocol support: 0x%08x\n", value);
+
+               frm->ptr += 24;
+               frm->len -= 24;
+
+               p_indent(level, frm);
+               printf("Manufacturer-specific information:\n");
+               hex_dump(level, frm, 20);
+       } else {
+               p_indent(level, frm);
+               printf("Number of controllers: %d\n", nctr);
+       }
+}
+
+static void cmd_common(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint32_t val;
+       uint16_t info, ncci;
+       uint8_t ctr, plci;
+
+       val = CAPI_U32(frm);
+       ctr = val & 0xff;
+       plci = (val & 0xff00) >> 8;
+       ncci = (val & 0xffff0000) >> 16;
+
+       p_indent(level, frm);
+       printf("Controller: %d %s\n", ctr & 0x7f, ctr & 0x80 ? "Ext." : "Int.");
+
+       if (plci > 0) {
+               p_indent(level, frm);
+               printf("PLCI: 0x%02x\n", plci);
+       }
+
+       if (ncci > 0) {
+               p_indent(level, frm);
+               printf("NCCI: 0x%04x\n", ncci);
+       }
+
+       if (subcmd == 0x81) {
+               info = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Info: 0x%04x (%s)\n", info, info2str(info));
+       }
+}
+
+static void cmd_alert(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x80) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Additional info:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+}
+
+static void cmd_connect(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t cip;
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x81)
+               return;
+
+       cip = CAPI_U16(frm);
+       p_indent(level, frm);
+       printf("CIP value: 0x%04x\n", cip);
+
+       len = CAPI_U8(frm);
+       frm->ptr += len;
+       frm->len -= len;
+       len = CAPI_U8(frm);
+       frm->ptr += len;
+       frm->len -= len;
+       len = CAPI_U8(frm);
+       frm->ptr += len;
+       frm->len -= len;
+       len = CAPI_U8(frm);
+       frm->ptr += len;
+       frm->len -= len;
+
+       raw_dump(level, frm);
+}
+
+static void cmd_disconnect(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t reason;
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x80) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Additional info:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+
+       if (subcmd == 0x82) {
+               reason = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Reason: 0x%04x (%s)\n", reason, info2str(reason));
+       }
+}
+
+static void cmd_connect_active(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x82) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Connected number:\n");
+                       hex_dump(level, frm, len);
+               }
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Connected subaddress:\n");
+                       hex_dump(level, frm, len);
+               }
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("LLC:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+}
+
+static void cmd_listen(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint32_t mask;
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x80) {
+               mask = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("Info mask: 0x%08x\n", mask);
+
+               mask = CAPI_U32(frm);
+               p_indent(level, frm);
+               printf("CIP mask:  0x%08x", mask);
+
+               mask = CAPI_U32(frm);
+               if (mask > 0)
+                       printf(" 0x%08x\n", mask);
+               else
+                       printf("\n");
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Calling party number:\n");
+                       hex_dump(level, frm, len);
+               }
+               frm->ptr += len;
+               frm->len -= len;
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Calling party subaddress:\n");
+                       hex_dump(level, frm, len);
+               }
+               frm->ptr += len;
+               frm->len -= len;
+       }
+}
+
+static void cmd_info(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint8_t len;
+       uint16_t info;
+
+       cmd_common(level, subcmd, frm);
+
+       switch (subcmd) {
+       case 0x80:
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Called party number:\n");
+                       hex_dump(level, frm, len);
+               }
+               frm->ptr += len;
+               frm->len -= len;
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Additional info:\n");
+                       hex_dump(level, frm, len);
+               }
+               break;
+
+       case 0x82:
+               info = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Info number: %d\n", info);
+
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("Info element:\n");
+                       hex_dump(level, frm, len);
+               }
+               break;
+       }
+}
+
+static void cmd_interoperability(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t sel, func, info;
+       uint16_t nconn, datablkcnt, datablklen;
+       uint32_t ctr, value, major, minor;
+
+       info = (subcmd == 0x81) ? CAPI_U16(frm) : 0;
+       sel = CAPI_U16(frm);
+       CAPI_U8(frm);
+       if (subcmd != 0x83) {
+               func = CAPI_U16(frm);
+               CAPI_U8(frm);
+       } else
+               func = 0;
+
+       p_indent(level, frm);
+       printf("Selector: 0x%04x (%s)\n", sel, interopsel2str(sel));
+
+       switch (sel) {
+       case 0x0001:
+               p_indent(level, frm);
+               printf("Function: %d (%s)\n", func, func2str(func));
+
+               switch (subcmd) {
+               case 0x80:
+                       switch (func) {
+                       case 0:
+                               nconn = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("maxLogicalConnections: %d\n", nconn);
+                               datablkcnt = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("maxBDataBlocks: %d\n", datablkcnt);
+                               datablklen = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("maxBDataLen: %d\n", datablklen);
+                               break;
+                       case 2:
+                       case 3:
+                       case 4:
+                       case 5:
+                               ctr = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Controller: %d\n", ctr);
+                               break;
+                       default:
+                               raw_dump(level + 1, frm);
+                               break;
+                       }
+                       break;
+
+               case 0x81:
+                       switch (func) {
+                       case 0:
+                       case 1:
+                               info = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("Info: 0x%04x (%s)\n", info, info2str(info));
+                               break;
+                       case 2:
+                               info = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("Info: 0x%04x (%s)\n", info, info2str(info));
+                               CAPI_U8(frm);
+                               profile(level + 1, frm);
+                               break;
+                       case 3:
+                               info = CAPI_U16(frm);
+                               p_indent(level + 1, frm);
+                               printf("Info: 0x%04x (%s)\n", info, info2str(info));
+                               ctr = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Controller: %d\n", ctr);
+                               CAPI_U8(frm);
+                               p_indent(level + 1, frm);
+                               printf("Identification: \"%s\"\n", (char *) frm->ptr);
+                               break;
+                       case 4:
+                               value = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Return value: 0x%04x\n", value);
+                               ctr = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Controller: %d\n", ctr);
+                               p_indent(level + 1, frm);
+                               major = CAPI_U32(frm);
+                               minor = CAPI_U32(frm);
+                               printf("CAPI: %d.%d\n", major, minor);
+                               major = CAPI_U32(frm);
+                               minor = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Manufacture: %u.%01x%01x-%02u (%d.%d)\n",
+                                       (major & 0xf0) >> 4, (major & 0x0f) << 4,
+                                       (minor & 0xf0) >> 4, minor & 0x0f,
+                                       major, minor);
+                               break;
+                       case 5:
+                               value = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Return value: 0x%04x\n", value);
+                               ctr = CAPI_U32(frm);
+                               p_indent(level + 1, frm);
+                               printf("Controller: %d\n", ctr);
+                               CAPI_U8(frm);
+                               p_indent(level + 1, frm);
+                               printf("Serial number: %.7s\n", (char *) frm->ptr);
+                               break;
+                       default:
+                               raw_dump(level + 1, frm);
+                               break;
+                       }
+                       break;
+
+               default:
+                       raw_dump(level, frm);
+                       break;
+               }
+               break;
+
+       default:
+               p_indent(level, frm);
+               printf("Function: %d\n", func);
+               if (subcmd == 0x81) {
+                       p_indent(level, frm);
+                       printf("Info: 0x%04x (%s)\n", info, info2str(info));
+               }
+               raw_dump(level + 1, frm);
+               break;
+       }
+}
+
+static void cmd_facility(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t sel;
+
+       cmd_common(level, subcmd, frm);
+
+       sel = CAPI_U16(frm);
+       CAPI_U8(frm);
+
+       p_indent(level, frm);
+       printf("Selector: 0x%04x (%s)\n", sel, facilitysel2str(sel));
+
+       raw_dump(level, frm);
+}
+
+static void cmd_connect_b3(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t reject;
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x81)
+               return;
+
+       if (subcmd == 0x83) {
+               reject = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Reject: 0x%04x (%s)\n", reject, info2str(reject));
+       }
+
+       len = CAPI_U8(frm);
+       if (len > 0) {
+               p_indent(level, frm);
+               printf("NCPI:\n");
+               hex_dump(level, frm, len);
+       }
+}
+
+static void cmd_connect_b3_active(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x82) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("NCPI:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+}
+
+static void cmd_disconnect_b3(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint16_t reason;
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x82) {
+               reason = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Reason: 0x%04x (%s)\n", reason, info2str(reason));
+       }
+
+       if (subcmd == 0x80 || subcmd == 0x82) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("NCPI:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+}
+
+static void cmd_data_b3(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint32_t data;
+       uint16_t length, handle, flags, info;
+
+       cmd_common(level, 0x00, frm);
+
+       if (subcmd == 0x81 || subcmd == 0x83) {
+               handle = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Data handle: 0x%04x\n", handle);
+
+               if (subcmd == 0x81) {
+                       info = CAPI_U16(frm);
+                       p_indent(level, frm);
+                       printf("Info: 0x%04x (%s)\n", info, info2str(info));
+               }
+       } else {
+               data = CAPI_U32(frm);
+
+               length = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Data length: 0x%04x (%d bytes)\n", length, length);
+
+               handle = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Data handle: 0x%04x\n", handle);
+
+               flags = CAPI_U16(frm);
+               p_indent(level, frm);
+               printf("Flags: 0x%04x\n", flags);
+
+               if (data == 0)
+                       (void) get_u64(frm);
+
+               raw_dump(level, frm);
+       }
+}
+
+static void cmd_reset_b3(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint8_t len;
+
+       cmd_common(level, subcmd, frm);
+
+       if (subcmd == 0x80 || subcmd == 0x82) {
+               len = CAPI_U8(frm);
+               if (len > 0) {
+                       p_indent(level, frm);
+                       printf("NCPI:\n");
+                       hex_dump(level, frm, len);
+               }
+       }
+}
+
+static void cmd_manufacturer(int level, uint8_t subcmd, struct frame *frm)
+{
+       uint32_t ctr, class, func;
+       uint16_t len;
+       unsigned char *id;
+
+       ctr = CAPI_U32(frm);
+       p_indent(level, frm);
+       printf("Controller: %d\n", ctr);
+
+       id = (unsigned char *) frm->ptr;
+       p_indent(level, frm);
+       if (isprint(id[0]) && isprint(id[1]) && isprint(id[2]) && isprint(id[3]))
+               printf("Manufacturer: %.4s", id);
+       else
+               printf("Manufacturer: 0x%02x 0x%02x 0x%02x 0x%02x",
+                                               id[0], id[1], id[2], id[3]);
+       frm->ptr += 4;
+       frm->len -= 4;
+
+       if (!strncmp((char *) id, "AVM!", 4)) {
+               class = CAPI_U32(frm);
+               func = CAPI_U32(frm);
+               len = CAPI_U8(frm);
+               if (len == 0xff)
+                       len = CAPI_U16(frm);
+
+               printf(" [class %d func %d len %d]\n", class, func, len);
+       } else
+               printf("\n");
+
+       raw_dump(level, frm);
+}
+
+void capi_dump(int level, struct frame *frm)
+{
+       uint16_t len, appl, msgnum;
+       uint8_t cmd, subcmd;
+
+       len = CAPI_U16(frm) - 8;
+       appl = CAPI_U16(frm);
+       cmd = CAPI_U8(frm);
+       subcmd = CAPI_U8(frm);
+       msgnum = CAPI_U16(frm);
+
+       p_indent(level, frm);
+
+       printf("CAPI_%s_%s: appl %d msgnum %d len %d\n",
+                       cmd2str(cmd), subcmd2str(subcmd), appl, msgnum, len);
+
+       switch (cmd) {
+       case 0x01:
+               cmd_alert(level + 1, subcmd, frm);
+               break;
+       case 0x02:
+               cmd_connect(level + 1, subcmd, frm);
+               break;
+       case 0x03:
+               cmd_connect_active(level + 1, subcmd, frm);
+               break;
+       case 0x04:
+               cmd_disconnect(level + 1, subcmd, frm);
+               break;
+       case 0x05:
+               cmd_listen(level + 1, subcmd, frm);
+               break;
+       case 0x08:
+               cmd_info(level + 1, subcmd, frm);
+               break;
+       case 0x20:
+               cmd_interoperability(level + 1, subcmd, frm);
+               break;
+       case 0x80:
+               cmd_facility(level + 1, subcmd, frm);
+               break;
+       case 0x82:
+               cmd_connect_b3(level + 1, subcmd, frm);
+               break;
+       case 0x83:
+       case 0x88:
+               cmd_connect_b3_active(level + 1, subcmd, frm);
+               break;
+       case 0x84:
+               cmd_disconnect_b3(level + 1, subcmd, frm);
+               break;
+       case 0x86:
+               cmd_data_b3(level + 1, subcmd, frm);
+               break;
+       case 0x87:
+               cmd_reset_b3(level + 1, subcmd, frm);
+               break;
+       case 0xff:
+               cmd_manufacturer(level + 1, subcmd, frm);
+               break;
+       default:
+               raw_dump(level, frm);
+               frm->ptr += len;
+               frm->len -= len;
+               break;
+       }
+}
diff --git a/tools/parser/cmtp.c b/tools/parser/cmtp.c
new file mode 100644 (file)
index 0000000..ac5cf84
--- /dev/null
@@ -0,0 +1,208 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2002-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+#define TABLE_SIZE 10
+
+static struct {
+       uint16_t handle;
+       uint16_t cid;
+       struct frame msg[16];
+} table[TABLE_SIZE];
+
+static void add_segment(uint8_t bid, struct frame *frm, int len)
+{
+       uint16_t handle = frm->handle, cid = frm->cid;
+       struct frame *msg;
+       void *data;
+       int i, pos = -1;
+
+       if (bid > 15)
+               return;
+
+       for (i = 0; i < TABLE_SIZE; i++) {
+               if (table[i].handle == handle && table[i].cid == cid) {
+                       pos = i;
+                       break;
+               }
+
+               if (pos < 0 && !table[i].handle && !table[i].cid)
+                       pos = i;
+       }
+
+       if (pos < 0)
+               return;
+
+       table[pos].handle = handle;
+       table[pos].cid    = cid;
+       msg = &table[pos].msg[bid];
+
+       data = malloc(msg->data_len + len);
+       if (!data)
+               return;
+
+       if (msg->data_len > 0)
+               memcpy(data, msg->data, msg->data_len);
+
+       memcpy(data + msg->data_len, frm->ptr, len);
+       free(msg->data);
+       msg->data = data;
+       msg->data_len += len;
+       msg->ptr = msg->data;
+       msg->len = msg->data_len;
+       msg->in  = frm->in;
+       msg->ts  = frm->ts;
+       msg->handle = handle;
+       msg->cid    = cid;
+}
+
+static void free_segment(uint8_t bid, struct frame *frm)
+{
+       uint16_t handle = frm->handle, cid = frm->cid;
+       struct frame *msg;
+       int i, len = 0, pos = -1;
+
+       if (bid > 15)
+               return;
+
+       for (i = 0; i < TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid) {
+                       pos = i;
+                       break;
+               }
+
+       if (pos < 0)
+               return;
+
+       msg = &table[pos].msg[bid];
+
+       if (msg->data)
+               free(msg->data);
+
+       msg->data = NULL;
+       msg->data_len = 0;
+
+       for (i = 0; i < 16; i++)
+               len += table[pos].msg[i].data_len;
+
+       if (!len) {
+               table[pos].handle = 0;
+               table[pos].cid = 0;
+       }
+}
+
+static struct frame *get_segment(uint8_t bid, struct frame *frm)
+{
+       uint16_t handle = frm->handle, cid = frm->cid;
+       int i;
+
+       if (bid > 15)
+               return NULL;
+
+       for (i = 0; i < TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       return &table[i].msg[bid];
+
+       return NULL;
+}
+
+static char *bst2str(uint8_t bst)
+{
+       switch (bst) {
+       case 0x00:
+               return "complete CAPI Message";
+       case 0x01:
+               return "segmented CAPI Message";
+       case 0x02:
+               return "error";
+       case 0x03:
+               return "reserved";
+       default:
+               return "unknown";
+       }
+}
+
+void cmtp_dump(int level, struct frame *frm)
+{
+       struct frame *msg;
+       uint8_t hdr, bid;
+       uint16_t len;
+
+       while (frm->len > 0) {
+
+               hdr = get_u8(frm);
+               bid = (hdr & 0x3c) >> 2;
+
+               switch ((hdr & 0xc0) >> 6) {
+               case 0x01:
+                       len = get_u8(frm);
+                       break;
+               case 0x02:
+                       len = htons(get_u16(frm));
+                       break;
+               default:
+                       len = 0;
+                       break;
+               }
+
+               p_indent(level, frm);
+
+               printf("CMTP: %s: id %d len %d\n", bst2str(hdr & 0x03), bid, len);
+
+               switch (hdr & 0x03) {
+               case 0x00:
+                       add_segment(bid, frm, len);
+                       msg = get_segment(bid, frm);
+                       if (!msg)
+                               break;
+
+                       if (!p_filter(FILT_CAPI))
+                               capi_dump(level + 1, msg);
+                       else
+                               raw_dump(level, msg);
+
+                       free_segment(bid, frm);
+                       break;
+               case 0x01:
+                       add_segment(bid, frm, len);
+                       break;
+               default:
+                       free_segment(bid, frm);
+                       break;
+               }
+
+               frm->ptr += len;
+               frm->len -= len;
+       }
+}
diff --git a/tools/parser/csr.c b/tools/parser/csr.c
new file mode 100644 (file)
index 0000000..1a63ae0
--- /dev/null
@@ -0,0 +1,625 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+#define CSR_U8(frm)  (get_u8(frm))
+#define CSR_U16(frm) (btohs(htons(get_u16(frm))))
+#define CSR_U32(frm) ((CSR_U16(frm) << 16) + CSR_U16(frm))
+#define CSR_S16(frm) (btohs(htons(get_u16(frm))))
+
+static char *type2str(uint16_t type)
+{
+       switch (type) {
+       case 0x0000:
+               return "Get req";
+       case 0x0001:
+               return "Get rsp";
+       case 0x0002:
+               return "Set req";
+       default:
+               return "Reserved";
+       }
+}
+
+static inline void valueless_dump(int level, char *str, struct frame *frm)
+{
+       p_indent(level, frm);
+       printf("%s\n", str);
+}
+
+static inline void complex_dump(int level, char *str, struct frame *frm)
+{
+       p_indent(level, frm);
+       printf("%s\n", str);
+
+       raw_dump(level, frm);
+}
+
+static inline void bool_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t value;
+
+       value = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: value %s (%d)\n", str, value ? "TRUE" : "FALSE", value);
+}
+
+static inline void int8_dump(int level, char *str, struct frame *frm)
+{
+       int16_t value;
+
+       value = CSR_S16(frm);
+
+       p_indent(level, frm);
+       printf("%s: value %d (0x%2.2x)\n", str, value, value);
+}
+
+static inline void int16_dump(int level, char *str, struct frame *frm)
+{
+       int16_t value;
+
+       value = CSR_S16(frm);
+
+       p_indent(level, frm);
+       printf("%s: value %d (0x%2.2x)\n", str, value, value);
+}
+
+static inline void uint16_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t value;
+
+       value = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: value %d (0x%4.4x)\n", str, value, value);
+}
+
+static inline void uint32_dump(int level, char *str, struct frame *frm)
+{
+       uint32_t value;
+
+       value = CSR_U32(frm);
+
+       p_indent(level, frm);
+       printf("%s: value %d (0x%4.4x)\n", str, value, value);
+}
+
+static inline void bdaddr_dump(int level, char *str, struct frame *frm)
+{
+       char addr[18];
+
+       p_ba2str(frm->ptr, addr);
+
+       p_indent(level, frm);
+       printf("%s: bdaddr %s\n", str, addr);
+}
+
+static inline void features_dump(int level, char *str, struct frame *frm)
+{
+       unsigned char features[8];
+       int i;
+
+       memcpy(features, frm->ptr, 8);
+
+       p_indent(level, frm);
+       printf("%s: features", str);
+       for (i = 0; i < 8; i++)
+               printf(" 0x%02x", features[i]);
+       printf("\n");
+}
+
+static inline void commands_dump(int level, char *str, struct frame *frm)
+{
+       unsigned char commands[64];
+       unsigned int i;
+
+       memcpy(commands, frm->ptr, frm->len);
+
+       p_indent(level, frm);
+       printf("%s: commands", str);
+       for (i = 0; i < frm->len; i++)
+               printf(" 0x%02x", commands[i]);
+       printf("\n");
+}
+
+static inline void handle_length_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t handle, length;
+
+       handle = CSR_U16(frm);
+       length = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: handle %d length %d\n", str, handle, length);
+}
+
+static inline void handle_clock_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t handle;
+       uint32_t clock;
+
+       handle = CSR_U16(frm);
+       clock  = CSR_U32(frm);
+
+       p_indent(level, frm);
+       printf("%s: handle %d clock 0x%4.4x\n", str, handle, clock);
+}
+
+static inline void radiotest_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t testid;
+
+       testid = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: test id %d\n", str, testid);
+
+       raw_dump(level, frm);
+}
+
+static inline void psmemtype_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t store, type;
+
+       store = CSR_U16(frm);
+       type  = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: store 0x%4.4x type %d\n", str, store, type);
+}
+
+static inline void psnext_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t key, stores, next;
+
+       key    = CSR_U16(frm);
+       stores = CSR_U16(frm);
+       next   = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: key 0x%4.4x stores 0x%4.4x next 0x%4.4x\n", str, key, stores, next);
+}
+
+static inline void pssize_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t key, length;
+
+       key    = CSR_U16(frm);
+       length = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: key 0x%4.4x %s 0x%4.4x\n", str, key,
+                               frm->in ? "len" : "stores", length);
+}
+
+static inline void psstores_dump(int level, char *str, struct frame *frm)
+{
+       uint16_t key, stores;
+
+       key    = CSR_U16(frm);
+       stores = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("%s: key 0x%4.4x stores 0x%4.4x\n", str, key, stores);
+}
+
+static inline void pskey_dump(int level, struct frame *frm)
+{
+       uint16_t key, length, stores;
+
+       key    = CSR_U16(frm);
+       length = CSR_U16(frm);
+       stores = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("PSKEY: key 0x%4.4x len %d stores 0x%4.4x\n", key, length, stores);
+
+       switch (key) {
+       case 0x0001:
+               bdaddr_dump(level + 1, "BDADDR", frm);
+               break;
+       case 0x0002:
+               uint16_dump(level + 1, "COUNTRYCODE", frm);
+               break;
+       case 0x0003:
+               uint32_dump(level + 1, "CLASSOFDEVICE", frm);
+               break;
+       case 0x0004:
+               uint16_dump(level + 1, "DEVICE_DRIFT", frm);
+               break;
+       case 0x0005:
+               uint16_dump(level + 1, "DEVICE_JITTER", frm);
+               break;
+       case 0x000d:
+               uint16_dump(level + 1, "MAX_ACLS", frm);
+               break;
+       case 0x000e:
+               uint16_dump(level + 1, "MAX_SCOS", frm);
+               break;
+       case 0x000f:
+               uint16_dump(level + 1, "MAX_REMOTE_MASTERS", frm);
+               break;
+       case 0x00da:
+               uint16_dump(level + 1, "ENC_KEY_LMIN", frm);
+               break;
+       case 0x00db:
+               uint16_dump(level + 1, "ENC_KEY_LMAX", frm);
+               break;
+       case 0x00ef:
+               features_dump(level + 1, "LOCAL_SUPPORTED_FEATURES", frm);
+               break;
+       case 0x0106:
+               commands_dump(level + 1, "LOCAL_SUPPORTED_COMMANDS", frm);
+               break;
+       case 0x010d:
+               uint16_dump(level + 1, "HCI_LMP_LOCAL_VERSION", frm);
+               break;
+       case 0x010e:
+               uint16_dump(level + 1, "LMP_REMOTE_VERSION", frm);
+               break;
+       case 0x01a5:
+               bool_dump(level + 1, "HOSTIO_USE_HCI_EXTN", frm);
+               break;
+       case 0x01ab:
+               bool_dump(level + 1, "HOSTIO_MAP_SCO_PCM", frm);
+               break;
+       case 0x01be:
+               uint16_dump(level + 1, "UART_BAUDRATE", frm);
+               break;
+       case 0x01f6:
+               uint16_dump(level + 1, "ANA_FTRIM", frm);
+               break;
+       case 0x01f9:
+               uint16_dump(level + 1, "HOST_INTERFACE", frm);
+               break;
+       case 0x01fe:
+               uint16_dump(level + 1, "ANA_FREQ", frm);
+               break;
+       case 0x02be:
+               uint16_dump(level + 1, "USB_VENDOR_ID", frm);
+               break;
+       case 0x02bf:
+               uint16_dump(level + 1, "USB_PRODUCT_ID", frm);
+               break;
+       case 0x02cb:
+               uint16_dump(level + 1, "USB_DFU_PRODUCT_ID", frm);
+               break;
+       case 0x03cd:
+               int16_dump(level + 1, "INITIAL_BOOTMODE", frm);
+               break;
+       default:
+               raw_dump(level + 1, frm);
+               break;
+       }
+}
+
+static inline void bccmd_dump(int level, struct frame *frm)
+{
+       uint16_t type, length, seqno, varid, status;
+
+       type   = CSR_U16(frm);
+       length = CSR_U16(frm);
+       seqno  = CSR_U16(frm);
+       varid  = CSR_U16(frm);
+       status = CSR_U16(frm);
+
+       p_indent(level, frm);
+       printf("BCCMD: %s: len %d seqno %d varid 0x%4.4x status %d\n",
+                       type2str(type), length, seqno, varid, status);
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level + 1, frm);
+               return;
+       }
+
+       switch (varid) {
+       case 0x000b:
+               valueless_dump(level + 1, "PS_CLR_ALL", frm);
+               break;
+       case 0x000c:
+               valueless_dump(level + 1, "PS_FACTORY_SET", frm);
+               break;
+       case 0x082d:
+               uint16_dump(level + 1, "PS_CLR_ALL_STORES", frm);
+               break;
+       case 0x2801:
+               uint16_dump(level + 1, "BC01_STATUS", frm);
+               break;
+       case 0x2819:
+               uint16_dump(level + 1, "BUILDID", frm);
+               break;
+       case 0x281a:
+               uint16_dump(level + 1, "CHIPVER", frm);
+               break;
+       case 0x281b:
+               uint16_dump(level + 1, "CHIPREV", frm);
+               break;
+       case 0x2825:
+               uint16_dump(level + 1, "INTERFACE_VERSION", frm);
+               break;
+       case 0x282a:
+               uint16_dump(level + 1, "RAND", frm);
+               break;
+       case 0x282c:
+               uint16_dump(level + 1, "MAX_CRYPT_KEY_LENGTH", frm);
+               break;
+       case 0x2833:
+               uint16_dump(level + 1, "E2_APP_SIZE", frm);
+               break;
+       case 0x2836:
+               uint16_dump(level + 1, "CHIPANAREV", frm);
+               break;
+       case 0x2838:
+               uint16_dump(level + 1, "BUILDID_LOADER", frm);
+               break;
+       case 0x2c00:
+               uint32_dump(level + 1, "BT_CLOCK", frm);
+               break;
+       case 0x3005:
+               psnext_dump(level + 1, "PS_NEXT", frm);
+               break;
+       case 0x3006:
+               pssize_dump(level + 1, "PS_SIZE", frm);
+               break;
+       case 0x3008:
+               handle_length_dump(level + 1, "CRYPT_KEY_LENGTH", frm);
+               break;
+       case 0x3009:
+               handle_clock_dump(level + 1, "PICONET_INSTANCE", frm);
+               break;
+       case 0x300a:
+               complex_dump(level + 1, "GET_CLR_EVT", frm);
+               break;
+       case 0x300b:
+               complex_dump(level + 1, "GET_NEXT_BUILDDEF", frm);
+               break;
+       case 0x300e:
+               complex_dump(level + 1, "E2_DEVICE", frm);
+               break;
+       case 0x300f:
+               complex_dump(level + 1, "E2_APP_DATA", frm);
+               break;
+       case 0x3012:
+               psmemtype_dump(level + 1, "PS_MEMORY_TYPE", frm);
+               break;
+       case 0x301c:
+               complex_dump(level + 1, "READ_BUILD_NAME", frm);
+               break;
+       case 0x4001:
+               valueless_dump(level + 1, "COLD_RESET", frm);
+               break;
+       case 0x4002:
+               valueless_dump(level + 1, "WARM_RESET", frm);
+               break;
+       case 0x4003:
+               valueless_dump(level + 1, "COLD_HALT", frm);
+               break;
+       case 0x4004:
+               valueless_dump(level + 1, "WARM_HALT", frm);
+               break;
+       case 0x4005:
+               valueless_dump(level + 1, "INIT_BT_STACK", frm);
+               break;
+       case 0x4006:
+               valueless_dump(level + 1, "ACTIVATE_BT_STACK", frm);
+               break;
+       case 0x4007:
+               valueless_dump(level + 1, "ENABLE_TX", frm);
+               break;
+       case 0x4008:
+               valueless_dump(level + 1, "DISABLE_TX", frm);
+               break;
+       case 0x4009:
+               valueless_dump(level + 1, "RECAL", frm);
+               break;
+       case 0x400d:
+               valueless_dump(level + 1, "PS_FACTORY_RESTORE", frm);
+               break;
+       case 0x400e:
+               valueless_dump(level + 1, "PS_FACTORY_RESTORE_ALL", frm);
+               break;
+       case 0x400f:
+               valueless_dump(level + 1, "PS_DEFRAG_RESET", frm);
+               break;
+       case 0x4011:
+               valueless_dump(level + 1, "HOPPING_ON", frm);
+               break;
+       case 0x4012:
+               valueless_dump(level + 1, "CANCEL_PAGE", frm);
+               break;
+       case 0x4818:
+               uint16_dump(level + 1, "PS_CLR", frm);
+               break;
+       case 0x481c:
+               uint16_dump(level + 1, "MAP_SCO_PCM", frm);
+               break;
+       case 0x482e:
+               uint16_dump(level + 1, "SINGLE_CHAN", frm);
+               break;
+       case 0x5004:
+               radiotest_dump(level + 1, "RADIOTEST", frm);
+               break;
+       case 0x500c:
+               psstores_dump(level + 1, "PS_CLR_STORES", frm);
+               break;
+       case 0x6000:
+               valueless_dump(level + 1, "NO_VARIABLE", frm);
+               break;
+       case 0x6802:
+               uint16_dump(level + 1, "CONFIG_UART", frm);
+               break;
+       case 0x6805:
+               uint16_dump(level + 1, "PANIC_ARG", frm);
+               break;
+       case 0x6806:
+               uint16_dump(level + 1, "FAULT_ARG", frm);
+               break;
+       case 0x6827:
+               int8_dump(level + 1, "MAX_TX_POWER", frm);
+               break;
+       case 0x682b:
+               int8_dump(level + 1, "DEFAULT_TX_POWER", frm);
+               break;
+       case 0x7003:
+               pskey_dump(level + 1, frm);
+               break;
+       default:
+               raw_dump(level + 1, frm);
+               break;
+       }
+}
+
+static char *cid2str(uint8_t cid)
+{
+       switch (cid & 0x3f) {
+       case 0:
+               return "BCSP Internal";
+       case 1:
+               return "BCSP Link";
+       case 2:
+               return "BCCMD";
+       case 3:
+               return "HQ";
+       case 4:
+               return "Device Mgt";
+       case 5:
+               return "HCI Cmd/Evt";
+       case 6:
+               return "HCI ACL";
+       case 7:
+               return "HCI SCO";
+       case 8:
+               return "L2CAP";
+       case 9:
+               return "RFCOMM";
+       case 10:
+               return "SDP";
+       case 11:
+               return "Debug";
+       case 12:
+               return "DFU";
+       case 13:
+               return "VM";
+       case 14:
+               return "Unused";
+       case 15:
+               return "Reserved";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *frag2str(uint8_t frag)
+{
+       switch (frag & 0xc0) {
+       case 0x00:
+               return " middle fragment";
+       case 0x40:
+               return " first fragment";
+       case 0x80:
+               return " last fragment";
+       default:
+               return "";
+       }
+}
+
+void csr_dump(int level, struct frame *frm)
+{
+       uint8_t desc, cid, type;
+       uint16_t handle, master, addr;
+
+       desc = CSR_U8(frm);
+
+       cid = desc & 0x3f;
+
+       switch (cid) {
+       case 2:
+               bccmd_dump(level, frm);
+               break;
+
+       case 20:
+               type = CSR_U8(frm);
+
+               if (!p_filter(FILT_LMP)) {
+                       switch (type) {
+                       case 0x0f:
+                               frm->handle =  ((uint8_t *) frm->ptr)[17];
+                               frm->master = 0;
+                               frm->len--;
+                               lmp_dump(level, frm);
+                               return;
+                       case 0x10:
+                               frm->handle = ((uint8_t *) frm->ptr)[17];
+                               frm->master = 1;
+                               frm->len--;
+                               lmp_dump(level, frm);
+                               return;
+                       case 0x12:
+                               handle = CSR_U16(frm);
+                               master = CSR_U16(frm);
+                               addr = CSR_U16(frm);
+                               p_indent(level, frm);
+                               printf("FHS: handle %d addr %d (%s)\n", handle,
+                                       addr, master ? "master" : "slave");
+                               if (!master) {
+                                       char addr[18];
+                                       p_ba2str((bdaddr_t *) frm->ptr, addr);
+                                       p_indent(level + 1, frm);
+                                       printf("bdaddr %s class "
+                                               "0x%2.2x%2.2x%2.2x\n", addr,
+                                               ((uint8_t *) frm->ptr)[8],
+                                               ((uint8_t *) frm->ptr)[7],
+                                               ((uint8_t *) frm->ptr)[6]);
+                               }
+                               return;
+                       case 0x7b:
+                               p_indent(level, frm);
+                               printf("LMP(r): duplicate (same SEQN)\n");
+                               return;
+                       }
+               }
+
+               p_indent(level, frm);
+               printf("CSR: Debug (type 0x%2.2x)\n", type);
+               raw_dump(level, frm);
+               break;
+
+       default:
+               p_indent(level, frm);
+               printf("CSR: %s (channel %d)%s\n", cid2str(cid), cid, frag2str(desc));
+               raw_dump(level, frm);
+               break;
+       }
+}
similarity index 62%
rename from deviceinfo/main.c
rename to tools/parser/ericsson.c
index 82ecc82..a401959 100644 (file)
@@ -2,7 +2,8 @@
  *
  *  BlueZ - Bluetooth protocol stack for Linux
  *
- *  Copyright (C) 2012 Texas Instruments, Inc.
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
  *
  *  This program is free software; you can redistribute it and/or modify
  *  it under the terms of the GNU General Public License as published by
 #include <config.h>
 #endif
 
-#include <glib.h>
+#include <stdio.h>
 #include <errno.h>
-#include <stdint.h>
 
-#include "plugin.h"
-#include "manager.h"
-#include "hcid.h"
-#include "log.h"
+#include "parser.h"
 
-static int deviceinfo_init(void)
+void ericsson_dump(int level, struct frame *frm)
 {
-       if (!main_opts.gatt_enabled) {
-               error("DIS cannot start: GATT is disabled");
-               return -ENOTSUP;
+       uint8_t event = get_u8(frm);
+       uint8_t *buf = (uint8_t *) frm->ptr;
+
+       if (event != 0x10) {
+               p_indent(level, frm);
+               printf("Ericsson: event 0x%2.2x\n", event);
+               raw_dump(level, frm);
        }
 
-       return deviceinfo_manager_init();
-}
+       frm->master = !(buf[0] & 0x01);
+       frm->handle = buf[1] | (buf[2] << 8);
 
-static void deviceinfo_exit(void)
-{
-       deviceinfo_manager_exit();
-}
+       buf[5] = (buf[5] << 1) | (buf[3] & 0x01);
+
+       frm->ptr += 5;
+       frm->len -= 5;
 
-BLUETOOTH_PLUGIN_DEFINE(deviceinfo, VERSION, BLUETOOTH_PLUGIN_PRIORITY_DEFAULT,
-                                       deviceinfo_init, deviceinfo_exit)
+       lmp_dump(level, frm);
+}
diff --git a/tools/parser/hci.c b/tools/parser/hci.c
new file mode 100644 (file)
index 0000000..17b776d
--- /dev/null
@@ -0,0 +1,4127 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+#include "lib/amp.h"
+
+static uint16_t manufacturer = DEFAULT_COMPID;
+
+static inline uint16_t get_manufacturer(void)
+{
+       return (manufacturer == DEFAULT_COMPID ? parser.defcompid : manufacturer);
+}
+
+#define EVENT_NUM 77
+static char *event_str[EVENT_NUM + 1] = {
+       "Unknown",
+       "Inquiry Complete",
+       "Inquiry Result",
+       "Connect Complete",
+       "Connect Request",
+       "Disconn Complete",
+       "Auth Complete",
+       "Remote Name Req Complete",
+       "Encrypt Change",
+       "Change Connection Link Key Complete",
+       "Master Link Key Complete",
+       "Read Remote Supported Features",
+       "Read Remote Ver Info Complete",
+       "QoS Setup Complete",
+       "Command Complete",
+       "Command Status",
+       "Hardware Error",
+       "Flush Occurred",
+       "Role Change",
+       "Number of Completed Packets",
+       "Mode Change",
+       "Return Link Keys",
+       "PIN Code Request",
+       "Link Key Request",
+       "Link Key Notification",
+       "Loopback Command",
+       "Data Buffer Overflow",
+       "Max Slots Change",
+       "Read Clock Offset Complete",
+       "Connection Packet Type Changed",
+       "QoS Violation",
+       "Page Scan Mode Change",
+       "Page Scan Repetition Mode Change",
+       "Flow Specification Complete",
+       "Inquiry Result with RSSI",
+       "Read Remote Extended Features",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Synchronous Connect Complete",
+       "Synchronous Connect Changed",
+       "Sniff Subrate",
+       "Extended Inquiry Result",
+       "Encryption Key Refresh Complete",
+       "IO Capability Request",
+       "IO Capability Response",
+       "User Confirmation Request",
+       "User Passkey Request",
+       "Remote OOB Data Request",
+       "Simple Pairing Complete",
+       "Unknown",
+       "Link Supervision Timeout Change",
+       "Enhanced Flush Complete",
+       "Unknown",
+       "User Passkey Notification",
+       "Keypress Notification",
+       "Remote Host Supported Features Notification",
+       "LE Meta Event",
+       "Unknown",
+       "Physical Link Complete",
+       "Channel Selected",
+       "Disconnection Physical Link Complete",
+       "Physical Link Loss Early Warning",
+       "Physical Link Recovery",
+       "Logical Link Complete",
+       "Disconnection Logical Link Complete",
+       "Flow Spec Modify Complete",
+       "Number Of Completed Data Blocks",
+       "AMP Start Test",
+       "AMP Test End",
+       "AMP Receiver Report",
+       "Short Range Mode Change Complete",
+       "AMP Status Change",
+};
+
+#define LE_EV_NUM 5
+static char *ev_le_meta_str[LE_EV_NUM + 1] = {
+       "Unknown",
+       "LE Connection Complete",
+       "LE Advertising Report",
+       "LE Connection Update Complete",
+       "LE Read Remote Used Features Complete",
+       "LE Long Term Key Request",
+};
+
+#define CMD_LINKCTL_NUM 60
+static char *cmd_linkctl_str[CMD_LINKCTL_NUM + 1] = {
+       "Unknown",
+       "Inquiry",
+       "Inquiry Cancel",
+       "Periodic Inquiry Mode",
+       "Exit Periodic Inquiry Mode",
+       "Create Connection",
+       "Disconnect",
+       "Add SCO Connection",
+       "Create Connection Cancel",
+       "Accept Connection Request",
+       "Reject Connection Request",
+       "Link Key Request Reply",
+       "Link Key Request Negative Reply",
+       "PIN Code Request Reply",
+       "PIN Code Request Negative Reply",
+       "Change Connection Packet Type",
+       "Unknown",
+       "Authentication Requested",
+       "Unknown",
+       "Set Connection Encryption",
+       "Unknown",
+       "Change Connection Link Key",
+       "Unknown",
+       "Master Link Key",
+       "Unknown",
+       "Remote Name Request",
+       "Remote Name Request Cancel",
+       "Read Remote Supported Features",
+       "Read Remote Extended Features",
+       "Read Remote Version Information",
+       "Unknown",
+       "Read Clock Offset",
+       "Read LMP Handle",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Setup Synchronous Connection",
+       "Accept Synchronous Connection",
+       "Reject Synchronous Connection",
+       "IO Capability Request Reply",
+       "User Confirmation Request Reply",
+       "User Confirmation Request Negative Reply",
+       "User Passkey Request Reply",
+       "User Passkey Request Negative Reply",
+       "Remote OOB Data Request Reply",
+       "Unknown",
+       "Unknown",
+       "Remote OOB Data Request Negative Reply",
+       "IO Capability Request Negative Reply",
+       "Create Physical Link",
+       "Accept Physical Link",
+       "Disconnect Physical Link",
+       "Create Logical Link",
+       "Accept Logical Link",
+       "Disconnect Logical Link",
+       "Logical Link Cancel",
+       "Flow Spec Modify",
+};
+
+#define CMD_LINKPOL_NUM 17
+static char *cmd_linkpol_str[CMD_LINKPOL_NUM + 1] = {
+       "Unknown",
+       "Hold Mode",
+       "Unknown",
+       "Sniff Mode",
+       "Exit Sniff Mode",
+       "Park State",
+       "Exit Park State",
+       "QoS Setup",
+       "Unknown",
+       "Role Discovery",
+       "Unknown",
+       "Switch Role",
+       "Read Link Policy Settings",
+       "Write Link Policy Settings",
+       "Read Default Link Policy Settings",
+       "Write Default Link Policy Settings",
+       "Flow Specification",
+       "Sniff Subrating",
+};
+
+#define CMD_HOSTCTL_NUM 109
+static char *cmd_hostctl_str[CMD_HOSTCTL_NUM + 1] = {
+       "Unknown",
+       "Set Event Mask",
+       "Unknown",
+       "Reset",
+       "Unknown",
+       "Set Event Filter",
+       "Unknown",
+       "Unknown",
+       "Flush",
+       "Read PIN Type ",
+       "Write PIN Type",
+       "Create New Unit Key",
+       "Unknown",
+       "Read Stored Link Key",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Write Stored Link Key",
+       "Delete Stored Link Key",
+       "Write Local Name",
+       "Read Local Name",
+       "Read Connection Accept Timeout",
+       "Write Connection Accept Timeout",
+       "Read Page Timeout",
+       "Write Page Timeout",
+       "Read Scan Enable",
+       "Write Scan Enable",
+       "Read Page Scan Activity",
+       "Write Page Scan Activity",
+       "Read Inquiry Scan Activity",
+       "Write Inquiry Scan Activity",
+       "Read Authentication Enable",
+       "Write Authentication Enable",
+       "Read Encryption Mode",
+       "Write Encryption Mode",
+       "Read Class of Device",
+       "Write Class of Device",
+       "Read Voice Setting",
+       "Write Voice Setting",
+       "Read Automatic Flush Timeout",
+       "Write Automatic Flush Timeout",
+       "Read Num Broadcast Retransmissions",
+       "Write Num Broadcast Retransmissions",
+       "Read Hold Mode Activity ",
+       "Write Hold Mode Activity",
+       "Read Transmit Power Level",
+       "Read Synchronous Flow Control Enable",
+       "Write Synchronous Flow Control Enable",
+       "Unknown",
+       "Set Host Controller To Host Flow Control",
+       "Unknown",
+       "Host Buffer Size",
+       "Unknown",
+       "Host Number of Completed Packets",
+       "Read Link Supervision Timeout",
+       "Write Link Supervision Timeout",
+       "Read Number of Supported IAC",
+       "Read Current IAC LAP",
+       "Write Current IAC LAP",
+       "Read Page Scan Period Mode",
+       "Write Page Scan Period Mode",
+       "Read Page Scan Mode",
+       "Write Page Scan Mode",
+       "Set AFH Host Channel Classification",
+       "Unknown",
+       "Unknown",
+       "Read Inquiry Scan Type",
+       "Write Inquiry Scan Type",
+       "Read Inquiry Mode",
+       "Write Inquiry Mode",
+       "Read Page Scan Type",
+       "Write Page Scan Type",
+       "Read AFH Channel Assessment Mode",
+       "Write AFH Channel Assessment Mode",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Read Extended Inquiry Response",
+       "Write Extended Inquiry Response",
+       "Refresh Encryption Key",
+       "Unknown",
+       "Read Simple Pairing Mode",
+       "Write Simple Pairing Mode",
+       "Read Local OOB Data",
+       "Read Inquiry Response Transmit Power Level",
+       "Write Inquiry Transmit Power Level",
+       "Read Default Erroneous Data Reporting",
+       "Write Default Erroneous Data Reporting",
+       "Unknown",
+       "Unknown",
+       "Unknown",
+       "Enhanced Flush",
+       "Unknown",
+       "Read Logical Link Accept Timeout",
+       "Write Logical Link Accept Timeout",
+       "Set Event Mask Page 2",
+       "Read Location Data",
+       "Write Location Data",
+       "Read Flow Control Mode",
+       "Write Flow Control Mode",
+       "Read Enhanced Transmit Power Level",
+       "Read Best Effort Flush Timeout",
+       "Write Best Effort Flush Timeout",
+       "Short Range Mode",
+       "Read LE Host Supported",
+       "Write LE Host Supported",
+};
+
+#define CMD_INFO_NUM 10
+static char *cmd_info_str[CMD_INFO_NUM + 1] = {
+       "Unknown",
+       "Read Local Version Information",
+       "Read Local Supported Commands",
+       "Read Local Supported Features",
+       "Read Local Extended Features",
+       "Read Buffer Size",
+       "Unknown",
+       "Read Country Code",
+       "Unknown",
+       "Read BD ADDR",
+       "Read Data Block Size",
+};
+
+#define CMD_STATUS_NUM 11
+static char *cmd_status_str[CMD_STATUS_NUM + 1] = {
+       "Unknown",
+       "Read Failed Contact Counter",
+       "Reset Failed Contact Counter",
+       "Read Link Quality",
+       "Unknown",
+       "Read RSSI",
+       "Read AFH Channel Map",
+       "Read Clock",
+       "Read Encryption Key Size",
+       "Read Local AMP Info",
+       "Read Local AMP ASSOC",
+       "Write Remote AMP ASSOC"
+};
+
+#define CMD_TESTING_NUM 4
+static char *cmd_testing_str[CMD_TESTING_NUM + 1] = {
+       "Unknown",
+       "Read Loopback Mode",
+       "Write Loopback Mode",
+       "Enable Device Under Test mode",
+       "Unknown",
+};
+
+#define CMD_LE_NUM 31
+static char *cmd_le_str[CMD_LE_NUM + 1] = {
+       "Unknown",
+       "LE Set Event Mask",
+       "LE Read Buffer Size",
+       "LE Read Local Supported Features",
+       "Unknown",
+       "LE Set Random Address",
+       "LE Set Advertising Parameters",
+       "LE Read Advertising Channel Tx Power",
+       "LE Set Advertising Data",
+       "LE Set Scan Response Data",
+       "LE Set Advertise Enable",
+       "LE Set Scan Parameters",
+       "LE Set Scan Enable",
+       "LE Create Connection",
+       "LE Create Connection Cancel",
+       "LE Read White List Size",
+       "LE Clear White List",
+       "LE Add Device To White List",
+       "LE Remove Device From White List",
+       "LE Connection Update",
+       "LE Set Host Channel Classification",
+       "LE Read Channel Map",
+       "LE Read Remote Used Features",
+       "LE Encrypt",
+       "LE Rand",
+       "LE Start Encryption",
+       "LE Long Term Key Request Reply",
+       "LE Long Term Key Request Negative Reply",
+       "LE Read Supported States",
+       "LE Receiver Test",
+       "LE Transmitter Test",
+       "LE Test End",
+};
+
+#define ERROR_CODE_NUM 63
+static char *error_code_str[ERROR_CODE_NUM + 1] = {
+       "Success",
+       "Unknown HCI Command",
+       "Unknown Connection Identifier",
+       "Hardware Failure",
+       "Page Timeout",
+       "Authentication Failure",
+       "PIN or Key Missing",
+       "Memory Capacity Exceeded",
+       "Connection Timeout",
+       "Connection Limit Exceeded",
+       "Synchronous Connection to a Device Exceeded",
+       "ACL Connection Already Exists",
+       "Command Disallowed",
+       "Connection Rejected due to Limited Resources",
+       "Connection Rejected due to Security Reasons",
+       "Connection Rejected due to Unacceptable BD_ADDR",
+       "Connection Accept Timeout Exceeded",
+       "Unsupported Feature or Parameter Value",
+       "Invalid HCI Command Parameters",
+       "Remote User Terminated Connection",
+       "Remote Device Terminated Connection due to Low Resources",
+       "Remote Device Terminated Connection due to Power Off",
+       "Connection Terminated by Local Host",
+       "Repeated Attempts",
+       "Pairing Not Allowed",
+       "Unknown LMP PDU",
+       "Unsupported Remote Feature / Unsupported LMP Feature",
+       "SCO Offset Rejected",
+       "SCO Interval Rejected",
+       "SCO Air Mode Rejected",
+       "Invalid LMP Parameters",
+       "Unspecified Error",
+       "Unsupported LMP Parameter Value",
+       "Role Change Not Allowed",
+       "LMP Response Timeout",
+       "LMP Error Transaction Collision",
+       "LMP PDU Not Allowed",
+       "Encryption Mode Not Acceptable",
+       "Link Key Can Not be Changed",
+       "Requested QoS Not Supported",
+       "Instant Passed",
+       "Pairing with Unit Key Not Supported",
+       "Different Transaction Collision",
+       "Reserved",
+       "QoS Unacceptable Parameter",
+       "QoS Rejected",
+       "Channel Classification Not Supported",
+       "Insufficient Security",
+       "Parameter out of Mandatory Range",
+       "Reserved",
+       "Role Switch Pending",
+       "Reserved",
+       "Reserved Slot Violation",
+       "Role Switch Failed",
+       "Extended Inquiry Response Too Large",
+       "Simple Pairing Not Supported by Host",
+       "Host Busy - Pairing",
+       "Connection Rejected due to No Suitable Channel Found",
+       "Controller Busy",
+       "Unacceptable Connection Interval",
+       "Directed Advertising Timeout",
+       "Connection Terminated Due to MIC Failure",
+       "Connection Failed to be Established",
+       "MAC Connection Failed",
+};
+
+static char *status2str(uint8_t status)
+{
+       char *str;
+
+       if (status <= ERROR_CODE_NUM)
+               str = error_code_str[status];
+       else
+               str = "Unknown";
+
+       return str;
+}
+
+static char *opcode2str(uint16_t opcode)
+{
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+       char *cmd;
+
+       switch (ogf) {
+       case OGF_INFO_PARAM:
+               if (ocf <= CMD_INFO_NUM)
+                       cmd = cmd_info_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_HOST_CTL:
+               if (ocf <= CMD_HOSTCTL_NUM)
+                       cmd = cmd_hostctl_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_LINK_CTL:
+               if (ocf <= CMD_LINKCTL_NUM)
+                       cmd = cmd_linkctl_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_LINK_POLICY:
+               if (ocf <= CMD_LINKPOL_NUM)
+                       cmd = cmd_linkpol_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_STATUS_PARAM:
+               if (ocf <= CMD_STATUS_NUM)
+                       cmd = cmd_status_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_TESTING_CMD:
+               if (ocf <= CMD_TESTING_NUM)
+                       cmd = cmd_testing_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_LE_CTL:
+               if (ocf <= CMD_LE_NUM)
+                       cmd = cmd_le_str[ocf];
+               else
+                       cmd = "Unknown";
+               break;
+
+       case OGF_VENDOR_CMD:
+               cmd = "Vendor";
+               break;
+
+       default:
+               cmd = "Unknown";
+               break;
+       }
+
+       return cmd;
+}
+
+static char *linktype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "SCO";
+       case 0x01:
+               return "ACL";
+       case 0x02:
+               return "eSCO";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *role2str(uint8_t role)
+{
+       switch (role) {
+       case 0x00:
+               return "Master";
+       case 0x01:
+               return "Slave";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *mode2str(uint8_t mode)
+{
+       switch (mode) {
+       case 0x00:
+               return "Active";
+       case 0x01:
+               return "Hold";
+       case 0x02:
+               return "Sniff";
+       case 0x03:
+               return "Park";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *airmode2str(uint8_t mode)
+{
+       switch (mode) {
+       case 0x00:
+               return "u-law log";
+       case 0x01:
+               return "A-law log";
+       case 0x02:
+               return "CVSD";
+       case 0x04:
+               return "Transparent data";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *bdaddrtype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "Public";
+       case 0x01:
+               return "Random";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *evttype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "ADV_IND - Connectable undirected advertising";
+       case 0x01:
+               return "ADV_DIRECT_IND - Connectable directed advertising";
+       case 0x02:
+               return "ADV_SCAN_IND - Scannable undirected advertising";
+       case 0x03:
+               return "ADV_NONCONN_IND - Non connectable undirected advertising";
+       case 0x04:
+               return "SCAN_RSP - Scan Response";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *keytype2str(uint8_t type)
+{
+       switch (type) {
+       case 0x00:
+               return "Combination Key";
+       case 0x01:
+               return "Local Unit Key";
+       case 0x02:
+               return "Remote Unit Key";
+       case 0x03:
+               return "Debug Combination Key";
+       case 0x04:
+               return "Unauthenticated Combination Key";
+       case 0x05:
+               return "Authenticated Combination Key";
+       case 0x06:
+               return "Changed Combination Key";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *capability2str(uint8_t capability)
+{
+       switch (capability) {
+       case 0x00:
+               return "DisplayOnly";
+       case 0x01:
+               return "DisplayYesNo";
+       case 0x02:
+               return "KeyboardOnly";
+       case 0x03:
+               return "NoInputNoOutput";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *authentication2str(uint8_t authentication)
+{
+       switch (authentication) {
+       case 0x00:
+               return "No Bonding (No MITM Protection)";
+       case 0x01:
+               return "No Bonding (MITM Protection)";
+       case 0x02:
+               return "Dedicated Bonding (No MITM Protection)";
+       case 0x03:
+               return "Dedicated Bonding (MITM Protection)";
+       case 0x04:
+               return "General Bonding (No MITM Protection)";
+       case 0x05:
+               return "General Bonding (MITM Protection)";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *eventmask2str(const uint8_t mask[8])
+{
+       int i;
+
+       for (i = 0; i < 7; i++) {
+               if (mask[i] != 0x00)
+                       return "Reserved";
+       }
+
+       switch (mask[7]) {
+       case 0x00:
+               return "No LE events specified";
+       case 0x01:
+               return "LE Connection Complete Event";
+       case 0x02:
+               return "LE Advertising Report Event";
+       case 0x04:
+               return "LE Connection Update Complete Event";
+       case 0x08:
+               return "LE Read Remote Used Features Complete Event";
+       case 0x10:
+               return "LE Long Term Key Request Event";
+       case 0x1F:
+               return "Default";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *lefeatures2str(const uint8_t features[8])
+{
+       if (features[0] & 0x01)
+               return "Link Layer supports LE Encryption";
+
+       return "RFU";
+}
+
+static char *filterpolicy2str(uint8_t policy)
+{
+       switch (policy) {
+       case 0x00:
+               return "Allow scan from any, connection from any";
+       case 0x01:
+               return "Allow scan from white list, connection from any";
+       case 0x02:
+               return "Allow scan from any, connection from white list";
+       case 0x03:
+               return "Allow scan and connection from white list";
+       default:
+               return "Reserved";
+       }
+}
+
+static inline void ext_inquiry_data_dump(int level, struct frame *frm,
+                                               uint8_t *data)
+{
+       uint8_t len = data[0];
+       uint8_t type;
+       char *str;
+       int i;
+
+       if (len == 0)
+               return;
+
+       type = data[1];
+       data += 2;
+       len -= 1;
+
+       switch (type) {
+       case 0x01:
+               p_indent(level, frm);
+               printf("Flags:");
+               for (i = 0; i < len; i++)
+                       printf(" 0x%2.2x", data[i]);
+               printf("\n");
+               break;
+
+       case 0x02:
+       case 0x03:
+               p_indent(level, frm);
+               printf("%s service classes:",
+                               type == 0x02 ? "Shortened" : "Complete");
+
+               for (i = 0; i < len / 2; i++)
+                       printf(" 0x%4.4x", bt_get_le16(data + i * 2));
+
+               printf("\n");
+               break;
+
+       case 0x08:
+       case 0x09:
+               str = malloc(len + 1);
+               if (str) {
+                       snprintf(str, len + 1, "%s", (char *) data);
+                       for (i = 0; i < len; i++)
+                               if (!isprint(str[i]))
+                                       str[i] = '.';
+                       p_indent(level, frm);
+                       printf("%s local name: \'%s\'\n",
+                               type == 0x08 ? "Shortened" : "Complete", str);
+                       free(str);
+               }
+               break;
+
+       case 0x0a:
+               p_indent(level, frm);
+               printf("TX power level: %d\n", *((uint8_t *) data));
+               break;
+
+       default:
+               p_indent(level, frm);
+               printf("Unknown type 0x%02x with %d bytes data\n",
+                                                       type, len);
+               break;
+       }
+}
+
+static inline void ext_inquiry_response_dump(int level, struct frame *frm)
+{
+       void *ptr = frm->ptr;
+       uint32_t len = frm->len;
+       uint8_t *data;
+       uint8_t length;
+
+       data = frm->ptr;
+       length = get_u8(frm);
+
+       while (length > 0) {
+               ext_inquiry_data_dump(level, frm, data);
+
+               frm->ptr += length;
+               frm->len -= length;
+
+               data = frm->ptr;
+               length = get_u8(frm);
+       }
+
+       frm->ptr = ptr +
+               (EXTENDED_INQUIRY_INFO_SIZE - INQUIRY_INFO_WITH_RSSI_SIZE);
+       frm->len = len +
+               (EXTENDED_INQUIRY_INFO_SIZE - INQUIRY_INFO_WITH_RSSI_SIZE);
+}
+
+static inline void bdaddr_command_dump(int level, struct frame *frm)
+{
+       bdaddr_t *bdaddr = frm->ptr;
+       char addr[18];
+
+       frm->ptr += sizeof(bdaddr_t);
+       frm->len -= sizeof(bdaddr_t);
+
+       p_indent(level, frm);
+       p_ba2str(bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+
+       raw_dump(level, frm);
+}
+
+static inline void generic_command_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle %d\n", handle);
+
+       raw_dump(level, frm);
+}
+
+static inline void generic_write_mode_dump(int level, struct frame *frm)
+{
+       uint8_t mode = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("mode 0x%2.2x\n", mode);
+}
+
+static inline void inquiry_dump(int level, struct frame *frm)
+{
+       inquiry_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("lap 0x%2.2x%2.2x%2.2x len %d num %d\n",
+               cp->lap[2], cp->lap[1], cp->lap[0], cp->length, cp->num_rsp);
+}
+
+static inline void periodic_inquiry_dump(int level, struct frame *frm)
+{
+       periodic_inquiry_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("max %d min %d lap 0x%2.2x%2.2x%2.2x len %d num %d\n",
+               btohs(cp->max_period), btohs(cp->min_period),
+               cp->lap[2], cp->lap[1], cp->lap[0], cp->length, cp->num_rsp);
+}
+
+static inline void create_conn_dump(int level, struct frame *frm)
+{
+       create_conn_cp *cp = frm->ptr;
+       uint16_t ptype = btohs(cp->pkt_type);
+       uint16_t clkoffset = btohs(cp->clock_offset);
+       char addr[18], *str;
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s ptype 0x%4.4x rswitch 0x%2.2x clkoffset 0x%4.4x%s\n",
+               addr, ptype, cp->role_switch,
+               clkoffset & 0x7fff, clkoffset & 0x8000 ? " (valid)" : "");
+
+       str = hci_ptypetostr(ptype);
+       if (str) {
+               p_indent(level, frm);
+               printf("Packet type: %s\n", str);
+               free(str);
+       }
+}
+
+static inline void disconnect_dump(int level, struct frame *frm)
+{
+       disconnect_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d reason 0x%2.2x\n", btohs(cp->handle), cp->reason);
+
+       p_indent(level, frm);
+       printf("Reason: %s\n", status2str(cp->reason));
+}
+
+static inline void add_sco_dump(int level, struct frame *frm)
+{
+       add_sco_cp *cp = frm->ptr;
+       uint16_t ptype = btohs(cp->pkt_type);
+       char *str;
+
+       p_indent(level, frm);
+       printf("handle %d ptype 0x%4.4x\n", btohs(cp->handle), ptype);
+
+       str = hci_ptypetostr(ptype);
+       if (str) {
+               p_indent(level, frm);
+               printf("Packet type: %s\n", str);
+               free(str);
+       }
+}
+
+static inline void accept_conn_req_dump(int level, struct frame *frm)
+{
+       accept_conn_req_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s role 0x%2.2x\n", addr, cp->role);
+
+       p_indent(level, frm);
+       printf("Role: %s\n", role2str(cp->role));
+}
+
+static inline void reject_conn_req_dump(int level, struct frame *frm)
+{
+       reject_conn_req_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s reason 0x%2.2x\n", addr, cp->reason);
+
+       p_indent(level, frm);
+       printf("Reason: %s\n", status2str(cp->reason));
+}
+
+static inline void pin_code_reply_dump(int level, struct frame *frm)
+{
+       pin_code_reply_cp *cp = frm->ptr;
+       char addr[18], pin[17];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       memset(pin, 0, sizeof(pin));
+       if (parser.flags & DUMP_NOVENDOR)
+               memset(pin, '*', cp->pin_len);
+       else
+               memcpy(pin, cp->pin_code, cp->pin_len);
+       printf("bdaddr %s len %d pin \'%s\'\n", addr, cp->pin_len, pin);
+}
+
+static inline void link_key_reply_dump(int level, struct frame *frm)
+{
+       link_key_reply_cp *cp = frm->ptr;
+       char addr[18];
+       int i;
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s key ", addr);
+       for (i = 0; i < 16; i++)
+               if (parser.flags & DUMP_NOVENDOR)
+                       printf("**");
+               else
+                       printf("%2.2X", cp->link_key[i]);
+       printf("\n");
+}
+
+static inline void pin_code_neg_reply_dump(int level, struct frame *frm)
+{
+       bdaddr_t *bdaddr = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+}
+
+static inline void user_passkey_reply_dump(int level, struct frame *frm)
+{
+       user_passkey_reply_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s passkey %d\n", addr, btohl(cp->passkey));
+}
+
+static inline void remote_oob_data_reply_dump(int level, struct frame *frm)
+{
+       remote_oob_data_reply_cp *cp = frm->ptr;
+       char addr[18];
+       int i;
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+
+       p_indent(level, frm);
+       printf("hash 0x");
+       for (i = 0; i < 16; i++)
+               printf("%02x", cp->hash[i]);
+       printf("\n");
+
+       p_indent(level, frm);
+       printf("randomizer 0x");
+       for (i = 0; i < 16; i++)
+                       printf("%02x", cp->randomizer[i]);
+       printf("\n");
+}
+
+static inline void io_capability_reply_dump(int level, struct frame *frm)
+{
+       io_capability_reply_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s capability 0x%2.2x oob 0x%2.2x auth 0x%2.2x\n",
+                                       addr, cp->capability, cp->oob_data,
+                                                       cp->authentication);
+
+       p_indent(level, frm);
+       printf("Capability: %s (OOB data %s)\n",
+                       capability2str(cp->capability),
+                       cp->oob_data == 0x00 ? "not present" : "available");
+
+       p_indent(level, frm);
+       printf("Authentication: %s\n", authentication2str(cp->authentication));
+}
+
+static inline void set_conn_encrypt_dump(int level, struct frame *frm)
+{
+       set_conn_encrypt_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d encrypt 0x%2.2x\n", btohs(cp->handle), cp->encrypt);
+}
+
+static inline void remote_name_req_dump(int level, struct frame *frm)
+{
+       remote_name_req_cp *cp = frm->ptr;
+       uint16_t clkoffset = btohs(cp->clock_offset);
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s mode %d clkoffset 0x%4.4x%s\n",
+               addr, cp->pscan_rep_mode,
+               clkoffset & 0x7fff, clkoffset & 0x8000 ? " (valid)" : "");
+}
+
+static inline void master_link_key_dump(int level, struct frame *frm)
+{
+       master_link_key_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("flag %d\n", cp->key_flag);
+}
+
+static inline void read_remote_ext_features_dump(int level, struct frame *frm)
+{
+       read_remote_ext_features_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d page %d\n", btohs(cp->handle), cp->page_num);
+}
+
+static inline void setup_sync_conn_dump(int level, struct frame *frm)
+{
+       setup_sync_conn_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d voice setting 0x%4.4x ptype 0x%4.4x\n",
+               btohs(cp->handle), btohs(cp->voice_setting),
+               btohs(cp->pkt_type));
+}
+
+static inline void create_physical_link_dump(int level, struct frame *frm)
+{
+       create_physical_link_cp *cp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("phy handle 0x%2.2x key length %d key type %d\n",
+               cp->handle, cp->key_length, cp->key_type);
+       p_indent(level, frm);
+       printf("key ");
+       for (i = 0; i < cp->key_length && cp->key_length <= 32; i++)
+               printf("%2.2x", cp->key[i]);
+       printf("\n");
+}
+
+static inline void create_logical_link_dump(int level, struct frame *frm)
+{
+       create_logical_link_cp *cp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("phy handle 0x%2.2x\n", cp->handle);
+
+       p_indent(level, frm);
+       printf("tx_flow ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", cp->tx_flow[i]);
+       printf("\n");
+
+       p_indent(level, frm);
+       printf("rx_flow ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", cp->rx_flow[i]);
+       printf("\n");
+}
+
+static inline void hold_mode_dump(int level, struct frame *frm)
+{
+       hold_mode_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d max %d min %d\n", btohs(cp->handle),
+                       btohs(cp->max_interval), btohs(cp->min_interval));
+}
+
+static inline void sniff_mode_dump(int level, struct frame *frm)
+{
+       sniff_mode_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d max %d min %d attempt %d timeout %d\n",
+               btohs(cp->handle), btohs(cp->max_interval),
+               btohs(cp->min_interval), btohs(cp->attempt), btohs(cp->timeout));
+}
+
+static inline void qos_setup_dump(int level, struct frame *frm)
+{
+       qos_setup_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d flags 0x%2.2x\n", btohs(cp->handle), cp->flags);
+
+       p_indent(level, frm);
+       printf("Service type: %d\n", cp->qos.service_type);
+       p_indent(level, frm);
+       printf("Token rate: %d\n", btohl(cp->qos.token_rate));
+       p_indent(level, frm);
+       printf("Peak bandwith: %d\n", btohl(cp->qos.peak_bandwidth));
+       p_indent(level, frm);
+       printf("Latency: %d\n", btohl(cp->qos.latency));
+       p_indent(level, frm);
+       printf("Delay variation: %d\n", btohl(cp->qos.delay_variation));
+}
+
+static inline void write_link_policy_dump(int level, struct frame *frm)
+{
+       write_link_policy_cp *cp = frm->ptr;
+       uint16_t policy = btohs(cp->policy);
+       char *str;
+
+       p_indent(level, frm);
+       printf("handle %d policy 0x%2.2x\n", btohs(cp->handle), policy);
+
+       str = hci_lptostr(policy);
+       if (str) {
+               p_indent(level, frm);
+               printf("Link policy: %s\n", str);
+               free(str);
+       }
+}
+
+static inline void write_default_link_policy_dump(int level, struct frame *frm)
+{
+       uint16_t policy = btohs(htons(get_u16(frm)));
+       char *str;
+
+       p_indent(level, frm);
+       printf("policy 0x%2.2x\n", policy);
+
+       str = hci_lptostr(policy);
+       if (str) {
+               p_indent(level, frm);
+               printf("Link policy: %s\n", str);
+               free(str);
+       }
+}
+
+static inline void sniff_subrating_dump(int level, struct frame *frm)
+{
+       sniff_subrating_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d\n", btohs(cp->handle));
+
+       p_indent(level, frm);
+       printf("max latency %d\n", btohs(cp->max_latency));
+
+       p_indent(level, frm);
+       printf("min timeout remote %d local %d\n",
+               btohs(cp->min_remote_timeout), btohs(cp->min_local_timeout));
+}
+
+static inline void set_event_mask_dump(int level, struct frame *frm)
+{
+       set_event_mask_cp *cp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("Mask: 0x");
+       for (i = 0; i < 8; i++)
+               printf("%2.2x", cp->mask[i]);
+       printf("\n");
+}
+
+static inline void set_event_flt_dump(int level, struct frame *frm)
+{
+       set_event_flt_cp *cp = frm->ptr;
+       uint8_t dev_class[3], dev_mask[3];
+       char addr[18];
+
+       p_indent(level, frm);
+       printf("type %d condition %d\n", cp->flt_type,
+                               (cp->flt_type == 0) ? 0 : cp->cond_type);
+
+       switch (cp->flt_type) {
+       case FLT_CLEAR_ALL:
+               p_indent(level, frm);
+               printf("Clear all filters\n");
+               break;
+       case FLT_INQ_RESULT:
+               p_indent(level, frm);
+               printf("Inquiry result");
+               switch (cp->cond_type) {
+               case INQ_RESULT_RETURN_ALL:
+                       printf(" for all devices\n");
+                       break;
+               case INQ_RESULT_RETURN_CLASS:
+                       memcpy(dev_class, cp->condition, 3);
+                       memcpy(dev_mask, cp->condition + 3, 3);
+                       printf(" with class 0x%2.2x%2.2x%2.2x mask 0x%2.2x%2.2x%2.2x\n",
+                               dev_class[2], dev_class[1], dev_class[0],
+                               dev_mask[2], dev_mask[1], dev_mask[0]);
+                       break;
+               case INQ_RESULT_RETURN_BDADDR:
+                       p_ba2str((bdaddr_t *) cp->condition, addr);
+                       printf(" with bdaddr %s\n", addr);
+                       break;
+               default:
+                       printf("\n");
+                       break;
+               }
+               break;
+       case FLT_CONN_SETUP:
+               p_indent(level, frm);
+               printf("Connection setup");
+               switch (cp->cond_type) {
+               case CONN_SETUP_ALLOW_ALL:
+               case CONN_SETUP_ALLOW_CLASS:
+               case CONN_SETUP_ALLOW_BDADDR:
+               default:
+                       printf("\n");
+                       break;
+               }
+               break;
+       }
+}
+
+static inline void write_pin_type_dump(int level, struct frame *frm)
+{
+       write_pin_type_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("type %d\n", cp->pin_type);
+}
+
+static inline void request_stored_link_key_dump(int level, struct frame *frm)
+{
+       read_stored_link_key_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s all %d\n", addr, cp->read_all);
+}
+
+static inline void return_link_keys_dump(int level, struct frame *frm)
+{
+       uint8_t num = get_u8(frm);
+       uint8_t key[16];
+       char addr[18];
+       int i, n;
+
+       for (n = 0; n < num; n++) {
+               p_ba2str(frm->ptr, addr);
+               memcpy(key, frm->ptr + 6, 16);
+
+               p_indent(level, frm);
+               printf("bdaddr %s key ", addr);
+               for (i = 0; i < 16; i++)
+                       if (parser.flags & DUMP_NOVENDOR)
+                               printf("**");
+                       else
+                               printf("%2.2X", key[i]);
+               printf("\n");
+
+               frm->ptr += 2;
+               frm->len -= 2;
+       }
+}
+
+static inline void change_local_name_dump(int level, struct frame *frm)
+{
+       change_local_name_cp *cp = frm->ptr;
+       char name[249];
+       int i;
+
+       memset(name, 0, sizeof(name));
+       for (i = 0; i < 248 && cp->name[i]; i++)
+               if (isprint(cp->name[i]))
+                       name[i] = cp->name[i];
+               else
+                       name[i] = '.';
+
+       p_indent(level, frm);
+       printf("name \'%s\'\n", name);
+}
+
+static inline void write_class_of_dev_dump(int level, struct frame *frm)
+{
+       write_class_of_dev_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("class 0x%2.2x%2.2x%2.2x\n",
+                       cp->dev_class[2], cp->dev_class[1], cp->dev_class[0]);
+}
+
+static inline void write_voice_setting_dump(int level, struct frame *frm)
+{
+       write_voice_setting_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("voice setting 0x%4.4x\n", btohs(cp->voice_setting));
+}
+
+static inline void write_current_iac_lap_dump(int level, struct frame *frm)
+{
+       write_current_iac_lap_cp *cp = frm->ptr;
+       int i;
+
+       for (i = 0; i < cp->num_current_iac; i++) {
+               p_indent(level, frm);
+               printf("IAC 0x%2.2x%2.2x%2.2x", cp->lap[i][2], cp->lap[i][1], cp->lap[i][0]);
+               if (cp->lap[i][2] == 0x9e && cp->lap[i][1] == 0x8b) {
+                       switch (cp->lap[i][0]) {
+                       case 0x00:
+                               printf(" (Limited Inquiry Access Code)");
+                               break;
+                       case 0x33:
+                               printf(" (General Inquiry Access Code)");
+                               break;
+                       }
+               }
+               printf("\n");
+       }
+}
+
+static inline void write_scan_enable_dump(int level, struct frame *frm)
+{
+       uint8_t enable = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("enable %d\n", enable);
+}
+
+static inline void write_page_timeout_dump(int level, struct frame *frm)
+{
+       write_page_timeout_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("timeout %d\n", btohs(cp->timeout));
+}
+
+static inline void write_page_activity_dump(int level, struct frame *frm)
+{
+       write_page_activity_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("interval %d window %d\n", btohs(cp->interval), btohs(cp->window));
+}
+
+static inline void write_inquiry_scan_type_dump(int level, struct frame *frm)
+{
+       write_inquiry_scan_type_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("type %d\n", cp->type);
+}
+
+static inline void write_inquiry_mode_dump(int level, struct frame *frm)
+{
+       write_inquiry_mode_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("mode %d\n", cp->mode);
+}
+
+static inline void set_afh_classification_dump(int level, struct frame *frm)
+{
+       set_afh_classification_cp *cp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("map 0x");
+       for (i = 0; i < 10; i++)
+               printf("%02x", cp->map[i]);
+       printf("\n");
+}
+
+static inline void write_link_supervision_timeout_dump(int level, struct frame *frm)
+{
+       write_link_supervision_timeout_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d timeout %d\n",
+                               btohs(cp->handle), btohs(cp->timeout));
+}
+
+static inline void write_ext_inquiry_response_dump(int level, struct frame *frm)
+{
+       write_ext_inquiry_response_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("fec 0x%2.2x\n", cp->fec);
+
+       frm->ptr++;
+       frm->len--;
+
+       ext_inquiry_response_dump(level, frm);
+}
+
+static inline void write_inquiry_transmit_power_level_dump(int level, struct frame *frm)
+{
+       write_inquiry_transmit_power_level_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("level %d\n", cp->level);
+}
+
+static inline void write_default_error_data_reporting_dump(int level, struct frame *frm)
+{
+       write_default_error_data_reporting_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("reporting %d\n", cp->reporting);
+}
+
+static inline void enhanced_flush_dump(int level, struct frame *frm)
+{
+       enhanced_flush_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d type %d\n", btohs(cp->handle), cp->type);
+}
+
+static inline void send_keypress_notify_dump(int level, struct frame *frm)
+{
+       send_keypress_notify_cp *cp = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s type %d\n", addr, cp->type);
+}
+
+static inline void request_transmit_power_level_dump(int level, struct frame *frm)
+{
+       read_transmit_power_level_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d type %d (%s)\n",
+                                       btohs(cp->handle), cp->type,
+                                       cp->type ? "maximum" : "current");
+}
+
+static inline void request_local_ext_features_dump(int level, struct frame *frm)
+{
+       read_local_ext_features_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("page %d\n", cp->page_num);
+}
+
+static inline void request_clock_dump(int level, struct frame *frm)
+{
+       read_clock_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d which %d (%s)\n",
+                                       btohs(cp->handle), cp->which_clock,
+                                       cp->which_clock ? "piconet" : "local");
+}
+
+static inline void host_buffer_size_dump(int level, struct frame *frm)
+{
+       host_buffer_size_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("ACL MTU %d:%d SCO MTU %d:%d\n",
+                               btohs(cp->acl_mtu), btohs(cp->acl_max_pkt),
+                               cp->sco_mtu, btohs(cp->sco_max_pkt));
+}
+
+static inline void num_comp_pkts_dump(int level, struct frame *frm)
+{
+       uint8_t num = get_u8(frm);
+       uint16_t handle, packets;
+       int i;
+
+       for (i = 0; i < num; i++) {
+               handle = btohs(htons(get_u16(frm)));
+               packets = btohs(htons(get_u16(frm)));
+
+               p_indent(level, frm);
+               printf("handle %d packets %d\n", handle, packets);
+       }
+}
+
+static inline void le_create_connection_dump(int level, struct frame *frm)
+{
+       char addr[18];
+       le_create_connection_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       p_ba2str(&cp->peer_bdaddr, addr);
+       printf("bdaddr %s type %d\n", addr, cp->peer_bdaddr_type);
+       p_indent(level, frm);
+       printf("interval %u window %u initiator_filter %u\n",
+               btohs(cp->interval), btohs(cp->window), cp->initiator_filter);
+       p_indent(level, frm);
+       printf("own_bdaddr_type %u min_interval %u max_interval %u\n",
+                       cp->own_bdaddr_type, btohs(cp->min_interval),
+                       btohs(cp->max_interval));
+       p_indent(level, frm);
+       printf("latency %u supervision_to %u min_ce %u max_ce %u\n",
+                       btohs(cp->latency), btohs(cp->supervision_timeout),
+                       btohs(cp->min_ce_length), btohs(cp->max_ce_length));
+}
+
+static inline void le_set_event_mask_dump(int level, struct frame *frm)
+{
+       int i;
+       le_set_event_mask_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("mask 0x");
+       for (i = 0; i < 8; i++)
+               printf("%.2x", cp->mask[i]);
+
+       printf(" (%s)\n", eventmask2str(cp->mask));
+}
+
+static inline void le_set_random_address_dump(int level, struct frame *frm)
+{
+       char addr[18];
+       le_set_random_address_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       p_ba2str(&cp->bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+}
+
+
+static inline void le_set_advertising_parameters_dump(int level, struct frame *frm)
+{
+       char addr[18];
+       le_set_advertising_parameters_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("min %.3fms, max %.3fms\n", btohs(cp->min_interval) * 0.625,
+                       btohs(cp->max_interval) * 0.625);
+
+       p_indent(level, frm);
+       printf("type 0x%02x (%s) ownbdaddr 0x%02x (%s)\n", cp->advtype,
+                       evttype2str(cp->advtype), cp->own_bdaddr_type,
+                       bdaddrtype2str(cp->own_bdaddr_type));
+
+       p_indent(level, frm);
+       p_ba2str(&cp->direct_bdaddr, addr);
+       printf("directbdaddr 0x%02x (%s) %s\n", cp->direct_bdaddr_type,
+                       bdaddrtype2str(cp->direct_bdaddr_type), addr);
+
+       p_indent(level, frm);
+       printf("channelmap 0x%02x filterpolicy 0x%02x (%s)\n",
+                       cp->chan_map, cp->filter, filterpolicy2str(cp->filter));
+}
+
+static inline void le_set_scan_parameters_dump(int level, struct frame *frm)
+{
+       le_set_scan_parameters_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("type 0x%02x (%s)\n", cp->type,
+               cp->type == 0x00 ? "passive" : "active");
+
+       p_indent(level, frm);
+       printf("interval %.3fms window %.3fms\n", btohs(cp->interval) * 0.625,
+               btohs(cp->window) * 0.625);
+
+       p_indent(level, frm);
+       printf("own address: 0x%02x (%s) policy: %s\n", cp->own_bdaddr_type,
+                       bdaddrtype2str(cp->own_bdaddr_type),
+               (cp->filter == 0x00 ? "All" :
+                       (cp->filter == 0x01 ? "white list only" : "reserved")));
+}
+
+static inline void le_set_scan_enable_dump(int level, struct frame *frm)
+{
+       le_set_scan_enable_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("value 0x%02x (%s)\n", cp->enable,
+               (cp->enable == 0x00 ? "scanning disabled" :
+               "scanning enabled"));
+
+       p_indent(level, frm);
+       printf("filter duplicates 0x%02x (%s)\n", cp->filter_dup,
+               (cp->filter_dup == 0x00 ? "disabled" : "enabled"));
+}
+
+static inline void write_remote_amp_assoc_cmd_dump(int level,
+                                                       struct frame *frm)
+{
+       write_remote_amp_assoc_cp *cp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle 0x%2.2x len_so_far %d remaining_len %d\n", cp->handle,
+                               cp->length_so_far, cp->remaining_length);
+
+       amp_assoc_dump(level + 1, cp->fragment, frm->len - 5);
+}
+
+static inline void command_dump(int level, struct frame *frm)
+{
+       hci_command_hdr *hdr = frm->ptr;
+       uint16_t opcode = btohs(hdr->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+
+       if (p_filter(FILT_HCI))
+               return;
+
+       if (ogf == OGF_VENDOR_CMD && (parser.flags & DUMP_NOVENDOR))
+               return;
+
+       p_indent(level, frm);
+       printf("HCI Command: %s (0x%2.2x|0x%4.4x) plen %d\n", 
+                               opcode2str(opcode), ogf, ocf, hdr->plen);
+
+       frm->ptr += HCI_COMMAND_HDR_SIZE;
+       frm->len -= HCI_COMMAND_HDR_SIZE;
+
+       if (ogf == OGF_VENDOR_CMD) {
+               if (ocf == 0 && get_manufacturer() == 10) {
+                       csr_dump(level + 1, frm);
+                       return;
+               }
+       }
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (ogf) {
+       case OGF_LINK_CTL:
+               switch (ocf) {
+               case OCF_INQUIRY:
+                       inquiry_dump(level + 1, frm);
+                       return;
+               case OCF_PERIODIC_INQUIRY:
+                       periodic_inquiry_dump(level + 1, frm);
+                       return;
+               case OCF_INQUIRY_CANCEL:
+               case OCF_EXIT_PERIODIC_INQUIRY:
+                       return;
+               case OCF_CREATE_CONN:
+                       create_conn_dump(level + 1, frm);
+                       return;
+               case OCF_DISCONNECT:
+                       disconnect_dump(level + 1, frm);
+                       return;
+               case OCF_CREATE_CONN_CANCEL:
+               case OCF_REMOTE_NAME_REQ_CANCEL:
+               case OCF_ACCEPT_SYNC_CONN_REQ:
+                       bdaddr_command_dump(level + 1, frm);
+                       return;
+               case OCF_ADD_SCO:
+               case OCF_SET_CONN_PTYPE:
+                       add_sco_dump(level + 1, frm);
+                       return;
+               case OCF_ACCEPT_CONN_REQ:
+                       accept_conn_req_dump(level + 1, frm);
+                       return;
+               case OCF_REJECT_CONN_REQ:
+               case OCF_REJECT_SYNC_CONN_REQ:
+               case OCF_IO_CAPABILITY_NEG_REPLY:
+                       reject_conn_req_dump(level + 1, frm);
+                       return;
+               case OCF_PIN_CODE_REPLY:
+                       pin_code_reply_dump(level + 1, frm);
+                       return;
+               case OCF_LINK_KEY_REPLY:
+                       link_key_reply_dump(level + 1, frm);
+                       return;
+               case OCF_PIN_CODE_NEG_REPLY:
+               case OCF_LINK_KEY_NEG_REPLY:
+               case OCF_USER_CONFIRM_REPLY:
+               case OCF_USER_CONFIRM_NEG_REPLY:
+               case OCF_USER_PASSKEY_NEG_REPLY:
+               case OCF_REMOTE_OOB_DATA_NEG_REPLY:
+                       pin_code_neg_reply_dump(level + 1, frm);
+                       return;
+               case OCF_USER_PASSKEY_REPLY:
+                       user_passkey_reply_dump(level + 1, frm);
+                       return;
+               case OCF_REMOTE_OOB_DATA_REPLY:
+                       remote_oob_data_reply_dump(level + 1, frm);
+                       return;
+               case OCF_IO_CAPABILITY_REPLY:
+                       io_capability_reply_dump(level + 1, frm);
+                       return;
+               case OCF_SET_CONN_ENCRYPT:
+                       set_conn_encrypt_dump(level + 1, frm);
+                       return;
+               case OCF_AUTH_REQUESTED:
+               case OCF_CHANGE_CONN_LINK_KEY:
+               case OCF_READ_REMOTE_FEATURES:
+               case OCF_READ_REMOTE_VERSION:
+               case OCF_READ_CLOCK_OFFSET:
+               case OCF_READ_LMP_HANDLE:
+               case OCF_DISCONNECT_LOGICAL_LINK:
+                       generic_command_dump(level + 1, frm);
+                       return;
+               case OCF_MASTER_LINK_KEY:
+                       master_link_key_dump(level + 1, frm);
+                       return;
+               case OCF_READ_REMOTE_EXT_FEATURES:
+                       read_remote_ext_features_dump(level + 1, frm);
+                       return;
+               case OCF_REMOTE_NAME_REQ:
+                       remote_name_req_dump(level + 1, frm);
+                       return;
+               case OCF_SETUP_SYNC_CONN:
+                       setup_sync_conn_dump(level + 1, frm);
+                       return;
+               case OCF_CREATE_PHYSICAL_LINK:
+               case OCF_ACCEPT_PHYSICAL_LINK:
+                       create_physical_link_dump(level + 1, frm);
+                       return;
+               case OCF_CREATE_LOGICAL_LINK:
+               case OCF_ACCEPT_LOGICAL_LINK:
+                       create_logical_link_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_LINK_POLICY:
+               switch (ocf) {
+               case OCF_HOLD_MODE:
+               case OCF_PARK_MODE:
+                       hold_mode_dump(level + 1, frm);
+                       return;
+               case OCF_SNIFF_MODE:
+                       sniff_mode_dump(level + 1, frm);
+                       return;
+               case OCF_EXIT_SNIFF_MODE:
+               case OCF_EXIT_PARK_MODE:
+               case OCF_ROLE_DISCOVERY:
+               case OCF_READ_LINK_POLICY:
+                       generic_command_dump(level + 1, frm);
+                       return;
+               case OCF_READ_DEFAULT_LINK_POLICY:
+                       return;
+               case OCF_SWITCH_ROLE:
+                       accept_conn_req_dump(level + 1, frm);
+                       return;
+               case OCF_QOS_SETUP:
+                       qos_setup_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_LINK_POLICY:
+                       write_link_policy_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_DEFAULT_LINK_POLICY:
+                       write_default_link_policy_dump(level + 1, frm);
+                       return;
+               case OCF_SNIFF_SUBRATING:
+                       sniff_subrating_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_HOST_CTL:
+               switch (ocf) {
+               case OCF_RESET:
+               case OCF_CREATE_NEW_UNIT_KEY:
+                       return;
+               case OCF_SET_EVENT_MASK:
+               case OCF_SET_EVENT_MASK_PAGE_2:
+                       set_event_mask_dump(level + 1, frm);
+                       return;
+               case OCF_SET_EVENT_FLT:
+                       set_event_flt_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_PIN_TYPE:
+                       write_pin_type_dump(level + 1, frm);
+                       return;
+               case OCF_READ_STORED_LINK_KEY:
+               case OCF_DELETE_STORED_LINK_KEY:
+                       request_stored_link_key_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_STORED_LINK_KEY:
+                       return_link_keys_dump(level + 1, frm);
+                       return;
+               case OCF_CHANGE_LOCAL_NAME:
+                       change_local_name_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_CLASS_OF_DEV:
+                       write_class_of_dev_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_VOICE_SETTING:
+                       write_voice_setting_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_CURRENT_IAC_LAP:
+                       write_current_iac_lap_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_SCAN_ENABLE:
+               case OCF_WRITE_AUTH_ENABLE:
+               case OCF_SET_CONTROLLER_TO_HOST_FC:
+                       write_scan_enable_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT:
+               case OCF_WRITE_CONN_ACCEPT_TIMEOUT:
+               case OCF_WRITE_PAGE_TIMEOUT:
+                       write_page_timeout_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_PAGE_ACTIVITY:
+               case OCF_WRITE_INQ_ACTIVITY:
+                       write_page_activity_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_INQUIRY_SCAN_TYPE:
+                       write_inquiry_scan_type_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_ENCRYPT_MODE:
+               case OCF_WRITE_INQUIRY_MODE:
+               case OCF_WRITE_AFH_MODE:
+                       write_inquiry_mode_dump(level + 1, frm);
+                       return;
+               case OCF_SET_AFH_CLASSIFICATION:
+                       set_afh_classification_dump(level + 1, frm);
+                       return;
+               case OCF_READ_TRANSMIT_POWER_LEVEL:
+                       request_transmit_power_level_dump(level + 1, frm);
+                       return;
+               case OCF_HOST_BUFFER_SIZE:
+                       host_buffer_size_dump(level + 1, frm);
+                       return;
+               case OCF_HOST_NUM_COMP_PKTS:
+                       num_comp_pkts_dump(level + 1, frm);
+                       return;
+               case OCF_FLUSH:
+               case OCF_READ_LINK_SUPERVISION_TIMEOUT:
+               case OCF_REFRESH_ENCRYPTION_KEY:
+               case OCF_READ_BEST_EFFORT_FLUSH_TIMEOUT:
+                       generic_command_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_LINK_SUPERVISION_TIMEOUT:
+                       write_link_supervision_timeout_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_EXT_INQUIRY_RESPONSE:
+                       write_ext_inquiry_response_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_SIMPLE_PAIRING_MODE:
+               case OCF_WRITE_FLOW_CONTROL_MODE:
+                       generic_write_mode_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL:
+                       write_inquiry_transmit_power_level_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_DEFAULT_ERROR_DATA_REPORTING:
+                       write_default_error_data_reporting_dump(level + 1, frm);
+                       return;
+               case OCF_ENHANCED_FLUSH:
+                       enhanced_flush_dump(level + 1, frm);
+                       return;
+               case OCF_SEND_KEYPRESS_NOTIFY:
+                       send_keypress_notify_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_INFO_PARAM:
+               switch (ocf) {
+               case OCF_READ_LOCAL_EXT_FEATURES:
+                       request_local_ext_features_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_STATUS_PARAM:
+               switch (ocf) {
+               case OCF_READ_LINK_QUALITY:
+               case OCF_READ_RSSI:
+               case OCF_READ_AFH_MAP:
+                       generic_command_dump(level + 1, frm);
+                       return;
+               case OCF_READ_CLOCK:
+                       request_clock_dump(level + 1, frm);
+                       return;
+               case OCF_WRITE_REMOTE_AMP_ASSOC:
+                       write_remote_amp_assoc_cmd_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_TESTING_CMD:
+               switch (ocf) {
+               case OCF_WRITE_LOOPBACK_MODE:
+               case OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE:
+                       generic_write_mode_dump(level + 1, frm);
+                       return;
+               }
+               break;
+
+       case OGF_LE_CTL:
+               switch (ocf) {
+               case OCF_LE_SET_EVENT_MASK:
+                       le_set_event_mask_dump(level + 1, frm);
+                       return;
+               case OCF_LE_READ_BUFFER_SIZE:
+               case OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:
+               case OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:
+                       return;
+               case OCF_LE_SET_RANDOM_ADDRESS:
+                       le_set_random_address_dump(level + 1, frm);
+                       return;
+               case OCF_LE_SET_ADVERTISING_PARAMETERS:
+                       le_set_advertising_parameters_dump(level + 1, frm);
+                       return;
+               case OCF_LE_SET_SCAN_PARAMETERS:
+                       le_set_scan_parameters_dump(level + 1, frm);
+                       return;
+               case OCF_LE_SET_SCAN_ENABLE:
+                       le_set_scan_enable_dump(level + 1, frm);
+                       return;
+               case OCF_LE_CREATE_CONN:
+                       le_create_connection_dump(level + 1, frm);
+                       return;
+               }
+               break;
+       }
+
+       raw_dump(level, frm);
+}
+
+static inline void status_response_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", status);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       }
+
+       raw_dump(level, frm);
+}
+
+static inline void handle_response_dump(int level, struct frame *frm)
+{
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("handle %d\n", handle);
+
+       raw_dump(level, frm);
+}
+
+static inline void bdaddr_response_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+       bdaddr_t *bdaddr = frm->ptr;
+       char addr[18];
+
+       frm->ptr += sizeof(bdaddr_t);
+       frm->len -= sizeof(bdaddr_t);
+
+       p_indent(level, frm);
+       p_ba2str(bdaddr, addr);
+       printf("status 0x%2.2x bdaddr %s\n", status, addr);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       }
+
+       raw_dump(level, frm);
+}
+
+static inline void read_data_block_size_dump(int level, struct frame *frm)
+{
+       read_data_block_size_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("Max ACL %d Block len %d Num blocks %d\n",
+                       btohs(rp->max_acl_len), btohs(rp->data_block_len),
+                                                       btohs(rp->num_blocks));
+       }
+}
+
+static inline void generic_response_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+       uint16_t handle = btohs(htons(get_u16(frm)));
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", status, handle);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       }
+
+       raw_dump(level, frm);
+}
+
+static inline void status_mode_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+       uint8_t mode = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x mode 0x%2.2x\n", status, mode);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       }
+}
+
+static inline void read_link_policy_dump(int level, struct frame *frm)
+{
+       read_link_policy_rp *rp = frm->ptr;
+       uint16_t policy = btohs(rp->policy);
+       char *str;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d policy 0x%2.2x\n",
+                               rp->status, btohs(rp->handle), policy);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               str = hci_lptostr(policy);
+               if (str) {
+                       p_indent(level, frm);
+                       printf("Link policy: %s\n", str);
+                       free(str);
+               }
+       }
+}
+
+static inline void read_default_link_policy_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+       uint16_t policy = btohs(htons(get_u16(frm)));
+       char *str;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x policy 0x%2.2x\n", status, policy);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       } else {
+               str = hci_lptostr(policy);
+               if (str) {
+                       p_indent(level, frm);
+                       printf("Link policy: %s\n", str);
+                       free(str);
+               }
+       }
+}
+
+static inline void read_pin_type_dump(int level, struct frame *frm)
+{
+       read_pin_type_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x type %d\n", rp->status, rp->pin_type);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_stored_link_key_dump(int level, struct frame *frm)
+{
+       read_stored_link_key_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x max %d num %d\n",
+                               rp->status, rp->max_keys, rp->num_keys);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void write_stored_link_key_dump(int level, struct frame *frm)
+{
+       write_stored_link_key_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x written %d\n", rp->status, rp->num_keys);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void delete_stored_link_key_dump(int level, struct frame *frm)
+{
+       delete_stored_link_key_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x deleted %d\n", rp->status, btohs(rp->num_keys));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_local_name_dump(int level, struct frame *frm)
+{
+       read_local_name_rp *rp = frm->ptr;
+       char name[249];
+       int i;
+
+       memset(name, 0, sizeof(name));
+       for (i = 0; i < 248 && rp->name[i]; i++)
+               if (isprint(rp->name[i]))
+                       name[i] = rp->name[i];
+               else
+                       name[i] = '.';
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x name \'%s\'\n", rp->status, name);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_class_of_dev_dump(int level, struct frame *frm)
+{
+       read_class_of_dev_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x class 0x%2.2x%2.2x%2.2x\n", rp->status,
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_voice_setting_dump(int level, struct frame *frm)
+{
+       read_voice_setting_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x voice setting 0x%4.4x\n",
+                                       rp->status, btohs(rp->voice_setting));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_current_iac_lap_dump(int level, struct frame *frm)
+{
+       read_current_iac_lap_rp *rp = frm->ptr;
+       int i;
+
+       for (i = 0; i < rp->num_current_iac; i++) {
+               p_indent(level, frm);
+               printf("IAC 0x%2.2x%2.2x%2.2x", rp->lap[i][2], rp->lap[i][1], rp->lap[i][0]);
+               if (rp->lap[i][2] == 0x9e && rp->lap[i][1] == 0x8b) {
+                       switch (rp->lap[i][0]) {
+                       case 0x00:
+                               printf(" (Limited Inquiry Access Code)");
+                               break;
+                       case 0x33:
+                               printf(" (General Inquiry Access Code)");
+                               break;
+                       }
+               }
+               printf("\n");
+       }
+}
+
+static inline void read_scan_enable_dump(int level, struct frame *frm)
+{
+       uint8_t status = get_u8(frm);
+       uint8_t enable = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x enable %d\n", status, enable);
+
+       if (status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(status));
+       }
+}
+
+static inline void read_page_timeout_dump(int level, struct frame *frm)
+{
+       read_page_timeout_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x timeout %d\n", rp->status, btohs(rp->timeout));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_page_activity_dump(int level, struct frame *frm)
+{
+       read_page_activity_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x interval %d window %d\n",
+                       rp->status, btohs(rp->interval), btohs(rp->window));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_inquiry_scan_type_dump(int level, struct frame *frm)
+{
+       read_inquiry_scan_type_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x type %d\n", rp->status, rp->type);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_inquiry_mode_dump(int level, struct frame *frm)
+{
+       read_inquiry_mode_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x mode %d\n", rp->status, rp->mode);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_link_supervision_timeout_dump(int level, struct frame *frm)
+{
+       read_link_supervision_timeout_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d timeout %d\n",
+                       rp->status, btohs(rp->handle), btohs(rp->timeout));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_transmit_power_level_dump(int level, struct frame *frm)
+{
+       read_transmit_power_level_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d level %d\n",
+                               rp->status, btohs(rp->handle), rp->level);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_ext_inquiry_response_dump(int level, struct frame *frm)
+{
+       read_ext_inquiry_response_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x fec 0x%2.2x\n", rp->status, rp->fec);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               frm->ptr += 2;
+               frm->len -= 2;
+
+               ext_inquiry_response_dump(level, frm);
+       }
+}
+
+static inline void read_inquiry_transmit_power_level_dump(int level, struct frame *frm)
+{
+       read_inquiry_transmit_power_level_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x level %d\n", rp->status, rp->level);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_default_error_data_reporting_dump(int level, struct frame *frm)
+{
+       read_default_error_data_reporting_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x reporting %d\n", rp->status, rp->reporting);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_local_oob_data_dump(int level, struct frame *frm)
+{
+       read_local_oob_data_rp *rp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("hash 0x");
+               for (i = 0; i < 16; i++)
+                       printf("%02x", rp->hash[i]);
+               printf("\n");
+
+               p_indent(level, frm);
+               printf("randomizer 0x");
+               for (i = 0; i < 16; i++)
+                       printf("%02x", rp->randomizer[i]);
+               printf("\n");
+       }
+}
+
+static inline void read_local_version_dump(int level, struct frame *frm)
+{
+       read_local_version_rp *rp = frm->ptr;
+       uint16_t manufacturer = btohs(rp->manufacturer);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("HCI Version: %s (0x%x) HCI Revision: 0x%x\n",
+                                       hci_vertostr(rp->hci_ver),
+                                       rp->hci_ver, btohs(rp->hci_rev));
+               p_indent(level, frm);
+               printf("LMP Version: %s (0x%x) LMP Subversion: 0x%x\n",
+                                       lmp_vertostr(rp->lmp_ver),
+                                       rp->lmp_ver, btohs(rp->lmp_subver));
+               p_indent(level, frm);
+               printf("Manufacturer: %s (%d)\n",
+                               bt_compidtostr(manufacturer), manufacturer);
+       }
+}
+
+static inline void read_local_commands_dump(int level, struct frame *frm)
+{
+       read_local_commands_rp *rp = frm->ptr;
+       int i, max = 0;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               for (i = 0; i < 64; i++)
+                       if (rp->commands[i])
+                               max = i + 1;
+               p_indent(level, frm);
+               printf("Commands: ");
+               for (i = 0; i < (max > 32 ? 32 : max); i++)
+                       printf("%2.2x", rp->commands[i]);
+               printf("\n");
+               if (max > 32) {
+                       p_indent(level, frm);
+                       printf("          ");
+                       for (i = 32; i < max; i++)
+                               printf("%2.2x", rp->commands[i]);
+                       printf("\n");
+               }
+       }
+}
+
+static inline void read_local_features_dump(int level, struct frame *frm)
+{
+       read_local_features_rp *rp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("Features:");
+               for (i = 0; i < 8; i++)
+                       printf(" 0x%2.2x", rp->features[i]);
+               printf("\n");
+       }
+}
+
+static inline void read_local_ext_features_dump(int level, struct frame *frm)
+{
+       read_local_ext_features_rp *rp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x page %d max %d\n",
+               rp->status, rp->page_num, rp->max_page_num);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("Features:");
+               for (i = 0; i < 8; i++)
+                        printf(" 0x%2.2x", rp->features[i]);
+               printf("\n");
+       }
+}
+
+static inline void read_buffer_size_dump(int level, struct frame *frm)
+{
+       read_buffer_size_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x\n", rp->status);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("ACL MTU %d:%d SCO MTU %d:%d\n",
+                               btohs(rp->acl_mtu), btohs(rp->acl_max_pkt),
+                               rp->sco_mtu, btohs(rp->sco_max_pkt));
+       }
+}
+
+static inline void read_link_quality_dump(int level, struct frame *frm)
+{
+       read_link_quality_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d lq %d\n",
+                       rp->status, btohs(rp->handle), rp->link_quality);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_rssi_dump(int level, struct frame *frm)
+{
+       read_rssi_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d rssi %d\n",
+                               rp->status, btohs(rp->handle), rp->rssi);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_afh_map_dump(int level, struct frame *frm)
+{
+       read_afh_map_rp *rp = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d mode %d\n",
+                               rp->status, btohs(rp->handle), rp->mode);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("AFH map: 0x");
+               for (i = 0; i < 10; i++)
+                       printf("%2.2x", rp->map[i]);
+               printf("\n");
+       }
+}
+
+static inline void read_clock_dump(int level, struct frame *frm)
+{
+       read_clock_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d clock 0x%4.4x accuracy %d\n",
+                                       rp->status, btohs(rp->handle),
+                                       btohl(rp->clock), btohs(rp->accuracy));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void read_local_amp_info_dump(int level, struct frame *frm)
+{
+       read_local_amp_info_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x amp status 0x%2.2x\n",
+                       rp->status, rp->amp_status);
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               p_indent(level, frm);
+               printf("total bandwidth %d, max guaranteed bandwidth %d\n",
+                       btohl(rp->total_bandwidth),
+                       btohl(rp->max_guaranteed_bandwidth));
+               p_indent(level, frm);
+               printf("min latency %d, max PDU %d, controller type 0x%2.2x\n",
+                       btohl(rp->min_latency), btohl(rp->max_pdu_size),
+                       rp->controller_type);
+               p_indent(level, frm);
+               printf("pal caps 0x%4.4x, max assoc len %d\n",
+                       btohs(rp->pal_caps), btohs(rp->max_amp_assoc_length));
+               p_indent(level, frm);
+               printf("max flush timeout %d, best effort flush timeout %d\n",
+                       btohl(rp->max_flush_timeout),
+                       btohl(rp->best_effort_flush_timeout));
+       }
+}
+
+static inline void read_local_amp_assoc_dump(int level, struct frame *frm)
+{
+       read_local_amp_assoc_rp *rp = frm->ptr;
+       uint16_t len = btohs(rp->length);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle 0x%2.2x remaining len %d\n",
+                       rp->status, rp->handle, len);
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       } else {
+               amp_assoc_dump(level + 1, rp->fragment, len);
+       }
+}
+
+static inline void write_remote_amp_assoc_dump(int level, struct frame *frm)
+{
+       write_remote_amp_assoc_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle 0x%2.2x\n", rp->status, rp->handle);
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void le_read_buffer_size_response_dump(int level, struct frame *frm)
+{
+       le_read_buffer_size_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x pktlen 0x%4.4x maxpkt 0x%2.2x\n", rp->status,
+                       rp->pkt_len, rp->max_pkt);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void le_read_local_supported_features_dump(int level, struct frame *frm)
+{
+       int i;
+       le_read_local_supported_features_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x features 0x", rp->status);
+       for (i = 0; i < 8; i++)
+               printf("%2.2x", rp->features[i]);
+       printf(" (%s)\n", lefeatures2str(rp->features));
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void le_read_advertising_channel_tx_power_dump(int level, struct frame *frm)
+{
+       le_read_advertising_channel_tx_power_rp *rp = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x level 0x%x (dBm)\n", rp->status, rp->level);
+
+       if (rp->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(rp->status));
+       }
+}
+
+static inline void cmd_complete_dump(int level, struct frame *frm)
+{
+       evt_cmd_complete *evt = frm->ptr;
+       uint16_t opcode = btohs(evt->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+
+       if (ogf == OGF_VENDOR_CMD && (parser.flags & DUMP_NOVENDOR))
+               return;
+
+       p_indent(level, frm);
+       printf("%s (0x%2.2x|0x%4.4x) ncmd %d\n",
+                               opcode2str(opcode), ogf, ocf, evt->ncmd);
+
+       frm->ptr += EVT_CMD_COMPLETE_SIZE;
+       frm->len -= EVT_CMD_COMPLETE_SIZE;
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (ogf) {
+       case OGF_LINK_CTL:
+               switch (ocf) {
+               case OCF_INQUIRY_CANCEL:
+               case OCF_PERIODIC_INQUIRY:
+               case OCF_EXIT_PERIODIC_INQUIRY:
+               case OCF_READ_REMOTE_EXT_FEATURES:
+                       status_response_dump(level, frm);
+                       return;
+               case OCF_CREATE_CONN_CANCEL:
+               case OCF_REMOTE_NAME_REQ_CANCEL:
+               case OCF_PIN_CODE_REPLY:
+               case OCF_LINK_KEY_REPLY:
+               case OCF_PIN_CODE_NEG_REPLY:
+               case OCF_LINK_KEY_NEG_REPLY:
+               case OCF_USER_CONFIRM_REPLY:
+               case OCF_USER_CONFIRM_NEG_REPLY:
+               case OCF_USER_PASSKEY_REPLY:
+               case OCF_USER_PASSKEY_NEG_REPLY:
+               case OCF_REMOTE_OOB_DATA_REPLY:
+               case OCF_REMOTE_OOB_DATA_NEG_REPLY:
+               case OCF_IO_CAPABILITY_REPLY:
+               case OCF_IO_CAPABILITY_NEG_REPLY:
+                       bdaddr_response_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_LINK_POLICY:
+               switch (ocf) {
+               case OCF_READ_LINK_POLICY:
+                       read_link_policy_dump(level, frm);
+                       return;
+               case OCF_WRITE_LINK_POLICY:
+               case OCF_SNIFF_SUBRATING:
+                       generic_response_dump(level, frm);
+                       return;
+               case OCF_READ_DEFAULT_LINK_POLICY:
+                       read_default_link_policy_dump(level, frm);
+                       return;
+               case OCF_WRITE_DEFAULT_LINK_POLICY:
+                       status_response_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_HOST_CTL:
+               switch (ocf) {
+               case OCF_READ_PIN_TYPE:
+                       read_pin_type_dump(level, frm);
+                       return;
+               case OCF_READ_STORED_LINK_KEY:
+                       read_stored_link_key_dump(level, frm);
+                       return;
+               case OCF_WRITE_STORED_LINK_KEY:
+                       write_stored_link_key_dump(level, frm);
+                       return;
+               case OCF_DELETE_STORED_LINK_KEY:
+                       delete_stored_link_key_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_NAME:
+                       read_local_name_dump(level, frm);
+                       return;
+               case OCF_READ_CLASS_OF_DEV:
+                       read_class_of_dev_dump(level, frm);
+                       return;
+               case OCF_READ_VOICE_SETTING:
+                       read_voice_setting_dump(level, frm);
+                       return;
+               case OCF_READ_CURRENT_IAC_LAP:
+                       read_current_iac_lap_dump(level, frm);
+                       return;
+               case OCF_READ_SCAN_ENABLE:
+               case OCF_READ_AUTH_ENABLE:
+                       read_scan_enable_dump(level, frm);
+                       return;
+               case OCF_READ_CONN_ACCEPT_TIMEOUT:
+               case OCF_READ_PAGE_TIMEOUT:
+               case OCF_READ_LOGICAL_LINK_ACCEPT_TIMEOUT:
+                       read_page_timeout_dump(level, frm);
+                       return;
+               case OCF_READ_PAGE_ACTIVITY:
+               case OCF_READ_INQ_ACTIVITY:
+                       read_page_activity_dump(level, frm);
+                       return;
+               case OCF_READ_INQUIRY_SCAN_TYPE:
+                       read_inquiry_scan_type_dump(level, frm);
+                       return;
+               case OCF_READ_ENCRYPT_MODE:
+               case OCF_READ_INQUIRY_MODE:
+               case OCF_READ_AFH_MODE:
+                       read_inquiry_mode_dump(level, frm);
+                       return;
+               case OCF_READ_LINK_SUPERVISION_TIMEOUT:
+                       read_link_supervision_timeout_dump(level, frm);
+                       return;
+               case OCF_READ_TRANSMIT_POWER_LEVEL:
+                       read_transmit_power_level_dump(level, frm);
+                       return;
+               case OCF_READ_EXT_INQUIRY_RESPONSE:
+                       read_ext_inquiry_response_dump(level, frm);
+                       return;
+               case OCF_READ_INQUIRY_TRANSMIT_POWER_LEVEL:
+                       read_inquiry_transmit_power_level_dump(level, frm);
+                       return;
+               case OCF_READ_DEFAULT_ERROR_DATA_REPORTING:
+                       read_default_error_data_reporting_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_OOB_DATA:
+                       read_local_oob_data_dump(level, frm);
+                       return;
+               case OCF_READ_SIMPLE_PAIRING_MODE:
+               case OCF_READ_FLOW_CONTROL_MODE:
+                       status_mode_dump(level, frm);
+                       return;
+               case OCF_FLUSH:
+               case OCF_WRITE_LINK_SUPERVISION_TIMEOUT:
+                       generic_response_dump(level, frm);
+                       return;
+               case OCF_RESET:
+               case OCF_SET_EVENT_MASK:
+               case OCF_SET_EVENT_FLT:
+               case OCF_WRITE_PIN_TYPE:
+               case OCF_CREATE_NEW_UNIT_KEY:
+               case OCF_CHANGE_LOCAL_NAME:
+               case OCF_WRITE_CLASS_OF_DEV:
+               case OCF_WRITE_VOICE_SETTING:
+               case OCF_WRITE_CURRENT_IAC_LAP:
+               case OCF_WRITE_SCAN_ENABLE:
+               case OCF_WRITE_AUTH_ENABLE:
+               case OCF_WRITE_ENCRYPT_MODE:
+               case OCF_WRITE_CONN_ACCEPT_TIMEOUT:
+               case OCF_WRITE_PAGE_TIMEOUT:
+               case OCF_WRITE_PAGE_ACTIVITY:
+               case OCF_WRITE_INQ_ACTIVITY:
+               case OCF_WRITE_INQUIRY_SCAN_TYPE:
+               case OCF_WRITE_INQUIRY_MODE:
+               case OCF_WRITE_AFH_MODE:
+               case OCF_SET_AFH_CLASSIFICATION:
+               case OCF_WRITE_EXT_INQUIRY_RESPONSE:
+               case OCF_WRITE_SIMPLE_PAIRING_MODE:
+               case OCF_WRITE_INQUIRY_TRANSMIT_POWER_LEVEL:
+               case OCF_WRITE_DEFAULT_ERROR_DATA_REPORTING:
+               case OCF_SET_CONTROLLER_TO_HOST_FC:
+               case OCF_HOST_BUFFER_SIZE:
+               case OCF_REFRESH_ENCRYPTION_KEY:
+               case OCF_SEND_KEYPRESS_NOTIFY:
+               case OCF_WRITE_LOGICAL_LINK_ACCEPT_TIMEOUT:
+               case OCF_SET_EVENT_MASK_PAGE_2:
+               case OCF_WRITE_LOCATION_DATA:
+               case OCF_WRITE_FLOW_CONTROL_MODE:
+               case OCF_READ_BEST_EFFORT_FLUSH_TIMEOUT:
+               case OCF_WRITE_BEST_EFFORT_FLUSH_TIMEOUT:
+                       status_response_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_INFO_PARAM:
+               switch (ocf) {
+               case OCF_READ_LOCAL_VERSION:
+                       read_local_version_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_COMMANDS:
+                       read_local_commands_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_FEATURES:
+                       read_local_features_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_EXT_FEATURES:
+                       read_local_ext_features_dump(level, frm);
+                       return;
+               case OCF_READ_BUFFER_SIZE:
+                       read_buffer_size_dump(level, frm);
+                       return;
+               case OCF_READ_BD_ADDR:
+                       bdaddr_response_dump(level, frm);
+                       return;
+               case OCF_READ_DATA_BLOCK_SIZE:
+                       read_data_block_size_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_STATUS_PARAM:
+               switch (ocf) {
+               case OCF_READ_FAILED_CONTACT_COUNTER:
+               case OCF_RESET_FAILED_CONTACT_COUNTER:
+                       status_response_dump(level, frm);
+                       return;
+               case OCF_READ_LINK_QUALITY:
+                       read_link_quality_dump(level, frm);
+                       return;
+               case OCF_READ_RSSI:
+                       read_rssi_dump(level, frm);
+                       return;
+               case OCF_READ_AFH_MAP:
+                       read_afh_map_dump(level, frm);
+                       return;
+               case OCF_READ_CLOCK:
+                       read_clock_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_AMP_INFO:
+                       read_local_amp_info_dump(level, frm);
+                       return;
+               case OCF_READ_LOCAL_AMP_ASSOC:
+                       read_local_amp_assoc_dump(level, frm);
+                       return;
+               case OCF_WRITE_REMOTE_AMP_ASSOC:
+                       write_remote_amp_assoc_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_TESTING_CMD:
+               switch (ocf) {
+               case OCF_READ_LOOPBACK_MODE:
+                       status_mode_dump(level, frm);
+                       return;
+               case OCF_WRITE_LOOPBACK_MODE:
+               case OCF_ENABLE_DEVICE_UNDER_TEST_MODE:
+               case OCF_WRITE_SIMPLE_PAIRING_DEBUG_MODE:
+                       status_response_dump(level, frm);
+                       return;
+               }
+               break;
+
+       case OGF_LE_CTL:
+               switch (ocf) {
+               case OCF_LE_SET_EVENT_MASK:
+               case OCF_LE_SET_RANDOM_ADDRESS:
+               case OCF_LE_SET_ADVERTISING_PARAMETERS:
+               case OCF_LE_SET_ADVERTISING_DATA:
+               case OCF_LE_SET_SCAN_RESPONSE_DATA:
+               case OCF_LE_SET_ADVERTISE_ENABLE:
+               case OCF_LE_SET_SCAN_PARAMETERS:
+               case OCF_LE_SET_SCAN_ENABLE:
+               case OCF_LE_CREATE_CONN:
+               case OCF_LE_CLEAR_WHITE_LIST:
+               case OCF_LE_ADD_DEVICE_TO_WHITE_LIST:
+               case OCF_LE_REMOVE_DEVICE_FROM_WHITE_LIST:
+               case OCF_LE_SET_HOST_CHANNEL_CLASSIFICATION:
+               case OCF_LE_RECEIVER_TEST:
+               case OCF_LE_TRANSMITTER_TEST:
+                       status_response_dump(level, frm);
+                       return;
+               case OCF_LE_READ_BUFFER_SIZE:
+                       le_read_buffer_size_response_dump(level, frm);
+                       return;
+               case OCF_LE_READ_LOCAL_SUPPORTED_FEATURES:
+                       le_read_local_supported_features_dump(level, frm);
+                       return;
+               case OCF_LE_READ_ADVERTISING_CHANNEL_TX_POWER:
+                       le_read_advertising_channel_tx_power_dump(level, frm);
+                       return;
+               }
+               break;
+       }
+
+       raw_dump(level, frm);
+}
+
+static inline void cmd_status_dump(int level, struct frame *frm)
+{
+       evt_cmd_status *evt = frm->ptr;
+       uint16_t opcode = btohs(evt->opcode);
+       uint16_t ogf = cmd_opcode_ogf(opcode);
+       uint16_t ocf = cmd_opcode_ocf(opcode);
+
+       if (ogf == OGF_VENDOR_CMD && (parser.flags & DUMP_NOVENDOR))
+               return;
+
+       p_indent(level, frm);
+       printf("%s (0x%2.2x|0x%4.4x) status 0x%2.2x ncmd %d\n",
+                       opcode2str(opcode), ogf, ocf, evt->status, evt->ncmd);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void hardware_error_dump(int level, struct frame *frm)
+{
+       evt_hardware_error *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("code %d\n", evt->code);
+}
+
+static inline void inq_result_dump(int level, struct frame *frm)
+{
+       uint8_t num = get_u8(frm);
+       char addr[18];
+       int i;
+
+       for (i = 0; i < num; i++) {
+               inquiry_info *info = frm->ptr;
+
+               p_ba2str(&info->bdaddr, addr);
+
+               p_indent(level, frm);
+               printf("bdaddr %s mode %d clkoffset 0x%4.4x class 0x%2.2x%2.2x%2.2x\n",
+                       addr, info->pscan_rep_mode, btohs(info->clock_offset),
+                       info->dev_class[2], info->dev_class[1], info->dev_class[0]);
+
+               frm->ptr += INQUIRY_INFO_SIZE;
+               frm->len -= INQUIRY_INFO_SIZE;
+       }
+}
+
+static inline void conn_complete_dump(int level, struct frame *frm)
+{
+       evt_conn_complete *evt = frm->ptr;
+       char addr[18];
+
+       p_ba2str(&evt->bdaddr, addr);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d bdaddr %s type %s encrypt 0x%2.2x\n",
+                       evt->status, btohs(evt->handle), addr,
+                       linktype2str(evt->link_type), evt->encr_mode);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void conn_request_dump(int level, struct frame *frm)
+{
+       evt_conn_request *evt = frm->ptr;
+       char addr[18];
+
+       p_ba2str(&evt->bdaddr, addr);
+
+       p_indent(level, frm);
+       printf("bdaddr %s class 0x%2.2x%2.2x%2.2x type %s\n",
+                       addr, evt->dev_class[2], evt->dev_class[1],
+                       evt->dev_class[0], linktype2str(evt->link_type));
+}
+
+static inline void disconn_complete_dump(int level, struct frame *frm)
+{
+       evt_disconn_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d reason 0x%2.2x\n",
+                               evt->status, btohs(evt->handle), evt->reason);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else if (evt->reason > 0) {
+               p_indent(level, frm);
+               printf("Reason: %s\n", status2str(evt->reason));
+       }
+}
+
+static inline void remote_name_req_complete_dump(int level, struct frame *frm)
+{
+       evt_remote_name_req_complete *evt = frm->ptr;
+       char addr[18], name[249];
+       int i;
+
+       p_ba2str(&evt->bdaddr, addr);
+
+       memset(name, 0, sizeof(name));
+       for (i = 0; i < 248 && evt->name[i]; i++)
+               if (isprint(evt->name[i]))
+                       name[i] = evt->name[i];
+               else
+                       name[i] = '.';
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x bdaddr %s name '%s'\n", evt->status, addr, name);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void master_link_key_complete_dump(int level, struct frame *frm)
+{
+       evt_master_link_key_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d flag %d\n",
+                               evt->status, btohs(evt->handle), evt->key_flag);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void encrypt_change_dump(int level, struct frame *frm)
+{
+       evt_encrypt_change *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d encrypt 0x%2.2x\n",
+                               evt->status, btohs(evt->handle), evt->encrypt);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void read_remote_features_complete_dump(int level, struct frame *frm)
+{
+       evt_read_remote_features_complete *evt = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", evt->status, btohs(evt->handle));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Features:");
+               for (i = 0; i < 8; i++)
+                       printf(" 0x%2.2x", evt->features[i]);
+               printf("\n");
+       }
+}
+
+static inline void read_remote_version_complete_dump(int level, struct frame *frm)
+{
+       evt_read_remote_version_complete *evt = frm->ptr;
+       uint16_t manufacturer = btohs(evt->manufacturer);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", evt->status, btohs(evt->handle));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("LMP Version: %s (0x%x) LMP Subversion: 0x%x\n",
+                       lmp_vertostr(evt->lmp_ver), evt->lmp_ver,
+                       btohs(evt->lmp_subver));
+               p_indent(level, frm);
+               printf("Manufacturer: %s (%d)\n",
+                       bt_compidtostr(manufacturer), manufacturer);
+       }
+}
+
+static inline void qos_setup_complete_dump(int level, struct frame *frm)
+{
+       evt_qos_setup_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d flags %d\n",
+                               evt->status, btohs(evt->handle), evt->flags);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Service type: %d\n", evt->qos.service_type);
+               p_indent(level, frm);
+               printf("Token rate: %d\n", btohl(evt->qos.token_rate));
+               p_indent(level, frm);
+               printf("Peak bandwith: %d\n", btohl(evt->qos.peak_bandwidth));
+               p_indent(level, frm);
+               printf("Latency: %d\n", btohl(evt->qos.latency));
+               p_indent(level, frm);
+               printf("Delay variation: %d\n", btohl(evt->qos.delay_variation));
+       }
+}
+
+static inline void role_change_dump(int level, struct frame *frm)
+{
+       evt_role_change *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("status 0x%2.2x bdaddr %s role 0x%2.2x\n",
+                                               evt->status, addr, evt->role);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Role: %s\n", role2str(evt->role));
+       }
+}
+
+static inline void mode_change_dump(int level, struct frame *frm)
+{
+       evt_mode_change *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d mode 0x%2.2x interval %d\n",
+               evt->status, btohs(evt->handle), evt->mode, btohs(evt->interval));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Mode: %s\n", mode2str(evt->mode));
+       }
+}
+
+static inline void pin_code_req_dump(int level, struct frame *frm)
+{
+       evt_pin_code_req *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+}
+
+static inline void link_key_notify_dump(int level, struct frame *frm)
+{
+       evt_link_key_notify *evt = frm->ptr;
+       char addr[18];
+       int i;
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s key ", addr);
+       for (i = 0; i < 16; i++)
+               if (parser.flags & DUMP_NOVENDOR)
+                       printf("**");
+               else
+                       printf("%2.2X", evt->link_key[i]);
+       printf(" type %d\n", evt->key_type);
+
+       p_indent(level, frm);
+       printf("Type: %s\n", keytype2str(evt->key_type));
+}
+
+static inline void max_slots_change_dump(int level, struct frame *frm)
+{
+       evt_max_slots_change *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d slots %d\n", btohs(evt->handle), evt->max_slots);
+}
+
+static inline void data_buffer_overflow_dump(int level, struct frame *frm)
+{
+       evt_data_buffer_overflow *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("type %s\n", linktype2str(evt->link_type));
+}
+
+static inline void read_clock_offset_complete_dump(int level, struct frame *frm)
+{
+       evt_read_clock_offset_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d clkoffset 0x%4.4x\n",
+               evt->status, btohs(evt->handle), btohs(evt->clock_offset));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void conn_ptype_changed_dump(int level, struct frame *frm)
+{
+       evt_conn_ptype_changed *evt = frm->ptr;
+       uint16_t ptype = btohs(evt->ptype);
+       char *str;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d ptype 0x%4.4x\n",
+                               evt->status, btohs(evt->handle), ptype);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               str = hci_ptypetostr(ptype);
+               if (str) {
+                       p_indent(level, frm);
+                       printf("Packet type: %s\n", str);
+                       free(str);
+               }
+       }
+}
+
+static inline void pscan_rep_mode_change_dump(int level, struct frame *frm)
+{
+       evt_pscan_rep_mode_change *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s mode %d\n", addr, evt->pscan_rep_mode);
+}
+
+static inline void flow_spec_complete_dump(int level, struct frame *frm)
+{
+       evt_flow_spec_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle 0x%4.4x flags %d %s\n",
+                               evt->status, btohs(evt->handle), evt->flags,
+                               evt->direction == 0 ? "outgoing" : "incoming");
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Service type: %d\n", evt->qos.service_type);
+               p_indent(level, frm);
+               printf("Token rate: %d\n", btohl(evt->qos.token_rate));
+               p_indent(level, frm);
+               printf("Peak bandwith: %d\n", btohl(evt->qos.peak_bandwidth));
+               p_indent(level, frm);
+               printf("Latency: %d\n", btohl(evt->qos.latency));
+               p_indent(level, frm);
+               printf("Delay variation: %d\n", btohl(evt->qos.delay_variation));
+       }
+}
+
+static inline void inq_result_with_rssi_dump(int level, struct frame *frm)
+{
+       uint8_t num = get_u8(frm);
+       char addr[18];
+       int i;
+
+       if (!num)
+               return;
+
+       if (frm->len / num == INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE) {
+               for (i = 0; i < num; i++) {
+                       inquiry_info_with_rssi_and_pscan_mode *info = frm->ptr;
+
+                       p_indent(level, frm);
+
+                       p_ba2str(&info->bdaddr, addr);
+                       printf("bdaddr %s mode %d clkoffset 0x%4.4x class 0x%2.2x%2.2x%2.2x rssi %d\n",
+                               addr, info->pscan_rep_mode, btohs(info->clock_offset),
+                               info->dev_class[2], info->dev_class[1], info->dev_class[0], info->rssi);
+
+                       frm->ptr += INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
+                       frm->len -= INQUIRY_INFO_WITH_RSSI_AND_PSCAN_MODE_SIZE;
+               }
+       } else {
+               for (i = 0; i < num; i++) {
+                       inquiry_info_with_rssi *info = frm->ptr;
+
+                       p_indent(level, frm);
+
+                       p_ba2str(&info->bdaddr, addr);
+                       printf("bdaddr %s mode %d clkoffset 0x%4.4x class 0x%2.2x%2.2x%2.2x rssi %d\n",
+                               addr, info->pscan_rep_mode, btohs(info->clock_offset),
+                               info->dev_class[2], info->dev_class[1], info->dev_class[0], info->rssi);
+
+                       frm->ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
+                       frm->len -= INQUIRY_INFO_WITH_RSSI_SIZE;
+               }
+       }
+}
+
+static inline void read_remote_ext_features_complete_dump(int level, struct frame *frm)
+{
+       evt_read_remote_ext_features_complete *evt = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d page %d max %d\n",
+                                       evt->status, btohs(evt->handle),
+                                       evt->page_num, evt->max_page_num);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Features:");
+               for (i = 0; i < 8; i++)
+                       printf(" 0x%2.2x", evt->features[i]);
+               printf("\n");
+       }
+}
+
+static inline void sync_conn_complete_dump(int level, struct frame *frm)
+{
+       evt_sync_conn_complete *evt = frm->ptr;
+       char addr[18];
+
+       p_ba2str(&evt->bdaddr, addr);
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d bdaddr %s type %s\n",
+                                       evt->status, btohs(evt->handle), addr,
+                                       evt->link_type == 0 ? "SCO" : "eSCO");
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Air mode: %s\n", airmode2str(evt->air_mode));
+       }
+}
+
+static inline void sync_conn_changed_dump(int level, struct frame *frm)
+{
+       evt_sync_conn_changed *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", evt->status, btohs(evt->handle));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void sniff_subrating_event_dump(int level, struct frame *frm)
+{
+       evt_sniff_subrating *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", evt->status, btohs(evt->handle));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else {
+               p_indent(level, frm);
+               printf("max latency transmit %d receive %d\n",
+                                       btohs(evt->max_tx_latency),
+                                       btohs(evt->max_rx_latency));
+
+               p_indent(level, frm);
+               printf("min timeout remote %d local %d\n",
+                                       btohs(evt->min_remote_timeout),
+                                       btohs(evt->min_local_timeout));
+       }
+}
+
+static inline void extended_inq_result_dump(int level, struct frame *frm)
+{
+       uint8_t num = get_u8(frm);
+       char addr[18];
+       int i;
+
+       for (i = 0; i < num; i++) {
+               extended_inquiry_info *info = frm->ptr;
+
+               p_ba2str(&info->bdaddr, addr);
+
+               p_indent(level, frm);
+               printf("bdaddr %s mode %d clkoffset 0x%4.4x class 0x%2.2x%2.2x%2.2x rssi %d\n",
+                       addr, info->pscan_rep_mode, btohs(info->clock_offset),
+                       info->dev_class[2], info->dev_class[1], info->dev_class[0], info->rssi);
+
+               frm->ptr += INQUIRY_INFO_WITH_RSSI_SIZE;
+               frm->len -= INQUIRY_INFO_WITH_RSSI_SIZE;
+
+               ext_inquiry_response_dump(level, frm);
+       }
+}
+
+static inline void link_supervision_timeout_changed_dump(int level, struct frame *frm)
+{
+       evt_link_supervision_timeout_changed *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("handle %d timeout %d\n",
+                               btohs(evt->handle), btohs(evt->timeout));
+}
+
+static inline void user_passkey_notify_dump(int level, struct frame *frm)
+{
+       evt_user_passkey_notify *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s passkey %d\n", addr, btohl(evt->passkey));
+}
+
+static inline void keypress_notify_dump(int level, struct frame *frm)
+{
+       evt_keypress_notify *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s type %d\n", addr, evt->type);
+}
+
+static inline void remote_host_features_notify_dump(int level, struct frame *frm)
+{
+       evt_remote_host_features_notify *evt = frm->ptr;
+       char addr[18];
+       int i;
+
+       p_indent(level, frm);
+       p_ba2str(&evt->bdaddr, addr);
+       printf("bdaddr %s\n", addr);
+
+       p_indent(level, frm);
+       printf("Features:");
+       for (i = 0; i < 8; i++)
+               printf(" 0x%2.2x", evt->features[i]);
+       printf("\n");
+}
+
+static inline void evt_le_conn_complete_dump(int level, struct frame *frm)
+{
+       evt_le_connection_complete *evt = frm->ptr;
+       char addr[18];
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d, role %s\n",
+                                       evt->status, btohs(evt->handle),
+                                       evt->role ? "slave" : "master");
+
+       p_indent(level, frm);
+       p_ba2str(&evt->peer_bdaddr, addr);
+       printf("bdaddr %s (%s)\n", addr, bdaddrtype2str(evt->peer_bdaddr_type));
+}
+
+static inline void evt_le_advertising_report_dump(int level, struct frame *frm)
+{
+       uint8_t num_reports = get_u8(frm);
+       const uint8_t RSSI_SIZE = 1;
+
+       while (num_reports--) {
+               char addr[18];
+               le_advertising_info *info = frm->ptr;
+               int offset = 0;
+
+               p_ba2str(&info->bdaddr, addr);
+
+               p_indent(level, frm);
+               printf("%s (%d)\n", evttype2str(info->evt_type), info->evt_type);
+
+               p_indent(level, frm);
+               printf("bdaddr %s (%s)\n", addr,
+                                       bdaddrtype2str(info->bdaddr_type));
+
+               while (offset < info->length) {
+                       int eir_data_len = info->data[offset];
+
+                       ext_inquiry_data_dump(level, frm, &info->data[offset]);
+
+                       offset += eir_data_len + 1;
+               }
+
+               frm->ptr += LE_ADVERTISING_INFO_SIZE + info->length;
+               frm->len -= LE_ADVERTISING_INFO_SIZE + info->length;
+
+               p_indent(level, frm);
+               printf("RSSI: %d\n", ((int8_t *) frm->ptr)[frm->len - 1]);
+
+               frm->ptr += RSSI_SIZE;
+               frm->len -= RSSI_SIZE;
+       }
+}
+
+static inline void evt_le_conn_update_complete_dump(int level,
+                                                       struct frame *frm)
+{
+       evt_le_connection_update_complete *uevt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", uevt->status, btohs(uevt->handle));
+
+       p_indent(level, frm);
+       printf("interval %.2fms, latency %.2fms, superv. timeout %.2fms\n",
+                       btohs(uevt->interval) * 1.25, btohs(uevt->latency) * 1.25,
+                       btohs(uevt->supervision_timeout) * 10.0);
+}
+
+static inline void evt_le_read_remote_used_features_complete_dump(int level, struct frame *frm)
+{
+       int i;
+       evt_le_read_remote_used_features_complete *revt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle %d\n", revt->status, btohs(revt->handle));
+
+       if (revt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(revt->status));
+       } else {
+               p_indent(level, frm);
+               printf("Features:");
+               for (i = 0; i < 8; i++)
+                       printf(" 0x%2.2x", revt->features[i]);
+               printf("\n");
+       }
+}
+
+static inline void le_meta_ev_dump(int level, struct frame *frm)
+{
+       evt_le_meta_event *mevt = frm->ptr;
+       uint8_t subevent;
+
+       subevent = mevt->subevent;
+
+       frm->ptr += EVT_LE_META_EVENT_SIZE;
+       frm->len -= EVT_LE_META_EVENT_SIZE;
+
+       p_indent(level, frm);
+       printf("%s\n", ev_le_meta_str[subevent]);
+
+       switch (mevt->subevent) {
+       case EVT_LE_CONN_COMPLETE:
+               evt_le_conn_complete_dump(level + 1, frm);
+               break;
+       case EVT_LE_ADVERTISING_REPORT:
+               evt_le_advertising_report_dump(level + 1, frm);
+               break;
+       case EVT_LE_CONN_UPDATE_COMPLETE:
+               evt_le_conn_update_complete_dump(level + 1, frm);
+               break;
+       case EVT_LE_READ_REMOTE_USED_FEATURES_COMPLETE:
+               evt_le_read_remote_used_features_complete_dump(level + 1, frm);
+               break;
+       default:
+               raw_dump(level, frm);
+               break;
+       }
+}
+
+static inline void phys_link_complete_dump(int level, struct frame *frm)
+{
+       evt_physical_link_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x phy handle 0x%2.2x\n", evt->status, evt->handle);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void disconn_phys_link_complete_dump(int level, struct frame *frm)
+{
+       evt_disconn_physical_link_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle 0x%2.2x reason 0x%2.2x\n",
+                               evt->status, evt->handle, evt->reason);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       } else if (evt->reason > 0) {
+               p_indent(level, frm);
+               printf("Reason: %s\n", status2str(evt->reason));
+       }
+}
+
+static inline void phys_link_loss_warning_dump(int level, struct frame *frm)
+{
+       evt_physical_link_loss_warning *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("phy handle 0x%2.2x reason 0x%2.2x\n", evt->handle, evt->reason);
+}
+
+static inline void phys_link_handle_dump(int level, struct frame *frm)
+{
+       evt_physical_link_recovery *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("phy handle 0x%2.2x\n", evt->handle);
+}
+
+static inline void logical_link_complete_dump(int level, struct frame *frm)
+{
+       evt_logical_link_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x log handle 0x%4.4x phy handle 0x%2.2x"
+                                                       " tx_flow_id %d\n",
+                       evt->status, btohs(evt->log_handle), evt->handle,
+                       evt->tx_flow_id);
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void flow_spec_modify_dump(int level, struct frame *frm)
+{
+       evt_flow_spec_modify_complete *evt = frm->ptr;
+
+       p_indent(level, frm);
+       printf("status 0x%2.2x handle 0x%4.4x\n",
+                                       evt->status, btohs(evt->handle));
+
+       if (evt->status > 0) {
+               p_indent(level, frm);
+               printf("Error: %s\n", status2str(evt->status));
+       }
+}
+
+static inline void num_completed_blocks_dump(int level, struct frame *frm)
+{
+       evt_num_completed_blocks *evt = frm->ptr;
+       int i;
+
+       p_indent(level, frm);
+       printf("Total num blocks %d Num handles %d\n",
+                       btohs(evt->total_num_blocks), evt->num_handles);
+
+       for (i = 0; i < evt->num_handles; i++) {
+               cmplt_handle *h = &evt->handles[i];
+
+               p_indent(level + 1, frm);
+               printf("Handle 0x%4.4x: Num complt pkts %d Num complt blks %d\n",
+                               btohs(h->handle), btohs(h->num_cmplt_pkts),
+                               btohs(h->num_cmplt_blks));
+       }
+}
+
+static inline void event_dump(int level, struct frame *frm)
+{
+       hci_event_hdr *hdr = frm->ptr;
+       uint8_t event = hdr->evt;
+
+       if (p_filter(FILT_HCI))
+               return;
+
+       if (event <= EVENT_NUM) {
+               p_indent(level, frm);
+               printf("HCI Event: %s (0x%2.2x) plen %d\n",
+                                       event_str[hdr->evt], hdr->evt, hdr->plen);
+       } else if (hdr->evt == EVT_TESTING) {
+               p_indent(level, frm);
+               printf("HCI Event: Testing (0x%2.2x) plen %d\n", hdr->evt, hdr->plen);
+       } else if (hdr->evt == EVT_VENDOR) {
+               uint16_t manufacturer;
+
+               if (parser.flags & DUMP_NOVENDOR)
+                       return;
+
+               p_indent(level, frm);
+               printf("HCI Event: Vendor (0x%2.2x) plen %d\n", hdr->evt, hdr->plen);
+
+               manufacturer = get_manufacturer();
+
+               switch (manufacturer) {
+               case 0:
+               case 37:
+               case 48:
+                       frm->ptr += HCI_EVENT_HDR_SIZE;
+                       frm->len -= HCI_EVENT_HDR_SIZE;
+                       ericsson_dump(level + 1, frm);
+                       return;
+               case 10:
+                       frm->ptr += HCI_EVENT_HDR_SIZE;
+                       frm->len -= HCI_EVENT_HDR_SIZE;
+                       csr_dump(level + 1, frm);
+                       return;
+               }
+       } else {
+               p_indent(level, frm);
+               printf("HCI Event: code 0x%2.2x plen %d\n", hdr->evt, hdr->plen);
+       }
+
+       frm->ptr += HCI_EVENT_HDR_SIZE;
+       frm->len -= HCI_EVENT_HDR_SIZE;
+
+       if (event == EVT_CMD_COMPLETE) {
+               evt_cmd_complete *cc = frm->ptr;
+               if (cc->opcode == cmd_opcode_pack(OGF_INFO_PARAM, OCF_READ_LOCAL_VERSION)) {
+                       read_local_version_rp *rp = frm->ptr + EVT_CMD_COMPLETE_SIZE;
+                       manufacturer = rp->manufacturer;
+               }
+       }
+
+       if (event == EVT_DISCONN_COMPLETE) {
+               evt_disconn_complete *evt = frm->ptr;
+               l2cap_clear(btohs(evt->handle));
+       }
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (event) {
+       case EVT_LOOPBACK_COMMAND:
+               command_dump(level + 1, frm);
+               break;
+       case EVT_CMD_COMPLETE:
+               cmd_complete_dump(level + 1, frm);
+               break;
+       case EVT_CMD_STATUS:
+               cmd_status_dump(level + 1, frm);
+               break;
+       case EVT_HARDWARE_ERROR:
+               hardware_error_dump(level + 1, frm);
+               break;
+       case EVT_FLUSH_OCCURRED:
+       case EVT_QOS_VIOLATION:
+               handle_response_dump(level + 1, frm);
+               break;
+       case EVT_INQUIRY_COMPLETE:
+               status_response_dump(level + 1, frm);
+               break;
+       case EVT_INQUIRY_RESULT:
+               inq_result_dump(level + 1, frm);
+               break;
+       case EVT_CONN_COMPLETE:
+               conn_complete_dump(level + 1, frm);
+               break;
+       case EVT_CONN_REQUEST:
+               conn_request_dump(level + 1, frm);
+               break;
+       case EVT_DISCONN_COMPLETE:
+       case EVT_DISCONNECT_LOGICAL_LINK_COMPLETE:
+               disconn_complete_dump(level + 1, frm);
+               break;
+       case EVT_AUTH_COMPLETE:
+       case EVT_CHANGE_CONN_LINK_KEY_COMPLETE:
+               generic_response_dump(level + 1, frm);
+               break;
+       case EVT_MASTER_LINK_KEY_COMPLETE:
+               master_link_key_complete_dump(level + 1, frm);
+               break;
+       case EVT_REMOTE_NAME_REQ_COMPLETE:
+               remote_name_req_complete_dump(level + 1, frm);
+               break;
+       case EVT_ENCRYPT_CHANGE:
+               encrypt_change_dump(level + 1, frm);
+               break;
+       case EVT_READ_REMOTE_FEATURES_COMPLETE:
+               read_remote_features_complete_dump(level + 1, frm);
+               break;
+       case EVT_READ_REMOTE_VERSION_COMPLETE:
+               read_remote_version_complete_dump(level + 1, frm);
+               break;
+       case EVT_QOS_SETUP_COMPLETE:
+               qos_setup_complete_dump(level + 1, frm);
+               break;
+       case EVT_ROLE_CHANGE:
+               role_change_dump(level + 1, frm);
+               break;
+       case EVT_NUM_COMP_PKTS:
+               num_comp_pkts_dump(level + 1, frm);
+               break;
+       case EVT_MODE_CHANGE:
+               mode_change_dump(level + 1, frm);
+               break;
+       case EVT_RETURN_LINK_KEYS:
+               return_link_keys_dump(level + 1, frm);
+               break;
+       case EVT_PIN_CODE_REQ:
+       case EVT_LINK_KEY_REQ:
+       case EVT_IO_CAPABILITY_REQUEST:
+       case EVT_USER_PASSKEY_REQUEST:
+       case EVT_REMOTE_OOB_DATA_REQUEST:
+               pin_code_req_dump(level + 1, frm);
+               break;
+       case EVT_LINK_KEY_NOTIFY:
+               link_key_notify_dump(level + 1, frm);
+               break;
+       case EVT_DATA_BUFFER_OVERFLOW:
+               data_buffer_overflow_dump(level + 1, frm);
+               break;
+       case EVT_MAX_SLOTS_CHANGE:
+               max_slots_change_dump(level + 1, frm);
+               break;
+       case EVT_READ_CLOCK_OFFSET_COMPLETE:
+               read_clock_offset_complete_dump(level + 1, frm);
+               break;
+       case EVT_CONN_PTYPE_CHANGED:
+               conn_ptype_changed_dump(level + 1, frm);
+               break;
+       case EVT_PSCAN_REP_MODE_CHANGE:
+               pscan_rep_mode_change_dump(level + 1, frm);
+               break;
+       case EVT_FLOW_SPEC_COMPLETE:
+               flow_spec_complete_dump(level + 1, frm);
+               break;
+       case EVT_INQUIRY_RESULT_WITH_RSSI:
+               inq_result_with_rssi_dump(level + 1, frm);
+               break;
+       case EVT_READ_REMOTE_EXT_FEATURES_COMPLETE:
+               read_remote_ext_features_complete_dump(level + 1, frm);
+               break;
+       case EVT_SYNC_CONN_COMPLETE:
+               sync_conn_complete_dump(level + 1, frm);
+               break;
+       case EVT_SYNC_CONN_CHANGED:
+               sync_conn_changed_dump(level + 1, frm);
+               break;
+       case EVT_SNIFF_SUBRATING:
+               sniff_subrating_event_dump(level + 1, frm);
+               break;
+       case EVT_EXTENDED_INQUIRY_RESULT:
+               extended_inq_result_dump(level + 1, frm);
+               break;
+       case EVT_ENCRYPTION_KEY_REFRESH_COMPLETE:
+               generic_response_dump(level + 1, frm);
+               break;
+       case EVT_SIMPLE_PAIRING_COMPLETE:
+               bdaddr_response_dump(level + 1, frm);
+               break;
+       case EVT_LINK_SUPERVISION_TIMEOUT_CHANGED:
+               link_supervision_timeout_changed_dump(level + 1, frm);
+               break;
+       case EVT_ENHANCED_FLUSH_COMPLETE:
+               generic_command_dump(level + 1, frm);
+               break;
+       case EVT_IO_CAPABILITY_RESPONSE:
+               io_capability_reply_dump(level + 1, frm);
+               break;
+       case EVT_USER_CONFIRM_REQUEST:
+       case EVT_USER_PASSKEY_NOTIFY:
+               user_passkey_notify_dump(level + 1, frm);
+               break;
+       case EVT_KEYPRESS_NOTIFY:
+               keypress_notify_dump(level + 1, frm);
+               break;
+       case EVT_REMOTE_HOST_FEATURES_NOTIFY:
+               remote_host_features_notify_dump(level + 1, frm);
+               break;
+       case EVT_LE_META_EVENT:
+               le_meta_ev_dump(level + 1, frm);
+               break;
+       case EVT_PHYSICAL_LINK_COMPLETE:
+               phys_link_complete_dump(level + 1, frm);
+               break;
+       case EVT_DISCONNECT_PHYSICAL_LINK_COMPLETE:
+               disconn_phys_link_complete_dump(level + 1, frm);
+               break;
+       case EVT_PHYSICAL_LINK_LOSS_EARLY_WARNING:
+               phys_link_loss_warning_dump(level + 1, frm);
+               break;
+       case EVT_PHYSICAL_LINK_RECOVERY:
+       case EVT_CHANNEL_SELECTED:
+               phys_link_handle_dump(level + 1, frm);
+               break;
+       case EVT_LOGICAL_LINK_COMPLETE:
+               logical_link_complete_dump(level + 1, frm);
+               break;
+       case EVT_FLOW_SPEC_MODIFY_COMPLETE:
+               flow_spec_modify_dump(level + 1, frm);
+               break;
+       case EVT_NUMBER_COMPLETED_BLOCKS:
+               num_completed_blocks_dump(level + 1, frm);
+               break;
+       default:
+               raw_dump(level, frm);
+               break;
+       }
+}
+
+static inline void acl_dump(int level, struct frame *frm)
+{
+       hci_acl_hdr *hdr = (void *) frm->ptr;
+       uint16_t handle = btohs(hdr->handle);
+       uint16_t dlen = btohs(hdr->dlen);
+       uint8_t flags = acl_flags(handle);
+
+       if (!p_filter(FILT_HCI)) {
+               p_indent(level, frm);
+               printf("ACL data: handle %d flags 0x%2.2x dlen %d\n",
+                       acl_handle(handle), flags, dlen);
+               level++;
+       }
+
+       frm->ptr += HCI_ACL_HDR_SIZE;
+       frm->len -= HCI_ACL_HDR_SIZE;
+       frm->flags  = flags;
+       frm->handle = acl_handle(handle);
+
+       if (parser.filter & ~FILT_HCI)
+               l2cap_dump(level, frm);
+       else
+               raw_dump(level, frm);
+}
+
+static inline void sco_dump(int level, struct frame *frm)
+{
+       hci_sco_hdr *hdr = (void *) frm->ptr;
+       uint16_t handle = btohs(hdr->handle);
+       uint8_t flags = acl_flags(handle);
+       int len;
+
+       if (frm->audio_fd > fileno(stderr)) {
+               len = write(frm->audio_fd, frm->ptr + HCI_SCO_HDR_SIZE, hdr->dlen);
+               if (len < 0)
+                       return;
+       }
+
+       if (!p_filter(FILT_SCO)) {
+               p_indent(level, frm);
+               printf("SCO data: handle %d flags 0x%2.2x dlen %d\n",
+                               acl_handle(handle), flags, hdr->dlen);
+               level++;
+
+               frm->ptr += HCI_SCO_HDR_SIZE;
+               frm->len -= HCI_SCO_HDR_SIZE;
+               raw_dump(level, frm);
+       }
+}
+
+static inline void vendor_dump(int level, struct frame *frm)
+{
+       if (p_filter(FILT_HCI))
+               return;
+
+       if (frm->dev_id == HCI_DEV_NONE) {
+               uint16_t device = btohs(htons(get_u16(frm)));
+               uint16_t proto = btohs(htons(get_u16(frm)));
+               uint16_t type = btohs(htons(get_u16(frm)));
+               uint16_t plen = btohs(htons(get_u16(frm)));
+
+               p_indent(level, frm);
+
+               printf("System %s: device hci%d proto 0x%2.2x type 0x%2.2x plen %d\n",
+                       frm->in ? "event" : "command", device, proto, type, plen);
+
+               raw_dump(level, frm);
+               return;
+       }
+
+       if (parser.flags & DUMP_NOVENDOR)
+               return;
+
+       if (get_manufacturer() == 12) {
+               bpa_dump(level, frm);
+               return;
+       }
+
+       p_indent(level, frm);
+       printf("Vendor data: len %d\n", frm->len);
+       raw_dump(level, frm);
+}
+
+void hci_dump(int level, struct frame *frm)
+{
+       uint8_t type = *(uint8_t *)frm->ptr;
+
+       frm->ptr++; frm->len--;
+
+       switch (type) {
+       case HCI_COMMAND_PKT:
+               command_dump(level, frm);
+               break;
+
+       case HCI_EVENT_PKT:
+               event_dump(level, frm);
+               break;
+
+       case HCI_ACLDATA_PKT:
+               acl_dump(level, frm);
+               break;
+
+       case HCI_SCODATA_PKT:
+               sco_dump(level, frm);
+               break;
+
+       case HCI_VENDOR_PKT:
+               vendor_dump(level, frm);
+               break;
+
+       default:
+               if (p_filter(FILT_HCI))
+                       break;
+
+               p_indent(level, frm);
+               printf("Unknown: type 0x%2.2x len %d\n", type, frm->len);
+               raw_dump(level, frm);
+               break;
+       }
+}
diff --git a/tools/parser/hcrp.c b/tools/parser/hcrp.c
new file mode 100644 (file)
index 0000000..0a16a22
--- /dev/null
@@ -0,0 +1,113 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+static char *pid2str(uint16_t pid)
+{
+       switch (pid) {
+       case 0x0001:
+               return "CreditGrant";
+       case 0x0002:
+               return "CreditRequest";
+       case 0x0003:
+               return "CreditReturn";
+       case 0x0004:
+               return "CreditQuery";
+       case 0x0005:
+               return "GetLPTStatus";
+       case 0x0006:
+               return "Get1284ID";
+       case 0x0007:
+               return "SoftReset";
+       case 0x0008:
+               return "HardRest";
+       case 0x0009:
+               return "RegisterNotification";
+       case 0x000A:
+               return "NotificationConnectionAlive";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *status2str(uint16_t status)
+{
+       switch (status) {
+       case 0x0000:
+               return "Feature unsupported";
+       case 0x0001:
+               return "Success";
+       case 0x0002:
+               return "Credit synchronization error";
+       case 0xFFFF:
+               return "Generic error";
+       default:
+               return "Unknown";
+       }
+}
+
+void hcrp_dump(int level, struct frame *frm)
+{
+       uint16_t pid, tid, plen, status;
+       uint32_t credits;
+
+       pid = get_u16(frm);
+       tid = get_u16(frm);
+       plen = get_u16(frm);
+
+       p_indent(level, frm);
+
+       printf("HCRP %s %s: tid 0x%x plen %d",
+                       pid2str(pid), frm->in ? "rsp" : "cmd",  tid, plen);
+
+       if (frm->in) {
+               status = get_u16(frm);
+               printf(" status %d (%s)\n", status, status2str(status));
+       } else
+               printf("\n");
+
+       if (pid == 0x0001 && !frm->in) {
+               credits = get_u32(frm);
+               p_indent(level + 1, frm);
+               printf("credits %d\n", credits);
+       }
+
+       if (pid == 0x0002 && frm->in) {
+               credits = get_u32(frm);
+               p_indent(level + 1, frm);
+               printf("credits %d\n", credits);
+       }
+
+       raw_dump(level + 1, frm);
+}
diff --git a/tools/parser/hidp.c b/tools/parser/hidp.c
new file mode 100644 (file)
index 0000000..6039eb9
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+static char *type2str(uint8_t head)
+{
+       switch (head & 0xf0) {
+       case 0x00:
+               return "Handshake";
+       case 0x10:
+               return "Control";
+       case 0x40:
+               return "Get report";
+       case 0x50:
+               return "Set report";
+       case 0x60:
+               return "Get protocol";
+       case 0x70:
+               return "Set protocol";
+       case 0x80:
+               return "Get idle";
+       case 0x90:
+               return "Set idle";
+       case 0xa0:
+               return "Data";
+       case 0xb0:
+               return "Data continuation";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *result2str(uint8_t head)
+{
+       switch (head & 0x0f) {
+       case 0x00:
+               return "Successful";
+       case 0x01:
+               return "Not ready";
+       case 0x02:
+               return "Invalid report ID";
+       case 0x03:
+               return "Unsupported request";
+       case 0x04:
+               return "Invalid parameter";
+       case 0x0e:
+               return "Unknown";
+       case 0x0f:
+               return "Fatal";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *operation2str(uint8_t head)
+{
+       switch (head & 0x0f) {
+       case 0x00:
+               return "No operation";
+       case 0x01:
+               return "Hard reset";
+       case 0x02:
+               return "Soft reset";
+       case 0x03:
+               return "Suspend";
+       case 0x04:
+               return "Exit suspend";
+       case 0x05:
+               return "Virtual cable unplug";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *report2str(uint8_t head)
+{
+       switch (head & 0x03) {
+       case 0x00:
+               return "Other report";
+       case 0x01:
+               return "Input report";
+       case 0x02:
+               return "Output report";
+       case 0x03:
+               return "Feature report";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *protocol2str(uint8_t head)
+{
+       switch (head & 0x01) {
+       case 0x00:
+               return "Boot protocol";
+       case 0x01:
+               return "Report protocol";
+       default:
+               return "Reserved";
+       }
+}
+
+void hidp_dump(int level, struct frame *frm)
+{
+       uint8_t hdr;
+       char *param;
+
+       hdr = get_u8(frm);
+
+       switch (hdr & 0xf0) {
+       case 0x00:
+               param = result2str(hdr);
+               break;
+       case 0x10:
+               param = operation2str(hdr);
+               break;
+       case 0x60:
+       case 0x70:
+               param = protocol2str(hdr);
+               break;
+       case 0x40:
+       case 0x50:
+       case 0xa0:
+       case 0xb0:
+               param = report2str(hdr);
+               break;
+       default:
+               param = "";
+               break;
+       }
+
+       p_indent(level, frm);
+
+       printf("HIDP: %s: %s\n", type2str(hdr), param);
+
+       raw_dump(level, frm);
+}
diff --git a/tools/parser/l2cap.c b/tools/parser/l2cap.c
new file mode 100644 (file)
index 0000000..f0fb78b
--- /dev/null
@@ -0,0 +1,1635 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+#include <inttypes.h>
+
+#include "parser.h"
+#include "sdp.h"
+#include "l2cap.h"
+#include "lib/hci.h"
+#include "lib/a2mp.h"
+#include "lib/amp.h"
+
+typedef struct {
+       uint16_t handle;
+       struct frame frm;
+} handle_info;
+#define HANDLE_TABLE_SIZE 10
+
+static handle_info handle_table[HANDLE_TABLE_SIZE];
+
+typedef struct {
+       uint16_t handle;
+       uint16_t cid;
+       uint16_t psm;
+       uint16_t num;
+       uint8_t mode;
+       uint8_t ext_ctrl;
+} cid_info;
+#define CID_TABLE_SIZE 20
+
+static cid_info cid_table[2][CID_TABLE_SIZE];
+
+#define SCID cid_table[0]
+#define DCID cid_table[1]
+
+/* Can we move this to l2cap.h? */
+struct features {
+       char    *name;
+       int     flag;
+};
+
+static struct features l2cap_features[] = {
+       { "Flow control mode",                  L2CAP_FEAT_FLOWCTL      },
+       { "Retransmission mode",                L2CAP_FEAT_RETRANS      },
+       { "Bi-directional QoS",                 L2CAP_FEAT_BIDIR_QOS    },
+       { "Enhanced Retransmission mode",       L2CAP_FEAT_ERTM         },
+       { "Streaming mode",                     L2CAP_FEAT_STREAMING    },
+       { "FCS Option",                         L2CAP_FEAT_FCS          },
+       { "Extended Flow Specification",        L2CAP_FEAT_EXT_FLOW     },
+       { "Fixed Channels",                     L2CAP_FEAT_FIXED_CHAN   },
+       { "Extended Window Size",               L2CAP_FEAT_EXT_WINDOW   },
+       { "Unicast Connectless Data Reception", L2CAP_FEAT_UCD          },
+       { 0 }
+};
+
+static struct features l2cap_fix_chan[] = {
+       { "L2CAP Signalling Channel",           L2CAP_FC_L2CAP          },
+       { "L2CAP Connless",                     L2CAP_FC_CONNLESS       },
+       { "AMP Manager Protocol",               L2CAP_FC_A2MP           },
+       { 0 }
+};
+
+static struct frame *add_handle(uint16_t handle)
+{
+       register handle_info *t = handle_table;
+       register int i;
+
+       for (i = 0; i < HANDLE_TABLE_SIZE; i++)
+               if (!t[i].handle) {
+                       t[i].handle = handle;
+                       return &t[i].frm;
+               }
+       return NULL;
+}
+
+static struct frame *get_frame(uint16_t handle)
+{
+       register handle_info *t = handle_table;
+       register int i;
+
+       for (i = 0; i < HANDLE_TABLE_SIZE; i++)
+               if (t[i].handle == handle)
+                       return &t[i].frm;
+
+       return add_handle(handle);
+}
+
+static void add_cid(int in, uint16_t handle, uint16_t cid, uint16_t psm)
+{
+       register cid_info *table = cid_table[in];
+       register int i, pos = -1;
+       uint16_t num = 1;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++) {
+               if ((pos < 0 && !table[i].cid) || table[i].cid == cid)
+                       pos = i;
+               if (table[i].psm == psm)
+                       num++;
+       }
+
+       if (pos >= 0) {
+               table[pos].handle = handle;
+               table[pos].cid    = cid;
+               table[pos].psm    = psm;
+               table[pos].num    = num;
+               table[pos].mode   = 0;
+       }
+}
+
+static void del_cid(int in, uint16_t dcid, uint16_t scid)
+{
+       register int t, i;
+       uint16_t cid[2];
+
+       if (!in) {
+               cid[0] = dcid;
+               cid[1] = scid;
+       } else {
+               cid[0] = scid;
+               cid[1] = dcid;
+       }
+
+       for (t = 0; t < 2; t++) {
+               for (i = 0; i < CID_TABLE_SIZE; i++)
+                       if (cid_table[t][i].cid == cid[t]) {
+                               cid_table[t][i].handle = 0;
+                               cid_table[t][i].cid    = 0;
+                               cid_table[t][i].psm    = 0;
+                               cid_table[t][i].num    = 0;
+                               cid_table[t][i].mode   = 0;
+                               break;
+                       }
+       }
+}
+
+static void del_handle(uint16_t handle)
+{
+       register int t, i;
+
+       for (t = 0; t < 2; t++) {
+               for (i = 0; i < CID_TABLE_SIZE; i++)
+                       if (cid_table[t][i].handle == handle) {
+                               cid_table[t][i].handle = 0;
+                               cid_table[t][i].cid    = 0;
+                               cid_table[t][i].psm    = 0;
+                               cid_table[t][i].num    = 0;
+                               cid_table[t][i].mode   = 0;
+                               break;
+                       }
+       }
+}
+static uint16_t get_psm(int in, uint16_t handle, uint16_t cid)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       return table[i].psm;
+       return parser.defpsm;
+}
+
+static uint16_t get_num(int in, uint16_t handle, uint16_t cid)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       return table[i].num;
+       return 0;
+}
+
+static void set_mode(int in, uint16_t handle, uint16_t cid, uint8_t mode)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       table[i].mode = mode;
+}
+
+static uint8_t get_mode(int in, uint16_t handle, uint16_t cid)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       return table[i].mode;
+       return 0;
+}
+
+static void set_ext_ctrl(int in, uint16_t handle, uint16_t cid,
+                                                       uint8_t ext_ctrl)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       table[i].ext_ctrl = ext_ctrl;
+}
+
+static uint8_t get_ext_ctrl(int in, uint16_t handle, uint16_t cid)
+{
+       register cid_info *table = cid_table[in];
+       register int i;
+
+       for (i = 0; i < CID_TABLE_SIZE; i++)
+               if (table[i].handle == handle && table[i].cid == cid)
+                       return table[i].ext_ctrl;
+       return 0;
+}
+
+static uint32_t get_val(uint8_t *ptr, uint8_t len)
+{
+       switch (len) {
+       case 1:
+               return *ptr;
+       case 2:
+               return bt_get_le16(ptr);
+       case 4:
+               return bt_get_le32(ptr);
+       }
+       return 0;
+}
+
+static char *reason2str(uint16_t reason)
+{
+       switch (reason) {
+       case 0x0000:
+               return "Command not understood";
+       case 0x0001:
+               return "Signalling MTU exceeded";
+       case 0x0002:
+               return "Invalid CID in request";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *a2mpreason2str(uint16_t reason)
+{
+       switch (reason) {
+       case A2MP_COMMAND_NOT_RECOGNIZED:
+               return "Command not recognized";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *connresult2str(uint16_t result)
+{
+       switch (result) {
+       case 0x0000:
+               return "Connection successful";
+       case 0x0001:
+               return "Connection pending";
+       case 0x0002:
+               return "Connection refused - PSM not supported";
+       case 0x0003:
+               return "Connection refused - security block";
+       case 0x0004:
+               return "Connection refused - no resources available";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *status2str(uint16_t status)
+{
+       switch (status) {
+       case 0x0000:
+               return "No futher information available";
+       case 0x0001:
+               return "Authentication pending";
+       case 0x0002:
+               return "Authorization pending";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *confresult2str(uint16_t result)
+{
+       switch (result) {
+       case L2CAP_CONF_SUCCESS:
+               return "Success";
+       case L2CAP_CONF_UNACCEPT:
+               return "Failure - unacceptable parameters";
+       case L2CAP_CONF_REJECT:
+               return "Failure - rejected (no reason provided)";
+       case L2CAP_CONF_UNKNOWN:
+               return "Failure - unknown options";
+       case L2CAP_CONF_PENDING:
+               return "Pending";
+       case L2CAP_CONF_EFS_REJECT:
+               return "Failure - flowspec reject";
+       default:
+               return "Reserved";
+       }
+}
+static char *inforesult2str(uint16_t result)
+{
+       switch (result) {
+       case 0x0000:
+               return "Success";
+       case 0x0001:
+               return "Not supported";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *type2str(uint8_t type)
+{
+       switch (type) {
+       case L2CAP_SERVTYPE_NOTRAFFIC:
+               return "No traffic";
+       case L2CAP_SERVTYPE_BESTEFFORT:
+               return "Best Effort";
+       case L2CAP_SERVTYPE_GUARANTEED:
+               return "Guaranteed";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *mode2str(uint8_t mode)
+{
+       switch (mode) {
+       case 0x00:
+               return "Basic";
+       case 0x01:
+               return "Retransmission";
+       case 0x02:
+               return "Flow control";
+       case 0x03:
+               return "Enhanced Retransmission";
+       case 0x04:
+               return "Streaming";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *fcs2str(uint8_t fcs)
+{
+       switch (fcs) {
+       case 0x00:
+               return "No FCS";
+       case 0x01:
+               return "CRC16 Check";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *sar2str(uint8_t sar)
+{
+       switch (sar) {
+       case L2CAP_SAR_UNSEGMENTED:
+               return "Unsegmented";
+       case L2CAP_SAR_START:
+               return "Start";
+       case L2CAP_SAR_END:
+               return "End";
+       case L2CAP_SAR_CONTINUE:
+               return "Continuation";
+       default:
+               return "Bad SAR";
+
+       }
+}
+
+static char *supervisory2str(uint8_t supervisory)
+{
+       switch (supervisory) {
+       case L2CAP_SUPER_RR:
+               return "Receiver Ready (RR)";
+       case L2CAP_SUPER_REJ:
+               return "Reject (REJ)";
+       case L2CAP_SUPER_RNR:
+               return "Receiver Not Ready (RNR)";
+       case L2CAP_SUPER_SREJ:
+               return "Select Reject (SREJ)";
+       default:
+               return "Bad Supervisory";
+       }
+}
+
+static char *ampctrltype2str(uint8_t type)
+{
+       switch (type) {
+       case HCI_BREDR:
+               return "BR-EDR";
+       case HCI_AMP:
+               return "802.11 AMP";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *ampctrlstatus2str(uint8_t status)
+{
+       switch (status) {
+       case AMP_CTRL_POWERED_DOWN:
+               return "Powered down";
+       case AMP_CTRL_BLUETOOTH_ONLY:
+               return "Bluetooth only";
+       case AMP_CTRL_NO_CAPACITY:
+               return "No capacity";
+       case AMP_CTRL_LOW_CAPACITY:
+               return "Low capacity";
+       case AMP_CTRL_MEDIUM_CAPACITY:
+               return "Medium capacity";
+       case AMP_CTRL_HIGH_CAPACITY:
+               return "High capacity";
+       case AMP_CTRL_FULL_CAPACITY:
+               return "Full capacity";
+       default:
+               return "Reserved";
+
+       }
+}
+
+static char *a2mpstatus2str(uint8_t status)
+{
+       switch (status) {
+       case A2MP_STATUS_SUCCESS:
+               return "Success";
+       case A2MP_STATUS_INVALID_CTRL_ID:
+               return "Invalid Controller ID";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *a2mpcplstatus2str(uint8_t status)
+{
+       switch (status) {
+       case A2MP_STATUS_SUCCESS:
+               return "Success";
+       case A2MP_STATUS_INVALID_CTRL_ID:
+               return "Invalid Controller ID";
+       case A2MP_STATUS_UNABLE_START_LINK_CREATION:
+               return "Failed - Unable to start link creation";
+       case A2MP_STATUS_COLLISION_OCCURED:
+               return "Failed - Collision occured";
+       case A2MP_STATUS_DISCONN_REQ_RECVD:
+               return "Failed - Disconnect physical link received";
+       case A2MP_STATUS_PHYS_LINK_EXISTS:
+               return "Failed - Physical link already exists";
+       case A2MP_STATUS_SECURITY_VIOLATION:
+               return "Failed - Security violation";
+       default:
+               return "Reserved";
+       }
+}
+
+static char *a2mpdplstatus2str(uint8_t status)
+{
+       switch (status) {
+       case A2MP_STATUS_SUCCESS:
+               return "Success";
+       case A2MP_STATUS_INVALID_CTRL_ID:
+               return "Invalid Controller ID";
+       case A2MP_STATUS_NO_PHYSICAL_LINK_EXISTS:
+               return "Failed - No Physical Link exists";
+       default:
+               return "Reserved";
+       }
+}
+
+static inline void command_rej(int level, struct frame *frm)
+{
+       l2cap_cmd_rej *h = frm->ptr;
+       uint16_t reason = btohs(h->reason);
+       uint32_t cid;
+
+       printf("Command rej: reason %d", reason);
+
+       switch (reason) {
+       case 0x0001:
+               printf(" mtu %d\n", get_val(frm->ptr + L2CAP_CMD_REJ_SIZE, 2));
+               break;
+       case 0x0002:
+               cid = get_val(frm->ptr + L2CAP_CMD_REJ_SIZE, 4);
+               printf(" dcid 0x%4.4x scid 0x%4.4x\n", cid & 0xffff, cid >> 16);
+               break;
+       default:
+               printf("\n");
+               break;
+       }
+
+       p_indent(level + 1, frm);
+       printf("%s\n", reason2str(reason));
+}
+
+static inline void conn_req(int level, struct frame *frm)
+{
+       l2cap_conn_req *h = frm->ptr;
+       uint16_t psm = btohs(h->psm);
+       uint16_t scid = btohs(h->scid);
+
+       add_cid(frm->in, frm->handle, scid, psm);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Connect req: psm %d scid 0x%4.4x\n", psm, scid);
+}
+
+static inline void conn_rsp(int level, struct frame *frm)
+{
+       l2cap_conn_rsp *h = frm->ptr;
+       uint16_t scid = btohs(h->scid);
+       uint16_t dcid = btohs(h->dcid);
+       uint16_t result = btohs(h->result);
+       uint16_t status = btohs(h->status);
+       uint16_t psm;
+
+       switch (h->result) {
+       case L2CAP_CR_SUCCESS:
+               if ((psm = get_psm(!frm->in, frm->handle, scid)))
+                       add_cid(frm->in, frm->handle, dcid, psm);
+               break;
+
+       case L2CAP_CR_PEND:
+               break;
+
+       default:
+               del_cid(frm->in, dcid, scid);
+               break;
+       }
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Connect rsp: dcid 0x%4.4x scid 0x%4.4x result %d status %d\n",
+               dcid, scid, result, status);
+
+       p_indent(level + 1, frm);
+       printf("%s", connresult2str(result));
+
+       if (result == 0x0001)
+               printf(" - %s\n", status2str(status));
+       else
+               printf("\n");
+}
+
+static void conf_rfc(void *ptr, int len, int in, uint16_t handle,
+                                                               uint16_t cid)
+{
+       uint8_t mode;
+
+       mode = *((uint8_t *) ptr);
+       set_mode(!in, handle, cid, mode);
+
+       printf("RFC 0x%02x (%s", mode, mode2str(mode));
+       if (mode >= 0x01 && mode <= 0x04) {
+               uint8_t txwin, maxtrans;
+               uint16_t rto, mto, mps;
+               txwin = *((uint8_t *) (ptr + 1));
+               maxtrans = *((uint8_t *) (ptr + 2));
+               rto = bt_get_le16(ptr + 3);
+               mto = bt_get_le16(ptr + 5);
+               mps = bt_get_le16(ptr + 7);
+               printf(", TxWin %d, MaxTx %d, RTo %d, MTo %d, MPS %d",
+                                       txwin, maxtrans, rto, mto, mps);
+       }
+       printf(")");
+}
+
+static void conf_efs(void *ptr)
+{
+       uint8_t id, ser_type;
+       uint16_t max_sdu;
+       uint32_t sdu_itime, access_lat, flush_to;
+
+       id = get_val(ptr, sizeof(id));
+       ser_type = get_val(ptr + 1, sizeof(ser_type));
+       max_sdu = get_val(ptr + 2, sizeof(max_sdu));
+       sdu_itime = get_val(ptr + 4, sizeof(sdu_itime));
+       access_lat = get_val(ptr + 8, sizeof(access_lat));
+       flush_to = get_val(ptr + 12, sizeof(flush_to));
+
+       printf("EFS (Id 0x%02x, SerType %s, MaxSDU 0x%04x, SDUitime 0x%08x, "
+                       "AccLat 0x%08x, FlushTO 0x%08x)",
+                       id, type2str(ser_type), max_sdu, sdu_itime,
+                       access_lat, flush_to);
+}
+
+static void conf_fcs(void *ptr, int len)
+{
+       uint8_t fcs;
+
+       fcs = *((uint8_t *) ptr);
+       printf("FCS Option");
+       if (len > 0)
+               printf(" 0x%2.2x (%s)", fcs, fcs2str(fcs));
+}
+
+static void conf_opt(int level, void *ptr, int len, int in, uint16_t handle,
+                                                               uint16_t cid)
+{
+       int indent = 0;
+       p_indent(level, 0);
+       while (len > 0) {
+               l2cap_conf_opt *h = ptr;
+
+               ptr += L2CAP_CONF_OPT_SIZE + h->len;
+               len -= L2CAP_CONF_OPT_SIZE + h->len;
+
+               if (h->type & 0x80)
+                       printf("[");
+
+               if (indent++) {
+                       printf("\n");
+                       p_indent(level, 0);
+               }
+
+               switch (h->type & 0x7f) {
+               case L2CAP_CONF_MTU:
+                       set_mode(in, handle, cid, 0x00);
+                       printf("MTU");
+                       if (h->len > 0)
+                               printf(" %d", get_val(h->val, h->len));
+                       break;
+
+               case L2CAP_CONF_FLUSH_TO:
+                       printf("FlushTO");
+                       if (h->len > 0)
+                               printf(" %d", get_val(h->val, h->len));
+                       break;
+
+               case L2CAP_CONF_QOS:
+                       printf("QoS");
+                       if (h->len > 0)
+                               printf(" 0x%02x (%s)", *(h->val + 1), type2str(*(h->val + 1)));
+                       break;
+
+               case L2CAP_CONF_RFC:
+                       conf_rfc(h->val, h->len, in, handle, cid);
+                       break;
+
+               case L2CAP_CONF_FCS:
+                       conf_fcs(h->val, h->len);
+                       break;
+
+               case L2CAP_CONF_EFS:
+                       conf_efs(h->val);
+                       break;
+
+               case L2CAP_CONF_EWS:
+                       printf("EWS");
+                       if (h->len > 0)
+                               printf(" %d", get_val(h->val, h->len));
+                       set_ext_ctrl(in, handle, cid, 1);
+                       break;
+
+               default:
+                       printf("Unknown (type %2.2x, len %d)", h->type & 0x7f, h->len);
+                       break;
+               }
+
+               if (h->type & 0x80)
+                       printf("] ");
+               else
+                       printf(" ");
+       }
+       printf("\n");
+}
+
+static void conf_list(int level, uint8_t *list, int len)
+{
+       int i;
+
+       p_indent(level, 0);
+       for (i = 0; i < len; i++) {
+               switch (list[i] & 0x7f) {
+               case L2CAP_CONF_MTU:
+                       printf("MTU ");
+                       break;
+               case L2CAP_CONF_FLUSH_TO:
+                       printf("FlushTo ");
+                       break;
+               case L2CAP_CONF_QOS:
+                       printf("QoS ");
+                       break;
+               case L2CAP_CONF_RFC:
+                       printf("RFC ");
+                       break;
+               case L2CAP_CONF_FCS:
+                       printf("FCS ");
+                       break;
+               case L2CAP_CONF_EFS:
+                       printf("EFS ");
+                       break;
+               case L2CAP_CONF_EWS:
+                       printf("EWS ");
+                       break;
+               default:
+                       printf("%2.2x ", list[i] & 0x7f);
+                       break;
+               }
+       }
+       printf("\n");
+}
+
+static inline void conf_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_conf_req *h = frm->ptr;
+       uint16_t dcid = btohs(h->dcid);
+       int clen = btohs(cmd->len) - L2CAP_CONF_REQ_SIZE;
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Config req: dcid 0x%4.4x flags 0x%2.2x clen %d\n",
+                       dcid, btohs(h->flags), clen);
+
+       if (clen > 0)
+               conf_opt(level + 1, h->data, clen, frm->in, frm->handle,
+                                                                       dcid);
+}
+
+static inline void conf_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_conf_rsp *h = frm->ptr;
+       uint16_t scid = btohs(h->scid);
+       uint16_t result = btohs(h->result);
+       int clen = btohs(cmd->len) - L2CAP_CONF_RSP_SIZE;
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Config rsp: scid 0x%4.4x flags 0x%2.2x result %d clen %d\n",
+                       scid, btohs(h->flags), result, clen);
+
+       if (clen > 0) {
+               if (result) {
+                       p_indent(level + 1, frm);
+                       printf("%s\n", confresult2str(result));
+               }
+               if (result == 0x0003)
+                       conf_list(level + 1, h->data, clen);
+               else
+                       conf_opt(level + 1, h->data, clen, frm->in,
+                                                       frm->handle, scid);
+       } else {
+               p_indent(level + 1, frm);
+               printf("%s\n", confresult2str(result));
+       }
+}
+
+static inline void disconn_req(int level, struct frame *frm)
+{
+       l2cap_disconn_req *h = frm->ptr;
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Disconn req: dcid 0x%4.4x scid 0x%4.4x\n",
+                       btohs(h->dcid), btohs(h->scid));
+}
+
+static inline void disconn_rsp(int level, struct frame *frm)
+{
+       l2cap_disconn_rsp *h = frm->ptr;
+       uint16_t dcid = btohs(h->dcid);
+       uint16_t scid = btohs(h->scid);
+
+       del_cid(frm->in, dcid, scid);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Disconn rsp: dcid 0x%4.4x scid 0x%4.4x\n",
+                       btohs(h->dcid), btohs(h->scid));
+}
+
+static inline void echo_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Echo req: dlen %d\n", btohs(cmd->len));
+       raw_dump(level, frm);
+}
+
+static inline void echo_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Echo rsp: dlen %d\n", btohs(cmd->len));
+       raw_dump(level, frm);
+}
+
+static void info_opt(int level, int type, void *ptr, int len)
+{
+       uint32_t mask;
+       uint64_t fc_mask;
+       int i;
+
+       p_indent(level, 0);
+
+       switch (type) {
+       case 0x0001:
+               printf("Connectionless MTU %d\n", get_val(ptr, len));
+               break;
+       case 0x0002:
+               mask = get_val(ptr, len);
+               printf("Extended feature mask 0x%4.4x\n", mask);
+               if (parser.flags & DUMP_VERBOSE)
+                       for (i=0; l2cap_features[i].name; i++)
+                               if (mask & l2cap_features[i].flag) {
+                                       p_indent(level + 1, 0);
+                                       printf("%s\n", l2cap_features[i].name);
+                               }
+               break;
+       case 0x0003:
+               fc_mask = bt_get_le64(ptr);
+               printf("Fixed channel list 0x%8.8" PRIx64 "\n", fc_mask);
+               if (parser.flags & DUMP_VERBOSE)
+                       for (i=0; l2cap_fix_chan[i].name; i++)
+                               if (fc_mask & l2cap_fix_chan[i].flag) {
+                                       p_indent(level + 1, 0);
+                                       printf("%s\n", l2cap_fix_chan[i].name);
+                               }
+               break;
+       default:
+               printf("Unknown (len %d)\n", len);
+               break;
+       }
+}
+
+static inline void info_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_info_req *h = frm->ptr;
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Info req: type %d\n", btohs(h->type));
+}
+
+static inline void info_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_info_rsp *h = frm->ptr;
+       uint16_t type = btohs(h->type);
+       uint16_t result = btohs(h->result);
+       int ilen = btohs(cmd->len) - L2CAP_INFO_RSP_SIZE;
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Info rsp: type %d result %d\n", type, result);
+
+       if (ilen > 0) {
+               info_opt(level + 1, type, h->data, ilen);
+       } else {
+               p_indent(level + 1, frm);
+               printf("%s\n", inforesult2str(result));
+       }
+}
+
+static void l2cap_ctrl_ext_parse(int level, struct frame *frm, uint32_t ctrl)
+{
+       p_indent(level, frm);
+
+       printf("%s:", ctrl & L2CAP_EXT_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
+
+       if (ctrl & L2CAP_EXT_CTRL_FRAME_TYPE) {
+               printf(" %s", supervisory2str((ctrl & L2CAP_EXT_CTRL_SUPERVISE_MASK) >>
+                                       L2CAP_EXT_CTRL_SUPER_SHIFT));
+
+               if (ctrl & L2CAP_EXT_CTRL_POLL)
+                       printf(" P-bit");
+       } else {
+               uint8_t sar = (ctrl & L2CAP_EXT_CTRL_SAR_MASK) >>
+                       L2CAP_EXT_CTRL_SAR_SHIFT;
+               printf(" %s", sar2str(sar));
+               if (sar == L2CAP_SAR_START) {
+                       uint16_t len;
+                       len = bt_get_le16(frm->ptr);
+                       frm->ptr += L2CAP_SDULEN_SIZE;
+                       frm->len -= L2CAP_SDULEN_SIZE;
+                       printf(" (len %d)", len);
+               }
+               printf(" TxSeq %d", (ctrl & L2CAP_EXT_CTRL_TXSEQ_MASK) >>
+                               L2CAP_EXT_CTRL_TXSEQ_SHIFT);
+       }
+
+       printf(" ReqSeq %d", (ctrl & L2CAP_EXT_CTRL_REQSEQ_MASK) >>
+                       L2CAP_EXT_CTRL_REQSEQ_SHIFT);
+
+       if (ctrl & L2CAP_EXT_CTRL_FINAL)
+               printf(" F-bit");
+}
+
+static void l2cap_ctrl_parse(int level, struct frame *frm, uint32_t ctrl)
+{
+       p_indent(level, frm);
+
+       printf("%s:", ctrl & L2CAP_CTRL_FRAME_TYPE ? "S-frame" : "I-frame");
+
+       if (ctrl & 0x01) {
+               printf(" %s", supervisory2str((ctrl & L2CAP_CTRL_SUPERVISE_MASK) >>
+                                       L2CAP_CTRL_SUPER_SHIFT));
+
+               if (ctrl & L2CAP_CTRL_POLL)
+                       printf(" P-bit");
+       } else {
+               uint8_t sar = (ctrl & L2CAP_CTRL_SAR_MASK) >> L2CAP_CTRL_SAR_SHIFT;
+               printf(" %s", sar2str(sar));
+               if (sar == L2CAP_SAR_START) {
+                       uint16_t len;
+                       len = bt_get_le16(frm->ptr);
+                       frm->ptr += L2CAP_SDULEN_SIZE;
+                       frm->len -= L2CAP_SDULEN_SIZE;
+                       printf(" (len %d)", len);
+               }
+               printf(" TxSeq %d", (ctrl & L2CAP_CTRL_TXSEQ_MASK) >> L2CAP_CTRL_TXSEQ_SHIFT);
+       }
+
+       printf(" ReqSeq %d", (ctrl & L2CAP_CTRL_REQSEQ_MASK) >> L2CAP_CTRL_REQSEQ_SHIFT);
+
+       if (ctrl & L2CAP_CTRL_FINAL)
+               printf(" F-bit");
+}
+
+static inline void create_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_create_req *h = frm->ptr;
+       uint16_t psm = btohs(h->psm);
+       uint16_t scid = btohs(h->scid);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Create chan req: psm 0x%4.4x scid 0x%4.4x ctrl id %d\n",
+                                                       psm, scid, h->id);
+}
+
+static inline void create_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_create_rsp *h = frm->ptr;
+       uint16_t scid = btohs(h->scid);
+       uint16_t dcid = btohs(h->dcid);
+       uint16_t result = btohs(h->result);
+       uint16_t status = btohs(h->status);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Create chan rsp: dcid 0x%4.4x scid 0x%4.4x result %d status %d\n",
+                                               dcid, scid, result, status);
+}
+
+static inline void move_req(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_move_req *h = frm->ptr;
+       uint16_t icid = btohs(h->icid);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Move chan req: icid 0x%4.4x ctrl id %d\n", icid, h->id);
+}
+
+static inline void move_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_move_rsp *h = frm->ptr;
+       uint16_t icid = btohs(h->icid);
+       uint16_t result = btohs(h->result);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Move chan rsp: icid 0x%4.4x result %d\n", icid, result);
+}
+
+static inline void move_cfm(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_move_cfm *h = frm->ptr;
+       uint16_t icid = btohs(h->icid);
+       uint16_t result = btohs(h->result);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Move chan cfm: icid 0x%4.4x result %d\n", icid, result);
+}
+
+static inline void move_cfm_rsp(int level, l2cap_cmd_hdr *cmd, struct frame *frm)
+{
+       l2cap_move_cfm_rsp *h = frm->ptr;
+       uint16_t icid = btohs(h->icid);
+
+       if (p_filter(FILT_L2CAP))
+               return;
+
+       printf("Move chan cfm rsp: icid 0x%4.4x\n", icid);
+}
+
+static inline void a2mp_command_rej(int level, struct frame *frm)
+{
+       struct a2mp_command_rej *h = frm->ptr;
+       uint16_t reason = btohs(h->reason);
+
+       printf("Command Reject: reason %d\n", reason);
+       p_indent(level + 1, 0);
+       printf("%s\n", a2mpreason2str(reason));
+}
+
+static inline void a2mp_discover_req(int level, struct frame *frm, uint16_t len)
+{
+       struct a2mp_discover_req *h = frm->ptr;
+       uint16_t mtu = btohs(h->mtu);
+       uint8_t  *octet = (uint8_t *)&(h->mask);
+       uint16_t mask;
+       uint8_t  extension;
+
+       printf("Discover req: mtu/mps %d ", mtu);
+       len -= 2;
+
+       printf("mask:");
+
+       do {
+               len -= 2;
+               mask = bt_get_le16(octet);
+               printf(" 0x%4.4x", mask);
+
+               extension = octet[1] & 0x80;
+               octet += 2;
+       } while ((extension != 0) && (len >= 2));
+
+       printf("\n");
+}
+
+static inline void a2mp_ctrl_list_dump(int level, struct a2mp_ctrl *list, uint16_t len)
+{
+       p_indent(level, 0);
+       printf("Controller list:\n");
+
+       while (len >= 3) {
+               p_indent(level + 1, 0);
+               printf("id %d type %d (%s) status 0x%2.2x (%s)\n",
+                          list->id, list->type, ampctrltype2str(list->type), list->status, ampctrlstatus2str(list->status));
+               list++;
+               len -= 3;
+       }
+
+}
+
+static inline void a2mp_discover_rsp(int level, struct frame *frm, uint16_t len)
+{
+       struct a2mp_discover_rsp *h = frm->ptr;
+       uint16_t mtu = btohs(h->mtu);
+       uint8_t  *octet = (uint8_t *)&(h->mask);
+       uint16_t mask;
+       uint8_t  extension;
+
+       printf("Discover rsp: mtu/mps %d ", mtu);
+       len -= 2;
+
+       printf("mask:");
+
+       do {
+               len -= 2;
+               mask = bt_get_le16(octet);
+               printf(" 0x%4.4x", mask);
+
+               extension = octet[1] & 0x80;
+               octet += 2;
+       } while ((extension != 0) && (len >= 2));
+
+       printf("\n");
+
+       if (len >= 3) {
+               a2mp_ctrl_list_dump(level + 1, (struct a2mp_ctrl *) octet, len);
+       }
+}
+
+static inline void a2mp_change_notify(int level, struct frame *frm, uint16_t len)
+{
+       struct a2mp_ctrl *list = frm->ptr;
+
+       printf("Change Notify\n");
+
+       if (len >= 3) {
+               a2mp_ctrl_list_dump(level + 1, list, len);
+       }
+}
+
+static inline void a2mp_change_rsp(int level, struct frame *frm)
+{
+       printf("Change Response\n");
+}
+
+static inline void a2mp_info_req(int level, struct frame *frm)
+{
+       struct a2mp_info_req *h = frm->ptr;
+
+       printf("Get Info req: id %d\n", h->id);
+}
+
+static inline void a2mp_info_rsp(int level, struct frame *frm)
+{
+       struct a2mp_info_rsp *h = frm->ptr;
+
+       printf("Get Info rsp: id %d status %d (%s)\n",
+                  h->id, h->status, a2mpstatus2str(h->status));
+
+       p_indent(level + 1, 0);
+       printf("Total bandwidth %d\n", btohl(h->total_bw));
+       p_indent(level + 1, 0);
+       printf("Max guaranteed bandwidth %d\n", btohl(h->max_bw));
+       p_indent(level + 1, 0);
+       printf("Min latency %d\n", btohl(h->min_latency));
+       p_indent(level + 1, 0);
+       printf("Pal capabilities 0x%4.4x\n", btohs(h->pal_caps));
+       p_indent(level + 1, 0);
+       printf("Assoc size %d\n", btohs(h->assoc_size));
+}
+
+static inline void a2mp_assoc_req(int level, struct frame *frm)
+{
+       struct a2mp_assoc_req *h = frm->ptr;
+
+       printf("Get AMP Assoc req: id %d\n", h->id);
+}
+
+static inline void a2mp_assoc_rsp(int level, struct frame *frm, uint16_t len)
+{
+       struct a2mp_assoc_rsp *h = frm->ptr;
+
+       printf("Get AMP Assoc rsp: id %d status (%d) %s\n",
+                       h->id, h->status, a2mpstatus2str(h->status));
+       amp_assoc_dump(level + 1, h->assoc_data, len - sizeof(*h));
+}
+
+static inline void a2mp_create_req(int level, struct frame *frm, uint16_t len)
+{
+       struct a2mp_create_req *h = frm->ptr;
+
+       printf("Create Physical Link req: local id %d remote id %d\n",
+                  h->local_id, h->remote_id);
+       amp_assoc_dump(level + 1, h->assoc_data, len - sizeof(*h));
+}
+
+static inline void a2mp_create_rsp(int level, struct frame *frm)
+{
+       struct a2mp_create_rsp *h = frm->ptr;
+
+       printf("Create Physical Link rsp: local id %d remote id %d status %d\n",
+                  h->local_id, h->remote_id, h->status);
+       p_indent(level+1, 0);
+       printf("%s\n", a2mpcplstatus2str(h->status));
+}
+
+static inline void a2mp_disconn_req(int level, struct frame *frm)
+{
+       struct a2mp_disconn_req *h = frm->ptr;
+
+       printf("Disconnect Physical Link req: local id %d remote id %d\n",
+                  h->local_id, h->remote_id);
+}
+
+static inline void a2mp_disconn_rsp(int level, struct frame *frm)
+{
+       struct a2mp_disconn_rsp *h = frm->ptr;
+
+       printf("Disconnect Physical Link rsp: local id %d remote id %d status %d\n",
+                  h->local_id, h->remote_id, h->status);
+       p_indent(level+1, 0);
+       printf("%s\n", a2mpdplstatus2str(h->status));
+}
+
+static void l2cap_parse(int level, struct frame *frm)
+{
+       l2cap_hdr *hdr = (void *)frm->ptr;
+       uint16_t dlen = btohs(hdr->len);
+       uint16_t cid  = btohs(hdr->cid);
+       uint16_t psm;
+
+       frm->ptr += L2CAP_HDR_SIZE;
+       frm->len -= L2CAP_HDR_SIZE;
+
+       if (cid == 0x1) {
+               /* Signaling channel */
+
+               while (frm->len >= L2CAP_CMD_HDR_SIZE) {
+                       l2cap_cmd_hdr *hdr = frm->ptr;
+
+                       frm->ptr += L2CAP_CMD_HDR_SIZE;
+                       frm->len -= L2CAP_CMD_HDR_SIZE;
+
+                       if (!p_filter(FILT_L2CAP)) {
+                               p_indent(level, frm);
+                               printf("L2CAP(s): ");
+                       }
+
+                       switch (hdr->code) {
+                       case L2CAP_COMMAND_REJ:
+                               command_rej(level, frm);
+                               break;
+
+                       case L2CAP_CONN_REQ:
+                               conn_req(level, frm);
+                               break;
+
+                       case L2CAP_CONN_RSP:
+                               conn_rsp(level, frm);
+                               break;
+
+                       case L2CAP_CONF_REQ:
+                               conf_req(level, hdr, frm);
+                               break;
+
+                       case L2CAP_CONF_RSP:
+                               conf_rsp(level, hdr, frm);
+                               break;
+
+                       case L2CAP_DISCONN_REQ:
+                               disconn_req(level, frm);
+                               break;
+
+                       case L2CAP_DISCONN_RSP:
+                               disconn_rsp(level, frm);
+                               break;
+
+                       case L2CAP_ECHO_REQ:
+                               echo_req(level, hdr, frm);
+                               break;
+
+                       case L2CAP_ECHO_RSP:
+                               echo_rsp(level, hdr, frm);
+                               break;
+
+                       case L2CAP_INFO_REQ:
+                               info_req(level, hdr, frm);
+                               break;
+
+                       case L2CAP_INFO_RSP:
+                               info_rsp(level, hdr, frm);
+                               break;
+
+                       case L2CAP_CREATE_REQ:
+                               create_req(level, hdr, frm);
+                               break;
+
+                       case L2CAP_CREATE_RSP:
+                               create_rsp(level, hdr, frm);
+                               break;
+
+                       case L2CAP_MOVE_REQ:
+                               move_req(level, hdr, frm);
+                               break;
+
+                       case L2CAP_MOVE_RSP:
+                               move_rsp(level, hdr, frm);
+                               break;
+
+                       case L2CAP_MOVE_CFM:
+                               move_cfm(level, hdr, frm);
+                               break;
+
+                       case L2CAP_MOVE_CFM_RSP:
+                               move_cfm_rsp(level, hdr, frm);
+                               break;
+
+                       default:
+                               if (p_filter(FILT_L2CAP))
+                                       break;
+                               printf("code 0x%2.2x ident %d len %d\n", 
+                                       hdr->code, hdr->ident, btohs(hdr->len));
+                               raw_dump(level, frm);
+                       }
+
+                       if (frm->len > btohs(hdr->len)) {
+                               frm->len -= btohs(hdr->len);
+                               frm->ptr += btohs(hdr->len);
+                       } else
+                               frm->len = 0;
+               }
+       } else if (cid == 0x2) {
+               /* Connectionless channel */
+
+               if (p_filter(FILT_L2CAP))
+                       return;
+
+               psm = bt_get_le16(frm->ptr);
+               frm->ptr += 2;
+               frm->len -= 2;
+
+               p_indent(level, frm);
+               printf("L2CAP(c): len %d psm %d\n", dlen, psm);
+               raw_dump(level, frm);
+       } else if (cid == 0x3) {
+               /* AMP Manager channel */
+
+               if (p_filter(FILT_A2MP))
+                       return;
+
+               /* Adjust for ERTM control bytes */
+               frm->ptr += 2;
+               frm->len -= 2;
+
+               while (frm->len >= A2MP_HDR_SIZE) {
+                       struct a2mp_hdr *hdr = frm->ptr;
+
+                       frm->ptr += A2MP_HDR_SIZE;
+                       frm->len -= A2MP_HDR_SIZE;
+
+                       p_indent(level, frm);
+                       printf("A2MP: ");
+
+                       switch (hdr->code) {
+                       case A2MP_COMMAND_REJ:
+                               a2mp_command_rej(level, frm);
+                               break;
+                       case A2MP_DISCOVER_REQ:
+                               a2mp_discover_req(level, frm, btohs(hdr->len));
+                               break;
+                       case A2MP_DISCOVER_RSP:
+                               a2mp_discover_rsp(level, frm, btohs(hdr->len));
+                               break;
+                       case A2MP_CHANGE_NOTIFY:
+                               a2mp_change_notify(level, frm, btohs(hdr->len));
+                               break;
+                       case A2MP_CHANGE_RSP:
+                               a2mp_change_rsp(level, frm);
+                               break;
+                       case A2MP_INFO_REQ:
+                               a2mp_info_req(level, frm);
+                               break;
+                       case A2MP_INFO_RSP:
+                               a2mp_info_rsp(level, frm);
+                               break;
+                       case A2MP_ASSOC_REQ:
+                               a2mp_assoc_req(level, frm);
+                               break;
+                       case A2MP_ASSOC_RSP:
+                               a2mp_assoc_rsp(level, frm, btohs(hdr->len));
+                               break;
+                       case A2MP_CREATE_REQ:
+                               a2mp_create_req(level, frm, btohs(hdr->len));
+                               break;
+                       case A2MP_CREATE_RSP:
+                               a2mp_create_rsp(level, frm);
+                               break;
+                       case A2MP_DISCONN_REQ:
+                               a2mp_disconn_req(level, frm);
+                               break;
+                       case A2MP_DISCONN_RSP:
+                               a2mp_disconn_rsp(level, frm);
+                               break;
+                       default:
+                               printf("code 0x%2.2x ident %d len %d\n",
+                                          hdr->code, hdr->ident, btohs(hdr->len));
+                               raw_dump(level, frm);
+                       }
+                       if (frm->len > btohs(hdr->len)) {
+                               frm->len -= btohs(hdr->len);
+                               frm->ptr += btohs(hdr->len);
+                       } else
+                               frm->len = 0;
+               }
+       } else if (cid == 0x04) {
+               if (!p_filter(FILT_ATT))
+                       att_dump(level, frm);
+               else
+                       raw_dump(level + 1, frm);
+       } else if (cid == 0x06) {
+               if (!p_filter(FILT_SMP))
+                       smp_dump(level, frm);
+               else
+                       raw_dump(level + 1, frm);
+       } else {
+               /* Connection oriented channel */
+
+               uint8_t mode = get_mode(!frm->in, frm->handle, cid);
+               uint8_t ext_ctrl = get_ext_ctrl(!frm->in, frm->handle, cid);
+               uint16_t psm = get_psm(!frm->in, frm->handle, cid);
+               uint16_t fcs = 0;
+               uint32_t proto, ctrl = 0;
+
+               frm->cid = cid;
+               frm->num = get_num(!frm->in, frm->handle, cid);
+
+               if (mode > 0) {
+                       if (ext_ctrl) {
+                               ctrl = get_val(frm->ptr, 4);
+                               frm->ptr += 4;
+                               frm->len -= 6;
+                       } else {
+                               ctrl = get_val(frm->ptr, 2);
+                               frm->ptr += 2;
+                               frm->len -= 4;
+                       }
+                       fcs = bt_get_le16(frm->ptr + frm->len);
+               }
+
+               if (!p_filter(FILT_L2CAP)) {
+                       p_indent(level, frm);
+                       printf("L2CAP(d): cid 0x%4.4x len %d", cid, dlen);
+                       if (mode > 0) {
+                               if (ext_ctrl)
+                                       printf(" ext_ctrl 0x%8.8x fcs 0x%4.4x", ctrl, fcs);
+                               else
+                                       printf(" ctrl 0x%4.4x fcs 0x%4.4x", ctrl, fcs);
+                       }
+
+                       printf(" [psm %d]\n", psm);
+                       level++;
+                       if (mode > 0) {
+                               if (ext_ctrl)
+                                       l2cap_ctrl_ext_parse(level, frm, ctrl);
+                               else
+                                       l2cap_ctrl_parse(level, frm, ctrl);
+
+                               printf("\n");
+                       }
+               }
+
+               switch (psm) {
+               case 0x01:
+                       if (!p_filter(FILT_SDP))
+                               sdp_dump(level + 1, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x03:
+                       if (!p_filter(FILT_RFCOMM))
+                               rfcomm_dump(level, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x0f:
+                       if (!p_filter(FILT_BNEP))
+                               bnep_dump(level, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x11:
+               case 0x13:
+                       if (!p_filter(FILT_HIDP))
+                               hidp_dump(level, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x17:
+               case 0x1B:
+                       if (!p_filter(FILT_AVCTP))
+                               avctp_dump(level, frm, psm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x19:
+                       if (!p_filter(FILT_AVDTP))
+                               avdtp_dump(level, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               case 0x1f:
+                       if (!p_filter(FILT_ATT))
+                               att_dump(level, frm);
+                       else
+                               raw_dump(level + 1, frm);
+                       break;
+
+               default:
+                       proto = get_proto(frm->handle, psm, 0);
+
+                       switch (proto) {
+                       case SDP_UUID_CMTP:
+                               if (!p_filter(FILT_CMTP))
+                                       cmtp_dump(level, frm);
+                               else
+                                       raw_dump(level + 1, frm);
+                               break;
+
+                       case SDP_UUID_HARDCOPY_CONTROL_CHANNEL:
+                               if (!p_filter(FILT_HCRP))
+                                       hcrp_dump(level, frm);
+                               else
+                                       raw_dump(level + 1, frm);
+                               break;
+
+                       case SDP_UUID_OBEX:
+                               if (!p_filter(FILT_OBEX))
+                                       obex_dump(level, frm);
+                               else
+                                       raw_dump(level + 1, frm);
+                               break;
+
+                       default:
+                               if (p_filter(FILT_L2CAP))
+                                       break;
+
+                               raw_dump(level, frm);
+                               break;
+                       }
+                       break;
+               }
+       }
+}
+
+void l2cap_dump(int level, struct frame *frm)
+{
+       struct frame *fr;
+       l2cap_hdr *hdr;
+       uint16_t dlen;
+
+       if ((frm->flags & ACL_START) || frm->flags == ACL_START_NO_FLUSH) {
+               hdr  = frm->ptr;
+               dlen = btohs(hdr->len);
+
+               if (dlen + L2CAP_HDR_SIZE < (int) frm->len) {
+                       /* invalid frame */
+                       raw_dump(level,frm);
+                       return;
+               }
+
+               if ((int) frm->len == (dlen + L2CAP_HDR_SIZE)) {
+                       /* Complete frame */
+                       l2cap_parse(level, frm);
+                       return;
+               }
+
+               if (!(fr = get_frame(frm->handle))) {
+                       fprintf(stderr, "Not enough connection handles\n");
+                       raw_dump(level, frm);
+                       return;
+               }
+
+               if (fr->data)
+                       free(fr->data);
+
+               if (!(fr->data = malloc(dlen + L2CAP_HDR_SIZE))) {
+                       perror("Can't allocate L2CAP reassembly buffer");
+                       return;
+               }
+               memcpy(fr->data, frm->ptr, frm->len);
+               fr->data_len   = dlen + L2CAP_HDR_SIZE;
+               fr->len        = frm->len;
+               fr->ptr        = fr->data;
+               fr->dev_id     = frm->dev_id;
+               fr->in         = frm->in;
+               fr->ts         = frm->ts;
+               fr->handle     = frm->handle;
+               fr->cid        = frm->cid;
+               fr->num        = frm->num;
+               fr->dlci       = frm->dlci;
+               fr->channel    = frm->channel;
+               fr->pppdump_fd = frm->pppdump_fd;
+               fr->audio_fd   = frm->audio_fd;
+       } else {
+               if (!(fr = get_frame(frm->handle))) {
+                       fprintf(stderr, "Not enough connection handles\n");
+                       raw_dump(level, frm);
+                       return;
+               }
+
+               if (!fr->data) {
+                       /* Unexpected fragment */
+                       raw_dump(level, frm);
+                       return;
+               }
+
+               if (frm->len > (fr->data_len - fr->len)) {
+                       /* Bad fragment */
+                       raw_dump(level, frm);
+                       free(fr->data); fr->data = NULL;
+                       return;
+               }
+
+               memcpy(fr->data + fr->len, frm->ptr, frm->len);
+               fr->len += frm->len;
+
+               if (fr->len == fr->data_len) {
+                       /* Complete frame */
+                       l2cap_parse(level, fr);
+
+                       free(fr->data); fr->data = NULL;
+                       return;
+               }
+       }
+}
+
+void l2cap_clear(uint16_t handle)
+{
+       del_handle(handle);
+}
diff --git a/tools/parser/l2cap.h b/tools/parser/l2cap.h
new file mode 100644 (file)
index 0000000..788aef0
--- /dev/null
@@ -0,0 +1,272 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __L2CAP_H
+#define __L2CAP_H
+
+/* L2CAP command codes */
+#define L2CAP_COMMAND_REJ      0x01
+#define L2CAP_CONN_REQ         0x02
+#define L2CAP_CONN_RSP         0x03
+#define L2CAP_CONF_REQ         0x04
+#define L2CAP_CONF_RSP         0x05
+#define L2CAP_DISCONN_REQ      0x06
+#define L2CAP_DISCONN_RSP      0x07
+#define L2CAP_ECHO_REQ         0x08
+#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
+#define L2CAP_FEAT_RETRANS     0x00000002
+#define L2CAP_FEAT_BIDIR_QOS   0x00000004
+#define L2CAP_FEAT_ERTM                0x00000008
+#define L2CAP_FEAT_STREAMING   0x00000010
+#define L2CAP_FEAT_FCS         0x00000020
+#define L2CAP_FEAT_EXT_FLOW    0x00000040
+#define L2CAP_FEAT_FIXED_CHAN  0x00000080
+#define L2CAP_FEAT_EXT_WINDOW  0x00000100
+#define L2CAP_FEAT_UCD         0x00000200
+
+/* L2CAP Control Field bit masks */
+#define L2CAP_CTRL_SAR_MASK            0xC000
+#define L2CAP_CTRL_REQSEQ_MASK         0x3F00
+#define L2CAP_CTRL_TXSEQ_MASK          0x007E
+#define L2CAP_CTRL_SUPERVISE_MASK      0x000C
+
+#define L2CAP_CTRL_RETRANS             0x0080
+#define L2CAP_CTRL_FINAL               0x0080
+#define L2CAP_CTRL_POLL                        0x0010
+#define L2CAP_CTRL_FRAME_TYPE          0x0001 /* I- or S-Frame */
+
+#define L2CAP_CTRL_TXSEQ_SHIFT         1
+#define L2CAP_CTRL_SUPER_SHIFT         2
+#define L2CAP_CTRL_REQSEQ_SHIFT                8
+#define L2CAP_CTRL_SAR_SHIFT           14
+
+#define L2CAP_EXT_CTRL_TXSEQ_MASK      0xFFFC0000
+#define L2CAP_EXT_CTRL_SAR_MASK                0x00030000
+#define L2CAP_EXT_CTRL_SUPERVISE_MASK  0x00030000
+#define L2CAP_EXT_CTRL_REQSEQ_MASK     0x0000FFFC
+
+#define L2CAP_EXT_CTRL_POLL            0x00040000
+#define L2CAP_EXT_CTRL_FINAL           0x00000002
+#define L2CAP_EXT_CTRL_FRAME_TYPE      0x00000001 /* I- or S-Frame */
+
+#define L2CAP_EXT_CTRL_REQSEQ_SHIFT    2
+#define L2CAP_EXT_CTRL_SAR_SHIFT       16
+#define L2CAP_EXT_CTRL_SUPER_SHIFT     16
+#define L2CAP_EXT_CTRL_TXSEQ_SHIFT     18
+
+/* L2CAP Supervisory Function */
+#define L2CAP_SUPER_RR         0x00
+#define L2CAP_SUPER_REJ                0x01
+#define L2CAP_SUPER_RNR                0x02
+#define L2CAP_SUPER_SREJ       0x03
+
+/* L2CAP Segmentation and Reassembly */
+#define L2CAP_SAR_UNSEGMENTED  0x00
+#define L2CAP_SAR_START                0x01
+#define L2CAP_SAR_END          0x02
+#define L2CAP_SAR_CONTINUE     0x03
+
+#define L2CAP_SDULEN_SIZE      2
+
+/* L2CAP fixed channels */
+#define L2CAP_FC_L2CAP         0x02
+#define L2CAP_FC_CONNLESS      0x04
+#define L2CAP_FC_A2MP          0x08
+
+/* L2CAP structures */
+typedef struct {
+       uint16_t        len;
+       uint16_t        cid;
+} __attribute__ ((packed)) l2cap_hdr;
+#define L2CAP_HDR_SIZE 4
+
+typedef struct {
+       uint8_t         code;
+       uint8_t         ident;
+       uint16_t        len;
+} __attribute__ ((packed)) l2cap_cmd_hdr;
+#define L2CAP_CMD_HDR_SIZE 4
+
+typedef struct {
+       uint16_t        reason;
+} __attribute__ ((packed)) l2cap_cmd_rej;
+#define L2CAP_CMD_REJ_SIZE 2
+
+typedef struct {
+       uint16_t        psm;
+       uint16_t        scid;
+} __attribute__ ((packed)) l2cap_conn_req;
+#define L2CAP_CONN_REQ_SIZE 4
+
+typedef struct {
+       uint16_t        dcid;
+       uint16_t        scid;
+       uint16_t        result;
+       uint16_t        status;
+} __attribute__ ((packed)) l2cap_conn_rsp;
+#define L2CAP_CONN_RSP_SIZE 8
+
+/* connect result */
+#define L2CAP_CR_SUCCESS       0x0000
+#define L2CAP_CR_PEND          0x0001
+#define L2CAP_CR_BAD_PSM       0x0002
+#define L2CAP_CR_SEC_BLOCK     0x0003
+#define L2CAP_CR_NO_MEM                0x0004
+
+/* connect status */
+#define L2CAP_CS_NO_INFO       0x0000
+#define L2CAP_CS_AUTHEN_PEND   0x0001
+#define L2CAP_CS_AUTHOR_PEND   0x0002
+
+typedef struct {
+       uint16_t        dcid;
+       uint16_t        flags;
+       uint8_t         data[0];
+} __attribute__ ((packed)) l2cap_conf_req;
+#define L2CAP_CONF_REQ_SIZE 4
+
+typedef struct {
+       uint16_t        scid;
+       uint16_t        flags;
+       uint16_t        result;
+       uint8_t         data[0];
+} __attribute__ ((packed)) l2cap_conf_rsp;
+#define L2CAP_CONF_RSP_SIZE 6
+
+#define L2CAP_CONF_SUCCESS     0x0000
+#define L2CAP_CONF_UNACCEPT    0x0001
+#define L2CAP_CONF_REJECT      0x0002
+#define L2CAP_CONF_UNKNOWN     0x0003
+#define L2CAP_CONF_PENDING     0x0004
+#define L2CAP_CONF_EFS_REJECT  0x0005
+
+typedef struct {
+       uint8_t         type;
+       uint8_t         len;
+       uint8_t         val[0];
+} __attribute__ ((packed)) l2cap_conf_opt;
+#define L2CAP_CONF_OPT_SIZE 2
+
+#define L2CAP_CONF_MTU         0x01
+#define L2CAP_CONF_FLUSH_TO    0x02
+#define L2CAP_CONF_QOS         0x03
+#define L2CAP_CONF_RFC         0x04
+#define L2CAP_CONF_FCS         0x05
+#define L2CAP_CONF_EFS         0x06
+#define L2CAP_CONF_EWS         0x07
+
+#define L2CAP_CONF_MAX_SIZE    22
+
+#define L2CAP_MODE_BASIC       0x00
+#define L2CAP_MODE_RETRANS     0x01
+#define L2CAP_MODE_FLOWCTL     0x02
+#define L2CAP_MODE_ERTM                0x03
+#define L2CAP_MODE_STREAMING   0x04
+
+#define L2CAP_SERVTYPE_NOTRAFFIC       0x00
+#define L2CAP_SERVTYPE_BESTEFFORT      0x01
+#define L2CAP_SERVTYPE_GUARANTEED      0x02
+
+typedef struct {
+       uint16_t        dcid;
+       uint16_t        scid;
+} __attribute__ ((packed)) l2cap_disconn_req;
+#define L2CAP_DISCONN_REQ_SIZE 4
+
+typedef struct {
+       uint16_t        dcid;
+       uint16_t        scid;
+} __attribute__ ((packed)) l2cap_disconn_rsp;
+#define L2CAP_DISCONN_RSP_SIZE 4
+
+typedef struct {
+       uint16_t        type;
+} __attribute__ ((packed)) l2cap_info_req;
+#define L2CAP_INFO_REQ_SIZE 2
+
+typedef struct {
+       uint16_t        type;
+       uint16_t        result;
+       uint8_t         data[0];
+} __attribute__ ((packed)) l2cap_info_rsp;
+#define L2CAP_INFO_RSP_SIZE 4
+
+/* info type */
+#define L2CAP_IT_CL_MTU                0x0001
+#define L2CAP_IT_FEAT_MASK     0x0002
+
+/* info result */
+#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
+
+#endif /* __L2CAP_H */
diff --git a/tools/parser/lmp.c b/tools/parser/lmp.c
new file mode 100644 (file)
index 0000000..c303c1b
--- /dev/null
@@ -0,0 +1,1347 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <sys/socket.h>
+
+#include "parser.h"
+#include "lib/hci.h"
+#include "lib/hci_lib.h"
+
+#define LMP_U8(frm)  (get_u8(frm))
+#define LMP_U16(frm) (btohs(htons(get_u16(frm))))
+#define LMP_U32(frm) (btohl(htonl(get_u32(frm))))
+
+static enum {
+       IN_RAND,
+       COMB_KEY_M,
+       COMB_KEY_S,
+       AU_RAND_M,
+       AU_RAND_S,
+       SRES_M,
+       SRES_S,
+} pairing_state = IN_RAND;
+
+static struct {
+       uint8_t in_rand[16];
+       uint8_t comb_key_m[16];
+       uint8_t comb_key_s[16];
+       uint8_t au_rand_m[16];
+       uint8_t au_rand_s[16];
+       uint8_t sres_m[4];
+       uint8_t sres_s[4];
+} pairing_data;
+
+static inline void pairing_data_dump(void)
+{
+       int i;
+
+       p_indent(6, NULL);
+       printf("IN_RAND  ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", pairing_data.in_rand[i]);
+       printf("\n");
+
+       p_indent(6, NULL);
+       printf("COMB_KEY ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", pairing_data.comb_key_m[i]);
+       printf(" (M)\n");
+
+       p_indent(6, NULL);
+       printf("COMB_KEY ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", pairing_data.comb_key_s[i]);
+       printf(" (S)\n");
+
+       p_indent(6, NULL);
+       printf("AU_RAND  ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", pairing_data.au_rand_m[i]);
+       printf(" SRES ");
+       for (i = 0; i < 4; i++)
+               printf("%2.2x", pairing_data.sres_m[i]);
+       printf(" (M)\n");
+
+       p_indent(6, NULL);
+       printf("AU_RAND  ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", pairing_data.au_rand_s[i]);
+       printf(" SRES ");
+       for (i = 0; i < 4; i++)
+               printf("%2.2x", pairing_data.sres_s[i]);
+       printf(" (S)\n");
+}
+
+static inline void in_rand(struct frame *frm)
+{
+       uint8_t *val = frm->ptr;
+
+       memcpy(pairing_data.in_rand, val, 16);
+       pairing_state = COMB_KEY_M;
+}
+
+static inline void comb_key(struct frame *frm)
+{
+       uint8_t *val = frm->ptr;
+
+       switch (pairing_state) {
+       case COMB_KEY_M:
+               memcpy(pairing_data.comb_key_m, val, 16);
+               pairing_state = COMB_KEY_S;
+               break;
+       case COMB_KEY_S:
+               memcpy(pairing_data.comb_key_s, val, 16);
+               pairing_state = AU_RAND_M;
+               break;
+       default:
+               pairing_state = IN_RAND;
+               break;
+       }
+}
+
+static inline void au_rand(struct frame *frm)
+{
+       uint8_t *val = frm->ptr;
+
+       switch (pairing_state) {
+       case AU_RAND_M:
+               memcpy(pairing_data.au_rand_m, val, 16);
+               pairing_state = SRES_M;
+               break;
+       case AU_RAND_S:
+               memcpy(pairing_data.au_rand_s, val, 16);
+               pairing_state = SRES_S;
+               break;
+       default:
+               pairing_state = IN_RAND;
+               break;
+       }
+}
+
+static inline void sres(struct frame *frm)
+{
+       uint8_t *val = frm->ptr;
+
+       switch (pairing_state) {
+       case SRES_M:
+               memcpy(pairing_data.sres_m, val, 4);
+               pairing_state = AU_RAND_S;
+               break;
+       case SRES_S:
+               memcpy(pairing_data.sres_s, val, 4);
+               pairing_state = IN_RAND;
+               pairing_data_dump();
+               break;
+       default:
+               pairing_state = IN_RAND;
+               break;
+       }
+}
+
+static char *opcode2str(uint16_t opcode)
+{
+       switch (opcode) {
+       case 1:
+               return "name_req";
+       case 2:
+               return "name_res";
+       case 3:
+               return "accepted";
+       case 4:
+               return "not_accepted";
+       case 5:
+               return "clkoffset_req";
+       case 6:
+               return "clkoffset_res";
+       case 7:
+               return "detach";
+       case 8:
+               return "in_rand";
+       case 9:
+               return "comb_key";
+       case 10:
+               return "unit_key";
+       case 11:
+               return "au_rand";
+       case 12:
+               return "sres";
+       case 13:
+               return "temp_rand";
+       case 14:
+               return "temp_key";
+       case 15:
+               return "encryption_mode_req";
+       case 16:
+               return "encryption_key_size_req";
+       case 17:
+               return "start_encryption_req";
+       case 18:
+               return "stop_encryption_req";
+       case 19:
+               return "switch_req";
+       case 20:
+               return "hold";
+       case 21:
+               return "hold_req";
+       case 22:
+               return "sniff";
+       case 23:
+               return "sniff_req";
+       case 24:
+               return "unsniff_req";
+       case 25:
+               return "park_req";
+       case 26:
+               return "park";
+       case 27:
+               return "set_broadcast_scan_window";
+       case 28:
+               return "modify_beacon";
+       case 29:
+               return "unpark_BD_ADDR_req";
+       case 30:
+               return "unpark_PM_ADDR_req";
+       case 31:
+               return "incr_power_req";
+       case 32:
+               return "decr_power_req";
+       case 33:
+               return "max_power";
+       case 34:
+               return "min_power";
+       case 35:
+               return "auto_rate";
+       case 36:
+               return "preferred_rate";
+       case 37:
+               return "version_req";
+       case 38:
+               return "version_res";
+       case 39:
+               return "feature_req";
+       case 40:
+               return "feature_res";
+       case 41:
+               return "quality_of_service";
+       case 42:
+               return "quality_of_service_req";
+       case 43:
+               return "SCO_link_req";
+       case 44:
+               return "remove_SCO_link_req";
+       case 45:
+               return "max_slot";
+       case 46:
+               return "max_slot_req";
+       case 47:
+               return "timing_accuracy_req";
+       case 48:
+               return "timing_accuracy_res";
+       case 49:
+               return "setup_complete";
+       case 50:
+               return "use_semi_permanent_key";
+       case 51:
+               return "host_connection_req";
+       case 52:
+               return "slot_offset";
+       case 53:
+               return "page_mode_req";
+       case 54:
+               return "page_scan_mode_req";
+       case 55:
+               return "supervision_timeout";
+       case 56:
+               return "test_activate";
+       case 57:
+               return "test_control";
+       case 58:
+               return "encryption_key_size_mask_req";
+       case 59:
+               return "encryption_key_size_mask_res";
+       case 60:
+               return "set_AFH";
+       case 61:
+               return "encapsulated_header";
+       case 62:
+               return "encapsulated_payload";
+       case 63:
+               return "simple_pairing_confirm";
+       case 64:
+               return "simple_pairing_number";
+       case 65:
+               return "DHkey_check";
+       case 127 + (1 << 7):
+               return "accepted_ext";
+       case 127 + (2 << 7):
+               return "not_accepted_ext";
+       case 127 + (3 << 7):
+               return "features_req_ext";
+       case 127 + (4 << 7):
+               return "features_res_ext";
+       case 127 + (11 << 7):
+               return "packet_type_table_req";
+       case 127 + (12 << 7):
+               return "eSCO_link_req";
+       case 127 + (13 << 7):
+               return "remove_eSCO_link_req";
+       case 127 + (16 << 7):
+               return "channel_classification_req";
+       case 127 + (17 << 7):
+               return "channel_classification";
+       case 127 + (21 << 7):
+               return "sniff_subrating_req";
+       case 127 + (22 << 7):
+               return "sniff_subrating_res";
+       case 127 + (23 << 7):
+               return "pause_encryption_req";
+       case 127 + (24 << 7):
+               return "resume_encryption_req";
+       case 127 + (25 << 7):
+               return "IO_capability_req";
+       case 127 + (26 << 7):
+               return "IO_capability_res";
+       case 127 + (27 << 7):
+               return "numeric_comparison_failed";
+       case 127 + (28 << 7):
+               return "passkey_failed";
+       case 127 + (29 << 7):
+               return "oob_failed";
+       case 127 + (30 << 7):
+               return "keypress_notification";
+       default:
+               return "unknown";
+       }
+}
+
+static inline void name_req_dump(int level, struct frame *frm)
+{
+       uint8_t offset = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("name offset %d\n", offset);
+}
+
+static inline void name_res_dump(int level, struct frame *frm)
+{
+       uint8_t offset = LMP_U8(frm);
+       uint8_t length = LMP_U8(frm);
+       uint8_t *name = frm->ptr;
+       int i, size;
+
+       frm->ptr += 14;
+       frm->len -= 14;
+
+       p_indent(level, frm);
+       printf("name offset %d\n", offset);
+
+       p_indent(level, frm);
+       printf("name length %d\n", length);
+
+       size = length - offset;
+       if (size > 14)
+               size = 14;
+
+       p_indent(level, frm);
+       printf("name fragment '");
+       for (i = 0; i < size; i++)
+               if (isprint(name[i]))
+                       printf("%c", name[i]);
+               else
+                       printf(".");
+       printf("'\n");
+}
+
+static inline void accepted_dump(int level, struct frame *frm)
+{
+       uint8_t opcode = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("op code %d (%s)\n", opcode, opcode2str(opcode));
+}
+
+static inline void not_accepted_dump(int level, struct frame *frm)
+{
+       uint8_t opcode = LMP_U8(frm);
+       uint8_t error = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("op code %d (%s)\n", opcode, opcode2str(opcode));
+
+       p_indent(level, frm);
+       printf("error code 0x%2.2x\n", error);
+}
+
+static inline void clkoffset_dump(int level, struct frame *frm)
+{
+       uint16_t clkoffset = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("clock offset 0x%4.4x\n", clkoffset);
+}
+
+static inline void detach_dump(int level, struct frame *frm)
+{
+       uint8_t error = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("error code 0x%2.2x\n", error);
+}
+
+static inline void random_number_dump(int level, struct frame *frm)
+{
+       uint8_t *number = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("random number ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", number[i]);
+       printf("\n");
+}
+
+static inline void key_dump(int level, struct frame *frm)
+{
+       uint8_t *key = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("key ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", key[i]);
+       printf("\n");
+}
+
+static inline void auth_resp_dump(int level, struct frame *frm)
+{
+       uint8_t *resp = frm->ptr;
+       int i;
+
+       frm->ptr += 4;
+       frm->ptr -= 4;
+
+       p_indent(level, frm);
+       printf("authentication response ");
+       for (i = 0; i < 4; i++)
+               printf("%2.2x", resp[i]);
+       printf("\n");
+}
+
+static inline void encryption_mode_req_dump(int level, struct frame *frm)
+{
+       uint8_t mode = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("encryption mode %d\n", mode);
+}
+
+static inline void encryption_key_size_req_dump(int level, struct frame *frm)
+{
+       uint8_t keysize = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("key size %d\n", keysize);
+}
+
+static inline void switch_req_dump(int level, struct frame *frm)
+{
+       uint32_t instant = LMP_U32(frm);
+
+       p_indent(level, frm);
+       printf("switch instant 0x%4.4x\n", instant);
+}
+
+static inline void hold_dump(int level, struct frame *frm)
+{
+       uint16_t time = LMP_U16(frm);
+       uint32_t instant = LMP_U32(frm);
+
+       p_indent(level, frm);
+       printf("hold time 0x%4.4x\n", time);
+
+       p_indent(level, frm);
+       printf("hold instant 0x%4.4x\n", instant);
+}
+
+static inline void sniff_req_dump(int level, struct frame *frm)
+{
+       uint8_t timing = LMP_U8(frm);
+       uint16_t dsniff = LMP_U16(frm);
+       uint16_t tsniff = LMP_U16(frm);
+       uint16_t attempt = LMP_U16(frm);
+       uint16_t timeout = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("timing control flags 0x%2.2x\n", timing);
+
+       p_indent(level, frm);
+       printf("D_sniff %d T_sniff %d\n", dsniff, tsniff);
+
+       p_indent(level, frm);
+       printf("sniff attempt %d\n", attempt);
+
+       p_indent(level, frm);
+       printf("sniff timeout %d\n", timeout);
+}
+
+static inline void park_req_dump(int level, struct frame *frm)
+{
+       uint8_t timing = LMP_U8(frm);
+       uint16_t db = LMP_U16(frm);
+       uint16_t tb = LMP_U16(frm);
+       uint8_t nb = LMP_U8(frm);
+       uint8_t xb = LMP_U8(frm);
+       uint8_t pmaddr = LMP_U8(frm);
+       uint8_t araddr = LMP_U8(frm);
+       uint8_t nbsleep = LMP_U8(frm);
+       uint8_t dbsleep = LMP_U8(frm);
+       uint8_t daccess = LMP_U8(frm);
+       uint8_t taccess = LMP_U8(frm);
+       uint8_t nslots = LMP_U8(frm);
+       uint8_t npoll = LMP_U8(frm);
+       uint8_t access = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("timing control flags 0x%2.2x\n", timing);
+
+       p_indent(level, frm);
+       printf("D_B %d T_B %d N_B %d X_B %d\n", db, tb, nb, xb);
+
+       p_indent(level, frm);
+       printf("PM_ADDR %d AR_ADDR %d\n", pmaddr, araddr);
+
+       p_indent(level, frm);
+       printf("N_Bsleep %d D_Bsleep %d\n", nbsleep, dbsleep);
+
+       p_indent(level, frm);
+       printf("D_access %d T_access %d\n", daccess, taccess);
+
+       p_indent(level, frm);
+       printf("N_acc-slots %d N_poll %d\n", nslots, npoll);
+
+       p_indent(level, frm);
+       printf("M_access %d\n", access & 0x0f);
+
+       p_indent(level, frm);
+       printf("access scheme 0x%2.2x\n", access >> 4);
+}
+
+static inline void modify_beacon_dump(int level, struct frame *frm)
+{
+       uint8_t timing = LMP_U8(frm);
+       uint16_t db = LMP_U16(frm);
+       uint16_t tb = LMP_U16(frm);
+       uint8_t nb = LMP_U8(frm);
+       uint8_t xb = LMP_U8(frm);
+       uint8_t daccess = LMP_U8(frm);
+       uint8_t taccess = LMP_U8(frm);
+       uint8_t nslots = LMP_U8(frm);
+       uint8_t npoll = LMP_U8(frm);
+       uint8_t access = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("timing control flags 0x%2.2x\n", timing);
+
+       p_indent(level, frm);
+       printf("D_B %d T_B %d N_B %d X_B %d\n", db, tb, nb, xb);
+
+       p_indent(level, frm);
+       printf("D_access %d T_access %d\n", daccess, taccess);
+
+       p_indent(level, frm);
+       printf("N_acc-slots %d N_poll %d\n", nslots, npoll);
+
+       p_indent(level, frm);
+       printf("M_access %d\n", access & 0x0f);
+
+       p_indent(level, frm);
+       printf("access scheme 0x%2.2x\n", access >> 4);
+}
+
+static inline void power_req_dump(int level, struct frame *frm)
+{
+       uint8_t val = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("future use 0x%2.2x\n", val);
+}
+
+static inline void preferred_rate_dump(int level, struct frame *frm)
+{
+       uint8_t rate = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("data rate 0x%2.2x\n", rate);
+
+       p_indent(level, frm);
+       printf("Basic: ");
+
+       printf("%suse FEC, ", rate & 0x01 ? "do not " : "");
+
+       switch ((rate >> 1) & 0x03) {
+       case 0x00:
+               printf("no packet-size preference\n");
+               break;
+       case 0x01:
+               printf("use 1-slot packets\n");
+               break;
+       case 0x02:
+               printf("use 3-slot packets\n");
+               break;
+       case 0x03:
+               printf("use 5-slot packets\n");
+               break;
+       }
+
+       p_indent(level, frm);
+       printf("EDR: ");
+
+       switch ((rate >> 3) & 0x03) {
+       case 0x00:
+               printf("use DM1 packets, ");
+               break;
+       case 0x01:
+               printf("use 2 Mbps packets, ");
+               break;
+       case 0x02:
+               printf("use 3 Mbps packets, ");
+               break;
+       case 0x03:
+               printf("reserved, \n");
+               break;
+       }
+
+       switch ((rate >> 5) & 0x03) {
+       case 0x00:
+               printf("no packet-size preference\n");
+               break;
+       case 0x01:
+               printf("use 1-slot packets\n");
+               break;
+       case 0x02:
+               printf("use 3-slot packets\n");
+               break;
+       case 0x03:
+               printf("use 5-slot packets\n");
+               break;
+       }
+}
+
+static inline void version_dump(int level, struct frame *frm)
+{
+       uint8_t ver = LMP_U8(frm);
+       uint16_t compid = LMP_U16(frm);
+       uint16_t subver = LMP_U16(frm);
+       char *tmp;
+
+       p_indent(level, frm);
+       tmp = lmp_vertostr(ver);
+       printf("VersNr %d (%s)\n", ver, tmp);
+       bt_free(tmp);
+
+       p_indent(level, frm);
+       printf("CompId %d (%s)\n", compid, bt_compidtostr(compid));
+
+       p_indent(level, frm);
+       printf("SubVersNr %d\n", subver);
+}
+
+static inline void features_dump(int level, struct frame *frm)
+{
+       uint8_t *features = frm->ptr;
+       int i;
+
+       frm->ptr += 8;
+       frm->len -= 8;
+
+       p_indent(level, frm);
+       printf("features");
+       for (i = 0; i < 8; i++)
+               printf(" 0x%2.2x", features[i]);
+       printf("\n");
+}
+
+static inline void set_afh_dump(int level, struct frame *frm)
+{
+       uint32_t instant = LMP_U32(frm);
+       uint8_t mode = LMP_U8(frm);
+       uint8_t *map = frm->ptr;
+       int i;
+
+       frm->ptr += 10;
+       frm->len -= 10;
+
+       p_indent(level, frm);
+       printf("AFH_instant 0x%04x\n", instant);
+
+       p_indent(level, frm);
+       printf("AFH_mode %d\n", mode);
+
+       p_indent(level, frm);
+       printf("AFH_channel_map 0x");
+       for (i = 0; i < 10; i++)
+               printf("%2.2x", map[i]);
+       printf("\n");
+}
+
+static inline void encapsulated_header_dump(int level, struct frame *frm)
+{
+       uint8_t major = LMP_U8(frm);
+       uint8_t minor = LMP_U8(frm);
+       uint8_t length = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("major type %d minor type %d payload length %d\n",
+                                               major, minor, length);
+
+       if (major == 1 && minor == 1) {
+               p_indent(level, frm);
+               printf("P-192 Public Key\n");
+       }
+}
+
+static inline void encapsulated_payload_dump(int level, struct frame *frm)
+{
+       uint8_t *value = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("data ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", value[i]);
+       printf("\n");
+}
+
+static inline void simple_pairing_confirm_dump(int level, struct frame *frm)
+{
+       uint8_t *value = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("commitment value ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", value[i]);
+       printf("\n");
+}
+
+static inline void simple_pairing_number_dump(int level, struct frame *frm)
+{
+       uint8_t *value = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("nounce value ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", value[i]);
+       printf("\n");
+}
+
+static inline void dhkey_check_dump(int level, struct frame *frm)
+{
+       uint8_t *value = frm->ptr;
+       int i;
+
+       frm->ptr += 16;
+       frm->len -= 16;
+
+       p_indent(level, frm);
+       printf("confirmation value ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", value[i]);
+       printf("\n");
+}
+
+static inline void accepted_ext_dump(int level, struct frame *frm)
+{
+       uint16_t opcode = LMP_U8(frm) + (LMP_U8(frm) << 7);
+
+       p_indent(level, frm);
+       printf("op code %d/%d (%s)\n", opcode & 0x7f, opcode >> 7, opcode2str(opcode));
+}
+
+static inline void not_accepted_ext_dump(int level, struct frame *frm)
+{
+       uint16_t opcode = LMP_U8(frm) + (LMP_U8(frm) << 7);
+       uint8_t error = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("op code %d/%d (%s)\n", opcode & 0x7f, opcode >> 7, opcode2str(opcode));
+
+       p_indent(level, frm);
+       printf("error code 0x%2.2x\n", error);
+}
+
+static inline void features_ext_dump(int level, struct frame *frm)
+{
+       uint8_t page = LMP_U8(frm);
+       uint8_t max = LMP_U8(frm);
+       uint8_t *features = frm->ptr;
+       int i;
+
+       frm->ptr += 8;
+       frm->len -= 8;
+
+       p_indent(level, frm);
+       printf("features page %d\n", page);
+
+       p_indent(level, frm);
+       printf("max supported page %d\n", max);
+
+       p_indent(level, frm);
+       printf("extended features");
+       for (i = 0; i < 8; i++)
+               printf(" 0x%2.2x", features[i]);
+       printf("\n");
+}
+
+static inline void quality_of_service_dump(int level, struct frame *frm)
+{
+       uint16_t interval = LMP_U16(frm);
+       uint8_t nbc = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("poll interval %d\n", interval);
+
+       p_indent(level, frm);
+       printf("N_BC %d\n", nbc);
+}
+
+static inline void sco_link_req_dump(int level, struct frame *frm)
+{
+       uint8_t handle = LMP_U8(frm);
+       uint8_t timing = LMP_U8(frm);
+       uint8_t dsco = LMP_U8(frm);
+       uint8_t tsco = LMP_U8(frm);
+       uint8_t packet = LMP_U8(frm);
+       uint8_t airmode = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("SCO handle %d\n", handle);
+
+       p_indent(level, frm);
+       printf("timing control flags 0x%2.2x\n", timing);
+
+       p_indent(level, frm);
+       printf("D_SCO %d T_SCO %d\n", dsco, tsco);
+
+       p_indent(level, frm);
+       printf("SCO packet 0x%2.2x\n", packet);
+
+       p_indent(level, frm);
+       printf("air mode 0x%2.2x\n", airmode);
+}
+
+static inline void remove_sco_link_req_dump(int level, struct frame *frm)
+{
+       uint8_t handle = LMP_U8(frm);
+       uint8_t error = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("SCO handle %d\n", handle);
+
+       p_indent(level, frm);
+       printf("error code 0x%2.2x\n", error);
+}
+
+static inline void max_slots_dump(int level, struct frame *frm)
+{
+       uint8_t slots = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("max slots %d\n", slots);
+}
+
+static inline void timing_accuracy_dump(int level, struct frame *frm)
+{
+       uint8_t drift = LMP_U8(frm);
+       uint8_t jitter = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("drift %d\n", drift);
+
+       p_indent(level, frm);
+       printf("jitter %d\n", jitter);
+}
+
+static inline void slot_offset_dump(int level, struct frame *frm)
+{
+       uint16_t offset = LMP_U16(frm);
+       char addr[18];
+
+       p_ba2str((bdaddr_t *) frm->ptr, addr);
+
+       p_indent(level, frm);
+       printf("slot offset %d\n", offset);
+
+       p_indent(level, frm);
+       printf("BD_ADDR %s\n", addr);
+}
+
+static inline void page_mode_dump(int level, struct frame *frm)
+{
+       uint8_t scheme = LMP_U8(frm);
+       uint8_t settings = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("page scheme %d\n", scheme);
+
+       p_indent(level, frm);
+       printf("page scheme settings %d\n", settings);
+}
+
+static inline void supervision_timeout_dump(int level, struct frame *frm)
+{
+       uint16_t timeout = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("supervision timeout %d\n", timeout);
+}
+
+static inline void test_control_dump(int level, struct frame *frm)
+{
+       uint8_t scenario = LMP_U8(frm);
+       uint8_t hopping = LMP_U8(frm);
+       uint8_t txfreq = LMP_U8(frm);
+       uint8_t rxfreq = LMP_U8(frm);
+       uint8_t power = LMP_U8(frm);
+       uint8_t poll = LMP_U8(frm);
+       uint8_t packet = LMP_U8(frm);
+       uint16_t length = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("test scenario %d\n", scenario);
+
+       p_indent(level, frm);
+       printf("hopping mode %d\n", hopping);
+
+       p_indent(level, frm);
+       printf("TX frequency %d\n", txfreq);
+
+       p_indent(level, frm);
+       printf("RX frequency %d\n", rxfreq);
+
+       p_indent(level, frm);
+       printf("power control mode %d\n", power);
+
+       p_indent(level, frm);
+       printf("poll period %d\n", poll);
+
+       p_indent(level, frm);
+       printf("poll period %d\n", poll);
+
+       p_indent(level, frm);
+       printf("packet type 0x%2.2x\n", packet);
+
+       p_indent(level, frm);
+       printf("length of test data %d\n", length);
+}
+
+static inline void encryption_key_size_mask_res_dump(int level, struct frame *frm)
+{
+       uint16_t mask = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("key size mask 0x%4.4x\n", mask);
+}
+
+static inline void packet_type_table_dump(int level, struct frame *frm)
+{
+       uint8_t type = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("packet type table %d ", type);
+       switch (type) {
+       case 0:
+               printf("(1Mbps only)\n");
+               break;
+       case 1:
+               printf("(2/3Mbps)\n");
+               break;
+       default:
+               printf("(Reserved)\n");
+               break;
+       }
+}
+
+static inline void esco_link_req_dump(int level, struct frame *frm)
+{
+       uint8_t handle = LMP_U8(frm);
+       uint8_t ltaddr = LMP_U8(frm);
+       uint8_t timing = LMP_U8(frm);
+       uint8_t desco = LMP_U8(frm);
+       uint8_t tesco = LMP_U8(frm);
+       uint8_t wesco = LMP_U8(frm);
+       uint8_t mspkt = LMP_U8(frm);
+       uint8_t smpkt = LMP_U8(frm);
+       uint16_t mslen = LMP_U16(frm);
+       uint16_t smlen = LMP_U16(frm);
+       uint8_t airmode = LMP_U8(frm);
+       uint8_t negstate = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("eSCO handle %d\n", handle);
+
+       p_indent(level, frm);
+       printf("eSCO LT_ADDR %d\n", ltaddr);
+
+       p_indent(level, frm);
+       printf("timing control flags 0x%2.2x\n", timing);
+
+       p_indent(level, frm);
+       printf("D_eSCO %d T_eSCO %d W_eSCO %d\n", desco, tesco, wesco);
+
+       p_indent(level, frm);
+       printf("eSCO M->S packet type 0x%2.2x length %d\n", mspkt, mslen);
+
+       p_indent(level, frm);
+       printf("eSCO S->M packet type 0x%2.2x length %d\n", smpkt, smlen);
+
+       p_indent(level, frm);
+       printf("air mode 0x%2.2x\n", airmode);
+
+       p_indent(level, frm);
+       printf("negotiation state 0x%2.2x\n", negstate);
+}
+
+static inline void remove_esco_link_req_dump(int level, struct frame *frm)
+{
+       uint8_t handle = LMP_U8(frm);
+       uint8_t error = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("eSCO handle %d\n", handle);
+
+       p_indent(level, frm);
+       printf("error code 0x%2.2x\n", error);
+}
+
+static inline void channel_classification_req_dump(int level, struct frame *frm)
+{
+       uint8_t mode = LMP_U8(frm);
+       uint16_t min = LMP_U16(frm);
+       uint16_t max = LMP_U16(frm);
+
+       p_indent(level, frm);
+       printf("AFH reporting mode %d\n", mode);
+
+       p_indent(level, frm);
+       printf("AFH min interval 0x%4.4x\n", min);
+
+       p_indent(level, frm);
+       printf("AFH max interval 0x%4.4x\n", max);
+}
+
+static inline void channel_classification_dump(int level, struct frame *frm)
+{
+       uint8_t *map = frm->ptr;
+       int i;
+
+       frm->ptr += 10;
+       frm->len -= 10;
+
+       p_indent(level, frm);
+       printf("AFH channel classification 0x");
+       for (i = 0; i < 10; i++)
+               printf("%2.2x", map[i]);
+       printf("\n");
+}
+
+static inline void sniff_subrating_dump(int level, struct frame *frm)
+{
+       uint8_t subrate = LMP_U8(frm);
+       uint16_t timeout = LMP_U16(frm);
+       uint32_t instant = LMP_U32(frm);
+
+       p_indent(level, frm);
+       printf("max subrate %d\n", subrate);
+
+       p_indent(level, frm);
+       printf("min sniff timeout %d\n", timeout);
+
+       p_indent(level, frm);
+       printf("subrate instant 0x%4.4x\n", instant);
+}
+
+static inline void io_capability_dump(int level, struct frame *frm)
+{
+       uint8_t capability = LMP_U8(frm);
+       uint8_t oob_data = LMP_U8(frm);
+       uint8_t authentication = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("capability 0x%2.2x oob 0x%2.2x auth 0x%2.2x\n",
+                               capability, oob_data, authentication);
+}
+
+static inline void keypress_notification_dump(int level, struct frame *frm)
+{
+       uint8_t value = LMP_U8(frm);
+
+       p_indent(level, frm);
+       printf("notification value %d\n", value);
+}
+
+void lmp_dump(int level, struct frame *frm)
+{
+       uint8_t tmp, tid;
+       uint16_t opcode;
+
+       p_indent(level, frm);
+
+       tmp = LMP_U8(frm);
+       tid = tmp & 0x01;
+       opcode = (tmp & 0xfe) >> 1;
+       if (opcode > 123) {
+               tmp = LMP_U8(frm);
+               opcode += tmp << 7;
+       }
+
+       printf("LMP(%c): %s(%c): ", frm->master ? 's' : 'r',
+                               opcode2str(opcode), tid ? 's' : 'm');
+
+       if (opcode > 123)
+               printf("op code %d/%d", opcode & 0x7f, opcode >> 7);
+       else
+               printf("op code %d", opcode);
+
+       if (frm->handle > 17)
+               printf(" handle %d\n", frm->handle);
+       else
+               printf("\n");
+
+       if (!(parser.flags & DUMP_VERBOSE)) {
+               raw_dump(level, frm);
+               return;
+       }
+
+       switch (opcode) {
+       case 1:
+               name_req_dump(level + 1, frm);
+               return;
+       case 2:
+               name_res_dump(level + 1, frm);
+               return;
+       case 3:
+               accepted_dump(level + 1, frm);
+               return;
+       case 4:
+               not_accepted_dump(level + 1, frm);
+               return;
+       case 6:
+               clkoffset_dump(level + 1, frm);
+               return;
+       case 7:
+               detach_dump(level + 1, frm);
+               return;
+       case 8:
+               in_rand(frm);
+               random_number_dump(level + 1, frm);
+               return;
+       case 9:
+               comb_key(frm);
+               random_number_dump(level + 1, frm);
+               return;
+       case 11:
+               au_rand(frm);
+               random_number_dump(level + 1, frm);
+               return;
+       case 12:
+               sres(frm);
+               auth_resp_dump(level + 1, frm);
+               return;
+       case 13:
+       case 17:
+               random_number_dump(level + 1, frm);
+               return;
+       case 10:
+       case 14:
+               key_dump(level + 1, frm);
+               return;
+       case 15:
+               encryption_mode_req_dump(level + 1, frm);
+               return;
+       case 16:
+               encryption_key_size_req_dump(level + 1, frm);
+               return;
+       case 19:
+               switch_req_dump(level + 1, frm);
+               return;
+       case 20:
+       case 21:
+               hold_dump(level + 1, frm);
+               return;
+       case 23:
+               sniff_req_dump(level + 1, frm);
+               return;
+       case 25:
+               park_req_dump(level + 1, frm);
+               return;
+       case 28:
+               modify_beacon_dump(level + 1, frm);
+               return;
+       case 31:
+       case 32:
+               power_req_dump(level + 1, frm);
+               return;
+       case 36:
+               preferred_rate_dump(level + 1, frm);
+               return;
+       case 37:
+       case 38:
+               version_dump(level + 1, frm);
+               return;
+       case 39:
+       case 40:
+               features_dump(level + 1, frm);
+               return;
+       case 41:
+       case 42:
+               quality_of_service_dump(level + 1, frm);
+               return;
+       case 43:
+               sco_link_req_dump(level + 1, frm);
+               return;
+       case 44:
+               remove_sco_link_req_dump(level + 1, frm);
+               return;
+       case 45:
+       case 46:
+               max_slots_dump(level + 1, frm);
+               return;
+       case 48:
+               timing_accuracy_dump(level + 1, frm);
+               return;
+       case 52:
+               slot_offset_dump(level + 1, frm);
+               return;
+       case 53:
+       case 54:
+               page_mode_dump(level + 1, frm);
+               return;
+       case 55:
+               supervision_timeout_dump(level + 1, frm);
+               return;
+       case 57:
+               test_control_dump(level + 1, frm);
+               return;
+       case 59:
+               encryption_key_size_mask_res_dump(level + 1, frm);
+               return;
+       case 60:
+               set_afh_dump(level + 1, frm);
+               return;
+       case 61:
+               encapsulated_header_dump(level + 1, frm);
+               return;
+       case 62:
+               encapsulated_payload_dump(level + 1, frm);
+               return;
+       case 63:
+               simple_pairing_confirm_dump(level + 1, frm);
+               return;
+       case 64:
+               simple_pairing_number_dump(level + 1, frm);
+               return;
+       case 65:
+               dhkey_check_dump(level + 1, frm);
+               return;
+       case 5:
+       case 18:
+       case 24:
+       case 33:
+       case 34:
+       case 35:
+       case 47:
+       case 49:
+       case 50:
+       case 51:
+       case 56:
+       case 58:
+       case 127 + (23 << 7):
+       case 127 + (24 << 7):
+       case 127 + (27 << 7):
+       case 127 + (28 << 7):
+       case 127 + (29 << 7):
+               return;
+       case 127 + (1 << 7):
+               accepted_ext_dump(level + 1, frm);
+               return;
+       case 127 + (2 << 7):
+               not_accepted_ext_dump(level + 1, frm);
+               return;
+       case 127 + (3 << 7):
+       case 127 + (4 << 7):
+               features_ext_dump(level + 1, frm);
+               return;
+       case 127 + (11 << 7):
+               packet_type_table_dump(level + 1, frm);
+               return;
+       case 127 + (12 << 7):
+               esco_link_req_dump(level + 1, frm);
+               return;
+       case 127 + (13 << 7):
+               remove_esco_link_req_dump(level + 1, frm);
+               return;
+       case 127 + (16 << 7):
+               channel_classification_req_dump(level + 1, frm);
+               return;
+       case 127 + (17 << 7):
+               channel_classification_dump(level + 1, frm);
+               return;
+       case 127 + (21 << 7):
+       case 127 + (22 << 7):
+               sniff_subrating_dump(level + 1, frm);
+               return;
+       case 127 + (25 << 7):
+       case 127 + (26 << 7):
+               io_capability_dump(level + 1, frm);
+               return;
+       case 127 + (30 << 7):
+               keypress_notification_dump(level + 1, frm);
+               return;
+       }
+
+       raw_dump(level, frm);
+}
diff --git a/tools/parser/obex.c b/tools/parser/obex.c
new file mode 100644 (file)
index 0000000..66b7eff
--- /dev/null
@@ -0,0 +1,351 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+static char *opcode2str(uint8_t opcode)
+{
+       switch (opcode & 0x7f) {
+       case 0x00:
+               return "Connect";
+       case 0x01:
+               return "Disconnect";
+       case 0x02:
+               return "Put";
+       case 0x03:
+               return "Get";
+       case 0x04:
+               return "Reserved";
+       case 0x05:
+               return "SetPath";
+       case 0x06:
+               return "Action";
+       case 0x07:
+               return "Session";
+       case 0x7f:
+               return "Abort";
+       case 0x10:
+               return "Continue";
+       case 0x20:
+               return "Success";
+       case 0x21:
+               return "Created";
+       case 0x22:
+               return "Accepted";
+       case 0x23:
+               return "Non-authoritative information";
+       case 0x24:
+               return "No content";
+       case 0x25:
+               return "Reset content";
+       case 0x26:
+               return "Partial content";
+       case 0x30:
+               return "Multiple choices";
+       case 0x31:
+               return "Moved permanently";
+       case 0x32:
+               return "Moved temporarily";
+       case 0x33:
+               return "See other";
+       case 0x34:
+               return "Not modified";
+       case 0x35:
+               return "Use Proxy";
+       case 0x40:
+               return "Bad request";
+       case 0x41:
+               return "Unauthorized";
+       case 0x42:
+               return "Payment required";
+       case 0x43:
+               return "Forbidden";
+       case 0x44:
+               return "Not found";
+       case 0x45:
+               return "Method not allowed";
+       case 0x46:
+               return "Not acceptable";
+       case 0x47:
+               return "Proxy authentication required";
+       case 0x48:
+               return "Request timeout";
+       case 0x49:
+               return "Conflict";
+       case 0x4a:
+               return "Gone";
+       case 0x4b:
+               return "Length required";
+       case 0x4c:
+               return "Precondition failed";
+       case 0x4d:
+               return "Requested entity too large";
+       case 0x4e:
+               return "Requested URL too large";
+       case 0x4f:
+               return "Unsupported media type";
+       case 0x50:
+               return "Internal server error";
+       case 0x51:
+               return "Not implemented";
+       case 0x52:
+               return "Bad gateway";
+       case 0x53:
+               return "Service unavailable";
+       case 0x54:
+               return "Gateway timeout";
+       case 0x55:
+               return "HTTP version not supported";
+       case 0x60:
+               return "Database full";
+       case 0x61:
+               return "Database locked";
+       default:
+               return "Unknown";
+       }
+}
+
+static char *hi2str(uint8_t hi)
+{
+       switch (hi & 0x3f) {
+       case 0x00:
+               return "Count";
+       case 0x01:
+               return "Name";
+       case 0x02:
+               return "Type";
+       case 0x03:
+               return "Length";
+       case 0x04:
+               return "Time";
+       case 0x05:
+               return "Description";
+       case 0x06:
+               return "Target";
+       case 0x07:
+               return "HTTP";
+       case 0x08:
+               return "Body";
+       case 0x09:
+               return "End of Body";
+       case 0x0a:
+               return "Who";
+       case 0x0b:
+               return "Connection ID";
+       case 0x0c:
+               return "App. Parameters";
+       case 0x0d:
+               return "Auth. Challenge";
+       case 0x0e:
+               return "Auth. Response";
+       case 0x0f:
+               return "Creator ID";
+       case 0x10:
+               return "WAN UUID";
+       case 0x11:
+               return "Object Class";
+       case 0x12:
+               return "Session Parameters";
+       case 0x13:
+               return "Session Sequence Number";
+       case 0x14:
+               return "Action ID";
+       case 0x15:
+               return "DestName";
+       case 0x16:
+               return "Permission";
+       case 0x17:
+               return "Single Response Mode";
+       case 0x18:
+               return "Single Response Mode Parameters";
+       default:
+               return "Unknown";
+       }
+}
+
+static void parse_headers(int level, struct frame *frm)
+{
+       uint8_t hi, hv8;
+       uint16_t len;
+       uint32_t hv32;
+
+       while (frm->len > 0) {
+               hi = get_u8(frm);
+
+               p_indent(level, frm);
+
+               printf("%s (0x%02x)", hi2str(hi), hi);
+               switch (hi & 0xc0) {
+               case 0x00:      /* Unicode */
+                       if (frm->len < 2) {
+                               printf("\n");
+                               return;
+                       }
+
+                       len = get_u16(frm) - 3;
+                       printf(" = Unicode length %d\n", len);
+
+                       if (frm->len < len)
+                               return;
+
+                       raw_ndump(level, frm, len);
+                       frm->ptr += len;
+                       frm->len -= len;
+                       break;
+
+               case 0x40:      /* Byte sequence */
+                       if (frm->len < 2) {
+                               printf("\n");
+                               return;
+                       }
+
+                       len = get_u16(frm) - 3;
+                       printf(" = Sequence length %d\n", len);
+
+                       if (frm->len < len)
+                               return;
+
+                       raw_ndump(level, frm, len);
+                       frm->ptr += len;
+                       frm->len -= len;
+                       break;
+
+               case 0x80:      /* One byte */
+                       if (frm->len < 1) {
+                               printf("\n");
+                               return;
+                       }
+
+                       hv8 = get_u8(frm);
+                       printf(" = %d\n", hv8);
+                       break;
+
+               case 0xc0:      /* Four bytes */
+                       if (frm->len < 4) {
+                               printf("\n");
+                               return;
+                       }
+
+                       hv32 = get_u32(frm);
+                       printf(" = %u\n", hv32);
+                       break;
+               }
+       }
+}
+
+void obex_dump(int level, struct frame *frm)
+{
+       uint8_t last_opcode, opcode, status;
+       uint8_t version, flags, constants;
+       uint16_t length, pktlen;
+
+       frm = add_frame(frm);
+
+       while (frm->len > 2) {
+               opcode = get_u8(frm);
+               length = get_u16(frm);
+               status = opcode & 0x7f;
+
+               if ((int) frm->len < length - 3) {
+                       frm->ptr -= 3;
+                       frm->len += 3;
+                       return;
+               }
+
+               p_indent(level, frm);
+
+               last_opcode = get_opcode(frm->handle, frm->dlci);
+
+               if (!(opcode & 0x70)) {
+                       printf("OBEX: %s cmd(%c): len %d",
+                                       opcode2str(opcode),
+                                       opcode & 0x80 ? 'f' : 'c', length);
+                       set_opcode(frm->handle, frm->dlci, opcode);
+               } else {
+                       printf("OBEX: %s rsp(%c): status %x%02d len %d",
+                                       opcode2str(last_opcode),
+                                       opcode & 0x80 ? 'f' : 'c',
+                                       status >> 4, status & 0xf, length);
+                       opcode = last_opcode;
+               }
+
+               if (get_status(frm->handle, frm->dlci) == 0x10)
+                       printf(" (continue)");
+
+               set_status(frm->handle, frm->dlci, status);
+
+               if (frm->len == 0) {
+                       printf("\n");
+                       break;
+               }
+
+               switch (opcode & 0x7f) {
+               case 0x00:      /* Connect */
+                       if (frm->len < 4) {
+                               printf("\n");
+                               return;
+                       }
+
+                       version = get_u8(frm);
+                       flags   = get_u8(frm);
+                       pktlen  = get_u16(frm);
+                       printf(" version %d.%d flags %d mtu %d\n",
+                               version >> 4, version & 0xf, flags, pktlen);
+                       break;
+
+               case 0x05:      /* SetPath */
+                       if (frm->len < 2) {
+                               printf("\n");
+                               return;
+                       }
+
+                       flags     = get_u8(frm);
+                       constants = get_u8(frm);
+                       printf(" flags %d constants %d\n", flags, constants);
+                       break;
+
+               default:
+                       printf("\n");
+                       break;
+               }
+
+               if ((status & 0x70) && (parser.flags & DUMP_VERBOSE)) {
+                       p_indent(level, frm);
+                       printf("Status %x%02d = %s\n",
+                                       status >> 4, status & 0xf,
+                                                       opcode2str(status));
+               }
+
+               parse_headers(level, frm);
+       }
+}
diff --git a/tools/parser/parser.c b/tools/parser/parser.c
new file mode 100644 (file)
index 0000000..de8dbe8
--- /dev/null
@@ -0,0 +1,343 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+#include "rfcomm.h"
+
+struct parser_t parser;
+
+void init_parser(unsigned long flags, unsigned long filter,
+               unsigned short defpsm, unsigned short defcompid,
+               int pppdump_fd, int audio_fd)
+{
+       if ((flags & DUMP_RAW) && !(flags & DUMP_TYPE_MASK))
+               flags |= DUMP_HEX;
+
+       parser.flags      = flags;
+       parser.filter     = filter;
+       parser.defpsm     = defpsm;
+       parser.defcompid  = defcompid;
+       parser.state      = 0;
+       parser.pppdump_fd = pppdump_fd;
+       parser.audio_fd   = audio_fd;
+}
+
+#define PROTO_TABLE_SIZE 20
+
+static struct {
+       uint16_t handle;
+       uint16_t psm;
+       uint8_t  channel;
+       uint32_t proto;
+} proto_table[PROTO_TABLE_SIZE];
+
+void set_proto(uint16_t handle, uint16_t psm, uint8_t channel, uint32_t proto)
+{
+       int i, pos = -1;
+
+       if (psm > 0 && psm < 0x1000 && !channel)
+               return;
+
+       if (!psm && channel)
+               psm = RFCOMM_PSM; 
+
+       for (i = 0; i < PROTO_TABLE_SIZE; i++) {
+               if (proto_table[i].handle == handle && proto_table[i].psm == psm && proto_table[i].channel == channel) {
+                       pos = i;
+                       break;
+               }
+
+               if (pos < 0 && !proto_table[i].handle && !proto_table[i].psm && !proto_table[i].channel)
+                       pos = i;
+       }
+
+       if (pos < 0)
+               return;
+
+       proto_table[pos].handle  = handle;
+       proto_table[pos].psm     = psm;
+       proto_table[pos].channel = channel;
+       proto_table[pos].proto   = proto;
+}
+
+uint32_t get_proto(uint16_t handle, uint16_t psm, uint8_t channel)
+{
+       int i, pos = -1;
+
+       if (!psm && channel)
+               psm = RFCOMM_PSM;
+
+       for (i = 0; i < PROTO_TABLE_SIZE; i++) {
+               if (proto_table[i].handle == handle && proto_table[i].psm == psm && proto_table[i].channel == channel)
+                       return proto_table[i].proto;
+
+               if (!proto_table[i].handle) {
+                       if (proto_table[i].psm == psm && proto_table[i].channel == channel)
+                               pos = i;
+               }
+       }
+
+       return (pos < 0) ? 0 : proto_table[pos].proto;
+}
+
+#define FRAME_TABLE_SIZE 20
+
+static struct {
+       uint16_t handle;
+       uint8_t dlci;
+       uint8_t opcode;
+       uint8_t status;
+       struct frame frm;
+} frame_table[FRAME_TABLE_SIZE];
+
+void del_frame(uint16_t handle, uint8_t dlci)
+{
+       int i;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++)
+               if (frame_table[i].handle == handle &&
+                                       frame_table[i].dlci == dlci) {
+                       frame_table[i].handle = 0;
+                       frame_table[i].dlci   = 0;
+                       frame_table[i].opcode = 0;
+                       frame_table[i].status = 0;
+                       if (frame_table[i].frm.data)
+                               free(frame_table[i].frm.data);
+                       memset(&frame_table[i].frm, 0, sizeof(struct frame));
+                       break;
+               }
+}
+
+struct frame *add_frame(struct frame *frm)
+{
+       struct frame *fr;
+       void *data;
+       int i, pos = -1;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++) {
+               if (frame_table[i].handle == frm->handle &&
+                                       frame_table[i].dlci == frm->dlci) {
+                       pos = i;
+                       break;
+               }
+
+               if (pos < 0 && !frame_table[i].handle && !frame_table[i].dlci)
+                       pos = i;
+       }
+
+       if (pos < 0)
+               return frm;
+
+       frame_table[pos].handle = frm->handle;
+       frame_table[pos].dlci   = frm->dlci;
+       fr = &frame_table[pos].frm;
+
+       data = malloc(fr->len + frm->len);
+       if (!data) {
+               perror("Can't allocate frame stream buffer");
+               del_frame(frm->handle, frm->dlci);
+               return frm;
+       }
+
+       if (fr->len > 0)
+               memcpy(data, fr->ptr, fr->len);
+
+       if (frm->len > 0)
+               memcpy(data + fr->len, frm->ptr, frm->len);
+
+       if (fr->data)
+               free(fr->data);
+
+       fr->data       = data;
+       fr->data_len   = fr->len + frm->len;
+       fr->len        = fr->data_len;
+       fr->ptr        = fr->data;
+       fr->dev_id     = frm->dev_id;
+       fr->in         = frm->in;
+       fr->ts         = frm->ts;
+       fr->handle     = frm->handle;
+       fr->cid        = frm->cid;
+       fr->num        = frm->num;
+       fr->dlci       = frm->dlci;
+       fr->channel    = frm->channel;
+       fr->pppdump_fd = frm->pppdump_fd;
+       fr->audio_fd   = frm->audio_fd;
+
+       return fr;
+}
+
+uint8_t get_opcode(uint16_t handle, uint8_t dlci)
+{
+       int i;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++)
+               if (frame_table[i].handle == handle &&
+                                       frame_table[i].dlci == dlci)
+                       return frame_table[i].opcode;
+
+       return 0x00;
+}
+
+void set_opcode(uint16_t handle, uint8_t dlci, uint8_t opcode)
+{
+       int i;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++)
+               if (frame_table[i].handle == handle && 
+                                       frame_table[i].dlci == dlci) {
+                       frame_table[i].opcode = opcode;
+                       break;
+               }
+}
+
+uint8_t get_status(uint16_t handle, uint8_t dlci)
+{
+       int i;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++)
+               if (frame_table[i].handle == handle &&
+                                       frame_table[i].dlci == dlci)
+                       return frame_table[i].status;
+
+       return 0x00;
+}
+
+void set_status(uint16_t handle, uint8_t dlci, uint8_t status)
+{
+       int i;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++)
+               if (frame_table[i].handle == handle &&
+                                       frame_table[i].dlci == dlci) {
+                       frame_table[i].status = status;
+                       break;
+               }
+}
+
+void ascii_dump(int level, struct frame *frm, int num)
+{
+       unsigned char *buf = frm->ptr;
+       register int i, n;
+
+       if ((num < 0) || (num > (int) frm->len))
+               num = frm->len;
+
+       for (i = 0, n = 1; i < num; i++, n++) {
+               if (n == 1)
+                       p_indent(level, frm);
+               printf("%1c ", isprint(buf[i]) ? buf[i] : '.');
+               if (n == DUMP_WIDTH) {
+                       printf("\n");
+                       n = 0;
+               }
+       }
+       if (i && n != 1)
+               printf("\n");
+}
+
+void hex_dump(int level, struct frame *frm, int num)
+{
+       unsigned char *buf = frm->ptr;
+       register int i, n;
+
+       if ((num < 0) || (num > (int) frm->len))
+               num = frm->len;
+
+       for (i = 0, n = 1; i < num; i++, n++) {
+               if (n == 1)
+                       p_indent(level, frm);
+               printf("%2.2X ", buf[i]);
+               if (n == DUMP_WIDTH) {
+                       printf("\n");
+                       n = 0;
+               }
+       }
+       if (i && n != 1)
+               printf("\n");
+}
+
+void ext_dump(int level, struct frame *frm, int num)
+{
+       unsigned char *buf = frm->ptr;
+       register int i, n = 0, size;
+
+       if ((num < 0) || (num > (int) frm->len))
+               num = frm->len;
+
+       while (num > 0) {
+               p_indent(level, frm);
+               printf("%04x: ", n);
+
+               size = num > 16 ? 16 : num;
+
+               for (i = 0; i < size; i++)
+                       printf("%02x%s", buf[i], (i + 1) % 8 ? " " : "  ");
+               for (i = size; i < 16; i++)
+                       printf("  %s", (i + 1) % 8 ? " " : "  ");
+
+               for (i = 0; i < size; i++)
+                       printf("%1c", isprint(buf[i]) ? buf[i] : '.');
+               printf("\n");
+
+               buf  += size;
+               num  -= size;
+               n    += size;
+       }
+}
+
+void raw_ndump(int level, struct frame *frm, int num)
+{
+       if (!frm->len)
+               return;
+
+       switch (parser.flags & DUMP_TYPE_MASK) {
+       case DUMP_ASCII:
+               ascii_dump(level, frm, num);
+               break;
+
+       case DUMP_HEX:
+               hex_dump(level, frm, num);
+               break;
+
+       case DUMP_EXT:
+               ext_dump(level, frm, num);
+               break;
+       }
+}
+
+void raw_dump(int level, struct frame *frm)
+{
+       raw_ndump(level, frm, -1);
+}
diff --git a/tools/parser/parser.h b/tools/parser/parser.h
new file mode 100644 (file)
index 0000000..c65b4b5
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2000-2002  Maxim Krasnyansky <maxk@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __PARSER_H
+#define __PARSER_H
+
+#include <time.h>
+#include <sys/time.h>
+#include <netinet/in.h>
+
+#include "lib/bluetooth.h"
+
+struct frame {
+       void            *data;
+       uint32_t        data_len;
+       void            *ptr;
+       uint32_t        len;
+       uint16_t        dev_id;
+       uint8_t         in;
+       uint8_t         master;
+       uint16_t        handle;
+       uint16_t        cid;
+       uint16_t        num;
+       uint8_t         dlci;
+       uint8_t         channel;
+       unsigned long   flags;
+       struct timeval  ts;
+       int             pppdump_fd;
+       int             audio_fd;
+};
+
+/* Parser flags */
+#define DUMP_WIDTH     20
+
+#define DUMP_ASCII     0x0001
+#define DUMP_HEX       0x0002
+#define DUMP_EXT       0x0004
+#define DUMP_RAW       0x0008
+#define DUMP_BPA       0x0010
+#define DUMP_TSTAMP    0x0100
+#define DUMP_VERBOSE   0x0200
+#define DUMP_BTSNOOP   0x1000
+#define DUMP_PKTLOG    0x2000
+#define DUMP_NOVENDOR  0x4000
+#define DUMP_TYPE_MASK (DUMP_ASCII | DUMP_HEX | DUMP_EXT)
+
+/* Parser filter */
+#define FILT_LMP       0x0001
+#define FILT_HCI       0x0002
+#define FILT_SCO       0x0004
+#define FILT_L2CAP     0x0008
+#define FILT_RFCOMM    0x0010
+#define FILT_SDP       0x0020
+#define FILT_BNEP      0x0040
+#define FILT_CMTP      0x0080
+#define FILT_HIDP      0x0100
+#define FILT_HCRP      0x0200
+#define FILT_AVDTP     0x0400
+#define FILT_AVCTP     0x0800
+#define FILT_ATT       0x1000
+#define FILT_SMP       0x2000
+#define FILT_A2MP      0x4000
+
+#define FILT_OBEX      0x00010000
+#define FILT_CAPI      0x00020000
+#define FILT_PPP       0x00040000
+#define FILT_SAP       0x00080000
+#define FILT_ERICSSON  0x10000000
+#define FILT_CSR       0x1000000a
+#define FILT_DGA       0x1000000c
+
+#define STRUCT_OFFSET(type, member)  ((uint8_t *)&(((type *)NULL)->member) - \
+                                     (uint8_t *)((type *)NULL))
+
+#define STRUCT_END(type, member)     (STRUCT_OFFSET(type, member) + \
+                                     sizeof(((type *)NULL)->member))
+
+#define DEFAULT_COMPID 65535
+
+struct parser_t {
+       unsigned long flags;
+       unsigned long filter;
+       unsigned short defpsm;
+       unsigned short defcompid;
+       int state;
+       int pppdump_fd;
+       int audio_fd;
+};
+
+extern struct parser_t parser;
+
+void init_parser(unsigned long flags, unsigned long filter,
+               unsigned short defpsm, unsigned short defcompid,
+               int pppdump_fd, int audio_fd);
+
+static inline int p_filter(unsigned long f)
+{
+       return !(parser.filter & f);
+}
+
+static inline void p_indent(int level, struct frame *f)
+{
+       if (level < 0) {
+               parser.state = 0;
+               return;
+       }
+
+       if (!parser.state) {
+               if (parser.flags & DUMP_TSTAMP) {
+                       if (parser.flags & DUMP_VERBOSE) {
+                               struct tm tm;
+                               time_t t = f->ts.tv_sec;
+                               localtime_r(&t, &tm);
+                               printf("%04d-%02d-%02d %02d:%02d:%02d.%06lu ",
+                                       tm.tm_year + 1900, tm.tm_mon + 1, tm.tm_mday,
+                                       tm.tm_hour, tm.tm_min, tm.tm_sec, f->ts.tv_usec);
+                       } else
+                               printf("%8lu.%06lu ", f->ts.tv_sec, f->ts.tv_usec);
+               }
+               printf("%c ", (f->in ? '>' : '<'));
+               parser.state = 1;
+       } else 
+               printf("  ");
+
+       if (level)
+               printf("%*c", (level*2), ' ');
+}
+
+static inline void p_ba2str(const bdaddr_t *ba, char *str)
+{
+       if (parser.flags & DUMP_NOVENDOR) {
+               uint8_t b[6];
+
+               baswap((bdaddr_t *) b, ba);
+               sprintf(str, "%2.2X:%2.2X:%2.2X:*:*:*", b[0], b[1], b[2]);
+       } else
+               ba2str(ba, str);
+}
+
+/* get_uXX functions do byte swaping */
+
+static inline uint8_t get_u8(struct frame *frm)
+{
+       uint8_t *u8_ptr = frm->ptr;
+       frm->ptr += 1;
+       frm->len -= 1;
+       return *u8_ptr;
+}
+
+static inline uint16_t get_u16(struct frame *frm)
+{
+       uint16_t *u16_ptr = frm->ptr;
+       frm->ptr += 2;
+       frm->len -= 2;
+       return ntohs(bt_get_unaligned(u16_ptr));
+}
+
+static inline uint32_t get_u32(struct frame *frm)
+{
+       uint32_t *u32_ptr = frm->ptr;
+       frm->ptr += 4;
+       frm->len -= 4;
+       return ntohl(bt_get_unaligned(u32_ptr));
+}
+
+static inline uint64_t get_u64(struct frame *frm)
+{
+       uint64_t *u64_ptr = frm->ptr;
+       uint64_t u64 = bt_get_unaligned(u64_ptr), tmp;
+       frm->ptr += 8;
+       frm->len -= 8;
+       tmp = ntohl(u64 & 0xffffffff);
+       u64 = (tmp << 32) | ntohl(u64 >> 32);
+       return u64;
+}
+
+static inline void get_u128(struct frame *frm, uint64_t *l, uint64_t *h)
+{
+       *h = get_u64(frm);
+       *l = get_u64(frm);
+}
+
+char *get_uuid_name(int uuid);
+
+void set_proto(uint16_t handle, uint16_t psm, uint8_t channel, uint32_t proto);
+uint32_t get_proto(uint16_t handle, uint16_t psm, uint8_t channel);
+
+struct frame *add_frame(struct frame *frm);
+void del_frame(uint16_t handle, uint8_t dlci);
+
+uint8_t get_opcode(uint16_t handle, uint8_t dlci);
+void set_opcode(uint16_t handle, uint8_t dlci, uint8_t opcode);
+
+uint8_t get_status(uint16_t handle, uint8_t dlci);
+void set_status(uint16_t handle, uint8_t dlci, uint8_t status);
+
+void l2cap_clear(uint16_t handle);
+
+void ascii_dump(int level, struct frame *frm, int num);
+void hex_dump(int level, struct frame *frm, int num);
+void ext_dump(int level, struct frame *frm, int num);
+void raw_dump(int level, struct frame *frm);
+void raw_ndump(int level, struct frame *frm, int num);
+
+void lmp_dump(int level, struct frame *frm);
+void hci_dump(int level, struct frame *frm);
+void l2cap_dump(int level, struct frame *frm);
+void rfcomm_dump(int level, struct frame *frm);
+void sdp_dump(int level, struct frame *frm);
+void bnep_dump(int level, struct frame *frm);
+void cmtp_dump(int level, struct frame *frm);
+void hidp_dump(int level, struct frame *frm);
+void hcrp_dump(int level, struct frame *frm);
+void avdtp_dump(int level, struct frame *frm);
+void avctp_dump(int level, struct frame *frm, uint16_t psm);
+void avrcp_dump(int level, struct frame *frm, uint8_t hdr, uint16_t psm);
+void att_dump(int level, struct frame *frm);
+void smp_dump(int level, struct frame *frm);
+void sap_dump(int level, struct frame *frm);
+
+void obex_dump(int level, struct frame *frm);
+void capi_dump(int level, struct frame *frm);
+void ppp_dump(int level, struct frame *frm);
+void arp_dump(int level, struct frame *frm);
+void ip_dump(int level, struct frame *frm);
+void ericsson_dump(int level, struct frame *frm);
+void csr_dump(int level, struct frame *frm);
+void bpa_dump(int level, struct frame *frm);
+
+void amp_assoc_dump(int level, uint8_t *assoc, uint16_t len);
+
+static inline void parse(struct frame *frm)
+{
+       p_indent(-1, NULL);
+       if (parser.flags & DUMP_RAW)
+               raw_dump(0, frm);
+       else
+               hci_dump(0, frm);
+       fflush(stdout);
+}
+
+#endif /* __PARSER_H */
diff --git a/tools/parser/ppp.c b/tools/parser/ppp.c
new file mode 100644 (file)
index 0000000..947ca56
--- /dev/null
@@ -0,0 +1,239 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2004-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+#define PPP_U8(frm)  (get_u8(frm))
+#define PPP_U16(frm) (btohs(htons(get_u16(frm))))
+#define PPP_U32(frm) (btohl(htonl(get_u32(frm))))
+
+static int ppp_traffic = 0;
+
+static unsigned char ppp_magic1[] = { 0x7e, 0xff, 0x03, 0xc0, 0x21 };
+static unsigned char ppp_magic2[] = { 0x7e, 0xff, 0x7d, 0x23, 0xc0, 0x21 };
+static unsigned char ppp_magic3[] = { 0x7e, 0x7d, 0xdf, 0x7d, 0x23, 0xc0, 0x21 };
+
+static inline int check_for_ppp_traffic(unsigned char *data, int size)
+{
+       unsigned int i;
+
+       for (i = 0; i < size - sizeof(ppp_magic1); i++)
+               if (!memcmp(data + i, ppp_magic1, sizeof(ppp_magic1))) {
+                       ppp_traffic = 1;
+                       return i;
+               }
+
+       for (i = 0; i < size - sizeof(ppp_magic2); i++)
+               if (!memcmp(data + i, ppp_magic2, sizeof(ppp_magic2))) {
+                       ppp_traffic = 1;
+                       return i;
+               }
+
+       for (i = 0; i < size - sizeof(ppp_magic3); i++)
+               if (!memcmp(data + i, ppp_magic3, sizeof(ppp_magic3))) {
+                       ppp_traffic = 1;
+                       return i;
+               }
+
+       return -1;
+}
+
+static inline char *dir2str(uint8_t in)
+{
+       return in ? "DCE" : "DTE";
+}
+
+static inline char *proto2str(uint16_t proto)
+{
+       switch (proto) {
+       case 0x0001:
+               return "Padding Protocol";
+       case 0x0021:
+               return "IP";
+       case 0x8021:
+               return "IP Control Protocol";
+       case 0x80fd:
+               return "Compression Control Protocol";
+       case 0xc021:
+               return "Link Control Protocol";
+       case 0xc023:
+               return "Password Authentication Protocol";
+       case 0xc025:
+               return "Link Quality Report";
+       case 0xc223:
+               return "Challenge Handshake Authentication Protocol";
+       default:
+               return "Unknown Protocol";
+       }
+}
+
+static void hdlc_dump(int level, struct frame *frm)
+{
+       uint8_t addr = get_u8(frm);
+       uint8_t ctrl = get_u8(frm);
+       uint16_t fcs, proto;
+
+       fcs = bt_get_unaligned((uint16_t *) (frm->ptr + frm->len - 2));
+       frm->len -= 2;
+
+       p_indent(level, frm);
+
+       if (addr != 0xff || ctrl != 0x03) {
+               frm->ptr -= 2;
+               frm->len += 2;
+               printf("HDLC: %s: len %d fcs 0x%04x\n",
+                               dir2str(frm->in), frm->len, fcs);
+       } else
+               printf("HDLC: %s: addr 0x%02x ctrl 0x%02x len %d fcs 0x%04x\n",
+                               dir2str(frm->in), addr, ctrl, frm->len, fcs);
+
+       if (*((uint8_t *) frm->ptr) & 0x80)
+               proto = get_u16(frm);
+       else
+               proto = get_u8(frm);
+
+       p_indent(level + 1, frm);
+       printf("PPP: %s (0x%04x): len %d\n", proto2str(proto), proto, frm->len);
+
+       raw_dump(level + 1, frm);
+}
+
+static inline void unslip_frame(int level, struct frame *frm, int len)
+{
+       struct frame msg;
+       unsigned char *data, *ptr;
+       int i, p = 0;
+
+       data = malloc(len * 2);
+       if (!data)
+               return;
+
+       ptr = frm->ptr;
+
+       for (i = 0; i < len; i++) {
+               if (ptr[i] == 0x7d) {
+                       data[p++] = ptr[i + 1] ^ 0x20;
+                       i++;
+               } else
+                       data[p++] = ptr[i];
+       }
+
+       memset(&msg, 0, sizeof(msg));
+       msg.data     = data;
+       msg.data_len = len * 2;
+       msg.ptr      = msg.data;
+       msg.len      = p;
+       msg.in       = frm->in;
+       msg.ts       = frm->ts;
+       msg.handle   = frm->handle;
+       msg.cid      = frm->cid;
+
+       hdlc_dump(level, &msg);
+
+       free(data);
+}
+
+void ppp_dump(int level, struct frame *frm)
+{
+       void *ptr, *end;
+       int err, len, pos = 0;
+
+       if (frm->pppdump_fd > fileno(stderr)) {
+               unsigned char id;
+               uint16_t len = htons(frm->len);
+               uint32_t ts = htonl(frm->ts.tv_sec & 0xffffffff);
+
+               id = 0x07;
+               err = write(frm->pppdump_fd, &id, 1);
+               if (err < 0)
+                       return;
+
+               err = write(frm->pppdump_fd, &ts, 4);
+               if (err < 0)
+                       return;
+
+               id = frm->in ? 0x02 : 0x01;
+               err = write(frm->pppdump_fd, &id, 1);
+               if (err < 0)
+                       return;
+               err = write(frm->pppdump_fd, &len, 2);
+               if (err < 0)
+                       return;
+               err = write(frm->pppdump_fd, frm->ptr, frm->len);
+               if (err < 0)
+                       return;
+       }
+
+       if (!ppp_traffic) {
+               pos = check_for_ppp_traffic(frm->ptr, frm->len);
+               if (pos < 0) {
+                       raw_dump(level, frm);
+                       return;
+               }
+
+               if (pos > 0) {
+                       raw_ndump(level, frm, pos);
+                       frm->ptr += pos;
+                       frm->len -= pos;
+               }
+       }
+
+       frm = add_frame(frm);
+
+       while (frm->len > 0) {
+               ptr = memchr(frm->ptr, 0x7e, frm->len);
+               if (!ptr)
+                       break;
+
+               if (frm->ptr != ptr) {
+                       frm->len -= (ptr - frm->ptr);
+                       frm->ptr = ptr;
+               }
+
+               end = memchr(frm->ptr + 1, 0x7e, frm->len - 1);
+               if (!end)
+                       break;
+
+               len = end - ptr - 1;
+
+               frm->ptr++;
+               frm->len--;
+
+               if (len > 0) {
+                       unslip_frame(level, frm, len);
+
+                       frm->ptr += len;
+                       frm->len -= len;
+               }
+       }
+}
diff --git a/tools/parser/rfcomm.c b/tools/parser/rfcomm.c
new file mode 100644 (file)
index 0000000..acf8d66
--- /dev/null
@@ -0,0 +1,350 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2001-2002  Wayne Lee <waynelee@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+#include "rfcomm.h"
+#include "sdp.h"
+
+static char *cr_str[] = {
+       "RSP",
+       "CMD"
+};
+
+#define CR_STR(mcc_head) cr_str[mcc_head->type.cr]
+#define GET_DLCI(addr) ((addr.server_chn << 1) | (addr.d & 1))
+
+static void print_rfcomm_hdr(long_frame_head* head, uint8_t *ptr, int len)
+{
+       address_field addr = head->addr;
+       uint8_t ctr = head->control;
+       uint16_t ilen = head->length.bits.len;
+       uint8_t pf, dlci, fcs;
+
+       dlci     = GET_DLCI(addr);
+       pf       = GET_PF(ctr);
+       fcs      = *(ptr + len - 1);
+
+       printf("cr %d dlci %d pf %d ilen %d fcs 0x%x ", addr.cr, dlci, pf, ilen, fcs); 
+}
+
+static void print_mcc(mcc_long_frame_head* mcc_head)
+{
+       printf("mcc_len %d\n", mcc_head->length.bits.len);
+}
+
+static inline void mcc_test(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       printf("TEST %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+}
+static inline void mcc_fcon(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       printf("FCON %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+}
+
+static inline void mcc_fcoff(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       printf("FCOFF %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+}
+
+static inline void mcc_msc(int level, uint8_t *ptr, unsigned int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       msc_msg *msc = (void*) (ptr - STRUCT_END(msc_msg, mcc_s_head));
+
+       printf("MSC %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+       p_indent(level, 0);
+       printf("dlci %d fc %d rtc %d rtr %d ic %d dv %d",
+               GET_DLCI(msc->dlci), msc->v24_sigs.fc, msc->v24_sigs.rtc, 
+               msc->v24_sigs.rtr, msc->v24_sigs.ic, msc->v24_sigs.dv );
+
+       /* Assuming that break_signals field is _not declared_ in struct msc_msg... */
+       if (len > STRUCT_OFFSET(msc_msg, fcs) - STRUCT_END(msc_msg, v24_sigs)) {
+               break_signals *brk = (break_signals *)
+                       (ptr + STRUCT_END(msc_msg, v24_sigs));
+               printf(" b1 %d b2 %d b3 %d len %d\n",
+                       brk->b1, brk->b2, brk->b3, brk->len);
+       } else
+               printf("\n");
+}
+
+static inline void mcc_rpn(int level, uint8_t *ptr, unsigned int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       rpn_msg *rpn = (void *) (ptr - STRUCT_END(rpn_msg, mcc_s_head));
+
+       printf("RPN %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+
+       p_indent(level, 0);
+       printf("dlci %d ", GET_DLCI(rpn->dlci));
+
+       /* Assuming that rpn_val is _declared_ as a member of rpn_msg... */
+       if (len <= STRUCT_OFFSET(rpn_msg, rpn_val) - STRUCT_END(rpn_msg, mcc_s_head)) {
+               printf("\n");
+               return;
+       }
+
+       printf("br %d db %d sb %d p %d pt %d xi %d xo %d\n",
+               rpn->rpn_val.bit_rate, rpn->rpn_val.data_bits, 
+               rpn->rpn_val.stop_bit, rpn->rpn_val.parity,
+               rpn->rpn_val.parity_type, rpn->rpn_val.xon_input,
+               rpn->rpn_val.xon_output);
+
+       p_indent(level, 0);
+       printf("rtri %d rtro %d rtci %d rtco %d xon %d xoff %d pm 0x%04x\n",
+               rpn->rpn_val.rtr_input, rpn->rpn_val.rtr_output,
+               rpn->rpn_val.rtc_input, rpn->rpn_val.rtc_output,
+               rpn->rpn_val.xon, rpn->rpn_val.xoff, btohs(rpn->rpn_val.pm));
+}
+
+static inline void mcc_rls(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       rls_msg* rls = (void*) (ptr - STRUCT_END(rls_msg, mcc_s_head));
+
+       printf("RLS %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+       printf("dlci %d error: %d", GET_DLCI(rls->dlci), rls->error);
+}
+
+static inline void mcc_pn(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+       pn_msg *pn = (void*) (ptr - STRUCT_END(pn_msg, mcc_s_head));
+
+       printf("PN %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+
+       p_indent(level, 0);
+       printf("dlci %d frame_type %d credit_flow %d pri %d ack_timer %d\n",
+               pn->dlci, pn->frame_type, pn->credit_flow, pn->prior, pn->ack_timer);
+       p_indent(level, 0);
+       printf("frame_size %d max_retrans %d credits %d\n",
+               btohs(pn->frame_size), pn->max_nbrof_retrans, pn->credits);
+}
+
+static inline void mcc_nsc(int level, uint8_t *ptr, int len,
+                               long_frame_head *head, mcc_long_frame_head *mcc_head)
+{
+
+       nsc_msg *nsc = (void*) (ptr - STRUCT_END(nsc_msg, mcc_s_head));
+
+       printf("NSC %s: ", CR_STR(mcc_head));
+       print_rfcomm_hdr(head, ptr, len);
+       print_mcc(mcc_head);
+
+       p_indent(level, 0);
+       printf("cr %d, mcc_cmd_type %x\n", 
+               nsc->command_type.cr, nsc->command_type.type );
+}
+
+static inline void mcc_frame(int level, struct frame *frm, long_frame_head *head)
+{
+       mcc_short_frame_head *mcc_short_head_p = frm->ptr;
+       mcc_long_frame_head mcc_head;
+       uint8_t hdr_size;
+
+       if ( mcc_short_head_p->length.ea == EA ) {
+               mcc_head.type = mcc_short_head_p->type;
+               mcc_head.length.bits.len = mcc_short_head_p->length.len;
+               hdr_size = sizeof(mcc_short_frame_head);
+       } else {
+               mcc_head = *(mcc_long_frame_head *)frm->ptr;
+               mcc_head.length.val = btohs(mcc_head.length.val);
+               hdr_size = sizeof(mcc_long_frame_head);
+       }
+
+       frm->ptr += hdr_size;
+       frm->len -= hdr_size;
+
+       p_indent(level, frm);
+       printf("RFCOMM(s): ");
+
+       switch (mcc_head.type.type) {
+       case TEST:
+               mcc_test(level, frm->ptr, frm->len, head, &mcc_head);
+               raw_dump(level, frm); 
+               break;
+       case FCON:
+               mcc_fcon(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case FCOFF:
+               mcc_fcoff(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case MSC:
+               mcc_msc(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case RPN:
+               mcc_rpn(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case RLS:
+               mcc_rls(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case PN:
+               mcc_pn(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       case NSC:
+               mcc_nsc(level, frm->ptr, frm->len, head, &mcc_head);
+               break;
+       default:
+               printf("MCC message type 0x%02x: ", mcc_head.type.type);
+               print_rfcomm_hdr(head, frm->ptr, frm->len);
+               printf("\n");
+
+               frm->len--;
+               raw_dump(level, frm); 
+       }
+}
+
+static inline void uih_frame(int level, struct frame *frm, long_frame_head *head)
+{
+       uint32_t proto;
+
+       if (!head->addr.server_chn) {
+               mcc_frame(level, frm, head); 
+       } else {
+               p_indent(level, frm);
+               printf("RFCOMM(d): UIH: ");
+               print_rfcomm_hdr(head, frm->ptr, frm->len);
+               if (GET_PF(head->control)) {
+                       printf("credits %d\n", *(uint8_t *)(frm->ptr));
+                       frm->ptr++;
+                       frm->len--;
+               } else
+                       printf("\n");
+
+               frm->len--;
+               frm->dlci = GET_DLCI(head->addr);
+               frm->channel = head->addr.server_chn;
+
+               proto = get_proto(frm->handle, RFCOMM_PSM, frm->channel);
+
+               if (frm->len > 0) {
+                       switch (proto) {
+                       case SDP_UUID_OBEX:
+                               if (!p_filter(FILT_OBEX))
+                                       obex_dump(level + 1, frm);
+                               else
+                                       raw_dump(level, frm);
+                               break;
+
+                       case SDP_UUID_LAN_ACCESS_PPP:
+                       case SDP_UUID_DIALUP_NETWORKING:
+                               if (!p_filter(FILT_PPP))
+                                       ppp_dump(level + 1, frm);
+                               else
+                                       raw_dump(level, frm);
+                               break;
+
+                       case SDP_UUID_SIM_ACCESS:
+                               if (!p_filter(FILT_SAP))
+                                       sap_dump(level + 1, frm);
+                               else
+                                       raw_dump(level, frm);
+                               break;
+
+                       default:
+                               if (p_filter(FILT_RFCOMM))
+                                       break;
+
+                               raw_dump(level, frm);
+                               break;
+                       }
+               }
+       }
+}
+
+void rfcomm_dump(int level, struct frame *frm)
+{
+       uint8_t hdr_size, ctr_type;
+       short_frame_head *short_head_p = (void *) frm->ptr;
+       long_frame_head head;
+
+       if (short_head_p->length.ea == EA) {
+               head.addr = short_head_p->addr;
+               head.control = short_head_p->control;
+               head.length.bits.len = short_head_p->length.len;
+               hdr_size = sizeof(short_frame_head);
+       } else {
+               head = *(long_frame_head *) frm->ptr;
+               head.length.val = btohs(head.length.val);
+               hdr_size = sizeof(long_frame_head);
+       }
+
+       frm->ptr += hdr_size;
+       frm->len -= hdr_size;
+
+       ctr_type = CLR_PF(head.control);
+
+       if (ctr_type == UIH) {
+               uih_frame(level, frm, &head);
+       } else {
+               p_indent(level, frm); 
+               printf("RFCOMM(s): ");
+
+               switch (ctr_type) {
+               case SABM:
+                       printf("SABM: ");
+                       break;
+               case UA:
+                       printf("UA: ");
+                       break;
+               case DM:
+                       printf("DM: ");
+                       break;
+               case DISC:
+                       printf("DISC: ");
+                       del_frame(frm->handle, GET_DLCI(head.addr));
+                       break;
+               default:
+                       printf("ERR: ");
+               }
+               print_rfcomm_hdr(&head, frm->ptr, frm->len);
+               printf("\n");
+       }
+}
diff --git a/tools/parser/rfcomm.h b/tools/parser/rfcomm.h
new file mode 100644 (file)
index 0000000..a9faa0b
--- /dev/null
@@ -0,0 +1,494 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2001-2002  Wayne Lee <waynelee@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __RFCOMM_H
+#define __RFCOMM_H
+
+#include <endian.h>
+
+#define RFCOMM_PSM 3
+
+#define TRUE  1
+#define FALSE 0
+
+#define RFCOMM_MAX_CONN 10
+#define BT_NBR_DATAPORTS RFCOMM_MAX_CONN
+
+#define GET_BIT(pos,bitfield) ((bitfield[(pos)/32]) & (1 << ((pos) % 32)))
+#define SET_BIT(pos,bitfield) ((bitfield[(pos)/32]) |= (1 << ((pos) % 32))) 
+#define CLR_BIT(pos,bitfield) ((bitfield[(pos)/32]) &= ((1 << ((pos) % 32)) ^ (~0)))
+
+/* Sets the P/F-bit in the control field */
+#define SET_PF(ctr) ((ctr) | (1 << 4)) 
+/* Clears the P/F-bit in the control field */
+#define CLR_PF(ctr) ((ctr) & 0xef)
+/* Returns the P/F-bit */
+#define GET_PF(ctr) (((ctr) >> 4) & 0x1)
+
+#define MIN(a, b) (((a) < (b)) ? (a) : (b))
+
+/* Endian-swapping macros for structs */
+#define swap_long_frame(x) ((x)->h.length.val = le16_to_cpu((x)->h.length.val))
+#define swap_mcc_long_frame(x) (swap_long_frame(x))
+
+/* Used for UIH packets */
+#define SHORT_CRC_CHECK 2
+/* Used for all packet exepts for the UIH packets */
+#define LONG_CRC_CHECK 3
+/* Short header for short UIH packets */
+#define SHORT_HDR 2
+/* Long header for long UIH packets */
+#define LONG_HDR 3
+
+/* FIXME: Should this one be defined here? */
+#define SHORT_PAYLOAD_SIZE 127
+/* Used for setting the EA field in different packets, really neccessary? */
+#define EA 1
+/* Yes the FCS size is only one byte */
+#define FCS_SIZE 1
+
+#define RFCOMM_MAX_HDR_SIZE 5
+
+#define MAX_CREDITS   30
+#define START_CREDITS 7
+#define MIN_CREDITS   6
+
+#define DEF_RFCOMM_MTU 127
+
+/* The values in the control field when sending ordinary rfcomm packets */
+#define SABM 0x2f      /* set asynchronous balanced mode */
+#define UA   0x63      /* unnumbered acknolodgement */
+#define DM   0x0f      /* disconnected mode */
+#define DISC 0x43      /* disconnect */
+#define UIH  0xef      /* unnumbered information with header check (only) */
+#define UI   0x03      /* unnumbered information (with all data check) */
+
+#define SABM_SIZE 4
+#define UA_SIZE   4
+
+/* The values in the type field in a multiplexer command packet */
+#define PN    (0x80 >> 2)      /* parameter negotiation */
+#define PSC   (0x40 >> 2)      /* power saving control */
+#define CLD   (0xc0 >> 2)      /* close down */
+#define TEST  (0x20 >> 2)      /* test */
+#define FCON  (0xa0 >> 2)      /* flow control on */
+#define FCOFF (0x60 >> 2)      /* flow control off */
+#define MSC   (0xe0 >> 2)      /* modem status command */
+#define NSC   (0x10 >> 2)      /* not supported command response */
+#define RPN   (0x90 >> 2)      /* remote port negotiation */
+#define RLS   (0x50 >> 2)      /* remote line status */
+#define SNC   (0xd0 >> 2)      /* service negotiation command */
+
+/* Define of some V.24 signals modem control signals in RFCOMM */
+#define DV  0x80       /* data valid */
+#define IC  0x40       /* incoming call */
+#define RTR 0x08       /* ready to receive */
+#define RTC 0x04       /* ready to communicate */
+#define FC  0x02       /* flow control (unable to accept frames) */
+
+#define CTRL_CHAN 0    /* The control channel is defined as DLCI 0 in rfcomm */
+#define MCC_CMD 1       /* Multiplexer command */
+#define MCC_RSP 0       /* Multiplexer response */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+typedef struct parameter_mask {
+       uint8_t bit_rate:1;
+       uint8_t data_bits:1;
+       uint8_t stop_bit:1;
+       uint8_t parity:1;
+       uint8_t parity_type:1;
+       uint8_t xon:1;
+       uint8_t xoff:1;
+       uint8_t res1:1;
+       uint8_t xon_input:1;
+       uint8_t xon_output:1;
+       uint8_t rtr_input:1;
+       uint8_t rtr_output:1;
+       uint8_t rtc_input:1;
+       uint8_t rtc_output:1;
+       uint8_t res2:2;
+} __attribute__ ((packed)) parameter_mask;
+
+typedef struct rpn_values {
+       uint8_t bit_rate;
+       uint8_t data_bits:2;
+       uint8_t stop_bit:1;
+       uint8_t parity:1;
+       uint8_t parity_type:2;
+       uint8_t res1:2;
+       uint8_t xon_input:1;
+       uint8_t xon_output:1;
+       uint8_t rtr_input:1;
+       uint8_t rtr_output:1;
+       uint8_t rtc_input:1;
+       uint8_t rtc_output:1;
+       uint8_t res2:2;
+       uint8_t xon;
+       uint8_t xoff;
+       uint16_t pm;
+       //parameter_mask pm;
+} __attribute__ ((packed)) rpn_values;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+typedef struct parameter_mask {
+       uint8_t res1:1;
+       uint8_t xoff:1;
+       uint8_t xon:1;
+       uint8_t parity_type:1;
+       uint8_t parity:1;
+       uint8_t stop_bit:1;
+       uint8_t data_bits:1;
+       uint8_t bit_rate:1;
+       uint8_t res2:2;
+       uint8_t rtc_output:1;
+       uint8_t rtc_input:1;
+       uint8_t rtr_output:1;
+       uint8_t rtr_input:1;
+       uint8_t xon_output:1;
+       uint8_t xon_input:1;
+
+} __attribute__ ((packed)) parameter_mask;
+
+typedef struct rpn_values {
+       uint8_t bit_rate;
+       uint8_t res1:2;
+       uint8_t parity_type:2;
+       uint8_t parity:1;
+       uint8_t stop_bit:1;
+       uint8_t data_bits:2;
+       uint8_t res2:2;
+       uint8_t rtc_output:1;
+       uint8_t rtc_input:1;
+       uint8_t rtr_output:1;
+       uint8_t rtr_input:1;
+       uint8_t xon_output:1;
+       uint8_t xon_input:1;
+       uint8_t xon;
+       uint8_t xoff;
+       uint16_t pm;
+       //parameter_mask pm;
+} __attribute__ ((packed)) rpn_values;
+
+#else
+#error "Unknown byte order"
+#endif
+
+/* Typedefinitions of stuctures used for creating and parsing packets, for a
+ * further description of the structures please se the bluetooth core
+ * specification part F:1 and the ETSI TS 07.10 specification  */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+
+typedef struct address_field {
+       uint8_t ea:1;
+       uint8_t cr:1;
+       uint8_t d:1;
+       uint8_t server_chn:5;
+} __attribute__ ((packed)) address_field;
+
+typedef struct short_length {
+       uint8_t ea:1;
+       uint8_t len:7;
+} __attribute__ ((packed)) short_length;
+
+typedef union long_length {
+       struct bits {
+               uint8_t ea:1;
+               unsigned short len:15;
+       } __attribute__ ((packed)) bits ;
+       uint16_t val ;
+} __attribute__ ((packed)) long_length;
+
+typedef struct short_frame_head {
+       address_field addr;
+       uint8_t control;
+       short_length length;
+} __attribute__ ((packed)) short_frame_head;
+
+typedef struct short_frame {
+       short_frame_head h;
+       uint8_t data[0]; 
+} __attribute__ ((packed)) short_frame;
+
+typedef struct long_frame_head {
+       address_field addr;
+       uint8_t control;
+       long_length length;
+       uint8_t data[0];
+} __attribute__ ((packed)) long_frame_head;
+
+typedef struct long_frame {
+       long_frame_head h;
+       uint8_t data[0];
+} __attribute__ ((packed)) long_frame;
+
+/* Typedefinitions for structures used for the multiplexer commands */
+typedef struct mcc_type {
+       uint8_t ea:1;
+       uint8_t cr:1;
+       uint8_t type:6;
+} __attribute__ ((packed)) mcc_type;
+
+typedef struct mcc_short_frame_head {
+       mcc_type type;
+       short_length length;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_short_frame_head;
+
+typedef struct mcc_short_frame {
+       mcc_short_frame_head h;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_short_frame;
+
+typedef struct mcc_long_frame_head {
+       mcc_type type;
+       long_length length;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_long_frame_head;
+
+typedef struct mcc_long_frame {
+       mcc_long_frame_head h;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_long_frame;
+
+/* MSC-command */
+typedef struct v24_signals {
+       uint8_t ea:1;
+       uint8_t fc:1;
+       uint8_t rtc:1;
+       uint8_t rtr:1;
+       uint8_t reserved:2;
+       uint8_t ic:1;
+       uint8_t dv:1;
+} __attribute__ ((packed)) v24_signals;
+
+typedef struct break_signals {
+       uint8_t ea:1;
+       uint8_t b1:1;
+       uint8_t b2:1;
+       uint8_t b3:1;
+       uint8_t len:4;
+} __attribute__ ((packed)) break_signals;
+
+typedef struct msc_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       v24_signals v24_sigs;
+       //break_signals break_sigs;
+       uint8_t fcs;
+} __attribute__ ((packed)) msc_msg;
+
+typedef struct rpn_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       rpn_values rpn_val;
+       uint8_t fcs;
+} __attribute__ ((packed)) rpn_msg;
+
+/* RLS-command */  
+typedef struct rls_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       uint8_t error:4;
+       uint8_t res:4;
+       uint8_t fcs;
+} __attribute__ ((packed)) rls_msg;
+
+/* PN-command */
+typedef struct pn_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+/* The res1, res2 and res3 values have to be set to 0 by the sender */
+       uint8_t dlci:6;
+       uint8_t res1:2;
+       uint8_t frame_type:4;
+       uint8_t credit_flow:4;
+       uint8_t prior:6;
+       uint8_t res2:2;
+       uint8_t ack_timer;
+       uint16_t frame_size:16;
+       uint8_t max_nbrof_retrans;
+       uint8_t credits;
+       uint8_t fcs;
+} __attribute__ ((packed)) pn_msg;
+
+/* NSC-command */
+typedef struct nsc_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       mcc_type command_type;
+       uint8_t fcs;
+} __attribute__ ((packed)) nsc_msg;
+
+#elif __BYTE_ORDER == __BIG_ENDIAN
+
+typedef struct address_field {
+       uint8_t server_chn:5;
+       uint8_t d:1;
+       uint8_t cr:1;
+       uint8_t ea:1;
+} __attribute__ ((packed)) address_field;
+
+typedef struct short_length {
+       uint8_t len:7;
+       uint8_t ea:1;
+} __attribute__ ((packed)) short_length;
+
+typedef union long_length {
+       struct bits {
+               unsigned short len:15;
+               uint8_t ea:1;
+       } __attribute__ ((packed)) bits;
+       uint16_t val;
+} __attribute__ ((packed)) long_length;
+
+typedef struct short_frame_head {
+       address_field addr;
+       uint8_t control;
+       short_length length;
+} __attribute__ ((packed)) short_frame_head;
+
+typedef struct short_frame {
+       short_frame_head h;
+       uint8_t data[0];
+} __attribute__ ((packed)) short_frame;
+
+typedef struct long_frame_head {
+       address_field addr;
+       uint8_t control;
+       long_length length;
+       uint8_t data[0];
+} __attribute__ ((packed)) long_frame_head;
+
+typedef struct long_frame {
+       long_frame_head h;
+       uint8_t data[0];
+} __attribute__ ((packed)) long_frame;
+
+typedef struct mcc_type {
+       uint8_t type:6;
+       uint8_t cr:1;
+       uint8_t ea:1;
+} __attribute__ ((packed)) mcc_type;
+
+typedef struct mcc_short_frame_head {
+       mcc_type type;
+       short_length length;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_short_frame_head;
+
+typedef struct mcc_short_frame {
+       mcc_short_frame_head h;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_short_frame;
+
+typedef struct mcc_long_frame_head {
+       mcc_type type;
+       long_length length;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_long_frame_head;
+
+typedef struct mcc_long_frame {
+       mcc_long_frame_head h;
+       uint8_t value[0];
+} __attribute__ ((packed)) mcc_long_frame;
+
+typedef struct v24_signals {
+       uint8_t dv:1;
+       uint8_t ic:1;
+       uint8_t reserved:2;
+       uint8_t rtr:1;
+       uint8_t rtc:1;
+       uint8_t fc:1;
+       uint8_t ea:1;
+} __attribute__ ((packed)) v24_signals;
+
+typedef struct break_signals {
+       uint8_t len:4;
+       uint8_t b3:1;
+       uint8_t b2:1;
+       uint8_t b1:1;
+       uint8_t ea:1;
+} __attribute__ ((packed)) break_signals;
+
+typedef struct msc_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       v24_signals v24_sigs;
+       //break_signals break_sigs;
+       uint8_t fcs;
+} __attribute__ ((packed)) msc_msg;
+
+typedef struct rpn_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       rpn_values rpn_val;
+       uint8_t fcs;
+} __attribute__ ((packed)) rpn_msg;
+
+typedef struct rls_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       address_field dlci;
+       uint8_t res:4;
+       uint8_t error:4;
+       uint8_t fcs;
+} __attribute__ ((packed)) rls_msg;
+
+typedef struct pn_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       uint8_t res1:2;
+       uint8_t dlci:6;
+       uint8_t credit_flow:4;
+       uint8_t frame_type:4;
+       uint8_t res2:2;
+       uint8_t prior:6;
+       uint8_t ack_timer;
+       uint16_t frame_size:16;
+       uint8_t max_nbrof_retrans;
+       uint8_t credits;
+       uint8_t fcs;
+} __attribute__ ((packed)) pn_msg;
+
+typedef struct nsc_msg {
+       short_frame_head s_head;
+       mcc_short_frame_head mcc_s_head;
+       mcc_type command_type;
+       uint8_t fcs;
+} __attribute__ ((packed)) nsc_msg;
+
+#else
+#error "Unknown byte order"
+#error Processor endianness unknown!
+#endif
+
+#endif /* __RFCOMM_H */
diff --git a/tools/parser/sap.c b/tools/parser/sap.c
new file mode 100644 (file)
index 0000000..0c87c36
--- /dev/null
@@ -0,0 +1,335 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2012  Tieto Poland
+ *
+ *
+ *  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 "parser.h"
+
+#define PADDING4(x) ((4 - ((x) & 0x03)) & 0x03)
+
+#define SAP_CONNECT_REQ                                0x00
+#define SAP_CONNECT_RESP                       0x01
+#define SAP_DISCONNECT_REQ                     0x02
+#define SAP_DISCONNECT_RESP                    0x03
+#define SAP_DISCONNECT_IND                     0x04
+#define SAP_TRANSFER_APDU_REQ                  0x05
+#define SAP_TRANSFER_APDU_RESP                 0x06
+#define SAP_TRANSFER_ATR_REQ                   0x07
+#define SAP_TRANSFER_ATR_RESP                  0x08
+#define SAP_POWER_SIM_OFF_REQ                  0x09
+#define SAP_POWER_SIM_OFF_RESP                 0x0A
+#define SAP_POWER_SIM_ON_REQ                   0x0B
+#define SAP_POWER_SIM_ON_RESP                  0x0C
+#define SAP_RESET_SIM_REQ                      0x0D
+#define SAP_RESET_SIM_RESP                     0x0E
+#define SAP_TRANSFER_CARD_READER_STATUS_REQ    0x0F
+#define SAP_TRANSFER_CARD_READER_STATUS_RESP   0x10
+#define SAP_STATUS_IND                         0x11
+#define SAP_ERROR_RESP                         0x12
+#define SAP_SET_TRANSPORT_PROTOCOL_REQ         0x13
+#define SAP_SET_TRANSPORT_PROTOCOL_RESP                0x14
+
+#define SAP_PARAM_ID_MAX_MSG_SIZE      0x00
+#define SAP_PARAM_ID_CONN_STATUS       0x01
+#define SAP_PARAM_ID_RESULT_CODE       0x02
+#define SAP_PARAM_ID_DISCONNECT_IND    0x03
+#define SAP_PARAM_ID_COMMAND_APDU      0x04
+#define SAP_PARAM_ID_COMMAND_APDU7816  0x10
+#define SAP_PARAM_ID_RESPONSE_APDU     0x05
+#define SAP_PARAM_ID_ATR               0x06
+#define SAP_PARAM_ID_CARD_READER_STATUS        0x07
+#define SAP_PARAM_ID_STATUS_CHANGE     0x08
+#define SAP_PARAM_ID_TRANSPORT_PROTOCOL        0x09
+
+#define SAP_STATUS_OK                          0x00
+#define SAP_STATUS_CONNECTION_FAILED           0x01
+#define SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED  0x02
+#define SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL      0x03
+#define SAP_STATUS_OK_ONGOING_CALL             0x04
+
+#define SAP_DISCONNECTION_TYPE_GRACEFUL                0x00
+#define SAP_DISCONNECTION_TYPE_IMMEDIATE       0x01
+#define SAP_DISCONNECTION_TYPE_CLIENT          0xFF
+
+#define SAP_RESULT_OK                  0x00
+#define SAP_RESULT_ERROR_NO_REASON     0x01
+#define SAP_RESULT_ERROR_NOT_ACCESSIBLE        0x02
+#define SAP_RESULT_ERROR_POWERED_OFF   0x03
+#define SAP_RESULT_ERROR_CARD_REMOVED  0x04
+#define SAP_RESULT_ERROR_POWERED_ON    0x05
+#define SAP_RESULT_ERROR_NO_DATA       0x06
+#define SAP_RESULT_NOT_SUPPORTED       0x07
+
+#define SAP_STATUS_CHANGE_UNKNOWN_ERROR                0x00
+#define SAP_STATUS_CHANGE_CARD_RESET           0x01
+#define SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE  0x02
+#define SAP_STATUS_CHANGE_CARD_REMOVED         0x03
+#define SAP_STATUS_CHANGE_CARD_INSERTED                0x04
+#define SAP_STATUS_CHANGE_CARD_RECOVERED       0x05
+
+#define SAP_TRANSPORT_PROTOCOL_T0      0x00
+#define SAP_TRANSPORT_PROTOCOL_T1      0x01
+
+static const char *msg2str(uint8_t msg)
+{
+       switch (msg) {
+       case SAP_CONNECT_REQ:
+               return "Connect Req";
+       case SAP_CONNECT_RESP:
+               return "Connect Resp";
+       case SAP_DISCONNECT_REQ:
+               return "Disconnect Req";
+       case SAP_DISCONNECT_RESP:
+               return "Disconnect Resp";
+       case SAP_DISCONNECT_IND:
+               return "Disconnect Ind";
+       case SAP_TRANSFER_APDU_REQ:
+               return "Transfer APDU Req";
+       case SAP_TRANSFER_APDU_RESP:
+               return "Transfer APDU Resp";
+       case SAP_TRANSFER_ATR_REQ:
+               return "Transfer ATR Req";
+       case SAP_TRANSFER_ATR_RESP:
+               return "Transfer ATR Resp";
+       case SAP_POWER_SIM_OFF_REQ:
+               return "Power SIM Off Req";
+       case SAP_POWER_SIM_OFF_RESP:
+               return "Power SIM Off Resp";
+       case SAP_POWER_SIM_ON_REQ:
+               return "Power SIM On Req";
+       case SAP_POWER_SIM_ON_RESP:
+               return "Power SIM On Resp";
+       case SAP_RESET_SIM_REQ:
+               return "Reset SIM Req";
+       case SAP_RESET_SIM_RESP:
+               return "Reset SIM Resp";
+       case SAP_TRANSFER_CARD_READER_STATUS_REQ:
+               return "Transfer Card Reader Status Req";
+       case SAP_TRANSFER_CARD_READER_STATUS_RESP:
+               return "Transfer Card Reader Status Resp";
+       case SAP_STATUS_IND:
+               return "Status Ind";
+       case SAP_ERROR_RESP:
+               return "Error Resp";
+       case SAP_SET_TRANSPORT_PROTOCOL_REQ:
+               return "Set Transport Protocol Req";
+       case SAP_SET_TRANSPORT_PROTOCOL_RESP:
+               return "Set Transport Protocol Resp";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *param2str(uint8_t param)
+{
+       switch (param) {
+       case SAP_PARAM_ID_MAX_MSG_SIZE:
+               return "MaxMsgSize";
+       case SAP_PARAM_ID_CONN_STATUS:
+               return "ConnectionStatus";
+       case SAP_PARAM_ID_RESULT_CODE:
+               return "ResultCode";
+       case SAP_PARAM_ID_DISCONNECT_IND:
+               return "DisconnectionType";
+       case SAP_PARAM_ID_COMMAND_APDU:
+               return "CommandAPDU";
+       case SAP_PARAM_ID_COMMAND_APDU7816:
+               return "CommandAPDU7816";
+       case SAP_PARAM_ID_RESPONSE_APDU:
+               return "ResponseAPDU";
+       case SAP_PARAM_ID_ATR:
+               return "ATR";
+       case SAP_PARAM_ID_CARD_READER_STATUS:
+               return "CardReaderStatus";
+       case SAP_PARAM_ID_STATUS_CHANGE:
+               return "StatusChange";
+       case SAP_PARAM_ID_TRANSPORT_PROTOCOL:
+               return "TransportProtocol";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *status2str(uint8_t status)
+{
+       switch (status) {
+       case  SAP_STATUS_OK:
+               return "OK, Server can fulfill requirements";
+       case  SAP_STATUS_CONNECTION_FAILED:
+               return "Error, Server unable to establish connection";
+       case  SAP_STATUS_MAX_MSG_SIZE_NOT_SUPPORTED:
+               return "Error, Server does not support maximum message size";
+       case  SAP_STATUS_MAX_MSG_SIZE_TOO_SMALL:
+               return "Error, maximum message size by Client is too small";
+       case  SAP_STATUS_OK_ONGOING_CALL:
+               return "OK, ongoing call";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *disctype2str(uint8_t disctype)
+{
+       switch (disctype) {
+       case  SAP_DISCONNECTION_TYPE_GRACEFUL:
+               return "Graceful";
+       case  SAP_DISCONNECTION_TYPE_IMMEDIATE:
+               return "Immediate";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *result2str(uint8_t result)
+{
+       switch (result) {
+       case  SAP_RESULT_OK:
+               return "OK, request processed correctly";
+       case  SAP_RESULT_ERROR_NO_REASON:
+               return "Error, no reason defined";
+       case SAP_RESULT_ERROR_NOT_ACCESSIBLE:
+               return "Error, card not accessible";
+       case  SAP_RESULT_ERROR_POWERED_OFF:
+               return "Error, card (already) powered off";
+       case  SAP_RESULT_ERROR_CARD_REMOVED:
+               return "Error, card removed";
+       case  SAP_RESULT_ERROR_POWERED_ON:
+               return "Error, card already powered on";
+       case  SAP_RESULT_ERROR_NO_DATA:
+               return "Error, data not available";
+       case  SAP_RESULT_NOT_SUPPORTED:
+               return "Error, not supported";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *statuschg2str(uint8_t statuschg)
+{
+       switch (statuschg) {
+       case  SAP_STATUS_CHANGE_UNKNOWN_ERROR:
+               return "Unknown Error";
+       case  SAP_STATUS_CHANGE_CARD_RESET:
+               return "Card reset";
+       case  SAP_STATUS_CHANGE_CARD_NOT_ACCESSIBLE:
+               return "Card not accessible";
+       case  SAP_STATUS_CHANGE_CARD_REMOVED:
+               return "Card removed";
+       case  SAP_STATUS_CHANGE_CARD_INSERTED:
+               return "Card inserted";
+       case  SAP_STATUS_CHANGE_CARD_RECOVERED:
+               return "Card recovered";
+       default:
+               return "Reserved";
+       }
+}
+
+static const char *prot2str(uint8_t prot)
+{
+       switch (prot) {
+       case SAP_TRANSPORT_PROTOCOL_T0:
+               return "T=0";
+       case SAP_TRANSPORT_PROTOCOL_T1:
+               return "T=1";
+       default:
+               return "Reserved";
+       }
+}
+
+static void parse_parameters(int level, struct frame *frm)
+{
+       uint8_t param;
+       uint16_t len;
+       uint8_t pv8;
+
+       while (frm->len > 3) {
+               p_indent(level, frm);
+
+               param = get_u8(frm);
+               get_u8(frm);
+               len = get_u16(frm);
+
+               printf("%s (0x%02x) len %d = ", param2str(param), param, len);
+
+               switch (param) {
+               case SAP_PARAM_ID_MAX_MSG_SIZE:
+                       printf("%d\n", get_u16(frm));
+                       break;
+               case SAP_PARAM_ID_CONN_STATUS:
+                       pv8 = get_u8(frm);
+                       printf("0x%02x (%s)\n", pv8, status2str(pv8));
+                       break;
+               case SAP_PARAM_ID_RESULT_CODE:
+               case SAP_PARAM_ID_CARD_READER_STATUS:
+                       pv8 = get_u8(frm);
+                       printf("0x%02x (%s)\n", pv8, result2str(pv8));
+                       break;
+               case SAP_PARAM_ID_DISCONNECT_IND:
+                       pv8 = get_u8(frm);
+                       printf("0x%02x (%s)\n", pv8, disctype2str(pv8));
+                       break;
+               case SAP_PARAM_ID_STATUS_CHANGE:
+                       pv8 = get_u8(frm);
+                       printf("0x%02x (%s)\n", pv8, statuschg2str(pv8));
+                       break;
+               case SAP_PARAM_ID_TRANSPORT_PROTOCOL:
+                       pv8 = get_u8(frm);
+                       printf("0x%02x (%s)\n", pv8, prot2str(pv8));
+                       break;
+               default:
+                       printf("\n");
+                       raw_ndump(level + 1, frm, len);
+                       frm->ptr += len;
+                       frm->len -= len;
+               }
+
+               /* Skip padding */
+               frm->ptr += PADDING4(len);
+               frm->len -= PADDING4(len);
+       }
+}
+
+void sap_dump(int level, struct frame *frm)
+{
+       uint8_t msg, params;
+
+       msg = get_u8(frm);
+       params = get_u8(frm);
+
+       /* Skip reserved field */
+       get_u16(frm);
+
+       p_indent(level, frm);
+
+       printf("SAP: %s: params %d\n", msg2str(msg), params);
+
+       parse_parameters(level, frm);
+}
diff --git a/tools/parser/sdp.c b/tools/parser/sdp.c
new file mode 100644 (file)
index 0000000..0e28328
--- /dev/null
@@ -0,0 +1,804 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2001-2002  Ricky Yuen <ryuen@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <ctype.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+#include "sdp.h"
+
+#define SDP_ERROR_RSP                                  0x01
+#define SDP_SERVICE_SEARCH_REQ                         0x02
+#define SDP_SERVICE_SEARCH_RSP                         0x03
+#define SDP_SERVICE_ATTR_REQ                           0x04
+#define SDP_SERVICE_ATTR_RSP                           0x05
+#define SDP_SERVICE_SEARCH_ATTR_REQ                    0x06
+#define SDP_SERVICE_SEARCH_ATTR_RSP                    0x07
+
+typedef struct {
+       uint8_t  pid;
+       uint16_t tid;
+       uint16_t len;
+} __attribute__ ((packed)) sdp_pdu_hdr;
+#define SDP_PDU_HDR_SIZE 5
+
+/* Data element type descriptor */
+#define SDP_DE_NULL   0
+#define SDP_DE_UINT   1
+#define SDP_DE_INT    2
+#define SDP_DE_UUID   3
+#define SDP_DE_STRING 4
+#define SDP_DE_BOOL   5
+#define SDP_DE_SEQ    6
+#define SDP_DE_ALT    7
+#define SDP_DE_URL    8
+
+/* Data element size index lookup table */
+typedef struct {
+       int addl_bits;
+       int num_bytes;
+} sdp_siz_idx_lookup_table_t;
+
+static sdp_siz_idx_lookup_table_t sdp_siz_idx_lookup_table[] = {
+       { 0, 1  }, /* Size index = 0 */
+       { 0, 2  }, /*              1 */
+       { 0, 4  }, /*              2 */
+       { 0, 8  }, /*              3 */
+       { 0, 16 }, /*              4 */
+       { 1, 1  }, /*              5 */
+       { 1, 2  }, /*              6 */
+       { 1, 4  }, /*              7 */
+};
+
+/* UUID name lookup table */
+typedef struct {
+       int   uuid;
+       char* name;
+} sdp_uuid_nam_lookup_table_t;
+
+static sdp_uuid_nam_lookup_table_t sdp_uuid_nam_lookup_table[] = {
+       { SDP_UUID_SDP,                      "SDP"          },
+       { SDP_UUID_UDP,                      "UDP"          },
+       { SDP_UUID_RFCOMM,                   "RFCOMM"       },
+       { SDP_UUID_TCP,                      "TCP"          },
+       { SDP_UUID_TCS_BIN,                  "TCS-BIN"      },
+       { SDP_UUID_TCS_AT,                   "TCS-AT"       },
+       { SDP_UUID_OBEX,                     "OBEX"         },
+       { SDP_UUID_IP,                       "IP"           },
+       { SDP_UUID_FTP,                      "FTP"          },
+       { SDP_UUID_HTTP,                     "HTTP"         },
+       { SDP_UUID_WSP,                      "WSP"          },
+       { SDP_UUID_L2CAP,                    "L2CAP"        },
+       { SDP_UUID_BNEP,                     "BNEP"         }, /* PAN */
+       { SDP_UUID_HIDP,                     "HIDP"         }, /* HID */
+       { SDP_UUID_AVCTP,                    "AVCTP"        }, /* AVCTP */
+       { SDP_UUID_AVDTP,                    "AVDTP"        }, /* AVDTP */
+       { SDP_UUID_CMTP,                     "CMTP"         }, /* CIP */
+       { SDP_UUID_UDI_C_PLANE,              "UDI_C-Plane"  }, /* UDI */
+       { SDP_UUID_SERVICE_DISCOVERY_SERVER, "SDServer"     },
+       { SDP_UUID_BROWSE_GROUP_DESCRIPTOR,  "BrwsGrpDesc"  },
+       { SDP_UUID_PUBLIC_BROWSE_GROUP,      "PubBrwsGrp"   },
+       { SDP_UUID_SERIAL_PORT,              "SP"           },
+       { SDP_UUID_LAN_ACCESS_PPP,           "LAN"          },
+       { SDP_UUID_DIALUP_NETWORKING,        "DUN"          },
+       { SDP_UUID_IR_MC_SYNC,               "IRMCSync"     },
+       { SDP_UUID_OBEX_OBJECT_PUSH,         "OBEXObjPush"  },
+       { SDP_UUID_OBEX_FILE_TRANSFER,       "OBEXObjTrnsf" },
+       { SDP_UUID_IR_MC_SYNC_COMMAND,       "IRMCSyncCmd"  },
+       { SDP_UUID_HEADSET,                  "Headset"      },
+       { SDP_UUID_CORDLESS_TELEPHONY,       "CordlessTel"  },
+       { SDP_UUID_AUDIO_SOURCE,             "AudioSource"  }, /* A2DP */
+       { SDP_UUID_AUDIO_SINK,               "AudioSink"    }, /* A2DP */
+       { SDP_UUID_AV_REMOTE_TARGET,         "AVRemTarget"  }, /* AVRCP */
+       { SDP_UUID_ADVANCED_AUDIO,           "AdvAudio"     }, /* A2DP */
+       { SDP_UUID_AV_REMOTE,                "AVRemote"     }, /* AVRCP */
+       { SDP_UUID_AV_REMOTE_CONTROLLER,     "AVRemCt"      }, /* AVRCP */
+       { SDP_UUID_INTERCOM,                 "Intercom"     },
+       { SDP_UUID_FAX,                      "Fax"          },
+       { SDP_UUID_HEADSET_AUDIO_GATEWAY,    "Headset AG"   },
+       { SDP_UUID_WAP,                      "WAP"          },
+       { SDP_UUID_WAP_CLIENT,               "WAP Client"   },
+       { SDP_UUID_PANU,                     "PANU"         }, /* PAN */
+       { SDP_UUID_NAP,                      "NAP"          }, /* PAN */
+       { SDP_UUID_GN,                       "GN"           }, /* PAN */
+       { SDP_UUID_DIRECT_PRINTING,          "DirectPrint"  }, /* BPP */
+       { SDP_UUID_REFERENCE_PRINTING,       "RefPrint"     }, /* BPP */
+       { SDP_UUID_IMAGING,                  "Imaging"      }, /* BIP */
+       { SDP_UUID_IMAGING_RESPONDER,        "ImagingResp"  }, /* BIP */
+       { SDP_UUID_HANDSFREE,                "Handsfree"    },
+       { SDP_UUID_HANDSFREE_AUDIO_GATEWAY,  "Handsfree AG" },
+       { SDP_UUID_DIRECT_PRINTING_REF_OBJS, "RefObjsPrint" }, /* BPP */
+       { SDP_UUID_REFLECTED_UI,             "ReflectedUI"  }, /* BPP */
+       { SDP_UUID_BASIC_PRINTING,           "BasicPrint"   }, /* BPP */
+       { SDP_UUID_PRINTING_STATUS,          "PrintStatus"  }, /* BPP */
+       { SDP_UUID_HUMAN_INTERFACE_DEVICE,   "HID"          }, /* HID */
+       { SDP_UUID_HARDCOPY_CABLE_REPLACE,   "HCRP"         }, /* HCRP */
+       { SDP_UUID_HCR_PRINT,                "HCRPrint"     }, /* HCRP */
+       { SDP_UUID_HCR_SCAN,                 "HCRScan"      }, /* HCRP */
+       { SDP_UUID_COMMON_ISDN_ACCESS,       "CIP"          }, /* CIP */
+       { SDP_UUID_UDI_MT,                   "UDI MT"       }, /* UDI */
+       { SDP_UUID_UDI_TA,                   "UDI TA"       }, /* UDI */
+       { SDP_UUID_AUDIO_VIDEO,              "AudioVideo"   }, /* VCP */
+       { SDP_UUID_SIM_ACCESS,               "SAP"          }, /* SAP */
+       { SDP_UUID_PHONEBOOK_ACCESS_PCE,     "PBAP PCE"     }, /* PBAP */
+       { SDP_UUID_PHONEBOOK_ACCESS_PSE,     "PBAP PSE"     }, /* PBAP */
+       { SDP_UUID_PHONEBOOK_ACCESS,         "PBAP"         }, /* PBAP */
+       { SDP_UUID_PNP_INFORMATION,          "PNPInfo"      },
+       { SDP_UUID_GENERIC_NETWORKING,       "Networking"   },
+       { SDP_UUID_GENERIC_FILE_TRANSFER,    "FileTrnsf"    },
+       { SDP_UUID_GENERIC_AUDIO,            "Audio"        },
+       { SDP_UUID_GENERIC_TELEPHONY,        "Telephony"    },
+       { SDP_UUID_UPNP_SERVICE,             "UPNP"         }, /* ESDP */
+       { SDP_UUID_UPNP_IP_SERVICE,          "UPNP IP"      }, /* ESDP */
+       { SDP_UUID_ESDP_UPNP_IP_PAN,         "UPNP PAN"     }, /* ESDP */
+       { SDP_UUID_ESDP_UPNP_IP_LAP,         "UPNP LAP"     }, /* ESDP */
+       { SDP_UUID_ESDP_UPNP_L2CAP,          "UPNP L2CAP"   }, /* ESDP */
+       { SDP_UUID_VIDEO_SOURCE,             "VideoSource"  }, /* VDP */
+       { SDP_UUID_VIDEO_SINK,               "VideoSink"    }, /* VDP */
+       { SDP_UUID_VIDEO_DISTRIBUTION,       "VideoDist"    }, /* VDP */
+       { SDP_UUID_APPLE_AGENT,              "AppleAgent"   },
+};
+
+#define SDP_UUID_NAM_LOOKUP_TABLE_SIZE \
+       (sizeof(sdp_uuid_nam_lookup_table)/sizeof(sdp_uuid_nam_lookup_table_t))
+
+/* AttrID name lookup table */
+typedef struct {
+       int   attr_id;
+       char* name;
+} sdp_attr_id_nam_lookup_table_t;
+
+static sdp_attr_id_nam_lookup_table_t sdp_attr_id_nam_lookup_table[] = {
+       { SDP_ATTR_ID_SERVICE_RECORD_HANDLE,             "SrvRecHndl"         },
+       { SDP_ATTR_ID_SERVICE_CLASS_ID_LIST,             "SrvClassIDList"     },
+       { SDP_ATTR_ID_SERVICE_RECORD_STATE,              "SrvRecState"        },
+       { SDP_ATTR_ID_SERVICE_SERVICE_ID,                "SrvID"              },
+       { SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST,          "ProtocolDescList"   },
+       { SDP_ATTR_ID_BROWSE_GROUP_LIST,                 "BrwGrpList"         },
+       { SDP_ATTR_ID_LANGUAGE_BASE_ATTRIBUTE_ID_LIST,   "LangBaseAttrIDList" },
+       { SDP_ATTR_ID_SERVICE_INFO_TIME_TO_LIVE,         "SrvInfoTimeToLive"  },
+       { SDP_ATTR_ID_SERVICE_AVAILABILITY,              "SrvAvail"           },
+       { SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST, "BTProfileDescList"  },
+       { SDP_ATTR_ID_DOCUMENTATION_URL,                 "DocURL"             },
+       { SDP_ATTR_ID_CLIENT_EXECUTABLE_URL,             "ClientExeURL"       },
+       { SDP_ATTR_ID_ICON_URL,                          "IconURL"            },
+       { SDP_ATTR_ID_ADDITIONAL_PROTOCOL_DESC_LISTS,    "AdditionalProtocolDescLists" },
+       { SDP_ATTR_ID_SERVICE_NAME,                      "SrvName"            },
+       { SDP_ATTR_ID_SERVICE_DESCRIPTION,               "SrvDesc"            },
+       { SDP_ATTR_ID_PROVIDER_NAME,                     "ProviderName"       },
+       { SDP_ATTR_ID_VERSION_NUMBER_LIST,               "VersionNumList"     },
+       { SDP_ATTR_ID_GROUP_ID,                          "GrpID"              },
+       { SDP_ATTR_ID_SERVICE_DATABASE_STATE,            "SrvDBState"         },
+       { SDP_ATTR_ID_SERVICE_VERSION,                   "SrvVersion"         },
+       { SDP_ATTR_ID_SECURITY_DESCRIPTION,              "SecurityDescription"}, /* PAN */
+       { SDP_ATTR_ID_SUPPORTED_DATA_STORES_LIST,        "SuppDataStoresList" }, /* Synchronization */
+       { SDP_ATTR_ID_SUPPORTED_FORMATS_LIST,            "SuppFormatsList"    }, /* OBEX Object Push */
+       { SDP_ATTR_ID_NET_ACCESS_TYPE,                   "NetAccessType"      }, /* PAN */
+       { SDP_ATTR_ID_MAX_NET_ACCESS_RATE,               "MaxNetAccessRate"   }, /* PAN */
+       { SDP_ATTR_ID_IPV4_SUBNET,                       "IPv4Subnet"         }, /* PAN */
+       { SDP_ATTR_ID_IPV6_SUBNET,                       "IPv6Subnet"         }, /* PAN */
+       { SDP_ATTR_ID_SUPPORTED_CAPABILITIES,            "SuppCapabilities"   }, /* Imaging */
+       { SDP_ATTR_ID_SUPPORTED_FEATURES,                "SuppFeatures"       }, /* Imaging and Hansfree */
+       { SDP_ATTR_ID_SUPPORTED_FUNCTIONS,               "SuppFunctions"      }, /* Imaging */
+       { SDP_ATTR_ID_TOTAL_IMAGING_DATA_CAPACITY,       "SuppTotalCapacity"  }, /* Imaging */
+       { SDP_ATTR_ID_SUPPORTED_REPOSITORIES,            "SuppRepositories"   }, /* PBAP */
+};
+
+#define SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE \
+       (sizeof(sdp_attr_id_nam_lookup_table)/sizeof(sdp_attr_id_nam_lookup_table_t))
+
+char* get_uuid_name(int uuid)
+{
+       unsigned int i;
+
+       for (i = 0; i < SDP_UUID_NAM_LOOKUP_TABLE_SIZE; i++) {
+               if (sdp_uuid_nam_lookup_table[i].uuid == uuid)
+                       return sdp_uuid_nam_lookup_table[i].name;
+       }
+
+       return 0;
+}
+
+static inline char* get_attr_id_name(int attr_id)
+{
+       unsigned int i;
+
+       for (i = 0; i < SDP_ATTR_ID_NAM_LOOKUP_TABLE_SIZE; i++)
+               if (sdp_attr_id_nam_lookup_table[i].attr_id == attr_id)
+                       return sdp_attr_id_nam_lookup_table[i].name;
+       return 0;
+}
+
+static inline uint8_t parse_de_hdr(struct frame *frm, int *n)
+{
+       uint8_t de_hdr = get_u8(frm);
+       uint8_t de_type = de_hdr >> 3;
+       uint8_t siz_idx = de_hdr & 0x07;
+
+       /* Get the number of bytes */
+       if (sdp_siz_idx_lookup_table[siz_idx].addl_bits) {
+               switch(sdp_siz_idx_lookup_table[siz_idx].num_bytes) {
+               case 1:
+                       *n = get_u8(frm); break;
+               case 2:
+                       *n = get_u16(frm); break;
+               case 4:
+                       *n = get_u32(frm); break;
+               case 8:
+                       *n = get_u64(frm); break;
+               }
+       } else
+               *n = sdp_siz_idx_lookup_table[siz_idx].num_bytes;
+
+       return de_type;
+}
+
+static inline void print_int(uint8_t de_type, int level, int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
+{
+       uint64_t val, val2;
+
+       switch(de_type) {
+       case SDP_DE_UINT:
+               printf(" uint");
+               break;
+       case SDP_DE_INT:
+               printf(" int");
+               break;
+       case SDP_DE_BOOL:
+               printf(" bool");
+               break;
+       }
+
+       switch(n) {
+       case 1: /* 8-bit */
+               val = get_u8(frm);
+               if (channel && de_type == SDP_DE_UINT)
+                       if (*channel == 0)
+                               *channel = val;
+               break;
+       case 2: /* 16-bit */
+               val = get_u16(frm);
+               if (psm && de_type == SDP_DE_UINT)
+                       if (*psm == 0)
+                               *psm = val;
+               break;
+       case 4: /* 32-bit */
+               val = get_u32(frm);
+               break;
+       case 8: /* 64-bit */
+               val = get_u64(frm);
+               break;
+       case 16:/* 128-bit */
+               get_u128(frm, &val, &val2);
+               printf(" 0x%jx", val2);
+               if (val < 0x1000000000000000LL)
+                       printf("0");
+               printf("%jx", val);
+               return;
+       default: /* syntax error */
+               printf(" err");
+               frm->ptr += n;
+               frm->len -= n;
+               return;
+       }
+
+       printf(" 0x%jx", val);
+}
+
+static inline void print_uuid(int n, struct frame *frm, uint16_t *psm, uint8_t *channel)
+{
+       uint32_t uuid = 0;
+       char* s;
+       int i;
+
+       switch(n) {
+       case 2: /* 16-bit UUID */
+               uuid = get_u16(frm);
+               s = "uuid-16";
+               break;
+       case 4: /* 32_bit UUID */
+               uuid = get_u32(frm);
+               s = "uuid-32";
+               break;
+       case 16: /* 128-bit UUID */
+               printf(" uuid-128 ");
+               for (i = 0; i < 16; i++) {
+                       printf("%02x", ((unsigned char *) frm->ptr)[i]);
+                       if (i == 3 || i == 5 || i == 7 || i == 9)
+                               printf("-");
+               }
+               frm->ptr += 16;
+               frm->len -= 16;
+               return;
+       default: /* syntax error */
+               printf(" *err*");
+               frm->ptr += n;
+               frm->len -= n;
+               return;
+       }
+
+       if (psm && *psm > 0 && *psm != 0xffff) {
+               set_proto(frm->handle, *psm, 0, uuid);
+               *psm = 0xffff;
+       }
+
+       if (channel && *channel > 0 && *channel != 0xff) {
+               set_proto(frm->handle, *psm, *channel, uuid);
+               *channel = 0xff;
+       }
+
+       printf(" %s 0x%04x", s, uuid);
+       if ((s = get_uuid_name(uuid)))
+               printf(" (%s)", s);
+}
+
+static inline void print_string(int n, struct frame *frm, const char *name)
+{
+       int i, hex = 0;
+
+       for (i = 0; i < n; i++) {
+               if (i == (n - 1) && ((char *) frm->ptr)[i] == '\0')
+                       break;
+
+               if (!isprint(((char *) frm->ptr)[i])) {
+                       hex = 1;
+                       break;
+               }
+       }
+
+       printf(" %s", name);
+       if (hex) {
+               for (i = 0; i < n; i++)
+                       printf(" %02x", ((unsigned char *) frm->ptr)[i]);
+       } else {
+               printf(" \"");
+               for (i = 0; i < n; i++)
+                       printf("%c", ((char *) frm->ptr)[i]);
+               printf("\"");
+       }
+
+       frm->ptr += n;
+       frm->len -= n;
+}
+
+static inline void print_de(int, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel);
+
+static inline void print_des(uint8_t de_type, int level, int n, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
+{
+       int len = frm->len;
+       while (len - (int) frm->len < n && (int) frm->len > 0)
+               print_de(level, frm, split, psm, channel);
+}
+
+static inline void print_de(int level, struct frame *frm, int *split, uint16_t *psm, uint8_t *channel)
+{
+       int n = 0;
+       uint8_t de_type = parse_de_hdr(frm, &n);
+
+       switch (de_type) {
+       case SDP_DE_NULL:
+               printf(" null");
+               break;
+       case SDP_DE_UINT:
+       case SDP_DE_INT:
+       case SDP_DE_BOOL:
+               print_int(de_type, level, n, frm, psm, channel);
+               break;
+       case SDP_DE_UUID:
+               if (split) {
+                       /* Split output by uuids.
+                        * Used for printing Protocol Desc List */
+                       if (*split) {
+                               printf("\n");
+                               p_indent(level, NULL);
+                       }
+                       ++*split;
+               }
+               print_uuid(n, frm, psm, channel);
+               break;
+       case SDP_DE_URL:
+       case SDP_DE_STRING:
+               print_string(n, frm, de_type == SDP_DE_URL? "url": "str");
+               break;
+       case SDP_DE_SEQ:
+               printf(" <");
+               print_des(de_type, level, n, frm, split, psm, channel);
+               printf(" >");
+               break;
+       case SDP_DE_ALT:
+               printf(" [");
+               print_des(de_type, level, n, frm, split, psm, channel);
+               printf(" ]");
+               break;
+       }
+}
+
+static inline void print_srv_srch_pat(int level, struct frame *frm)
+{
+       int len, n1 = 0, n2 = 0;
+
+       p_indent(level, frm);
+       printf("pat");
+
+       if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
+               len = frm->len;
+               while (len - (int) frm->len < n1 && (int) frm->len > 0) {
+                       if (parse_de_hdr(frm, &n2) == SDP_DE_UUID) {
+                               print_uuid(n2, frm, NULL, NULL);
+                       } else {
+                               printf("\nERROR: Unexpected syntax (UUID)\n");
+                               raw_dump(level, frm);
+                       }
+               }
+               printf("\n");
+       } else {
+               printf("\nERROR: Unexpected syntax (SEQ)\n");
+               raw_dump(level, frm);
+       }
+}
+
+static inline void print_attr_id_list(int level, struct frame *frm)
+{
+       uint16_t attr_id;
+       uint32_t attr_id_range;
+       int len, n1 = 0, n2 = 0;
+
+       p_indent(level, frm);
+       printf("aid(s)");
+
+       if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
+               len = frm->len;
+               while (len - (int) frm->len < n1 && (int) frm->len > 0) {
+                       /* Print AttributeID */
+                       if (parse_de_hdr(frm, &n2) == SDP_DE_UINT) {
+                               char *name;
+                               switch(n2) {
+                               case 2:
+                                       attr_id = get_u16(frm);
+                                       name = get_attr_id_name(attr_id);
+                                       if (!name)
+                                               name = "unknown";
+                                       printf(" 0x%04x (%s)", attr_id, name);
+                                       break;
+                               case 4:
+                                       attr_id_range = get_u32(frm);
+                                       printf(" 0x%04x - 0x%04x",
+                                                       (attr_id_range >> 16),
+                                                       (attr_id_range & 0xFFFF));
+                                       break;
+                               }
+                       } else {
+                               printf("\nERROR: Unexpected syntax\n");
+                               raw_dump(level, frm);
+                       }
+               }
+               printf("\n");
+       } else {
+               printf("\nERROR: Unexpected syntax\n");
+               raw_dump(level, frm);
+       }
+}
+
+static inline void print_attr_list(int level, struct frame *frm)
+{
+       uint16_t attr_id, psm;
+       uint8_t channel;
+       int len, split, n1 = 0, n2 = 0;
+
+       if (parse_de_hdr(frm, &n1) == SDP_DE_SEQ) {
+               len = frm->len;
+               while (len - (int) frm->len < n1 && (int) frm->len > 0) {
+                       /* Print AttributeID */
+                       if (parse_de_hdr(frm, &n2) == SDP_DE_UINT && n2 == sizeof(attr_id)) {
+                               char *name;
+                               attr_id = get_u16(frm);
+                               p_indent(level, 0);
+                               name = get_attr_id_name(attr_id);
+                               if (!name)
+                                       name = "unknown";
+                               printf("aid 0x%04x (%s)\n", attr_id, name);
+                               split = (attr_id != SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST);
+                               psm = 0;
+                               channel = 0;
+
+                               /* Print AttributeValue */
+                               p_indent(level + 1, 0);
+                               print_de(level + 1, frm, split ? NULL: &split,
+                                       attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &psm : NULL,
+                                       attr_id == SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST ? &channel : NULL);
+                               printf("\n");
+                       } else {
+                               printf("\nERROR: Unexpected syntax\n");
+                               raw_dump(level, frm);
+                               break;
+                       }
+               }
+       } else {
+               printf("\nERROR: Unexpected syntax\n");
+               raw_dump(level, frm);
+       }
+}
+
+static inline void print_attr_lists(int level, struct frame *frm)
+{
+       int n = 0, cnt = 0;
+       int count = frm->len;
+
+       if (parse_de_hdr(frm, &n) == SDP_DE_SEQ) {
+               while (count - (int) frm->len < n && (int) frm->len > 0) {
+                       p_indent(level, 0);
+                       printf("record #%d\n", cnt++);
+                       print_attr_list(level + 2, frm);
+               }
+       } else {
+               printf("\nERROR: Unexpected syntax\n");
+               raw_dump(level, frm);
+       }
+}
+
+static inline void print_cont_state(int level, unsigned char *buf)
+{
+       uint8_t cont = buf[0];
+       int i;
+
+       p_indent(level, 0);
+       printf("cont");
+       for (i = 0; i < cont + 1; i++)
+               printf(" %2.2X", buf[i]);
+       printf("\n");
+}
+
+static char *pid2str(uint8_t pid)
+{
+       switch (pid) {
+       case SDP_ERROR_RSP:
+               return "Error Rsp";
+       case SDP_SERVICE_SEARCH_REQ:
+               return "SS Req";
+       case SDP_SERVICE_SEARCH_RSP:
+               return "SS Rsp";
+       case SDP_SERVICE_ATTR_REQ:
+               return "SA Req";
+       case SDP_SERVICE_ATTR_RSP:
+               return "SA Rsp";
+       case SDP_SERVICE_SEARCH_ATTR_REQ:
+               return "SSA Req";
+       case SDP_SERVICE_SEARCH_ATTR_RSP:
+               return "SSA Rsp";
+       default:
+               return "Unknown";
+       }
+}
+
+#define FRAME_TABLE_SIZE 10
+
+static struct frame frame_table[FRAME_TABLE_SIZE];
+
+static int frame_add(struct frame *frm, int count)
+{
+       register struct frame *fr;
+       register unsigned char *data;
+       register int i, len = 0, pos = -1;
+
+       for (i = 0; i < FRAME_TABLE_SIZE; i++) {
+               if (frame_table[i].handle == frm->handle &&
+                               frame_table[i].cid == frm->cid) {
+                       pos = i;
+                       len = frame_table[i].data_len;
+                       break;
+               }
+               if (pos < 0 && !frame_table[i].handle)
+                       pos = i;
+       }
+
+       if (pos < 0 || count <= 0)
+               return -EIO;
+
+       data = malloc(len + count);
+       if (!data)
+               return -ENOMEM;
+
+       fr = &frame_table[pos];
+
+       if (len > 0) {
+               memcpy(data, fr->data, len);
+               memcpy(data + len, frm->ptr, count);
+       } else
+               memcpy(data, frm->ptr, count);
+
+       if (fr->data)
+               free(fr->data);
+
+       fr->data       = data;
+       fr->data_len   = len + count;
+       fr->len        = fr->data_len;
+       fr->ptr        = fr->data;
+       fr->dev_id     = frm->dev_id;
+       fr->in         = frm->in;
+       fr->ts         = frm->ts;
+       fr->handle     = frm->handle;
+       fr->cid        = frm->cid;
+       fr->num        = frm->num;
+       fr->channel    = frm->channel;
+       fr->pppdump_fd = frm->pppdump_fd;
+       fr->audio_fd   = frm->audio_fd;
+
+       return pos;
+}
+
+static struct frame *frame_get(struct frame *frm, int count)
+{
+       register int pos;
+
+       pos = frame_add(frm, count);
+       if (pos < 0)
+               return frm;
+
+       frame_table[pos].handle = 0;
+
+       return &frame_table[pos];
+}
+
+void sdp_dump(int level, struct frame *frm)
+{
+       sdp_pdu_hdr *hdr = frm->ptr;
+       uint16_t tid = ntohs(hdr->tid);
+       uint16_t len = ntohs(hdr->len);
+       uint16_t total, count;
+       uint8_t cont;
+
+       frm->ptr += SDP_PDU_HDR_SIZE;
+       frm->len -= SDP_PDU_HDR_SIZE;
+
+       p_indent(level, frm);
+       printf("SDP %s: tid 0x%x len 0x%x\n", pid2str(hdr->pid), tid, len);
+
+       switch (hdr->pid) {
+       case SDP_ERROR_RSP:
+               p_indent(level + 1, frm);
+               printf("code 0x%x info ", get_u16(frm));
+               if (frm->len > 0)
+                       hex_dump(0, frm, frm->len);
+               else
+                       printf("none\n");
+               break;
+
+       case SDP_SERVICE_SEARCH_REQ:
+               /* Parse ServiceSearchPattern */
+               print_srv_srch_pat(level + 1, frm);
+
+               /* Parse MaximumServiceRecordCount */
+               p_indent(level + 1, frm);
+               printf("max %d\n", get_u16(frm));
+
+               /* Parse ContinuationState */
+               print_cont_state(level + 1, frm->ptr);
+               break;
+
+       case SDP_SERVICE_SEARCH_RSP:
+               /* Parse TotalServiceRecordCount */
+               total = get_u16(frm);
+
+               /* Parse CurrentServiceRecordCount */
+               count = get_u16(frm);
+               p_indent(level + 1, frm);
+               if (count < total)
+                       printf("count %d of %d\n", count, total);
+               else
+                       printf("count %d\n", count);
+
+               /* Parse service record handle(s) */
+               if (count > 0) {
+                       int i;
+                       p_indent(level + 1, frm);
+                       printf("handle%s", count > 1 ? "s" : "");
+                       for (i = 0; i < count; i++)
+                               printf(" 0x%x", get_u32(frm));
+                       printf("\n");
+               }
+
+               /* Parse ContinuationState */
+               print_cont_state(level + 1, frm->ptr);
+               break;
+
+       case SDP_SERVICE_ATTR_REQ:
+               /* Parse ServiceRecordHandle */
+               p_indent(level + 1, frm);
+               printf("handle 0x%x\n", get_u32(frm));
+
+               /* Parse MaximumAttributeByteCount */
+               p_indent(level + 1, frm);
+               printf("max %d\n", get_u16(frm));
+
+               /* Parse ServiceSearchPattern */
+               print_attr_id_list(level + 1, frm);
+
+               /* Parse ContinuationState */
+               print_cont_state(level + 1, frm->ptr);
+               break;
+
+       case SDP_SERVICE_ATTR_RSP:
+               /* Parse AttributeByteCount */
+               count = get_u16(frm);
+               p_indent(level + 1, frm);
+               printf("count %d\n", count);
+
+               /* Parse ContinuationState */
+               cont = *(unsigned char *)(frm->ptr + count);
+
+               if (cont == 0) {
+                       /* Parse AttributeList */
+                       print_attr_list(level + 1, frame_get(frm, count));
+               } else
+                       frame_add(frm, count);
+
+               print_cont_state(level + 1, frm->ptr + count);
+               break;
+
+       case SDP_SERVICE_SEARCH_ATTR_REQ:
+               /* Parse ServiceSearchPattern */
+               print_srv_srch_pat(level + 1, frm);
+
+               /* Parse MaximumAttributeByteCount */
+               p_indent(level + 1, frm);
+               printf("max %d\n", get_u16(frm));
+
+               /* Parse AttributeList */
+               print_attr_id_list(level + 1, frm);
+
+               /* Parse ContinuationState */
+               print_cont_state(level + 1, frm->ptr);
+               break;
+
+       case SDP_SERVICE_SEARCH_ATTR_RSP:
+               /* Parse AttributeByteCount */
+               count = get_u16(frm);
+               p_indent(level + 1, frm);
+               printf("count %d\n", count);
+
+               /* Parse ContinuationState */
+               cont = *(unsigned char *)(frm->ptr + count);
+
+               if (cont == 0) {
+                       /* Parse AttributeLists */
+                       print_attr_lists(level + 1, frame_get(frm, count));
+               } else
+                       frame_add(frm, count);
+
+               print_cont_state(level + 1, frm->ptr + count);
+               break;
+
+       default:
+               raw_dump(level + 1, frm);
+               break;
+       }
+}
diff --git a/tools/parser/sdp.h b/tools/parser/sdp.h
new file mode 100644 (file)
index 0000000..ed55a23
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2001-2002  Ricky Yuen <ryuen@qualcomm.com>
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef __SDP_H
+#define __SDP_H
+
+/* Bluetooth assigned UUIDs for protocols */
+#define SDP_UUID_SDP                                   0x0001
+#define SDP_UUID_UDP                                   0x0002
+#define SDP_UUID_RFCOMM                                0x0003
+#define SDP_UUID_TCP                                   0x0004
+#define SDP_UUID_TCS_BIN                               0x0005
+#define SDP_UUID_TCS_AT                                0x0006
+#define SDP_UUID_OBEX                                  0x0008
+#define SDP_UUID_IP                                    0x0009
+#define SDP_UUID_FTP                                   0x000A
+#define SDP_UUID_HTTP                                  0x000C
+#define SDP_UUID_WSP                                   0x000E
+#define SDP_UUID_BNEP                                  0x000F /* PAN */
+#define SDP_UUID_HIDP                                  0x0011 /* HID */
+#define SDP_UUID_HARDCOPY_CONTROL_CHANNEL              0x0012 /* HCRP */
+#define SDP_UUID_HARDCOPY_DATA_CHANNEL                 0x0014 /* HCRP */
+#define SDP_UUID_HARDCOPY_NOTIFICATION                 0x0016 /* HCRP */
+#define SDP_UUID_AVCTP                                 0x0017 /* AVCTP */
+#define SDP_UUID_AVDTP                                 0x0019 /* AVDTP */
+#define SDP_UUID_CMTP                                  0x001B /* CIP */
+#define SDP_UUID_UDI_C_PLANE                           0x001D /* UDI */
+#define SDP_UUID_L2CAP                                 0x0100
+
+/* Bluetooth assigned UUIDs for Service Classes */
+#define SDP_UUID_SERVICE_DISCOVERY_SERVER              0x1000
+#define SDP_UUID_BROWSE_GROUP_DESCRIPTOR               0x1001
+#define SDP_UUID_PUBLIC_BROWSE_GROUP                   0x1002
+#define SDP_UUID_SERIAL_PORT                           0x1101
+#define SDP_UUID_LAN_ACCESS_PPP                        0x1102
+#define SDP_UUID_DIALUP_NETWORKING                     0x1103
+#define SDP_UUID_IR_MC_SYNC                            0x1104
+#define SDP_UUID_OBEX_OBJECT_PUSH                      0x1105
+#define SDP_UUID_OBEX_FILE_TRANSFER                    0x1106
+#define SDP_UUID_IR_MC_SYNC_COMMAND                    0x1107
+#define SDP_UUID_HEADSET                               0x1108
+#define SDP_UUID_CORDLESS_TELEPHONY                    0x1109
+#define SDP_UUID_AUDIO_SOURCE                          0x110a /* A2DP */
+#define SDP_UUID_AUDIO_SINK                            0x110b /* A2DP */
+#define SDP_UUID_AV_REMOTE_TARGET                      0x110c /* AVRCP */
+#define SDP_UUID_ADVANCED_AUDIO                        0x110d /* A2DP */
+#define SDP_UUID_AV_REMOTE                             0x110e /* AVRCP */
+#define SDP_UUID_AV_REMOTE_CONTROLLER                  0x110f /* AVRCP */
+#define SDP_UUID_INTERCOM                              0x1110
+#define SDP_UUID_FAX                                   0x1111
+#define SDP_UUID_HEADSET_AUDIO_GATEWAY                 0x1112
+#define SDP_UUID_WAP                                   0x1113
+#define SDP_UUID_WAP_CLIENT                            0x1114
+#define SDP_UUID_PANU                                  0x1115 /* PAN */
+#define SDP_UUID_NAP                                   0x1116 /* PAN */
+#define SDP_UUID_GN                                    0x1117 /* PAN */
+#define SDP_UUID_DIRECT_PRINTING                       0x1118 /* BPP */
+#define SDP_UUID_REFERENCE_PRINTING                    0x1119 /* BPP */
+#define SDP_UUID_IMAGING                               0x111a /* BIP */
+#define SDP_UUID_IMAGING_RESPONDER                     0x111b /* BIP */
+#define SDP_UUID_IMAGING_AUTOMATIC_ARCHIVE             0x111c /* BIP */
+#define SDP_UUID_IMAGING_REFERENCED_OBJECTS            0x111d /* BIP */
+#define SDP_UUID_HANDSFREE                             0x111e
+#define SDP_UUID_HANDSFREE_AUDIO_GATEWAY               0x111f
+#define SDP_UUID_DIRECT_PRINTING_REF_OBJS              0x1120 /* BPP */
+#define SDP_UUID_DIRECT_PRINTING_REFERENCE_OBJECTS     0x1120 /* BPP */
+#define SDP_UUID_REFLECTED_UI                          0x1121 /* BPP */
+#define SDP_UUID_BASIC_PRINTING                        0x1122 /* BPP */
+#define SDP_UUID_PRINTING_STATUS                       0x1123 /* BPP */
+#define SDP_UUID_HUMAN_INTERFACE_DEVICE                0x1124 /* HID */
+#define SDP_UUID_HARDCOPY_CABLE_REPLACE                0x1125 /* HCRP */
+#define SDP_UUID_HCR_PRINT                             0x1126 /* HCRP */
+#define SDP_UUID_HCR_SCAN                              0x1127 /* HCRP */
+#define SDP_UUID_COMMON_ISDN_ACCESS                    0x1128 /* CIP */
+#define SDP_UUID_UDI_MT                                0x112a /* UDI */
+#define SDP_UUID_UDI_TA                                0x112b /* UDI */
+#define SDP_UUID_AUDIO_VIDEO                           0x112c /* VCP */
+#define SDP_UUID_SIM_ACCESS                            0x112d /* SAP */
+#define SDP_UUID_PHONEBOOK_ACCESS_PCE                  0x112e /* PBAP */
+#define SDP_UUID_PHONEBOOK_ACCESS_PSE                  0x112f /* PBAP */
+#define SDP_UUID_PHONEBOOK_ACCESS                      0x1130 /* PBAP */
+#define SDP_UUID_PNP_INFORMATION                       0x1200
+#define SDP_UUID_GENERIC_NETWORKING                    0x1201
+#define SDP_UUID_GENERIC_FILE_TRANSFER                 0x1202
+#define SDP_UUID_GENERIC_AUDIO                         0x1203
+#define SDP_UUID_GENERIC_TELEPHONY                     0x1204
+#define SDP_UUID_UPNP_SERVICE                          0x1205 /* ESDP */
+#define SDP_UUID_UPNP_IP_SERVICE                       0x1206 /* ESDP */
+#define SDP_UUID_ESDP_UPNP_IP_PAN                      0x1300 /* ESDP */
+#define SDP_UUID_ESDP_UPNP_IP_LAP                      0x1301 /* ESDP */
+#define SDP_UUID_ESDP_UPNP_L2CAP                       0x1302 /* ESDP */
+#define SDP_UUID_VIDEO_SOURCE                          0x1303 /* VDP */
+#define SDP_UUID_VIDEO_SINK                            0x1304 /* VDP */
+#define SDP_UUID_VIDEO_DISTRIBUTION                    0x1305 /* VDP */
+#define SDP_UUID_APPLE_AGENT                           0x2112
+
+/* Bluetooth assigned numbers for Attribute IDs */
+#define SDP_ATTR_ID_SERVICE_RECORD_HANDLE              0x0000
+#define SDP_ATTR_ID_SERVICE_CLASS_ID_LIST              0x0001
+#define SDP_ATTR_ID_SERVICE_RECORD_STATE               0x0002
+#define SDP_ATTR_ID_SERVICE_SERVICE_ID                 0x0003
+#define SDP_ATTR_ID_PROTOCOL_DESCRIPTOR_LIST           0x0004
+#define SDP_ATTR_ID_BROWSE_GROUP_LIST                  0x0005
+#define SDP_ATTR_ID_LANGUAGE_BASE_ATTRIBUTE_ID_LIST    0x0006
+#define SDP_ATTR_ID_SERVICE_INFO_TIME_TO_LIVE          0x0007
+#define SDP_ATTR_ID_SERVICE_AVAILABILITY               0x0008
+#define SDP_ATTR_ID_BLUETOOTH_PROFILE_DESCRIPTOR_LIST  0x0009
+#define SDP_ATTR_ID_DOCUMENTATION_URL                  0x000A
+#define SDP_ATTR_ID_CLIENT_EXECUTABLE_URL              0x000B
+#define SDP_ATTR_ID_ICON_URL                           0x000C
+#define SDP_ATTR_ID_ADDITIONAL_PROTOCOL_DESC_LISTS     0x000D
+#define SDP_ATTR_ID_SERVICE_NAME                       0x0100
+#define SDP_ATTR_ID_SERVICE_DESCRIPTION                0x0101
+#define SDP_ATTR_ID_PROVIDER_NAME                      0x0102
+#define SDP_ATTR_ID_VERSION_NUMBER_LIST                0x0200
+#define SDP_ATTR_ID_GROUP_ID                           0x0200
+#define SDP_ATTR_ID_SERVICE_DATABASE_STATE             0x0201
+#define SDP_ATTR_ID_SERVICE_VERSION                    0x0300
+
+#define SDP_ATTR_ID_EXTERNAL_NETWORK                   0x0301 /* Cordless Telephony */
+#define SDP_ATTR_ID_SUPPORTED_DATA_STORES_LIST         0x0301 /* Synchronization */
+#define SDP_ATTR_ID_REMOTE_AUDIO_VOLUME_CONTROL        0x0302 /* GAP */
+#define SDP_ATTR_ID_SUPPORTED_FORMATS_LIST             0x0303 /* OBEX Object Push */
+#define SDP_ATTR_ID_FAX_CLASS_1_SUPPORT                0x0302 /* Fax */
+#define SDP_ATTR_ID_FAX_CLASS_2_0_SUPPORT              0x0303
+#define SDP_ATTR_ID_FAX_CLASS_2_SUPPORT                0x0304
+#define SDP_ATTR_ID_AUDIO_FEEDBACK_SUPPORT             0x0305
+#define SDP_ATTR_ID_SECURITY_DESCRIPTION               0x030a /* PAN */
+#define SDP_ATTR_ID_NET_ACCESS_TYPE                    0x030b /* PAN */
+#define SDP_ATTR_ID_MAX_NET_ACCESS_RATE                0x030c /* PAN */
+#define SDP_ATTR_ID_IPV4_SUBNET                        0x030d /* PAN */
+#define SDP_ATTR_ID_IPV6_SUBNET                        0x030e /* PAN */
+
+#define SDP_ATTR_ID_SUPPORTED_CAPABILITIES             0x0310 /* Imaging */
+#define SDP_ATTR_ID_SUPPORTED_FEATURES                 0x0311 /* Imaging and Hansfree */
+#define SDP_ATTR_ID_SUPPORTED_FUNCTIONS                0x0312 /* Imaging */
+#define SDP_ATTR_ID_TOTAL_IMAGING_DATA_CAPACITY        0x0313 /* Imaging */
+#define SDP_ATTR_ID_SUPPORTED_REPOSITORIES             0x0314 /* PBAP */
+
+#endif /* __SDP_H */
diff --git a/tools/parser/smp.c b/tools/parser/smp.c
new file mode 100644 (file)
index 0000000..c81b585
--- /dev/null
@@ -0,0 +1,336 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "parser.h"
+
+/* SMP command codes */
+#define SMP_CMD_PAIRING_REQ    0x01
+#define SMP_CMD_PAIRING_RESP   0x02
+#define SMP_CMD_PAIRING_CONFIRM        0x03
+#define SMP_CMD_PAIRING_RANDOM 0x04
+#define SMP_CMD_PAIRING_FAILED 0x05
+#define SMP_CMD_ENCRYPT_INFO   0x06
+#define SMP_CMD_MASTER_IDENT   0x07
+#define SMP_CMD_IDENT_INFO     0X08
+#define SMP_CMD_IDENT_ADDR_INFO        0x09
+#define SMP_CMD_SIGN_INFO      0x0a
+#define SMP_CMD_SECURITY_REQ   0x0b
+
+/* IO Capabilities values */
+#define SMP_IO_DISPLAY_ONLY    0x00
+#define SMP_IO_DISPLAY_YESNO   0x01
+#define SMP_IO_KEYBOARD_ONLY   0x02
+#define SMP_IO_NO_INPUT_OUTPUT 0x03
+#define SMP_IO_KEYBOARD_DISPLAY        0x04
+
+/* OOB Data Present Values */
+#define SMP_OOB_NOT_PRESENT    0x00
+#define SMP_OOB_PRESENT                0x01
+
+#define SMP_DIST_ENC_KEY       0x01
+#define SMP_DIST_ID_KEY                0x02
+#define SMP_DIST_SIGN          0x04
+
+#define SMP_AUTH_NONE          0x00
+#define SMP_AUTH_BONDING       0x01
+#define SMP_AUTH_MITM          0x04
+
+#define SMP_REASON_PASSKEY_ENTRY_FAILED                0x01
+#define SMP_REASON_OOB_NOT_AVAIL               0x02
+#define SMP_REASON_AUTH_REQUIREMENTS           0x03
+#define SMP_REASON_CONFIRM_FAILED              0x04
+#define SMP_REASON_PAIRING_NOTSUPP             0x05
+#define SMP_REASON_ENC_KEY_SIZE                        0x06
+#define SMP_REASON_CMD_NOTSUPP                 0x07
+#define SMP_REASON_UNSPECIFIED                 0x08
+#define SMP_REASON_REPEATED_ATTEMPTS           0x09
+
+static const char *smpcmd2str(uint8_t cmd)
+{
+       switch (cmd) {
+       case SMP_CMD_PAIRING_REQ:
+               return "Pairing Request";
+       case SMP_CMD_PAIRING_RESP:
+               return "Pairing Response";
+       case SMP_CMD_PAIRING_CONFIRM:
+               return "Pairing Confirm";
+       case SMP_CMD_PAIRING_RANDOM:
+               return "Pairing Random";
+       case SMP_CMD_PAIRING_FAILED:
+               return "Pairing Failed";
+       case SMP_CMD_ENCRYPT_INFO:
+               return "Encryption Information";
+       case SMP_CMD_MASTER_IDENT:
+               return "Master Identification";
+       case SMP_CMD_IDENT_INFO:
+               return "Identity Information";
+       case SMP_CMD_IDENT_ADDR_INFO:
+               return "Identity Address Information";
+       case SMP_CMD_SIGN_INFO:
+               return "Signing Information";
+       case SMP_CMD_SECURITY_REQ:
+               return "Security Request";
+       default:
+               return "Unknown";
+       }
+}
+
+static const char *smpio2str(uint8_t cap)
+{
+       switch(cap) {
+       case SMP_IO_DISPLAY_ONLY:
+               return "DisplayOnly";
+       case SMP_IO_DISPLAY_YESNO:
+               return "DisplayYesNo";
+       case SMP_IO_KEYBOARD_ONLY:
+               return "KeyboardOnly";
+       case SMP_IO_NO_INPUT_OUTPUT:
+               return "NoInputNoOutput";
+       case SMP_IO_KEYBOARD_DISPLAY:
+               return "KeyboardDisplay";
+       default:
+               return "Unkown";
+       }
+}
+
+static const char *smpreason2str(uint8_t reason)
+{
+       switch (reason) {
+       case SMP_REASON_PASSKEY_ENTRY_FAILED:
+               return "Passkey Entry Failed";
+       case SMP_REASON_OOB_NOT_AVAIL:
+               return "OOB Not Available";
+       case SMP_REASON_AUTH_REQUIREMENTS:
+               return "Authentication Requirements";
+       case SMP_REASON_CONFIRM_FAILED:
+               return "Confirm Value Failed";
+       case SMP_REASON_PAIRING_NOTSUPP:
+               return "Pairing Not Supported";
+       case SMP_REASON_ENC_KEY_SIZE:
+               return "Encryption Key Size";
+       case SMP_REASON_CMD_NOTSUPP:
+               return "Command Not Supported";
+       case SMP_REASON_UNSPECIFIED:
+               return "Unspecified Reason";
+       case SMP_REASON_REPEATED_ATTEMPTS:
+               return "Repeated Attempts";
+       default:
+               return "Unkown";
+       }
+}
+
+static void smp_cmd_pairing_dump(int level, struct frame *frm)
+{
+       uint8_t cap = get_u8(frm);
+       uint8_t oob = get_u8(frm);
+       uint8_t auth = get_u8(frm);
+       uint8_t key_size = get_u8(frm);
+       uint8_t int_dist = get_u8(frm);
+       uint8_t resp_dist = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("capability 0x%2.2x oob 0x%2.2x auth req 0x%2.2x\n", cap, oob,
+                                                                       auth);
+
+       p_indent(level , frm);
+       printf("max key size 0x%2.2x init key dist 0x%2.2x "
+               "resp key dist 0x%2.2x\n", key_size, int_dist, resp_dist);
+
+       p_indent(level , frm);
+       printf("Capability: %s (OOB data %s)\n", smpio2str(cap),
+                               oob == 0x00 ? "not present" : "available");
+
+       p_indent(level , frm);
+       printf("Authentication: %s (%s)\n",
+                       auth & SMP_AUTH_BONDING ? "Bonding" : "No Bonding",
+                       auth & SMP_AUTH_MITM ? "MITM Protection" :
+                       "No MITM Protection");
+
+       p_indent(level , frm);
+       printf("Initiator Key Distribution:  %s %s %s\n",
+                       int_dist & SMP_DIST_ENC_KEY ? "LTK" : "",
+                       int_dist & SMP_DIST_ID_KEY ? "IRK" : "",
+                       int_dist & SMP_DIST_SIGN ? "CSRK" : "");
+
+       p_indent(level , frm);
+       printf("Responder Key Distribution:  %s %s %s\n",
+                       resp_dist & SMP_DIST_ENC_KEY ? "LTK" : "",
+                       resp_dist & SMP_DIST_ID_KEY ? "IRK" : "",
+                       resp_dist & SMP_DIST_SIGN ? "CSRK" : "");
+}
+
+static void smp_cmd_pairing_confirm_dump(int level, struct frame *frm)
+{
+       int i;
+
+       p_indent(level, frm);
+       printf("key ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_pairing_random_dump(int level, struct frame *frm)
+{
+       int i;
+
+       p_indent(level, frm);
+       printf("random ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_pairing_failed_dump(int level, struct frame *frm)
+{
+       uint8_t reason = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("reason 0x%2.2x\n", reason);
+
+       p_indent(level, frm);
+       printf("Reason %s\n", smpreason2str(reason));
+}
+
+static void smp_cmd_encrypt_info_dump(int level, struct frame *frm)
+{
+       int i;
+
+       p_indent(level, frm);
+       printf("LTK ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_master_ident_dump(int level, struct frame *frm)
+{
+       uint16_t ediv = btohs(htons(get_u16(frm)));
+       int i;
+
+       p_indent(level, frm);
+       printf("EDIV 0x%4.4x ", ediv);
+
+       printf("Rand 0x");
+       for (i = 0; i < 8; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_ident_info_dump(int level, struct frame *frm)
+{
+       int i;
+
+       p_indent(level, frm);
+       printf("IRK ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_ident_addr_info_dump(int level, struct frame *frm)
+{
+       uint8_t type = get_u8(frm);
+       char addr[18];
+
+       p_indent(level, frm);
+       p_ba2str((bdaddr_t *) frm, addr);
+       printf("bdaddr %s (%s)\n", addr, type == 0x00 ? "Public" : "Random");
+}
+
+static void smp_cmd_sign_info_dump(int level, struct frame *frm)
+{
+       int i;
+
+       p_indent(level, frm);
+       printf("CSRK ");
+       for (i = 0; i < 16; i++)
+               printf("%2.2x", get_u8(frm));
+       printf("\n");
+}
+
+static void smp_cmd_security_req_dump(int level, struct frame *frm)
+{
+       uint8_t auth = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("auth req 0x%2.2x\n", auth);
+}
+
+void smp_dump(int level, struct frame *frm)
+{
+       uint8_t cmd;
+
+       cmd = get_u8(frm);
+
+       p_indent(level, frm);
+       printf("SMP: %s (0x%.2x)\n", smpcmd2str(cmd), cmd);
+
+       switch (cmd) {
+       case SMP_CMD_PAIRING_REQ:
+               smp_cmd_pairing_dump(level + 1, frm);
+               break;
+       case SMP_CMD_PAIRING_RESP:
+               smp_cmd_pairing_dump(level + 1, frm);
+               break;
+       case SMP_CMD_PAIRING_CONFIRM:
+               smp_cmd_pairing_confirm_dump(level + 1, frm);
+               break;
+       case SMP_CMD_PAIRING_RANDOM:
+               smp_cmd_pairing_random_dump(level + 1, frm);
+               break;
+       case SMP_CMD_PAIRING_FAILED:
+               smp_cmd_pairing_failed_dump(level + 1, frm);
+               break;
+       case SMP_CMD_ENCRYPT_INFO:
+               smp_cmd_encrypt_info_dump(level + 1, frm);
+               break;
+       case SMP_CMD_MASTER_IDENT:
+               smp_cmd_master_ident_dump(level + 1, frm);
+               break;
+       case SMP_CMD_IDENT_INFO:
+               smp_cmd_ident_info_dump(level + 1, frm);
+               break;
+       case SMP_CMD_IDENT_ADDR_INFO:
+               smp_cmd_ident_addr_info_dump(level + 1, frm);
+               break;
+       case SMP_CMD_SIGN_INFO:
+               smp_cmd_sign_info_dump(level + 1, frm);
+               break;
+       case SMP_CMD_SECURITY_REQ:
+               smp_cmd_security_req_dump(level + 1, frm);
+               break;
+       default:
+               raw_dump(level, frm);
+       }
+}
diff --git a/tools/parser/tcpip.c b/tools/parser/tcpip.c
new file mode 100644 (file)
index 0000000..6f2c3cb
--- /dev/null
@@ -0,0 +1,140 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2003-2011  Marcel Holtmann <marcel@holtmann.org>
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdio.h>
+#include <errno.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <net/ethernet.h>
+#include <netinet/in.h>
+#include <netinet/ip.h>
+#include <netinet/ip6.h>
+#include <netinet/if_ether.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+
+#include "parser.h"
+
+void arp_dump(int level, struct frame *frm)
+{
+       int i;
+       char buf[20];
+       struct sockaddr_in sai;
+       struct ether_arp *arp = (struct ether_arp *) frm->ptr;
+
+       printf("Src ");
+       for (i = 0; i < 5; i++)
+               printf("%02x:", arp->arp_sha[i]);
+       printf("%02x", arp->arp_sha[5]);
+       sai.sin_family = AF_INET;
+       memcpy(&sai.sin_addr, &arp->arp_spa, sizeof(sai.sin_addr));
+       getnameinfo((struct sockaddr *) &sai, sizeof(sai), buf, sizeof(buf),
+                   NULL, 0, NI_NUMERICHOST);
+       printf("(%s) ", buf);
+       printf("Tgt ");
+       for (i = 0; i < 5; i++)
+               printf("%02x:", arp->arp_tha[i]);
+       printf("%02x", arp->arp_tha[5]);
+       memcpy(&sai.sin_addr, &arp->arp_tpa, sizeof(sai.sin_addr));
+       getnameinfo((struct sockaddr *) &sai, sizeof(sai), buf, sizeof(buf),
+                   NULL, 0, NI_NUMERICHOST);
+       printf("(%s)\n", buf);
+       frm->ptr += sizeof(struct ether_arp);
+       frm->len -= sizeof(struct ether_arp);
+       raw_dump(level, frm);           // not needed.
+}
+
+void ip_dump(int level, struct frame *frm)
+{
+       char src[50], dst[50];
+       struct ip *ip = (struct ip *) (frm->ptr);
+       uint8_t proto;
+       int len;
+
+       if (ip->ip_v == 4) {
+               struct sockaddr_in sai;
+               proto = ip->ip_p;
+               len = ip->ip_hl << 2;
+               memset(&sai, 0, sizeof(sai));
+               sai.sin_family = AF_INET;
+               memcpy(&sai.sin_addr, &ip->ip_src, sizeof(struct in_addr));
+               getnameinfo((struct sockaddr *) &sai, sizeof(sai),
+                           src, sizeof(src), NULL, 0, NI_NUMERICHOST);
+               memcpy(&sai.sin_addr, &ip->ip_dst, sizeof(struct in_addr));
+               getnameinfo((struct sockaddr *) &sai, sizeof(sai),
+                           dst, sizeof(dst), NULL, 0, NI_NUMERICHOST);
+       } else if (ip->ip_v == 6) {
+               struct sockaddr_in6 sai6;
+               struct ip6_hdr *ip6 = (struct ip6_hdr *) ip;
+               proto = ip6->ip6_nxt;
+               len = sizeof(struct ip6_hdr);
+               memset(&sai6, 0, sizeof(sai6));
+               sai6.sin6_family = AF_INET6;
+               memcpy(&sai6.sin6_addr, &ip6->ip6_src, sizeof(struct in6_addr));
+               getnameinfo((struct sockaddr *) &sai6, sizeof(sai6),
+                           src, sizeof(src), NULL, 0, NI_NUMERICHOST);
+               memcpy(&sai6.sin6_addr, &ip6->ip6_dst, sizeof(struct in6_addr));
+               getnameinfo((struct sockaddr *) &sai6, sizeof(sai6),
+                           dst, sizeof(dst), NULL, 0, NI_NUMERICHOST);
+       } else {
+               raw_dump(level, frm);
+               return;
+       }
+
+       printf("src %s ", src);
+       printf("dst %s\n", dst);
+
+       frm->ptr += len;
+       frm->len -= len;
+       p_indent(++level, frm);
+
+       switch (proto) {
+       case IPPROTO_TCP:
+               printf("TCP:\n");
+               break;
+
+       case IPPROTO_UDP:
+               printf("UDP:\n");
+               break;
+
+       case IPPROTO_ICMP:
+               printf("ICMP:\n");
+               break;
+
+       case IPPROTO_ICMPV6:
+               printf("ICMPv6:\n");
+               break;
+
+       default:
+               printf("Unknown Protocol: 0x%02x\n", ip->ip_p);
+               break;
+       }
+
+       raw_dump(level, frm);
+}
diff --git a/tools/ppporc.c b/tools/ppporc.c
deleted file mode 100644 (file)
index ca44b40..0000000
+++ /dev/null
@@ -1,271 +0,0 @@
-/*
- *
- *  BlueZ - Bluetooth protocol stack for Linux
- *
- *  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 <fcntl.h>
-#include <unistd.h>
-#include <stdlib.h>
-#include <signal.h>
-#include <syslog.h>
-#include <getopt.h>
-#include <sys/poll.h>
-#include <sys/ioctl.h>
-#include <sys/socket.h>
-
-#include <bluetooth/bluetooth.h>
-#include <bluetooth/rfcomm.h>
-
-/* IO cancelation */
-static volatile sig_atomic_t __io_canceled;
-
-static inline void io_init(void)
-{
-       __io_canceled = 0;
-}
-
-static inline void io_cancel(void)
-{
-       __io_canceled = 1;
-}
-
-/* Signal functions */
-static void sig_hup(int sig)
-{
-       return;
-}
-
-static void sig_term(int sig)
-{
-       syslog(LOG_INFO, "Closing RFCOMM channel");
-       io_cancel();
-}
-
-/* Read exactly len bytes (Signal safe)*/
-static inline int read_n(int fd, char *buf, int len)
-{
-       register int t = 0, w;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = read(fd, buf, len)) < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w;
-               buf += w;
-               t += w;
-       }
-
-       return t;
-}
-
-/* Write exactly len bytes (Signal safe)*/
-static inline int write_n(int fd, char *buf, int len)
-{
-       register int t = 0, w;
-
-       while (!__io_canceled && len > 0) {
-               if ((w = write(fd, buf, len)) < 0) {
-                       if (errno == EINTR || errno == EAGAIN)
-                               continue;
-                       return -1;
-               }
-               if (!w)
-                       return 0;
-               len -= w;
-               buf += w;
-               t += w;
-       }
-
-       return t;
-}
-
-/* Create the RFCOMM connection */
-static int create_connection(bdaddr_t *bdaddr, uint8_t channel)
-{
-       struct sockaddr_rc remote_addr, local_addr;
-       int fd, err;
-
-       if ((fd = socket(PF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM)) < 0)
-               return fd;
-
-       memset(&local_addr, 0, sizeof(local_addr));
-       local_addr.rc_family = AF_BLUETOOTH;
-       bacpy(&local_addr.rc_bdaddr, BDADDR_ANY);
-       if ((err = bind(fd, (struct sockaddr *)&local_addr, sizeof(local_addr))) < 0) {
-               close(fd);
-               return err;
-       }
-
-       memset(&remote_addr, 0, sizeof(remote_addr));
-       remote_addr.rc_family = AF_BLUETOOTH;
-       bacpy(&remote_addr.rc_bdaddr, bdaddr);
-       remote_addr.rc_channel = channel;
-       if ((err = connect(fd, (struct sockaddr *)&remote_addr, sizeof(remote_addr))) < 0) {
-               close(fd);
-               return err;
-       }
-
-       syslog(LOG_INFO, "RFCOMM channel %d connected", channel);
-
-       return fd;
-}
-
-/* Process the data from socket and pseudo tty */
-static int process_data(int fd)
-{
-       struct pollfd p[2];
-       char buf[1024];
-       int err, r;
-
-       p[0].fd = 0;
-       p[0].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
-
-       p[1].fd = fd;
-       p[1].events = POLLIN | POLLERR | POLLHUP | POLLNVAL;
-
-       err = 0;
-
-       while (!__io_canceled) {
-               p[0].revents = 0;
-               p[1].revents = 0;
-
-               err = poll(p, 2, -1);
-               if (err < 0)
-                       break;
-
-               err = 0;
-
-               if (p[0].revents) {
-                       if (p[0].revents & (POLLERR | POLLHUP | POLLNVAL))
-                         break;
-                       r = read(0, buf, sizeof(buf));
-                       if (r < 0) {
-                               if (errno != EINTR && errno != EAGAIN) {
-                                       err = r;
-                                       break;
-                               }
-                       }
-
-                       err = write_n(fd, buf, r);
-                       if (err < 0)
-                               break;
-               }
-
-               if (p[1].revents) {
-                       if (p[1].revents & (POLLERR | POLLHUP | POLLNVAL))
-                               break;
-                       r = read(fd, buf, sizeof(buf));
-                       if (r < 0) {
-                               if (errno != EINTR && errno != EAGAIN) {
-                                       err = r;
-                                       break;
-                               }
-                       }
-
-                       err = write_n(1, buf, r);
-                       if (err < 0)
-                               break;
-               }
-       }
-
-       return err;
-}
-
-static void usage(void)
-{
-       printf("Usage:\tppporc <bdaddr> [channel]\n");
-}
-
-int main(int argc, char** argv)
-{
-       struct sigaction sa;
-       int fd, err, opt;
-
-       bdaddr_t bdaddr;
-       uint8_t channel;
-
-       /* Parse command line options */
-       while ((opt = getopt(argc, argv, "h")) != EOF) {
-               switch(opt) {
-               case 'h':
-                       usage();
-                       exit(0);
-               }
-       }
-
-       argc -= optind;
-       argv += optind;
-
-       switch (argc) {
-       case 1:
-               str2ba(argv[0], &bdaddr);
-               channel = 1;
-               break;
-       case 2:
-               str2ba(argv[0], &bdaddr);
-               channel = atoi(argv[1]);
-               break;
-       default:
-               usage();
-               exit(0);
-       }
-
-       /* Initialize syslog */
-       openlog("ppporc", LOG_PID | LOG_NDELAY | LOG_PERROR, LOG_DAEMON);
-       syslog(LOG_INFO, "PPP over RFCOMM");
-
-       /* Initialize signals */
-       memset(&sa, 0, sizeof(sa));
-       sa.sa_flags   = SA_NOCLDSTOP;
-       sa.sa_handler = SIG_IGN;
-       sigaction(SIGCHLD, &sa, NULL);
-       sigaction(SIGPIPE, &sa, NULL);
-
-       sa.sa_handler = sig_term;
-       sigaction(SIGTERM, &sa, NULL);
-       sigaction(SIGINT,  &sa, NULL);
-
-       sa.sa_handler = sig_hup;
-       sigaction(SIGHUP, &sa, NULL);
-
-       syslog(LOG_INFO, "Connecting to %s", argv[0]);
-
-       if ((fd = create_connection(&bdaddr, channel)) < 0) {
-               syslog(LOG_ERR, "Can't connect to remote device (%s)", strerror(errno));
-               return fd;
-       }
-
-       err = process_data(fd);
-
-       close(fd);
-
-       return err;
-}
similarity index 100%
rename from test/rctest.1
rename to tools/rctest.1
similarity index 89%
rename from test/rctest.c
rename to tools/rctest.c
index 4d7c90a..77fa03c 100644 (file)
@@ -38,6 +38,7 @@
 #include <sys/time.h>
 #include <sys/ioctl.h>
 #include <sys/socket.h>
+#include <sys/stat.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
@@ -55,7 +56,8 @@ enum {
        DUMP,
        CONNECT,
        CRECV,
-       LSEND
+       LSEND,
+       AUTO,
 };
 
 static unsigned char *buf;
@@ -72,14 +74,17 @@ static unsigned long delay = 0;
 
 /* Default addr and channel */
 static bdaddr_t bdaddr;
+static bdaddr_t auto_bdaddr;
 static uint16_t uuid = 0x0000;
 static uint8_t channel = 10;
 
 static char *filename = NULL;
+static char *savefile = NULL;
+static int save_fd = -1;
 
 static int master = 0;
 static int auth = 0;
-static int encrypt = 0;
+static int encr = 0;
 static int secure = 0;
 static int socktype = SOCK_STREAM;
 static int linger = 0;
@@ -162,7 +167,11 @@ static int do_connect(const char *svr)
        /* Bind to local address */
        memset(&addr, 0, sizeof(addr));
        addr.rc_family = AF_BLUETOOTH;
-       bacpy(&addr.rc_bdaddr, &bdaddr);
+
+       if (bacmp(&auto_bdaddr, BDADDR_ANY))
+               bacpy(&addr.rc_bdaddr, &auto_bdaddr);
+       else
+               bacpy(&addr.rc_bdaddr, &bdaddr);
 
        if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
                syslog(LOG_ERR, "Can't bind socket: %s (%d)",
@@ -200,7 +209,7 @@ static int do_connect(const char *svr)
                opt |= RFCOMM_LM_MASTER;
        if (auth)
                opt |= RFCOMM_LM_AUTH;
-       if (encrypt)
+       if (encr)
                opt |= RFCOMM_LM_ENCRYPT;
        if (secure)
                opt |= RFCOMM_LM_SECURE;
@@ -291,7 +300,7 @@ static void do_listen(void (*handler)(int sk))
                opt |= RFCOMM_LM_MASTER;
        if (auth)
                opt |= RFCOMM_LM_AUTH;
-       if (encrypt)
+       if (encr)
                opt |= RFCOMM_LM_ENCRYPT;
        if (secure)
                opt |= RFCOMM_LM_SECURE;
@@ -439,7 +448,26 @@ static void dump_mode(int sk)
 
        syslog(LOG_INFO, "Receiving ...");
        while ((len = read(sk, buf, data_size)) > 0)
-               syslog(LOG_INFO, "Recevied %d bytes", len);
+               syslog(LOG_INFO, "Received %d bytes", len);
+}
+
+static void save_mode(int sk)
+{
+       int len, ret;
+       char *b;
+
+       b = malloc(data_size);
+       if (!b) {
+               syslog(LOG_ERR, "Failed to open file to save recv data");
+               return;
+       }
+
+       syslog(LOG_INFO, "Receiving ...");
+       while ((len = read(sk, b, data_size)) > 0) {
+               ret = write(save_fd, b, len);
+               if (ret < 0)
+                       return;
+       }
 }
 
 static void recv_mode(int sk)
@@ -536,8 +564,9 @@ static void do_send(int sk)
 
        seq = 0;
        while ((num_frames == -1) || (num_frames-- > 0)) {
-               *(uint32_t *) buf = htobl(seq);
-               *(uint16_t *) (buf + 4) = htobs(data_size);
+               bt_put_le32(seq, buf);
+               bt_put_le16(data_size, buf + 4);
+
                seq++;
 
                if (send(sk, buf, data_size, 0) <= 0) {
@@ -591,6 +620,44 @@ static void multi_connect_mode(int argc, char *argv[])
        }
 }
 
+static void automated_send_recv()
+{
+       int sk;
+       char device[18];
+
+       if (fork()) {
+               if (!savefile) {
+                       do_listen(recv_mode);
+                       return;
+               }
+
+               save_fd = open(savefile, O_CREAT | O_WRONLY,
+                                               S_IRUSR | S_IWUSR);
+               if (save_fd < 0)
+                       syslog(LOG_ERR, "Failed to open file to save data");
+
+               do_listen(save_mode);
+
+               close(save_fd);
+       } else {
+               ba2str(&bdaddr, device);
+
+               sk = do_connect(device);
+               if (sk < 0)
+                       exit(1);
+               send_mode(sk);
+       }
+}
+
+static void sig_child_exit(int code)
+{
+       if (save_fd >= 0)
+               close(save_fd);
+
+       syslog(LOG_INFO, "Exit");
+       exit(0);
+}
+
 static void usage(void)
 {
        printf("rctest - RFCOMM testing\n"
@@ -604,13 +671,15 @@ static void usage(void)
                "\t-u connect and receive\n"
                "\t-n connect and be silent\n"
                "\t-c connect, disconnect, connect, ...\n"
-               "\t-m multiple connects\n");
+               "\t-m multiple connects\n"
+               "\t-a automated test (receive hcix as parameter)\n");
 
        printf("Options:\n"
                "\t[-b bytes] [-i device] [-P channel] [-U uuid]\n"
                "\t[-L seconds] enabled SO_LINGER option\n"
                "\t[-W seconds] enable deferred setup\n"
                "\t[-B filename] use data packets from file\n"
+               "\t[-O filename] save received data to file\n"
                "\t[-N num] number of frames to send\n"
                "\t[-C num] send num frames before delay (default = 1)\n"
                "\t[-D milliseconds] delay after sending num frames (default = 0)\n"
@@ -628,8 +697,9 @@ int main(int argc, char *argv[])
        int opt, sk, mode = RECV, need_addr = 0;
 
        bacpy(&bdaddr, BDADDR_ANY);
+       bacpy(&auto_bdaddr, BDADDR_ANY);
 
-       while ((opt=getopt(argc,argv,"rdscuwmnb:i:P:U:B:N:MAESL:W:C:D:Y:T")) != EOF) {
+       while ((opt=getopt(argc,argv,"rdscuwmna:b:i:P:U:B:O:N:MAESL:W:C:D:Y:T")) != EOF) {
                switch (opt) {
                case 'r':
                        mode = RECV;
@@ -668,6 +738,15 @@ int main(int argc, char *argv[])
                        need_addr = 1;
                        break;
 
+               case 'a':
+                       mode = AUTO;
+
+                       if (!strncasecmp(optarg, "hci", 3))
+                               hci_devba(atoi(optarg + 3), &auto_bdaddr);
+                       else
+                               str2ba(optarg, &auto_bdaddr);
+                       break;
+
                case 'b':
                        data_size = atoi(optarg);
                        break;
@@ -701,7 +780,7 @@ int main(int argc, char *argv[])
                        break;
 
                case 'E':
-                       encrypt = 1;
+                       encr = 1;
                        break;
 
                case 'S':
@@ -720,6 +799,10 @@ int main(int argc, char *argv[])
                        filename = strdup(optarg);
                        break;
 
+               case 'O':
+                       savefile = strdup(optarg);
+                       break;
+
                case 'N':
                        num_frames = atoi(optarg);
                        break;
@@ -757,7 +840,10 @@ int main(int argc, char *argv[])
        }
 
        memset(&sa, 0, sizeof(sa));
-       sa.sa_handler = SIG_IGN;
+       if (mode == AUTO)
+               sa.sa_handler = sig_child_exit;
+       else
+               sa.sa_handler = SIG_IGN;
        sa.sa_flags   = SA_NOCLDSTOP;
        sigaction(SIGCHLD, &sa, NULL);
 
@@ -804,6 +890,10 @@ int main(int argc, char *argv[])
                                exit(1);
                        dump_mode(sk);
                        break;
+
+               case AUTO:
+                       automated_send_recv();
+                       break;
        }
 
        syslog(LOG_INFO, "Exit");
index 06303cd..a108609 100644 (file)
@@ -48,24 +48,10 @@ Prints information about all configured RFCOMM devices.
 .BI -r
 Switch TTY into raw mode (doesn't work with "bind").
 .TP
-.BI -f " <file>"
-Specify alternate config file.
-.TP
 .BI -i " <hciX> | <bdaddr>"
-The command is applied to device
-.BI -A
-Enable authentication.
-.BI -E
-Enable encryption.
-.BI -S
-Secure connection.
-.BI -M
-Become the master of a piconet.
-.I
-hciX
-, which must be the name or the address of an installed Bluetooth
-device. If not specified, the command will be use the first
-available Bluetooth device.
+The command is applied to device hciX, which must be the name or the address of
+an installed Bluetooth device. If not specified, the command will be use the
+first available Bluetooth device.
 .TP
 .BI -A
 Enable authentification
@@ -89,9 +75,8 @@ Display the information about the specified device.
 .BI connect " <dev> [bdaddr] [channel]"
 Connect the RFCOMM device to the remote Bluetooth device on the
 specified channel. If no channel is specified, it will use the
-channel number 1. If also the Bluetooth address is left out, it
-tries to read the data from the config file. This command can
-be terminated with the key sequence CTRL-C.
+channel number 1. This command can be terminated with the key
+sequence CTRL-C.
 .TP
 .BI listen " <dev> [channel] [cmd]"
 Listen on a specified RFCOMM channel for incoming connections.
@@ -112,18 +97,10 @@ parameters.
 .TP
 .BI bind " <dev> [bdaddr] [channel]"
 This binds the RFCOMM device to a remote Bluetooth device. The
-command did not establish a connection to the remote device, it
+command does not establish a connection to the remote device, it
 only creates the binding. The connection will be established right
 after an application tries to open the RFCOMM device. If no channel
-number is specified, it uses the channel number 1. If the Bluetooth
-address is also left out, it tries to read the data from the config
-file.
-
-If
-.B all
-is specified for the RFCOMM device, then all devices that have
-.B "bind yes"
-set in the config will be bound.
+number is specified, it uses the channel number 1.
 .TP
 .BI release " <dev>"
 This command releases a defined RFCOMM binding.
@@ -131,7 +108,6 @@ This command releases a defined RFCOMM binding.
 If
 .B all
 is specified for the RFCOMM device, then all bindings will be removed.
-This command didn't care about the settings in the config file.
 .SH AUTHOR
 Written by Marcel Holtmann <marcel@holtmann.org>.
 .br
index e73b0ba..b5bea38 100644 (file)
@@ -25,7 +25,6 @@
 #include <config.h>
 #endif
 
-#define _GNU_SOURCE
 #include <stdio.h>
 #include <errno.h>
 #include <fcntl.h>
 #include <bluetooth/hci_lib.h>
 #include <bluetooth/rfcomm.h>
 
-#include "kword.h"
-
-#ifdef NEED_PPOLL
-#include "ppoll.h"
-#endif
-
-static char *rfcomm_config_file = NULL;
 static int rfcomm_raw_tty = 0;
 static int auth = 0;
 static int encryption = 0;
@@ -159,64 +151,28 @@ static int create_dev(int ctl, int dev, uint32_t flags, bdaddr_t *bdaddr, int ar
        bacpy(&req.src, bdaddr);
 
        if (argc < 2) {
-               err = rfcomm_read_config(rfcomm_config_file);
-               if (err < 0) {
-                       perror("Can't open RFCOMM config file");
-                       return err;
-               }
-
-               bacpy(&req.dst, &rfcomm_opts[dev].bdaddr);
-               req.channel = rfcomm_opts[dev].channel;
-
-               if (bacmp(&req.dst, BDADDR_ANY) == 0) {
-                       fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
-                       return -EFAULT;
-               }
-       } else {
-               str2ba(argv[1], &req.dst);
-
-               if (argc > 2)
-                       req.channel = atoi(argv[2]);
-               else
-                       req.channel = 1;
+               fprintf(stderr, "Missing dev parameter");
+               return -EINVAL;
        }
 
-       err = ioctl(ctl, RFCOMMCREATEDEV, &req);
-       if (err == EOPNOTSUPP)
-               fprintf(stderr, "RFCOMM TTY support not available\n");
-       else if (err < 0)
-               perror("Can't create device");
+       str2ba(argv[1], &req.dst);
 
-       return err;
-}
-
-static int create_all(int ctl)
-{
-       struct rfcomm_dev_req req;
-       int i, err;
-
-       err = rfcomm_read_config(rfcomm_config_file);
-       if (err < 0) {
-               perror("Can't open RFCOMM config file");
-               return err;
-       }
-
-       for (i = 0; i < RFCOMM_MAX_DEV; i++) {
-               if (!rfcomm_opts[i].bind)
-                       continue;
+       if (argc > 2)
+               req.channel = atoi(argv[2]);
+       else
+               req.channel = 1;
 
-               memset(&req, 0, sizeof(req));
-               req.dev_id = i;
-               req.flags = 0;
-               bacpy(&req.src, BDADDR_ANY);
-               bacpy(&req.dst, &rfcomm_opts[i].bdaddr);
-               req.channel = rfcomm_opts[i].channel;
+       err = ioctl(ctl, RFCOMMCREATEDEV, &req);
+       if (err == -1) {
+               err = -errno;
 
-               if (bacmp(&req.dst, BDADDR_ANY) != 0)
-                       ioctl(ctl, RFCOMMCREATEDEV, &req);
+               if (err == -EOPNOTSUPP)
+                       fprintf(stderr, "RFCOMM TTY support not available\n");
+               else
+                       perror("Can't create device");
        }
 
-       return 0;
+       return err;
 }
 
 static int release_dev(int ctl, int dev, uint32_t flags)
@@ -262,14 +218,14 @@ static int release_all(int ctl)
        return 0;
 }
 
-static void run_cmdline(struct pollfd *p, sigset_tsigs, char *devname,
+static void run_cmdline(struct pollfd *p, sigset_t *sigs, char *devname,
                        int argc, char **argv)
 {
        int i;
        pid_t pid;
        char **cmdargv;
 
-       cmdargv = malloc((argc + 1) * sizeof(char*));
+       cmdargv = malloc((argc + 1) * sizeof(char *));
        if (!cmdargv)
                return;
 
@@ -331,28 +287,17 @@ static void cmd_connect(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **arg
        laddr.rc_channel = 0;
 
        if (argc < 2) {
-               if (rfcomm_read_config(rfcomm_config_file) < 0) {
-                       perror("Can't open RFCOMM config file");
-                       return;
-               }
+               fprintf(stderr, "Missing dev parameter");
+               return;
+       }
 
-               raddr.rc_family = AF_BLUETOOTH;
-               bacpy(&raddr.rc_bdaddr, &rfcomm_opts[dev].bdaddr);
-               raddr.rc_channel = rfcomm_opts[dev].channel;
+       raddr.rc_family = AF_BLUETOOTH;
+       str2ba(argv[1], &raddr.rc_bdaddr);
 
-               if (bacmp(&raddr.rc_bdaddr, BDADDR_ANY) == 0) {
-                       fprintf(stderr, "Can't find a config entry for rfcomm%d\n", dev);
-                       return;
-               }
-       } else {
-               raddr.rc_family = AF_BLUETOOTH;
-               str2ba(argv[1], &raddr.rc_bdaddr);
-
-               if (argc > 2)
-                       raddr.rc_channel = atoi(argv[2]);
-               else
-                       raddr.rc_channel = 1;
-       }
+       if (argc > 2)
+               raddr.rc_channel = atoi(argv[2]);
+       else
+               raddr.rc_channel = 1;
 
        sk = socket(AF_BLUETOOTH, SOCK_STREAM, BTPROTO_RFCOMM);
        if (sk < 0) {
@@ -654,10 +599,7 @@ static void cmd_watch(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 
 static void cmd_create(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
 {
-       if (strcmp(argv[0], "all") == 0)
-               create_all(ctl);
-       else
-               create_dev(ctl, dev, 0, bdaddr, argc, argv);
+       create_dev(ctl, dev, 0, bdaddr, argc, argv);
 }
 
 static void cmd_release(int ctl, int dev, bdaddr_t *bdaddr, int argc, char **argv)
@@ -710,15 +652,15 @@ static void usage(void)
                "\n");
 
        printf("Options:\n"
-               "\t-i [hciX|bdaddr]      Local HCI device or BD Address\n"
-               "\t-h, --help            Display help\n"
-               "\t-r, --raw             Switch TTY into raw mode\n"
-               "\t-A, --auth            Enable authentication\n"
-               "\t-E, --encrypt         Enable encryption\n"
-               "\t-S, --secure          Secure connection\n"
-               "\t-M, --master          Become the master of a piconet\n"
-               "\t-f, --config [file]   Specify alternate config file\n"
-               "\t-a                    Show all devices (default)\n"
+               "\t-i, --device [hciX|bdaddr]     Local HCI device or BD Address\n"
+               "\t-h, --help                     Display help\n"
+               "\t-r, --raw                      Switch TTY into raw mode\n"
+               "\t-A, --auth                     Enable authentication\n"
+               "\t-E, --encrypt                  Enable encryption\n"
+               "\t-S, --secure                   Secure connection\n"
+               "\t-M, --master                   Become the master of a piconet\n"
+               "\t-L, --linger [seconds]         Set linger timeout\n"
+               "\t-a                             Show all devices (default)\n"
                "\n");
 
        printf("Commands:\n");
@@ -750,7 +692,7 @@ int main(int argc, char *argv[])
 
        bacpy(&bdaddr, BDADDR_ANY);
 
-       while ((opt = getopt_long(argc, argv, "+i:f:rahAESML:", main_options, NULL)) != -1) {
+       while ((opt = getopt_long(argc, argv, "+i:rahAESML:", main_options, NULL)) != -1) {
                switch(opt) {
                case 'i':
                        if (strncmp(optarg, "hci", 3) == 0)
@@ -759,10 +701,6 @@ int main(int argc, char *argv[])
                                str2ba(optarg, &bdaddr);
                        break;
 
-               case 'f':
-                       rfcomm_config_file = strdup(optarg);
-                       break;
-
                case 'r':
                        rfcomm_raw_tty = 1;
                        break;
diff --git a/tools/rfcomm.conf b/tools/rfcomm.conf
deleted file mode 100644 (file)
index 6179ef7..0000000
+++ /dev/null
@@ -1,17 +0,0 @@
-#
-# RFCOMM configuration file.
-#
-
-#rfcomm0 {
-#      # Automatically bind the device at startup
-#      bind no;
-#
-#      # Bluetooth address of the device
-#      device 11:22:33:44:55:66;
-#
-#      # RFCOMM channel for the connection
-#      channel 1;
-#
-#      # Description of the connection
-#      comment "Example Bluetooth device";
-#}
diff --git a/tools/sco-tester.c b/tools/sco-tester.c
new file mode 100644 (file)
index 0000000..1e8351f
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <stdlib.h>
+#include <unistd.h>
+#include <errno.h>
+#include <stdbool.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sco.h"
+#include "lib/mgmt.h"
+
+#include "monitor/bt.h"
+#include "emulator/bthost.h"
+
+#include "src/shared/tester.h"
+#include "src/shared/mgmt.h"
+#include "src/shared/hciemu.h"
+
+struct test_data {
+       const void *test_data;
+       struct mgmt *mgmt;
+       uint16_t mgmt_index;
+       struct hciemu *hciemu;
+       enum hciemu_type hciemu_type;
+       unsigned int io_id;
+       bool disable_esco;
+};
+
+struct sco_client_data {
+       int expect_err;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       tester_print("%s%s", prefix, str);
+}
+
+static void read_info_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct mgmt_rp_read_info *rp = param;
+       char addr[18];
+       uint16_t manufacturer;
+       uint32_t supported_settings, current_settings;
+
+       tester_print("Read Info callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       ba2str(&rp->bdaddr, addr);
+       manufacturer = btohs(rp->manufacturer);
+       supported_settings = btohl(rp->supported_settings);
+       current_settings = btohl(rp->current_settings);
+
+       tester_print("  Address: %s", addr);
+       tester_print("  Version: 0x%02x", rp->version);
+       tester_print("  Manufacturer: 0x%04x", manufacturer);
+       tester_print("  Supported settings: 0x%08x", supported_settings);
+       tester_print("  Current settings: 0x%08x", current_settings);
+       tester_print("  Class: 0x%02x%02x%02x",
+                       rp->dev_class[2], rp->dev_class[1], rp->dev_class[0]);
+       tester_print("  Name: %s", rp->name);
+       tester_print("  Short name: %s", rp->short_name);
+
+       if (strcmp(hciemu_get_address(data->hciemu), addr)) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       tester_pre_setup_complete();
+}
+
+static void index_added_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Added callback");
+       tester_print("  Index: 0x%04x", index);
+
+       data->mgmt_index = index;
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INFO, data->mgmt_index, 0, NULL,
+                                       read_info_callback, NULL, NULL);
+}
+
+static void index_removed_callback(uint16_t index, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Index Removed callback");
+       tester_print("  Index: 0x%04x", index);
+
+       if (index != data->mgmt_index)
+               return;
+
+       mgmt_unregister_index(data->mgmt, data->mgmt_index);
+
+       mgmt_unref(data->mgmt);
+       data->mgmt = NULL;
+
+       tester_post_teardown_complete();
+}
+
+static void read_index_list_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+
+       tester_print("Read Index List callback");
+       tester_print("  Status: 0x%02x", status);
+
+       if (status || !param) {
+               tester_pre_setup_failed();
+               return;
+       }
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_ADDED, MGMT_INDEX_NONE,
+                                       index_added_callback, NULL, NULL);
+
+       mgmt_register(data->mgmt, MGMT_EV_INDEX_REMOVED, MGMT_INDEX_NONE,
+                                       index_removed_callback, NULL, NULL);
+
+       data->hciemu = hciemu_new(HCIEMU_TYPE_BREDRLE);
+       if (!data->hciemu) {
+               tester_warn("Failed to setup HCI emulation");
+               tester_pre_setup_failed();
+       }
+
+       tester_print("New hciemu instance created");
+
+       if (data->disable_esco) {
+               uint8_t *features;
+
+               tester_print("Disabling eSCO packet type support");
+
+               features = hciemu_get_features(data->hciemu);
+               if (features)
+                       features[3] &= ~0x80;
+       }
+}
+
+static void test_pre_setup(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       data->mgmt = mgmt_new_default();
+       if (!data->mgmt) {
+               tester_warn("Failed to setup management interface");
+               tester_pre_setup_failed();
+               return;
+       }
+
+       if (tester_use_debug())
+               mgmt_set_debug(data->mgmt, mgmt_debug, "mgmt: ", NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_READ_INDEX_LIST, MGMT_INDEX_NONE, 0, NULL,
+                                       read_index_list_callback, NULL, NULL);
+}
+
+static void test_post_teardown(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+
+       hciemu_unref(data->hciemu);
+       data->hciemu = NULL;
+}
+
+static void test_data_free(void *test_data)
+{
+       struct test_data *data = test_data;
+
+       if (data->io_id > 0)
+               g_source_remove(data->io_id);
+
+       free(data);
+}
+
+#define test_sco_full(name, data, setup, func, _disable_esco) \
+       do { \
+               struct test_data *user; \
+               user = malloc(sizeof(struct test_data)); \
+               if (!user) \
+                       break; \
+               user->hciemu_type = HCIEMU_TYPE_BREDRLE; \
+               user->io_id = 0; \
+               user->test_data = data; \
+               user->disable_esco = _disable_esco; \
+               tester_add_full(name, data, \
+                               test_pre_setup, setup, func, NULL, \
+                               test_post_teardown, 2, user, test_data_free); \
+       } while (0)
+
+#define test_sco(name, data, setup, func) \
+       test_sco_full(name, data, setup, func, false)
+
+#define test_sco_11(name, data, setup, func) \
+       test_sco_full(name, data, setup, func, true)
+
+static const struct sco_client_data connect_success = {
+       .expect_err = 0
+};
+
+static const struct sco_client_data connect_failure = {
+       .expect_err = EOPNOTSUPP
+};
+
+static void client_connectable_complete(uint16_t opcode, uint8_t status,
+                                       const void *param, uint8_t len,
+                                       void *user_data)
+{
+       if (opcode != BT_HCI_CMD_WRITE_SCAN_ENABLE)
+               return;
+
+       tester_print("Client set connectable status 0x%02x", status);
+
+       if (status)
+               tester_setup_failed();
+       else
+               tester_setup_complete();
+}
+
+static void setup_powered_callback(uint8_t status, uint16_t length,
+                                       const void *param, void *user_data)
+{
+       struct test_data *data = tester_get_data();
+       struct bthost *bthost;
+
+       if (status != MGMT_STATUS_SUCCESS) {
+               tester_setup_failed();
+               return;
+       }
+
+       tester_print("Controller powered on");
+
+       bthost = hciemu_client_get_host(data->hciemu);
+       bthost_set_cmd_complete_cb(bthost, client_connectable_complete, data);
+       bthost_write_scan_enable(bthost, 0x03);
+}
+
+static void setup_powered(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       unsigned char param[] = { 0x01 };
+
+       tester_print("Powering on controller");
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_CONNECTABLE, data->mgmt_index,
+                                       sizeof(param), param,
+                                       NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_SSP, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_LE, data->mgmt_index,
+                               sizeof(param), param, NULL, NULL, NULL);
+
+       mgmt_send(data->mgmt, MGMT_OP_SET_POWERED, data->mgmt_index,
+                                       sizeof(param), param,
+                                       setup_powered_callback, NULL, NULL);
+}
+
+static void test_framework(const void *test_data)
+{
+       tester_test_passed();
+}
+
+static void test_socket(const void *test_data)
+{
+       int sk;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+       if (sk < 0) {
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               tester_test_failed();
+               return;
+       }
+
+       close(sk);
+
+       tester_test_passed();
+}
+
+static void test_getsockopt(const void *test_data)
+{
+       int sk, err;
+       socklen_t len;
+       struct bt_voice voice;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+       if (sk < 0) {
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               tester_test_failed();
+               return;
+       }
+
+       voice.setting = 0;
+       len = sizeof(voice);
+       err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+       if (err < 0) {
+               tester_warn("Can't get socket option : %s (%d)",
+                                                       strerror(errno), errno);
+               tester_test_failed();
+               goto end;
+       }
+
+       if (voice.setting != BT_VOICE_CVSD_16BIT) {
+               tester_warn("Invalid voice setting");
+               tester_test_failed();
+               goto end;
+       }
+
+       tester_test_passed();
+
+end:
+       close(sk);
+}
+
+static void test_setsockopt(const void *test_data)
+{
+       int sk, err;
+       socklen_t len;
+       struct bt_voice voice;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET, BTPROTO_SCO);
+       if (sk < 0) {
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               tester_test_failed();
+               goto end;
+       }
+
+
+       voice.setting = 0;
+       len = sizeof(voice);
+       err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+       if (err < 0) {
+               tester_warn("Can't get socket option : %s (%d)",
+                                                       strerror(errno), errno);
+               tester_test_failed();
+               goto end;
+       }
+
+       if (voice.setting != BT_VOICE_CVSD_16BIT) {
+               tester_warn("Invalid voice setting");
+               tester_test_failed();
+               goto end;
+       }
+
+       voice.setting = BT_VOICE_TRANSPARENT;
+       err = setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice));
+       if (err < 0) {
+               tester_warn("Can't set socket option : %s (%d)",
+                                                       strerror(errno), errno);
+               tester_test_failed();
+               goto end;
+       }
+
+       voice.setting = 0;
+       len = sizeof(voice);
+       err = getsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, &len);
+       if (err < 0) {
+               tester_warn("Can't get socket option : %s (%d)",
+                                                       strerror(errno), errno);
+               tester_test_failed();
+               goto end;
+       }
+
+       if (voice.setting != BT_VOICE_TRANSPARENT) {
+               tester_warn("Invalid voice setting");
+               tester_test_failed();
+               goto end;
+       }
+
+       tester_test_passed();
+
+end:
+       close(sk);
+}
+
+static int create_sco_sock(struct test_data *data, uint16_t psm)
+{
+       const uint8_t *master_bdaddr;
+       struct sockaddr_sco addr;
+       int sk, err;
+
+       sk = socket(PF_BLUETOOTH, SOCK_SEQPACKET | SOCK_NONBLOCK,
+                                                               BTPROTO_SCO);
+       if (sk < 0) {
+               err = -errno;
+               tester_warn("Can't create socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               return err;
+       }
+
+       master_bdaddr = hciemu_get_master_bdaddr(data->hciemu);
+       if (!master_bdaddr) {
+               tester_warn("No master bdaddr");
+               return -ENODEV;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sco_family = AF_BLUETOOTH;
+       bacpy(&addr.sco_bdaddr, (void *) master_bdaddr);
+
+       if (bind(sk, (struct sockaddr *) &addr, sizeof(addr)) < 0) {
+               err = -errno;
+               tester_warn("Can't bind socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               close(sk);
+               return err;
+       }
+
+       return sk;
+}
+
+static int connect_sco_sock(struct test_data *data, int sk)
+{
+       const uint8_t *client_bdaddr;
+       struct sockaddr_sco addr;
+       int err;
+
+       client_bdaddr = hciemu_get_client_bdaddr(data->hciemu);
+       if (!client_bdaddr) {
+               tester_warn("No client bdaddr");
+               return -ENODEV;
+       }
+
+       memset(&addr, 0, sizeof(addr));
+       addr.sco_family = AF_BLUETOOTH;
+       bacpy(&addr.sco_bdaddr, (void *) client_bdaddr);
+
+       err = connect(sk, (struct sockaddr *) &addr, sizeof(addr));
+       if (err < 0 && !(errno == EAGAIN || errno == EINPROGRESS)) {
+               err = -errno;
+               tester_warn("Can't connect socket: %s (%d)", strerror(errno),
+                                                                       errno);
+               return err;
+       }
+
+       return 0;
+}
+
+static gboolean sco_connect_cb(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct sco_client_data *scodata = data->test_data;
+       int err, sk_err, sk;
+       socklen_t len = sizeof(sk_err);
+
+       data->io_id = 0;
+
+       sk = g_io_channel_unix_get_fd(io);
+
+       if (getsockopt(sk, SOL_SOCKET, SO_ERROR, &sk_err, &len) < 0)
+               err = -errno;
+       else
+               err = -sk_err;
+
+       if (err < 0)
+               tester_warn("Connect failed: %s (%d)", strerror(-err), -err);
+       else
+               tester_print("Successfully connected");
+
+       if (-err != scodata->expect_err)
+               tester_test_failed();
+       else
+               tester_test_passed();
+
+       return FALSE;
+}
+
+static void test_connect(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       GIOChannel *io;
+       int sk;
+
+       sk = create_sco_sock(data, 0);
+       if (sk < 0) {
+               tester_test_failed();
+               return;
+       }
+
+       if (connect_sco_sock(data, sk) < 0) {
+               close(sk);
+               tester_test_failed();
+               return;
+       }
+
+       io = g_io_channel_unix_new(sk);
+       g_io_channel_set_close_on_unref(io, TRUE);
+
+       data->io_id = g_io_add_watch(io, G_IO_OUT, sco_connect_cb, NULL);
+
+       g_io_channel_unref(io);
+
+       tester_print("Connect in progress");
+}
+
+static void test_connect_transp(const void *test_data)
+{
+       struct test_data *data = tester_get_data();
+       const struct sco_client_data *scodata = data->test_data;
+       int sk, err;
+       struct bt_voice voice;
+
+       sk = create_sco_sock(data, 0);
+       if (sk < 0) {
+               tester_test_failed();
+               return;
+       }
+
+       voice.setting = BT_VOICE_TRANSPARENT;
+       err = setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &voice, sizeof(voice));
+       if (err < 0) {
+               tester_warn("Can't set socket option : %s (%d)",
+                                                       strerror(errno), errno);
+               tester_test_failed();
+               goto end;
+       }
+
+       err = connect_sco_sock(data, sk);
+
+       tester_warn("Connect returned %s (%d), expected %s (%d)",
+                       strerror(-err), -err,
+                       strerror(scodata->expect_err), scodata->expect_err);
+
+       if (-err != scodata->expect_err)
+               tester_test_failed();
+       else
+               tester_test_passed();
+
+end:
+       close(sk);
+}
+
+int main(int argc, char *argv[])
+{
+       tester_init(&argc, &argv);
+
+       test_sco("Basic Framework - Success", NULL, setup_powered,
+                                                       test_framework);
+
+       test_sco("Basic SCO Socket - Success", NULL, setup_powered,
+                                                       test_socket);
+
+       test_sco("Basic SCO Get Socket Option - Success", NULL, setup_powered,
+                                                       test_getsockopt);
+
+       test_sco("Basic SCO Set Socket Option - Success", NULL, setup_powered,
+                                                       test_setsockopt);
+
+       test_sco("eSCO CVSD - Success", &connect_success, setup_powered,
+                                                       test_connect);
+
+       test_sco("eSCO MSBC - Success", &connect_success, setup_powered,
+                                                       test_connect_transp);
+
+       test_sco_11("SCO CVSD 1.1 - Success", &connect_success, setup_powered,
+                                                       test_connect);
+
+       test_sco_11("SCO MSBC 1.1 - Failure", &connect_failure, setup_powered,
+                                                       test_connect_transp);
+
+       return tester_run();
+}
similarity index 77%
rename from test/scotest.c
rename to tools/scotest.c
index 17bd8a6..69150b1 100644 (file)
@@ -57,6 +57,9 @@ static long data_size = 672;
 
 static bdaddr_t bdaddr;
 
+static int defer_setup = 0;
+static int voice = 0;
+
 static float tv2fl(struct timeval tv)
 {
        return (float)tv.tv_sec + (float)(tv.tv_usec/1000000.0);
@@ -88,6 +91,20 @@ static int do_connect(char *svr)
                goto error;
        }
 
+       if (voice) {
+               struct bt_voice opts;
+
+               /* SCO voice setting */
+               memset(&opts, 0, sizeof(opts));
+               opts.setting = voice;
+               if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0) {
+                       syslog(LOG_ERR,
+                               "Can't set voice socket option: %s (%d)",
+                               strerror(errno), errno);
+                       goto error;
+               }
+       }
+
        /* Connect to remote device */
        memset(&addr, 0, sizeof(addr));
        addr.sco_family = AF_BLUETOOTH;
@@ -147,6 +164,14 @@ static void do_listen(void (*handler)(int sk))
                goto error;
        }
 
+       /* Enable deferred setup */
+       if (defer_setup && setsockopt(sk, SOL_BLUETOOTH, BT_DEFER_SETUP,
+                               &defer_setup, sizeof(defer_setup)) < 0) {
+               syslog(LOG_ERR, "Can't enable deferred setup : %s (%d)",
+                                                       strerror(errno), errno);
+               goto error;
+       }
+
        /* Listen for connections */
        if (listen(sk, 10)) {
                syslog(LOG_ERR,"Can not listen on the socket: %s (%d)",
@@ -181,8 +206,10 @@ static void do_listen(void (*handler)(int sk))
                if (getsockopt(nsk, SOL_SCO, SCO_CONNINFO, &conn, &optlen) < 0) {
                        syslog(LOG_ERR, "Can't get SCO connection information: %s (%d)",
                                                        strerror(errno), errno);
-                       close(nsk);
-                       goto error;
+                       if (!defer_setup) {
+                               close(nsk);
+                               goto error;
+                       }
                }
 
                ba2str(&addr.sco_bdaddr, ba);
@@ -190,6 +217,18 @@ static void do_listen(void (*handler)(int sk))
                        ba, conn.hci_handle,
                        conn.dev_class[2], conn.dev_class[1], conn.dev_class[0]);
 
+               /* Handle deferred setup */
+               if (defer_setup) {
+                       syslog(LOG_INFO, "Waiting for %d seconds",
+                                                       abs(defer_setup) - 1);
+                       sleep(abs(defer_setup) - 1);
+
+                       if (defer_setup < 0) {
+                               close(nsk);
+                               goto error;
+                       }
+               }
+
                handler(nsk);
 
                syslog(LOG_INFO, "Disconnect");
@@ -205,8 +244,25 @@ error:
 
 static void dump_mode(int sk)
 {
+       struct bt_voice opts;
        int len;
 
+       /* SCO voice setting */
+       memset(&opts, 0, sizeof(opts));
+       opts.setting = voice;
+       if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0)
+               syslog(LOG_ERR, "Can't set socket options: %s (%d)",
+                                                       strerror(errno), errno);
+
+       if (defer_setup) {
+               len = read(sk, buf, sizeof(buf));
+               if (len < 0)
+                       syslog(LOG_ERR, "Initial read error: %s (%d)",
+                                               strerror(errno), errno);
+               else
+                       syslog(LOG_INFO, "Initial bytes %d", len);
+       }
+
        syslog(LOG_INFO,"Receiving ...");
        while ((len = read(sk, buf, data_size)) > 0)
                syslog(LOG_INFO, "Recevied %d bytes", len);
@@ -215,7 +271,25 @@ static void dump_mode(int sk)
 static void recv_mode(int sk)
 {
        struct timeval tv_beg,tv_end,tv_diff;
+       struct bt_voice opts;
        long total;
+       int len;
+
+       /* SCO voice setting */
+       memset(&opts, 0, sizeof(opts));
+       opts.setting = voice;
+       if (setsockopt(sk, SOL_BLUETOOTH, BT_VOICE, &opts, sizeof(opts)) < 0)
+               syslog(LOG_ERR, "Can't set socket options: %s (%d)",
+                                                       strerror(errno), errno);
+
+       if (defer_setup) {
+               len = read(sk, buf, sizeof(buf));
+               if (len < 0)
+                       syslog(LOG_ERR, "Initial read error: %s (%d)",
+                                               strerror(errno), errno);
+               else
+                       syslog(LOG_INFO, "Initial bytes %d", len);
+       }
 
        syslog(LOG_INFO, "Receiving ...");
 
@@ -228,7 +302,9 @@ static void recv_mode(int sk)
                                if (r < 0)
                                        syslog(LOG_ERR, "Read failed: %s (%d)",
                                                        strerror(errno), errno);
-                               return;
+                               if (errno != ENOTCONN)
+                                       return;
+                               r = 0;
                        }
                        total += r;
                }
@@ -269,8 +345,9 @@ static void send_mode(char *svr)
 
        seq = 0;
        while (1) {
-               *(uint32_t *) buf = htobl(seq);
-               *(uint16_t *) (buf + 4) = htobs(data_size);
+               bt_put_le32(seq, buf);
+               bt_put_le16(data_size, buf + 4);
+
                seq++;
 
                if (send(sk, buf, so.mtu, 0) <= 0) {
@@ -327,14 +404,18 @@ static void usage(void)
 {
        printf("scotest - SCO testing\n"
                "Usage:\n");
-       printf("\tscotest <mode> [-b bytes] [bd_addr]\n");
+       printf("\tscotest <mode> [options] [bd_addr]\n");
        printf("Modes:\n"
                "\t-d dump (server)\n"
                "\t-c reconnect (client)\n"
                "\t-m multiple connects (client)\n"
                "\t-r receive (server)\n"
                "\t-s connect and send (client)\n"
-               "\t-n connect and be silent (client)\n");
+               "\t-n connect and be silent (client)\n"
+               "Options:\n"
+               "\t[-b bytes]\n"
+               "\t[-W seconds] enable deferred setup\n"
+               "\t[-V voice] select SCO voice setting (0x0060 cvsd, 0x0003 transparent)\n");
 }
 
 int main(int argc ,char *argv[])
@@ -342,7 +423,7 @@ int main(int argc ,char *argv[])
        struct sigaction sa;
        int opt, sk, mode = RECV;
 
-       while ((opt=getopt(argc,argv,"rdscmnb:")) != EOF) {
+       while ((opt = getopt(argc, argv, "rdscmnb:W:V:")) != EOF) {
                switch(opt) {
                case 'r':
                        mode = RECV;
@@ -372,6 +453,14 @@ int main(int argc ,char *argv[])
                        data_size = atoi(optarg);
                        break;
 
+               case 'W':
+                       defer_setup = atoi(optarg);
+                       break;
+
+               case 'V':
+                       voice = strtol(optarg, NULL, 0);
+                       break;
+
                default:
                        usage();
                        exit(1);
index 0f100e2..ea95933 100644 (file)
@@ -61,12 +61,12 @@ sdptool \(em control and interrogate SDP servers
 .PP
 \fBsdptool\fR provides the interface for
 performing SDP queries on Bluetooth devices, and administering a
-local \fBsdpd\fR.
+local SDP database.
 .SH "COMMANDS"
 .PP
 The following commands are available.  In all cases \fBbdaddr\fR
 specifies the device to search or browse.  If \fIlocal\fP is used
-for \fBbdaddr\fP, then the local \fBsdpd\fR is searched.
+for \fBbdaddr\fP, then the local SDP database is searched.
 .PP
 Services are identified and manipulated with a 4-byte \fBrecord_handle\fP
 (NOT the service name).  To find a service's \fBrecord_handle\fP, look for the
@@ -84,19 +84,25 @@ specified by a Bluetooth address as a parameter.
 Retrieve all possible service records.
 .IP "\fBadd [ --handle=N --channel=N ]\fP" 10
 Add a service to the local
-\fBsdpd\fR.
+SDP database.
 .IP "" 10
 You can specify a handle for this record using
 the \fB--handle\fP option.
 .IP "" 10
 You can specify a channel to add the service on
 using the \fB--channel\fP option.
+.IP "" 10
+NOTE: Local adapters configuration will not be updated and this command should
+be used only for SDP testing.
 .IP "\fBdel record_handle\fP" 10
 Remove a service from the local
-\fBsdpd\fR.
+SDP database.
+.IP "" 10
+NOTE: Local adapters configuration will not be updated and this command should
+be used only for SDP testing.
 .IP "\fBget [--tree] [--raw] [--xml] [--bdaddr bdaddr] record_handle\fP" 10
 Retrieve a service from the local
-\fBsdpd\fR.
+SDP database.
 .IP "\fBsetattr record_handle attrib_id attrib_value\fP" 10
 Set or add an attribute to an SDP record.
 
@@ -123,8 +129,4 @@ Documentation needs improving.
 .PP
 Maxim Krasnyansky <maxk@qualcomm.com>. Man page written
 by Edd Dumbill <ejad@debian.org>.
-
-.SH "SEE ALSO"
-.PP
-sdpd(8)
 .\" created by instant / docbook-to-man, Thu 15 Jan 2004, 21:01
index 4e9da64..f985b1e 100644 (file)
@@ -52,6 +52,7 @@
 #endif
 
 #define for_each_opt(opt, long, short) while ((opt=getopt_long(argc, argv, short ? short:"+", long, 0)) != -1)
+#define N_ELEMENTS(x) (sizeof(x) / sizeof((x)[0]))
 
 /*
  * Convert a string to a BDADDR, with a few "enhancements" - Jean II
@@ -152,14 +153,14 @@ static struct attrib_def attrib_names[] = {
        { 0x2, "ServiceRecordState", NULL, 0 },
        { 0x3, "ServiceID", NULL, 0 },
        { 0x4, "ProtocolDescriptorList",
-               protocol_members, sizeof(protocol_members)/sizeof(struct member_def) },
+               protocol_members, N_ELEMENTS(protocol_members) },
        { 0x5, "BrowseGroupList", NULL, 0 },
        { 0x6, "LanguageBaseAttributeIDList",
-               language_members, sizeof(language_members)/sizeof(struct member_def) },
+               language_members, N_ELEMENTS(language_members) },
        { 0x7, "ServiceInfoTimeToLive", NULL, 0 },
        { 0x8, "ServiceAvailability", NULL, 0 },
        { 0x9, "BluetoothProfileDescriptorList",
-               profile_members, sizeof(profile_members)/sizeof(struct member_def) },
+               profile_members, N_ELEMENTS(profile_members) },
        { 0xA, "DocumentationURL", NULL, 0 },
        { 0xB, "ClientExecutableURL", NULL, 0 },
        { 0xC, "IconURL", NULL, 0 },
@@ -167,7 +168,7 @@ static struct attrib_def attrib_names[] = {
        /* Definitions after that are tricky (per profile or offset) */
 };
 
-const int attrib_max = sizeof(attrib_names)/sizeof(struct attrib_def);
+const int attrib_max = N_ELEMENTS(attrib_names);
 
 /* Name of the various SPD attributes. See BT assigned numbers */
 static struct attrib_def sdp_attrib_names[] = {
@@ -231,6 +232,12 @@ static struct attrib_def goep_attrib_names[] = {
        { 0x200, "GoepL2capPsm", NULL, 0 },
 };
 
+/* Name of the various MAS attributes. See BT assigned numbers */
+static struct attrib_def mas_attrib_names[] = {
+       { 0x0315, "MASInstanceID", NULL, 0 },
+       { 0x0316, "SupportedMessageTypes", NULL, 0 },
+};
+
 /* Same for the UUIDs. See BT assigned numbers */
 static struct uuid_def uuid16_names[] = {
        /* -- Protocols -- */
@@ -258,39 +265,39 @@ static struct uuid_def uuid16_names[] = {
        { 0x0100, "L2CAP", NULL, 0 },
        /* -- Services -- */
        { 0x1000, "ServiceDiscoveryServerServiceClassID",
-               sdp_attrib_names, sizeof(sdp_attrib_names)/sizeof(struct attrib_def) },
+               sdp_attrib_names, N_ELEMENTS(sdp_attrib_names) },
        { 0x1001, "BrowseGroupDescriptorServiceClassID",
-               browse_attrib_names, sizeof(browse_attrib_names)/sizeof(struct attrib_def) },
+               browse_attrib_names, N_ELEMENTS(browse_attrib_names) },
        { 0x1002, "PublicBrowseGroup", NULL, 0 },
        { 0x1101, "SerialPort", NULL, 0 },
        { 0x1102, "LANAccessUsingPPP", NULL, 0 },
        { 0x1103, "DialupNetworking (DUN)", NULL, 0 },
        { 0x1104, "IrMCSync", NULL, 0 },
        { 0x1105, "OBEXObjectPush",
-               goep_attrib_names, sizeof(goep_attrib_names)/sizeof(struct attrib_def) },
+               goep_attrib_names, N_ELEMENTS(goep_attrib_names) },
        { 0x1106, "OBEXFileTransfer",
-               goep_attrib_names, sizeof(goep_attrib_names)/sizeof(struct attrib_def) },
+               goep_attrib_names, N_ELEMENTS(goep_attrib_names) },
        { 0x1107, "IrMCSyncCommand", NULL, 0 },
        { 0x1108, "Headset",
-               audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
+               audio_attrib_names, N_ELEMENTS(audio_attrib_names) },
        { 0x1109, "CordlessTelephony", NULL, 0 },
        { 0x110a, "AudioSource", NULL, 0 },
        { 0x110b, "AudioSink", NULL, 0 },
        { 0x110c, "RemoteControlTarget", NULL, 0 },
        { 0x110d, "AdvancedAudio", NULL, 0 },
        { 0x110e, "RemoteControl", NULL, 0 },
-       { 0x110f, "VideoConferencing", NULL, 0 },
+       { 0x110f, "RemoteControlController", NULL, 0 },
        { 0x1110, "Intercom", NULL, 0 },
        { 0x1111, "Fax", NULL, 0 },
        { 0x1112, "HeadsetAudioGateway", NULL, 0 },
        { 0x1113, "WAP", NULL, 0 },
        { 0x1114, "WAP Client", NULL, 0 },
        { 0x1115, "PANU (PAN/BNEP)",
-               pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+               pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
        { 0x1116, "NAP (PAN/BNEP)",
-               pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+               pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
        { 0x1117, "GN (PAN/BNEP)",
-               pan_attrib_names, sizeof(pan_attrib_names)/sizeof(struct attrib_def) },
+               pan_attrib_names, N_ELEMENTS(pan_attrib_names) },
        { 0x1118, "DirectPrinting (BPP)", NULL, 0 },
        { 0x1119, "ReferencePrinting (BPP)", NULL, 0 },
        { 0x111a, "Imaging (BIP)", NULL, 0 },
@@ -304,12 +311,11 @@ static struct uuid_def uuid16_names[] = {
        { 0x1122, "BasicPrinting (BPP)", NULL, 0 },
        { 0x1123, "PrintingStatus (BPP)", NULL, 0 },
        { 0x1124, "HumanInterfaceDeviceService (HID)",
-               hid_attrib_names, sizeof(hid_attrib_names)/sizeof(struct attrib_def) },
+               hid_attrib_names, N_ELEMENTS(hid_attrib_names) },
        { 0x1125, "HardcopyCableReplacement (HCR)", NULL, 0 },
        { 0x1126, "HCR_Print (HCR)", NULL, 0 },
        { 0x1127, "HCR_Scan (HCR)", NULL, 0 },
        { 0x1128, "Common ISDN Access (CIP)", NULL, 0 },
-       { 0x1129, "VideoConferencingGW (VCP)", NULL, 0 },
        { 0x112a, "UDI-MT", NULL, 0 },
        { 0x112b, "UDI-TA", NULL, 0 },
        { 0x112c, "Audio/Video", NULL, 0 },
@@ -317,13 +323,18 @@ static struct uuid_def uuid16_names[] = {
        { 0x112e, "Phonebook Access (PBAP) - PCE", NULL, 0 },
        { 0x112f, "Phonebook Access (PBAP) - PSE", NULL, 0 },
        { 0x1130, "Phonebook Access (PBAP)", NULL, 0 },
+       { 0x1131, "Headset (HSP)", NULL, 0 },
+       { 0x1132, "Message Access (MAP) - MAS",
+               mas_attrib_names, N_ELEMENTS(mas_attrib_names) },
+       { 0x1133, "Message Access (MAP) - MNS", NULL, 0 },
+       { 0x1134, "Message Access (MAP)", NULL, 0 },
        /* ... */
        { 0x1200, "PnPInformation",
-               did_attrib_names, sizeof(did_attrib_names)/sizeof(struct attrib_def) },
+               did_attrib_names, N_ELEMENTS(did_attrib_names) },
        { 0x1201, "GenericNetworking", NULL, 0 },
        { 0x1202, "GenericFileTransfer", NULL, 0 },
        { 0x1203, "GenericAudio",
-               audio_attrib_names, sizeof(audio_attrib_names)/sizeof(struct attrib_def) },
+               audio_attrib_names, N_ELEMENTS(audio_attrib_names) },
        { 0x1204, "GenericTelephony", NULL, 0 },
        /* ... */
        { 0x1303, "VideoSource", NULL, 0 },
@@ -335,7 +346,7 @@ static struct uuid_def uuid16_names[] = {
        { 0x2112, "AppleAgent", NULL, 0 },
 };
 
-static const int uuid16_max = sizeof(uuid16_names)/sizeof(struct uuid_def);
+static const int uuid16_max = N_ELEMENTS(uuid16_names);
 
 static void sdp_data_printf(sdp_data_t *, struct attrib_context *, int);
 
@@ -2581,7 +2592,7 @@ static int add_cip(sdp_session_t *session, svc_info_t *si)
        proto[0] = sdp_list_append(0, &l2cap);
        apseq = sdp_list_append(0, proto[0]);
        proto[0] = sdp_list_append(proto[0], sdp_data_alloc(SDP_UINT16, &psm));
-       apseq = sdp_list_append(0, proto[0]);
+       apseq = sdp_list_append(apseq, proto[0]);
 
        sdp_uuid16_create(&cmtp, CMTP_UUID);
        proto[1] = sdp_list_append(0, &cmtp);
@@ -3287,6 +3298,9 @@ static unsigned char ngage_uuid[] = {     0x00, 0x00, 0x13, 0x01, 0x00, 0x00, 0x10,
 static unsigned char apple_uuid[] = {  0xf0, 0x72, 0x2e, 0x20, 0x0f, 0x8b, 0x4e, 0x90,
                                        0x8c, 0xc2, 0x1b, 0x46, 0xf5, 0xf2, 0xef, 0xe2 };
 
+static unsigned char iap_uuid[] = {    0x00, 0x00, 0x00, 0x00, 0xde, 0xca, 0xfa, 0xde,
+                                       0xde, 0xca, 0xde, 0xaf, 0xde, 0xca, 0xca, 0xfe };
+
 static int add_apple(sdp_session_t *session, svc_info_t *si)
 {
        sdp_record_t record;
@@ -3540,6 +3554,7 @@ struct {
        { "NSYNCML",    0,                              NULL,           nsyncml_uuid    },
        { "NGAGE",      0,                              NULL,           ngage_uuid      },
        { "APPLE",      0,                              add_apple,      apple_uuid      },
+       { "IAP",        0,                              NULL,           iap_uuid        },
 
        { "ISYNC",      APPLE_AGENT_SVCLASS_ID,         add_isync,      },
        { "GATT",       GENERIC_ATTRIB_SVCLASS_ID,      add_gatt,       },
@@ -3773,6 +3788,8 @@ static int do_search(bdaddr_t *bdaddr, struct search_context *context)
        search = sdp_list_append(0, &context->group);
        if (sdp_service_search_attr_req(sess, search, SDP_ATTR_REQ_RANGE, attrid, &seq)) {
                printf("Service Search failed: %s\n", strerror(errno));
+               sdp_list_free(attrid, 0);
+               sdp_list_free(search, 0);
                sdp_close(sess);
                return -1;
        }
@@ -3804,9 +3821,10 @@ static int do_search(bdaddr_t *bdaddr, struct search_context *context)
                        break;
                }
 
+               /* Set the subcontext for browsing the sub tree */
+               memcpy(&sub_context, context, sizeof(struct search_context));
+
                if (sdp_get_group_id(rec, &sub_context.group) != -1) {
-                       /* Set the subcontext for browsing the sub tree */
-                       memcpy(&sub_context, context, sizeof(struct search_context));
                        /* Browse the next level down if not done */
                        if (sub_context.group.value.uuid16 != context->group.value.uuid16)
                                do_search(bdaddr, &sub_context);
diff --git a/unit/test-crc.c b/unit/test-crc.c
new file mode 100644 (file)
index 0000000..db40dc9
--- /dev/null
@@ -0,0 +1,194 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include "monitor/crc.h"
+
+#include <glib.h>
+
+struct crc_data {
+       const void *packet;
+       size_t size;
+       uint32_t crc_init;
+};
+
+static const unsigned char packet_1[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x00, 0x17, 0x7e, 0x01,
+       0x00, 0xd0, 0x22, 0x00, 0x02, 0x01, 0x06, 0x03,
+       0x02, 0x0d, 0x18, 0x06, 0xff, 0x6b, 0x00, 0x03,
+       0x16, 0x52, 0x02, 0x0a, 0x00, 0xf4, 0x09, 0x92,
+};
+
+static const struct crc_data crc_1 = {
+       .packet = packet_1,
+       .size = sizeof(packet_1),
+};
+
+static const unsigned char packet_2[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x00, 0x17, 0x7e, 0x01,
+       0x00, 0xd0, 0x22, 0x00, 0x02, 0x01, 0x06, 0x03,
+       0x02, 0x0d, 0x18, 0x06, 0xff, 0x6b, 0x00, 0x03,
+       0x16, 0x54, 0x02, 0x0a, 0x00, 0x95, 0x5f, 0x14,
+};
+
+static const struct crc_data crc_2 = {
+       .packet = packet_2,
+       .size = sizeof(packet_2),
+};
+
+static const unsigned char packet_3[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x00, 0x17, 0x7e, 0x01,
+       0x00, 0xd0, 0x22, 0x00, 0x02, 0x01, 0x06, 0x03,
+       0x02, 0x0d, 0x18, 0x06, 0xff, 0x6b, 0x00, 0x03,
+       0x16, 0x55, 0x02, 0x0a, 0x00, 0x85, 0x66, 0x63,
+};
+
+static const struct crc_data crc_3 = {
+       .packet = packet_3,
+       .size = sizeof(packet_3),
+};
+
+static const unsigned char packet_4[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x00, 0x17, 0x7e, 0x01,
+       0x00, 0xd0, 0x22, 0x00, 0x02, 0x01, 0x06, 0x03,
+       0x02, 0x0d, 0x18, 0x06, 0xff, 0x6b, 0x00, 0x03,
+       0x16, 0x53, 0x02, 0x0a, 0x00, 0xe4, 0x30, 0xe5,
+};
+
+static const struct crc_data crc_4 = {
+       .packet = packet_4,
+       .size = sizeof(packet_4),
+};
+
+static const unsigned char packet_5[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x03, 0x0c, 0x46, 0x1c,
+       0xda, 0x72, 0x02, 0x00, 0x7e, 0x01, 0x00, 0xd0,
+       0x22, 0x00, 0x6e, 0xf4, 0x6f,
+};
+
+static const struct crc_data crc_5 = {
+       .packet = packet_5,
+       .size = sizeof(packet_5),
+};
+
+static const unsigned char packet_6[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x04, 0x17, 0x7e, 0x01,
+       0x00, 0xd0, 0x22, 0x00, 0x10, 0x09, 0x50, 0x6f,
+       0x6c, 0x61, 0x72, 0x20, 0x48, 0x37, 0x20, 0x30,
+       0x30, 0x30, 0x31, 0x37, 0x45, 0x0f, 0x8a, 0x65,
+};
+
+static const struct crc_data crc_6 = {
+       .packet = packet_6,
+       .size = sizeof(packet_6),
+};
+
+static const unsigned char packet_7[] = {
+       0xd6, 0xbe, 0x89, 0x8e, 0x05, 0x22, 0x46, 0x1c,
+       0xda, 0x72, 0x02, 0x00, 0x7e, 0x01, 0x00, 0xd0,
+       0x22, 0x00, 0x96, 0x83, 0x9a, 0xaf, 0xbe, 0x1d,
+       0x16, 0x03, 0x05, 0x00, 0x36, 0x00, 0x00, 0x00,
+       0x2a, 0x00, 0xff, 0xff, 0xff, 0xff, 0x1f, 0xa5,
+       0x77, 0x2d, 0x95,
+};
+
+static const struct crc_data crc_7 = {
+       .packet = packet_7,
+       .size = sizeof(packet_7),
+};
+
+static const unsigned char packet_8[] = {
+       0x96, 0x83, 0x9a, 0xaf, 0x01, 0x00, 0xc7, 0x15,
+       0x4d,
+};
+
+static const struct crc_data crc_8 = {
+       .packet = packet_8,
+       .size = sizeof(packet_8),
+       .crc_init = 0x161dbe,           /* from packet_7 = 0xbe 0x1d 0x16 */
+};
+
+static const unsigned char packet_9[] = {
+       0x96, 0x83, 0x9a, 0xaf, 0x06, 0x14, 0x10, 0x00,
+       0x04, 0x00, 0x09, 0x07, 0x10, 0x00, 0x10, 0x11,
+       0x00, 0x37, 0x2a, 0x13, 0x00, 0x02, 0x14, 0x00,
+       0x38, 0x2a, 0x73, 0x2a, 0xa3,
+};
+
+static const struct crc_data crc_9 = {
+       .packet = packet_9,
+       .size = sizeof(packet_9),
+       .crc_init = 0x161dbe,           /* from packet_7 = 0xbe 0x1d 0x16 */
+};
+
+static void test_crc(gconstpointer data)
+{
+       const struct crc_data *test_data = data;
+       const uint8_t *buf = test_data->packet + test_data->size - 3;
+       uint32_t crc_init, crc_value, crc, rev;
+
+       if (test_data->crc_init)
+               crc_init = crc24_bit_reverse(test_data->crc_init);
+       else
+               crc_init = crc24_bit_reverse(0x555555);
+
+       crc_value = buf[0] | buf[1] << 8 | buf[2] << 16;
+
+       crc = crc24_calculate(crc_init, test_data->packet + 4,
+                                               test_data->size - 7);
+
+       if (g_test_verbose())
+               g_print("CRC: 0x%6.6x, Calculated: 0x%6.6x\n",
+                                               crc_value, crc);
+
+       g_assert(crc_value == crc);
+
+       rev = crc24_reverse(crc_value, test_data->packet + 4,
+                                               test_data->size - 7);
+
+       if (g_test_verbose())
+               g_print("Preset: 0x%6.6x, Calculated: 0x%6.6x\n",
+                                               crc_init, rev);
+
+       g_assert(crc_init == rev);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_data_func("/crc/1", &crc_1, test_crc);
+       g_test_add_data_func("/crc/2", &crc_2, test_crc);
+       g_test_add_data_func("/crc/3", &crc_3, test_crc);
+       g_test_add_data_func("/crc/4", &crc_4, test_crc);
+       g_test_add_data_func("/crc/5", &crc_5, test_crc);
+       g_test_add_data_func("/crc/6", &crc_6, test_crc);
+       g_test_add_data_func("/crc/7", &crc_7, test_crc);
+       g_test_add_data_func("/crc/8", &crc_8, test_crc);
+       g_test_add_data_func("/crc/9", &crc_9, test_crc);
+
+       return g_test_run();
+}
index cefcacd..1a6e1c9 100644 (file)
 #include <config.h>
 #endif
 
-#include <check.h>
-
-#include <stdint.h>
-
 #include <glib.h>
 
 #include <bluetooth/bluetooth.h>
 #include <bluetooth/hci.h>
 #include <bluetooth/sdp.h>
 
-#include "eir.h"
+#include "src/eir.h"
+
+struct test_data {
+       const void *eir_data;
+       size_t eir_size;
+       int flags;
+       const char *name;
+       gboolean name_complete;
+       int8_t tx_power;
+       const char **uuid;
+};
+
+static const unsigned char macbookair_data[] = {
+               0x17, 0x09, 0x4d, 0x61, 0x72, 0x63, 0x65, 0x6c,
+               0xe2, 0x80, 0x99, 0x73, 0x20, 0x4d, 0x61, 0x63,
+               0x42, 0x6f, 0x6f, 0x6b, 0x20, 0x41, 0x69, 0x72,
+               0x11, 0x03, 0x12, 0x11, 0x0c, 0x11, 0x0a, 0x11,
+               0x1f, 0x11, 0x01, 0x11, 0x00, 0x10, 0x0a, 0x11,
+               0x17, 0x11, 0x11, 0xff, 0x4c, 0x00, 0x01, 0x4d,
+               0x61, 0x63, 0x42, 0x6f, 0x6f, 0x6b, 0x41, 0x69,
+               0x72, 0x33, 0x2c, 0x31, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *macbookair_uuid[] = {
+               "00001112-0000-1000-8000-00805f9b34fb",
+               "0000110c-0000-1000-8000-00805f9b34fb",
+               "0000110a-0000-1000-8000-00805f9b34fb",
+               "0000111f-0000-1000-8000-00805f9b34fb",
+               "00001101-0000-1000-8000-00805f9b34fb",
+               "00001000-0000-1000-8000-00805f9b34fb",
+               "0000110a-0000-1000-8000-00805f9b34fb",
+               "00001117-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data macbookair_test = {
+       .eir_data = macbookair_data,
+       .eir_size = sizeof(macbookair_data),
+       .flags = -1,
+       .name = "Marcel’s MacBook Air",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = macbookair_uuid,
+};
+
+static const unsigned char iphone5_data[] = {
+               0x14, 0x09, 0x4d, 0x61, 0x72, 0x63, 0x65, 0x6c,
+               0xe2, 0x80, 0x99, 0x73, 0x20, 0x69, 0x50, 0x68,
+               0x6f, 0x6e, 0x65, 0x20, 0x35, 0x0f, 0x03, 0x00,
+               0x12, 0x1f, 0x11, 0x2f, 0x11, 0x0a, 0x11, 0x0c,
+               0x11, 0x16, 0x11, 0x32, 0x11, 0x01, 0x05, 0x11,
+               0x07, 0xfe, 0xca, 0xca, 0xde, 0xaf, 0xde, 0xca,
+               0xde, 0xde, 0xfa, 0xca, 0xde, 0x00, 0x00, 0x00,
+               0x00, 0x27, 0xff, 0x00, 0x4c, 0x02, 0x24, 0x02,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *iphone5_uuid[] = {
+               "00001200-0000-1000-8000-00805f9b34fb",
+               "0000111f-0000-1000-8000-00805f9b34fb",
+               "0000112f-0000-1000-8000-00805f9b34fb",
+               "0000110a-0000-1000-8000-00805f9b34fb",
+               "0000110c-0000-1000-8000-00805f9b34fb",
+               "00001116-0000-1000-8000-00805f9b34fb",
+               "00001132-0000-1000-8000-00805f9b34fb",
+               "00000000-deca-fade-deca-deafdecacafe",
+               NULL
+};
+
+static const struct test_data iphone5_test = {
+       .eir_data = iphone5_data,
+       .eir_size = sizeof(iphone5_data),
+       .flags = -1,
+       .name = "Marcel’s iPhone 5",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = iphone5_uuid,
+};
+
+static const unsigned char ipadmini_data[] = {
+               0x13, 0x09, 0x4d, 0x61, 0x72, 0x63, 0x65, 0x6c,
+               0x27, 0x73, 0x20, 0x69, 0x50, 0x61, 0x64, 0x20,
+               0x6d, 0x69, 0x6e, 0x69, 0x0b, 0x03, 0x00, 0x12,
+               0x1f, 0x11, 0x0a, 0x11, 0x0c, 0x11, 0x32, 0x11,
+               0x01, 0x05, 0x11, 0x07, 0xfe, 0xca, 0xca, 0xde,
+               0xaf, 0xde, 0xca, 0xde, 0xde, 0xfa, 0xca, 0xde,
+               0x00, 0x00, 0x00, 0x00, 0x27, 0xff, 0x00, 0x4c,
+               0x02, 0x24, 0x02, 0x0c, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *ipadmini_uuid[] = {
+               "00001200-0000-1000-8000-00805f9b34fb",
+               "0000111f-0000-1000-8000-00805f9b34fb",
+               "0000110a-0000-1000-8000-00805f9b34fb",
+               "0000110c-0000-1000-8000-00805f9b34fb",
+               "00001132-0000-1000-8000-00805f9b34fb",
+               "00000000-deca-fade-deca-deafdecacafe",
+               NULL
+};
+
+static const struct test_data ipadmini_test = {
+       .eir_data = ipadmini_data,
+       .eir_size = sizeof(ipadmini_data),
+       .flags = -1,
+       .name = "Marcel's iPad mini",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = ipadmini_uuid,
+};
+
+static const unsigned char gigaset_sl400h_data[] = {
+               0x0b, 0x03, 0x01, 0x11, 0x05, 0x11, 0x12, 0x11,
+               0x03, 0x12, 0x1f, 0x11, 0x10, 0x09, 0x4d, 0x61,
+               0x72, 0x63, 0x65, 0x6c, 0x27, 0x73, 0x20, 0x53,
+               0x4c, 0x34, 0x30, 0x30, 0x48, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *gigaset_sl400h_uuid[] = {
+               "00001101-0000-1000-8000-00805f9b34fb",
+               "00001105-0000-1000-8000-00805f9b34fb",
+               "00001112-0000-1000-8000-00805f9b34fb",
+               "00001203-0000-1000-8000-00805f9b34fb",
+               "0000111f-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data gigaset_sl400h_test = {
+       .eir_data = gigaset_sl400h_data,
+       .eir_size = sizeof(gigaset_sl400h_data),
+       .flags = -1,
+       .name = "Marcel's SL400H",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = gigaset_sl400h_uuid,
+};
+
+static const unsigned char gigaset_sl910_data[] = {
+               0x0b, 0x03, 0x01, 0x11, 0x05, 0x11, 0x12, 0x11,
+               0x03, 0x12, 0x1f, 0x11, 0x0f, 0x09, 0x4d, 0x61,
+               0x72, 0x63, 0x65, 0x6c, 0x27, 0x73, 0x20, 0x53,
+               0x4c, 0x39, 0x31, 0x30, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *gigaset_sl910_uuid[] = {
+               "00001101-0000-1000-8000-00805f9b34fb",
+               "00001105-0000-1000-8000-00805f9b34fb",
+               "00001112-0000-1000-8000-00805f9b34fb",
+               "00001203-0000-1000-8000-00805f9b34fb",
+               "0000111f-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data gigaset_sl910_test = {
+       .eir_data = gigaset_sl910_data,
+       .eir_size = sizeof(gigaset_sl910_data),
+       .flags = -1,
+       .name = "Marcel's SL910",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = gigaset_sl910_uuid,
+};
+
+static const unsigned char nokia_bh907_data[] = {
+               0x16, 0x09, 0x4e, 0x6f, 0x6b, 0x69, 0x61, 0x20,
+               0x52, 0x65, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e,
+               0x20, 0x42, 0x48, 0x2d, 0x39, 0x30, 0x37, 0x02,
+               0x0a, 0x04, 0x0f, 0x02, 0x0d, 0x11, 0x0b, 0x11,
+               0x0e, 0x11, 0x0f, 0x11, 0x1e, 0x11, 0x08, 0x11,
+               0x31, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *nokia_bh907_uuid[] = {
+               "0000110d-0000-1000-8000-00805f9b34fb",
+               "0000110b-0000-1000-8000-00805f9b34fb",
+               "0000110e-0000-1000-8000-00805f9b34fb",
+               "0000110f-0000-1000-8000-00805f9b34fb",
+               "0000111e-0000-1000-8000-00805f9b34fb",
+               "00001108-0000-1000-8000-00805f9b34fb",
+               "00001131-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data nokia_bh907_test = {
+       .eir_data = nokia_bh907_data,
+       .eir_size = sizeof(nokia_bh907_data),
+       .flags = -1,
+       .name = "Nokia Reaction BH-907",
+       .name_complete = TRUE,
+       .tx_power = 4,
+       .uuid = nokia_bh907_uuid,
+};
+
+static const unsigned char fuelband_data[] = {
+               0x0f, 0x09, 0x4e, 0x69, 0x6b, 0x65, 0x2b, 0x20,
+               0x46, 0x75, 0x65, 0x6c, 0x42, 0x61, 0x6e, 0x64,
+               0x11, 0x07, 0x00, 0x00, 0x00, 0x00, 0xde, 0xca,
+               0xfa, 0xde, 0xde, 0xca, 0xde, 0xaf, 0xde, 0xca,
+               0xca, 0xff, 0x02, 0x0a, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+               0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+static const char *fuelband_uuid[] = {
+               "ffcacade-afde-cade-defa-cade00000000",
+               NULL
+};
+
+static const struct test_data fuelband_test = {
+       .eir_data = fuelband_data,
+       .eir_size = sizeof(fuelband_data),
+       .flags = -1,
+       .name = "Nike+ FuelBand",
+       .name_complete = TRUE,
+       .tx_power = 0,
+       .uuid = fuelband_uuid,
+};
+
+static const unsigned char bluesc_data[] = {
+               0x02, 0x01, 0x06, 0x03, 0x02, 0x16, 0x18, 0x12,
+               0x09, 0x57, 0x61, 0x68, 0x6f, 0x6f, 0x20, 0x42,
+               0x6c, 0x75, 0x65, 0x53, 0x43, 0x20, 0x76, 0x31,
+               0x2e, 0x34,
+};
+
+static const char *bluesc_uuid[] = {
+               "00001816-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data bluesc_test = {
+       .eir_data = bluesc_data,
+       .eir_size = sizeof(bluesc_data),
+       .flags = 0x06,
+       .name = "Wahoo BlueSC v1.4",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = bluesc_uuid,
+};
 
-START_TEST(test_basic)
+static const unsigned char wahoo_scale_data[] = {
+               0x02, 0x01, 0x06, 0x03, 0x02, 0x01, 0x19, 0x11,
+               0x09, 0x57, 0x61, 0x68, 0x6f, 0x6f, 0x20, 0x53,
+               0x63, 0x61, 0x6c, 0x65, 0x20, 0x76, 0x31, 0x2e,
+               0x33, 0x05, 0xff, 0x00, 0x00, 0x00, 0x9c,
+};
+
+static const char *wahoo_scale_uuid[] = {
+               "00001901-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data wahoo_scale_test = {
+       .eir_data = wahoo_scale_data,
+       .eir_size = sizeof(wahoo_scale_data),
+       .flags = 0x06,
+       .name = "Wahoo Scale v1.3",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = wahoo_scale_uuid,
+};
+
+static const unsigned char mio_alpha_data[] = {
+               0x02, 0x01, 0x06, 0x03, 0x02, 0x0d, 0x18, 0x06,
+               0x09, 0x41, 0x4c, 0x50, 0x48, 0x41,
+};
+
+static const char *mio_alpha_uuid[] = {
+               "0000180d-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data mio_alpha_test = {
+       .eir_data = mio_alpha_data,
+       .eir_size = sizeof(mio_alpha_data),
+       .flags = 0x06,
+       .name = "ALPHA",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = mio_alpha_uuid,
+};
+
+static const unsigned char cookoo_data[] = {
+               0x02, 0x01, 0x05, 0x05, 0x02, 0x02, 0x18, 0x0a,
+               0x18, 0x0d, 0x09, 0x43, 0x4f, 0x4f, 0x4b, 0x4f,
+               0x4f, 0x20, 0x77, 0x61, 0x74, 0x63, 0x68,
+};
+
+static const char *cookoo_uuid[] = {
+               "00001802-0000-1000-8000-00805f9b34fb",
+               "0000180a-0000-1000-8000-00805f9b34fb",
+               NULL
+};
+
+static const struct test_data cookoo_test = {
+       .eir_data = cookoo_data,
+       .eir_size = sizeof(cookoo_data),
+       .flags = 0x05,
+       .name = "COOKOO watch",
+       .name_complete = TRUE,
+       .tx_power = 127,
+       .uuid = cookoo_uuid,
+};
+
+static const unsigned char citizen_adv_data[] = {
+               0x02, 0x01, 0x05, 0x05, 0x12, 0x7f, 0x01, 0x8f,
+               0x01, 0x14, 0x09, 0x45, 0x63, 0x6f, 0x2d, 0x44,
+               0x72, 0x69, 0x76, 0x65, 0x20, 0x50, 0x72, 0x6f,
+               0x78, 0x69, 0x6d, 0x69, 0x74, 0x79,
+};
+
+static const struct test_data citizen_adv_test = {
+       .eir_data = citizen_adv_data,
+       .eir_size = sizeof(citizen_adv_data),
+       .flags = 0x05,
+       .name = "Eco-Drive Proximity",
+       .name_complete = TRUE,
+       .tx_power = 127,
+};
+
+static const unsigned char citizen_scan_data[] = {
+               0x02, 0x0a, 0x00, 0x11, 0x07, 0x1b, 0xc5, 0xd5,
+               0xa5, 0x02, 0x00, 0x46, 0x9a, 0xe1, 0x11, 0xb7,
+               0x8d, 0x60, 0xb4, 0x45, 0x2d,
+};
+
+static const char *citizen_scan_uuid[] = {
+               "2d45b460-8db7-11e1-9a46-0002a5d5c51b",
+               NULL
+};
+
+static const struct test_data citizen_scan_test = {
+       .eir_data = citizen_scan_data,
+       .eir_size = sizeof(citizen_scan_data),
+       .flags = -1,
+       .tx_power = 0,
+       .uuid = citizen_scan_uuid,
+};
+
+static void test_basic(void)
 {
        struct eir_data data;
        unsigned char buf[HCI_MAX_EIR_LENGTH];
@@ -47,43 +543,83 @@ START_TEST(test_basic)
        memset(&data, 0, sizeof(data));
 
        err = eir_parse(&data, buf, HCI_MAX_EIR_LENGTH);
-       ck_assert(err == 0);
-       ck_assert(data.services == NULL);
-       ck_assert(data.name == NULL);
+       g_assert(err == 0);
+       g_assert(data.services == NULL);
+       g_assert(data.name == NULL);
 
        eir_data_free(&data);
 }
-END_TEST
 
-static void add_test(Suite *s, const char *name, TFun func)
+static void test_parsing(gconstpointer data)
 {
-       TCase *t;
+       const struct test_data *test = data;
+       struct eir_data eir;
+       int err;
 
-       t = tcase_create(name);
-       tcase_add_test(t, func);
-       suite_add_tcase(s, t);
-}
+       memset(&eir, 0, sizeof(eir));
 
-int main(int argc, char *argv[])
-{
-       int fails;
-       SRunner *sr;
-       Suite *s;
+       err = eir_parse(&eir, test->eir_data, test->eir_size);
+       g_assert(err == 0);
+
+       if (g_test_verbose() == TRUE) {
+               GSList *list;
+
+               g_print("Flags: %d\n", eir.flags);
+               g_print("Name: %s\n", eir.name);
+               g_print("TX power: %d\n", eir.tx_power);
 
-       s = suite_create("EIR");
+               for (list = eir.services; list; list = list->next) {
+                       char *uuid_str = list->data;
+                       g_print("UUID: %s\n", uuid_str);
+               }
+       }
 
-       add_test(s, "basic", test_basic);
+       g_assert(eir.flags == test->flags);
 
-       sr = srunner_create(s);
+       if (test->name) {
+               g_assert_cmpstr(eir.name, ==, test->name);
+               g_assert(eir.name_complete == test->name_complete);
+       } else {
+               g_assert(eir.name == NULL);
+       }
 
-       srunner_run_all(sr, CK_NORMAL);
+       g_assert(eir.tx_power == test->tx_power);
 
-       fails = srunner_ntests_failed(sr);
+       if (test->uuid) {
+               GSList *list;
+               int n = 0;
+
+               for (list = eir.services; list; list = list->next, n++) {
+                       char *uuid_str = list->data;
+                       g_assert(test->uuid[n]);
+                       g_assert_cmpstr(test->uuid[n], ==, uuid_str);
+               }
+       } else {
+               g_assert(eir.services == NULL);
+       }
+
+       eir_data_free(&eir);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
 
-       srunner_free(sr);
+       g_test_add_func("/eir/basic", test_basic);
 
-       if (fails > 0)
-               return -1;
+       g_test_add_data_func("/eir/macbookair", &macbookair_test, test_parsing);
+       g_test_add_data_func("/eir/iphone5", &iphone5_test, test_parsing);
+       g_test_add_data_func("/eir/ipadmini", &ipadmini_test, test_parsing);
+       g_test_add_data_func("/eir/sl400h", &gigaset_sl400h_test, test_parsing);
+       g_test_add_data_func("/eir/sl910", &gigaset_sl910_test, test_parsing);
+       g_test_add_data_func("/eir/bh907", &nokia_bh907_test, test_parsing);
+       g_test_add_data_func("/eir/fuelband", &fuelband_test, test_parsing);
+       g_test_add_data_func("/ad/bluesc", &bluesc_test, test_parsing);
+       g_test_add_data_func("/ad/wahooscale", &wahoo_scale_test, test_parsing);
+       g_test_add_data_func("/ad/mioalpha", &mio_alpha_test, test_parsing);
+       g_test_add_data_func("/ad/cookoo", &cookoo_test, test_parsing);
+       g_test_add_data_func("/ad/citizen1", &citizen_adv_test, test_parsing);
+       g_test_add_data_func("/ad/citizen2", &citizen_scan_test, test_parsing);
 
-       return 0;
+       return g_test_run();
 }
diff --git a/unit/test-gdbus-client.c b/unit/test-gdbus-client.c
new file mode 100644 (file)
index 0000000..685729a
--- /dev/null
@@ -0,0 +1,1000 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+#include <gdbus.h>
+
+#define SERVICE_NAME "org.bluez.unit.test-gdbus-client"
+#define SERVICE_NAME1 "org.bluez.unit.test-gdbus-client1"
+#define SERVICE_PATH "/org/bluez/unit/test_gdbus_client"
+
+struct context {
+       GMainLoop *main_loop;
+       DBusConnection *dbus_conn;
+       GDBusClient *dbus_client;
+       GDBusProxy *proxy;
+       void *data;
+       guint timeout_source;
+};
+
+static const GDBusMethodTable methods[] = {
+       { }
+};
+
+static const GDBusSignalTable signals[] = {
+       { }
+};
+
+static const GDBusPropertyTable properties[] = {
+       { }
+};
+
+static struct context *create_context(void)
+{
+       struct context *context = g_new0(struct context, 1);
+       DBusError err;
+
+       context->main_loop = g_main_loop_new(NULL, FALSE);
+       if (context->main_loop == NULL) {
+               g_free(context);
+               return NULL;
+       }
+
+       dbus_error_init(&err);
+
+       context->dbus_conn = g_dbus_setup_private(DBUS_BUS_SESSION,
+                                                       SERVICE_NAME, &err);
+       if (context->dbus_conn == NULL) {
+               if (dbus_error_is_set(&err)) {
+                       if (g_test_verbose())
+                               g_printerr("D-Bus setup failed: %s\n",
+                                                               err.message);
+                       dbus_error_free(&err);
+               }
+
+               g_main_loop_unref(context->main_loop);
+               g_free(context);
+               return NULL;
+       }
+
+       /* Avoid D-Bus library calling _exit() before next test finishes. */
+       dbus_connection_set_exit_on_disconnect(context->dbus_conn, FALSE);
+
+       g_dbus_attach_object_manager(context->dbus_conn);
+
+       return context;
+}
+
+static void destroy_context(struct context *context)
+{
+       if (context == NULL)
+               return;
+
+       if (context->timeout_source > 0)
+               g_source_remove(context->timeout_source);
+
+       g_dbus_detach_object_manager(context->dbus_conn);
+
+       dbus_connection_flush(context->dbus_conn);
+       dbus_connection_close(context->dbus_conn);
+
+       g_main_loop_unref(context->main_loop);
+
+       g_free(context->data);
+       g_free(context);
+}
+
+static gboolean timeout_handler(gpointer user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("timeout triggered\n");
+
+       context->timeout_source = 0;
+
+       g_dbus_client_unref(context->dbus_client);
+
+       return FALSE;
+}
+
+static void connect_handler(DBusConnection *connection, void *user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("service connected\n");
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static void disconnect_handler(DBusConnection *connection, void *user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("service disconnected\n");
+
+       g_main_loop_quit(context->main_loop);
+}
+
+static void simple_client(void)
+{
+       struct context *context = create_context();
+
+       if (context == NULL)
+               return;
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_connect_watch(context->dbus_client,
+                                               connect_handler, context);
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       g_main_loop_run(context->main_loop);
+
+       destroy_context(context);
+}
+
+static void client_connect_disconnect(void)
+{
+       struct context *context = create_context();
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, properties, NULL, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_connect_watch(context->dbus_client,
+                                               connect_handler, context);
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       context->timeout_source = g_timeout_add_seconds(10, timeout_handler,
+                                                               context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void append_variant(DBusMessageIter *iter, int type, void *val)
+{
+       DBusMessageIter value;
+       char sig[2] = { type, '\0' };
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_VARIANT, sig, &value);
+
+       dbus_message_iter_append_basic(&value, type, val);
+
+       dbus_message_iter_close_container(iter, &value);
+}
+
+static void dict_append_entry(DBusMessageIter *dict, const char *key, int type,
+                                                               void *val)
+{
+       DBusMessageIter entry;
+
+       if (type == DBUS_TYPE_STRING) {
+               const char *str = *((const char **) val);
+               if (str == NULL)
+                       return;
+       }
+
+       dbus_message_iter_open_container(dict, DBUS_TYPE_DICT_ENTRY,
+                                                       NULL, &entry);
+
+       dbus_message_iter_append_basic(&entry, DBUS_TYPE_STRING, &key);
+
+       append_variant(&entry, type, val);
+
+       dbus_message_iter_close_container(dict, &entry);
+}
+
+static gboolean get_dict(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       DBusMessageIter dict;
+       const char *string = "value";
+       dbus_bool_t boolean = TRUE;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY,
+                       DBUS_DICT_ENTRY_BEGIN_CHAR_AS_STRING
+                       DBUS_TYPE_STRING_AS_STRING DBUS_TYPE_VARIANT_AS_STRING
+                       DBUS_DICT_ENTRY_END_CHAR_AS_STRING, &dict);
+
+       dict_append_entry(&dict, "String", DBUS_TYPE_STRING, &string);
+       dict_append_entry(&dict, "Boolean", DBUS_TYPE_BOOLEAN, &boolean);
+
+       dbus_message_iter_close_container(iter, &dict);
+
+       return TRUE;
+}
+
+static void proxy_get_dict(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter, dict, var1, var2, entry1, entry2;
+       const char *string;
+       dbus_bool_t boolean;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "Dict", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
+
+       dbus_message_iter_recurse(&iter, &dict);
+       g_assert(dbus_message_iter_get_arg_type(&dict) ==
+                                                       DBUS_TYPE_DICT_ENTRY);
+
+       dbus_message_iter_recurse(&dict, &entry1);
+       g_assert(dbus_message_iter_get_arg_type(&entry1) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&entry1, &string);
+       g_assert(g_strcmp0(string, "String") == 0);
+
+       dbus_message_iter_next(&entry1);
+       g_assert(dbus_message_iter_get_arg_type(&entry1) == DBUS_TYPE_VARIANT);
+
+       dbus_message_iter_recurse(&entry1, &var1);
+       g_assert(dbus_message_iter_get_arg_type(&var1) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&var1, &string);
+       g_assert(g_strcmp0(string, "value") == 0);
+
+       dbus_message_iter_next(&dict);
+       g_assert(dbus_message_iter_get_arg_type(&dict) ==
+                                                       DBUS_TYPE_DICT_ENTRY);
+
+       dbus_message_iter_recurse(&dict, &entry2);
+       g_assert(dbus_message_iter_get_arg_type(&entry2) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&entry2, &string);
+       g_assert(g_strcmp0(string, "Boolean") == 0);
+
+       dbus_message_iter_next(&entry2);
+       g_assert(dbus_message_iter_get_arg_type(&entry2) == DBUS_TYPE_VARIANT);
+
+       dbus_message_iter_recurse(&entry2, &var2);
+       g_assert(dbus_message_iter_get_arg_type(&var2) == DBUS_TYPE_BOOLEAN);
+
+       dbus_message_iter_get_basic(&var2, &boolean);
+       g_assert(boolean == TRUE);
+
+       dbus_message_iter_next(&dict);
+       g_assert(dbus_message_iter_get_arg_type(&dict) == DBUS_TYPE_INVALID);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static void client_get_dict_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable dict_properties[] = {
+               { "Dict", "a{sv}", get_dict },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, dict_properties,
+                               NULL, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+       g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_dict,
+                                               NULL, NULL, context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void proxy_get_string(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter;
+       const char *string;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&iter, &string);
+       g_assert(g_strcmp0(string, "value") == 0);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static gboolean get_string(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       struct context *context = data;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_STRING, &context->data);
+
+       return TRUE;
+}
+
+static void client_get_string_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       context->data = g_strdup("value");
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+       g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_string,
+                                               NULL, NULL, context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void proxy_get_boolean(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter;
+       dbus_bool_t value;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "Boolean", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_BOOLEAN);
+
+       dbus_message_iter_get_basic(&iter, &value);
+       g_assert(value == TRUE);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static gboolean get_boolean(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       dbus_bool_t value = TRUE;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_BOOLEAN, &value);
+
+       return TRUE;
+}
+
+static void client_get_boolean_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable boolean_properties[] = {
+               { "Boolean", "b", get_boolean },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, boolean_properties,
+                               NULL, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                               proxy_get_boolean,
+                                               NULL, NULL, context);
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void proxy_get_array(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter, entry;
+       const char *value1, *value2;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "Array", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_ARRAY);
+
+       dbus_message_iter_recurse(&iter, &entry);
+       g_assert(dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&entry, &value1);
+       g_assert(g_strcmp0(value1, "value1") == 0);
+
+       dbus_message_iter_next(&entry);
+       g_assert(dbus_message_iter_get_arg_type(&entry) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&entry, &value2);
+       g_assert(g_strcmp0(value2, "value2") == 0);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static gboolean get_array(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       const char *value[2] = { "value1", "value2" };
+       DBusMessageIter array;
+
+       dbus_message_iter_open_container(iter, DBUS_TYPE_ARRAY, "s", &array);
+
+       dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &value[0]);
+       dbus_message_iter_append_basic(&array, DBUS_TYPE_STRING, &value[1]);
+
+       dbus_message_iter_close_container(iter, &array);
+
+       return TRUE;
+}
+
+static void client_get_array_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable array_properties[] = {
+               { "Array", "as", get_array },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, array_properties,
+                               NULL, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_get_array,
+                                               NULL, NULL, context);
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void proxy_get_uint64(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter;
+       guint64 value;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "Number", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_UINT64);
+
+       dbus_message_iter_get_basic(&iter, &value);
+       g_assert(value == G_MAXUINT64);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static gboolean get_uint64(const GDBusPropertyTable *property,
+                                       DBusMessageIter *iter, void *data)
+{
+       guint64 value = G_MAXUINT64;
+
+       dbus_message_iter_append_basic(iter, DBUS_TYPE_UINT64, &value);
+
+       return TRUE;
+}
+
+static void client_get_uint64_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable uint64_properties[] = {
+               { "Number", "t", get_uint64 },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, uint64_properties,
+                               NULL, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                               proxy_get_uint64,
+                                               NULL, NULL, context);
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void property_set_success(const DBusError *err, void *user_data)
+{
+       g_assert(!dbus_error_is_set(err));
+}
+
+static void proxy_set_string(GDBusProxy *proxy, void *user_data)
+{
+       DBusMessageIter iter;
+       const char *string;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
+       g_assert(dbus_message_iter_get_arg_type(&iter) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(&iter, &string);
+       g_assert(g_strcmp0(string, "value") == 0);
+
+       string = "value1";
+       g_assert(g_dbus_proxy_set_property_basic(proxy, "String",
+                                       DBUS_TYPE_STRING, &string,
+                                       property_set_success, user_data,
+                                       NULL));
+}
+
+static void property_string_changed(GDBusProxy *proxy, const char *name,
+                                       DBusMessageIter *iter, void *user_data)
+{
+       struct context *context = user_data;
+       const char *string;
+
+       if (g_test_verbose())
+               g_print("property %s changed\n", name);
+
+       g_assert(g_strcmp0(name, "String") == 0);
+       g_assert(dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(iter, &string);
+       g_assert(g_strcmp0(string, "value1") == 0);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static void set_string(const GDBusPropertyTable *property,
+                       DBusMessageIter *iter, GDBusPendingPropertySet id,
+                       void *data)
+{
+       struct context *context = data;
+       const char *string;
+
+       g_assert(dbus_message_iter_get_arg_type(iter) == DBUS_TYPE_STRING);
+
+       dbus_message_iter_get_basic(iter, &string);
+       g_assert(g_strcmp0(string, "value1") == 0);
+
+       g_free(context->data);
+       context->data = g_strdup(string);
+
+       g_dbus_emit_property_changed(context->dbus_conn, SERVICE_PATH,
+                                               SERVICE_NAME, "String");
+
+       g_dbus_pending_property_success(id);
+}
+
+static void client_set_string_property(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, set_string },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       context->data = g_strdup("value");
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+       g_dbus_client_set_proxy_handlers(context->dbus_client, proxy_set_string,
+                                               NULL, property_string_changed,
+                                               context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static gboolean string_exists(const GDBusPropertyTable *property, void *data)
+{
+       struct context *context = data;
+
+       return context->data != NULL;
+}
+
+static gboolean timeout_test(gpointer user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("timeout triggered\n");
+
+       context->timeout_source = 0;
+
+       g_assert_not_reached();
+
+       return FALSE;
+}
+
+static gboolean emit_string_change(void *user_data)
+{
+       struct context *context = user_data;
+
+       context->data = g_strdup("value1");
+
+       g_dbus_emit_property_changed(context->dbus_conn, SERVICE_PATH,
+                                               SERVICE_NAME, "String");
+
+       context->timeout_source = g_timeout_add_seconds(2, timeout_test,
+                                                               context);
+
+       return FALSE;
+}
+
+static void proxy_string_changed(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusMessageIter iter;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(!g_dbus_proxy_get_property(proxy, "String", &iter));
+
+       g_idle_add(emit_string_change, context);
+}
+
+static void client_string_changed(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, NULL, string_exists },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                               proxy_string_changed, NULL,
+                                               property_string_changed,
+                                               context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void property_check_order(const DBusError *err, void *user_data)
+{
+       struct context *context = user_data;
+       GDBusProxy *proxy = context->proxy;
+       DBusMessageIter iter;
+       const char *string;
+
+       g_assert(!dbus_error_is_set(err));
+
+       g_assert(g_dbus_proxy_get_property(proxy, "String", &iter));
+
+       dbus_message_iter_get_basic(&iter, &string);
+       g_assert(g_strcmp0(string, "value1") == 0);
+
+       g_dbus_client_unref(context->dbus_client);
+}
+
+static void proxy_check_order(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       const char *string;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       context->proxy = proxy;
+       string = "value1";
+       g_assert(g_dbus_proxy_set_property_basic(proxy, "String",
+                                       DBUS_TYPE_STRING, &string,
+                                       property_check_order, context,
+                                       NULL));
+}
+
+static void client_check_order(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, set_string, string_exists },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       context->data = g_strdup("value");
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_disconnect_watch(context->dbus_client,
+                                               disconnect_handler, context);
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                               proxy_check_order, NULL, NULL,
+                                               context);
+
+       g_main_loop_run(context->main_loop);
+
+       g_dbus_unregister_interface(context->dbus_conn,
+                                       SERVICE_PATH, SERVICE_NAME);
+
+       destroy_context(context);
+}
+
+static void proxy_removed(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("proxy removed\n");
+
+       g_main_loop_quit(context->main_loop);
+}
+
+static void proxy_set_removed(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_set_removed_watch(proxy, proxy_removed, context));
+
+       context->timeout_source = g_timeout_add_seconds(2, timeout_test,
+                                                               context);
+
+       g_dbus_unregister_interface(context->dbus_conn, SERVICE_PATH,
+                                                               SERVICE_NAME);
+}
+
+static void client_proxy_removed(void)
+{
+       struct context *context = create_context();
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, set_string, string_exists },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       g_dbus_register_interface(context->dbus_conn,
+                               SERVICE_PATH, SERVICE_NAME,
+                               methods, signals, string_properties,
+                               context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME, SERVICE_PATH);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                               proxy_set_removed, NULL, NULL,
+                                               context);
+
+       g_main_loop_run(context->main_loop);
+
+       destroy_context(context);
+}
+
+static void proxy_force_disconnect(GDBusProxy *proxy, void *user_data)
+{
+       struct context *context = user_data;
+       DBusConnection *conn = context->data;
+
+       if (g_test_verbose())
+               g_print("proxy %s found\n",
+                                       g_dbus_proxy_get_interface(proxy));
+
+       g_assert(g_dbus_proxy_set_removed_watch(proxy, proxy_removed, context));
+
+       context->timeout_source = g_timeout_add_seconds(2, timeout_test,
+                                                               context);
+
+       dbus_connection_flush(conn);
+       dbus_connection_close(conn);
+       context->data = NULL;
+}
+
+static void client_force_disconnect(void)
+{
+       struct context *context = create_context();
+       DBusConnection *conn;
+       static const GDBusPropertyTable string_properties[] = {
+               { "String", "s", get_string, set_string, string_exists },
+               { },
+       };
+
+       if (context == NULL)
+               return;
+
+       conn = g_dbus_setup_private(DBUS_BUS_SESSION, SERVICE_NAME1, NULL);
+       g_assert(conn != NULL);
+
+       /* Avoid D-Bus library calling _exit() before next test finishes. */
+       dbus_connection_set_exit_on_disconnect(conn, FALSE);
+       g_dbus_attach_object_manager(conn);
+       context->data = conn;
+
+       g_dbus_register_interface(conn, SERVICE_PATH, SERVICE_NAME1,
+                                       methods, signals, string_properties,
+                                       context, NULL);
+
+       context->dbus_client = g_dbus_client_new(context->dbus_conn,
+                                               SERVICE_NAME1, SERVICE_PATH);
+
+       g_dbus_client_set_proxy_handlers(context->dbus_client,
+                                       proxy_force_disconnect, NULL, NULL,
+                                       context);
+
+       g_main_loop_run(context->main_loop);
+
+       destroy_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gdbus/simple_client", simple_client);
+
+       g_test_add_func("/gdbus/client_connect_disconnect",
+                                               client_connect_disconnect);
+
+       g_test_add_func("/gdbus/client_get_string_property",
+                                               client_get_string_property);
+
+       g_test_add_func("/gdbus/client_get_boolean_property",
+                                               client_get_boolean_property);
+
+       g_test_add_func("/gdbus/client_get_uint64_property",
+                                               client_get_uint64_property);
+
+       g_test_add_func("/gdbus/client_get_array_property",
+                                               client_get_array_property);
+
+       g_test_add_func("/gdbus/client_get_dict_property",
+                                               client_get_dict_property);
+
+       g_test_add_func("/gdbus/client_set_string_property",
+                                               client_set_string_property);
+
+       g_test_add_func("/gdbus/client_string_changed",
+                                               client_string_changed);
+
+       g_test_add_func("/gdbus/client_check_order", client_check_order);
+
+       g_test_add_func("/gdbus/client_proxy_removed", client_proxy_removed);
+
+       g_test_add_func("/gdbus/client_force_disconnect",
+                                               client_force_disconnect);
+
+       return g_test_run();
+}
diff --git a/unit/test-gobex-apparam.c b/unit/test-gobex-apparam.c
new file mode 100644 (file)
index 0000000..e6a42cc
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2012  Intel Corporation.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gobex/gobex-apparam.h>
+
+#include "util.h"
+
+#define TAG_U8 0x00
+#define TAG_U16 0x01
+#define TAG_U32 0x02
+#define TAG_U64 0x03
+#define TAG_STRING 0x04
+#define TAG_BYTES 0x05
+
+static uint8_t tag_nval_short[] = { TAG_U8 };
+static uint8_t tag_nval_data[] = { TAG_U8, 0x01 };
+static uint8_t tag_nval2_short[] = { TAG_U8, 0x01, 0x1, TAG_U16 };
+static uint8_t tag_nval2_data[] = { TAG_U8, 0x01, 0x1, TAG_U16, 0x02 };
+static uint8_t tag_uint8[] = { TAG_U8, 0x01, 0x01 };
+static uint8_t tag_uint16[] = { TAG_U16, 0x02, 0x01, 0x02 };
+static uint8_t tag_uint32[] = { TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04 };
+static uint8_t tag_uint64[] = { TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+                                               0x05, 0x06, 0x07, 0x08 };
+static uint8_t tag_string[] = { TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+static uint8_t tag_bytes[257] = { TAG_BYTES, 0xFF };
+static uint8_t tag_multi[] = { TAG_U8, 0x01, 0x01,
+                               TAG_U16, 0x02, 0x01, 0x02,
+                               TAG_U32, 0x04, 0x01, 0x02, 0x03, 0x04,
+                               TAG_U64, 0x08, 0x01, 0x02, 0x03, 0x04,
+                                               0x05, 0x06, 0x07, 0x08,
+                               TAG_STRING, 0x04, 'A', 'B', 'C', '\0' };
+
+
+static GObexApparam *parse_and_decode(const void *data, gsize size)
+{
+       GObexApparam *apparam;
+       guint8 encoded[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_decode(data, size);
+
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, encoded, sizeof(encoded));
+
+       assert_memequal(data, size, encoded, len);
+
+       return apparam;
+}
+
+static void test_apparam_nval_short(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval_short,
+                                               sizeof(tag_nval_short));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval_data(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval_data,
+                                               sizeof(tag_nval_data));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_short(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval2_short,
+                                               sizeof(tag_nval2_short));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_nval2_data(void)
+{
+       GObexApparam *apparam;
+
+       apparam = g_obex_apparam_decode(tag_nval2_data,
+                                               sizeof(tag_nval2_data));
+
+       g_assert(apparam == NULL);
+}
+
+static void test_apparam_get_uint8(void)
+{
+       GObexApparam *apparam;
+       guint8 data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint8, sizeof(tag_uint8));
+
+       ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint16(void)
+{
+       GObexApparam *apparam;
+       uint16_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint16, sizeof(tag_uint16));
+
+       ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x0102);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint32(void)
+{
+       GObexApparam *apparam;
+       uint32_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint32, sizeof(tag_uint32));
+
+       ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01020304);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_uint64(void)
+{
+       GObexApparam *apparam;
+       uint64_t data;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_uint64, sizeof(tag_uint64));
+
+       ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data);
+
+       g_assert(ret == TRUE);
+       g_assert(data == 0x0102030405060708);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_string(void)
+{
+       GObexApparam *apparam;
+       char *string;
+
+       apparam = parse_and_decode(tag_string, sizeof(tag_string));
+
+       string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+       g_assert(string != NULL);
+       g_assert_cmpstr(string, ==, "ABC");
+
+       g_free(string);
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_bytes(void)
+{
+       GObexApparam *apparam;
+       const uint8_t *data;
+       gsize len;
+       gboolean ret;
+
+       apparam = parse_and_decode(tag_bytes, sizeof(tag_bytes));
+
+       ret = g_obex_apparam_get_bytes(apparam, TAG_BYTES, &data, &len);
+
+       g_assert(ret == TRUE);
+       assert_memequal(tag_bytes + 2, sizeof(tag_bytes) - 2, data, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_get_multi(void)
+{
+       GObexApparam *apparam;
+       char *string;
+       uint8_t data8;
+       uint16_t data16;
+       uint32_t data32;
+       uint64_t data64;
+       gboolean ret;
+
+       apparam = g_obex_apparam_decode(tag_multi, sizeof(tag_multi));
+
+       g_assert(apparam != NULL);
+
+       ret = g_obex_apparam_get_uint8(apparam, TAG_U8, &data8);
+
+       g_assert(ret == TRUE);
+       g_assert(data8 == 0x01);
+
+       ret = g_obex_apparam_get_uint16(apparam, TAG_U16, &data16);
+
+       g_assert(ret == TRUE);
+       g_assert(data16 == 0x0102);
+
+       ret = g_obex_apparam_get_uint32(apparam, TAG_U32, &data32);
+
+       g_assert(ret == TRUE);
+       g_assert(data32 == 0x01020304);
+
+       ret = g_obex_apparam_get_uint64(apparam, TAG_U64, &data64);
+
+       g_assert(ret == TRUE);
+       g_assert(data64 == 0x0102030405060708);
+
+       string = g_obex_apparam_get_string(apparam, TAG_STRING);
+
+       g_assert(string != NULL);
+       g_assert_cmpstr(string, ==, "ABC");
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint8(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint8, sizeof(tag_uint8), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint16(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint16(NULL, TAG_U16, 0x0102);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint16, sizeof(tag_uint16), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint32(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint32(NULL, TAG_U32, 0x01020304);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint32, sizeof(tag_uint32), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_uint64(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint64(NULL, TAG_U64, 0x0102030405060708);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_uint64, sizeof(tag_uint64), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_string(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_string(NULL, TAG_STRING, "ABC");
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_string, sizeof(tag_string), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_bytes(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_bytes(NULL, TAG_BYTES, tag_bytes + 2, 255);
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+       assert_memequal(tag_bytes, sizeof(tag_bytes), buf, len);
+
+       g_obex_apparam_free(apparam);
+}
+
+static void test_apparam_set_multi(void)
+{
+       GObexApparam *apparam;
+       guint8 buf[1024];
+       gsize len;
+
+       apparam = g_obex_apparam_set_uint8(NULL, TAG_U8, 0x01);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint16(apparam, TAG_U16, 0x0102);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint32(apparam, TAG_U32, 0x01020304);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_uint64(apparam, TAG_U64,
+                                                       0x0102030405060708);
+
+       g_assert(apparam != NULL);
+
+       apparam = g_obex_apparam_set_string(apparam, TAG_STRING, "ABC");
+
+       g_assert(apparam != NULL);
+
+       len = g_obex_apparam_encode(apparam, buf, sizeof(buf));
+
+       g_assert_cmpuint(len, ==, sizeof(tag_multi));
+
+       g_obex_apparam_free(apparam);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/test_apparam_nval_short",
+                                               test_apparam_nval_short);
+       g_test_add_func("/gobex/test_apparam_nval_data",
+                                               test_apparam_nval_data);
+
+       g_test_add_func("/gobex/test_apparam_nval2_short",
+                                               test_apparam_nval2_short);
+       g_test_add_func("/gobex/test_apparam_nval2_data",
+                                               test_apparam_nval2_data);
+
+       g_test_add_func("/gobex/test_apparam_get_uint8",
+                                               test_apparam_get_uint8);
+       g_test_add_func("/gobex/test_apparam_get_uint16",
+                                               test_apparam_get_uint16);
+       g_test_add_func("/gobex/test_apparam_get_uint32",
+                                               test_apparam_get_uint32);
+       g_test_add_func("/gobex/test_apparam_get_uint64",
+                                               test_apparam_get_uint64);
+       g_test_add_func("/gobex/test_apparam_get_string",
+                                               test_apparam_get_string);
+       g_test_add_func("/gobex/test_apparam_get_bytes",
+                                               test_apparam_get_bytes);
+       g_test_add_func("/gobex/test_apparam_get_multi",
+                                               test_apparam_get_multi);
+
+       g_test_add_func("/gobex/test_apparam_set_uint8",
+                                               test_apparam_set_uint8);
+       g_test_add_func("/gobex/test_apparam_set_uint16",
+                                               test_apparam_set_uint16);
+       g_test_add_func("/gobex/test_apparam_set_uint32",
+                                               test_apparam_set_uint32);
+       g_test_add_func("/gobex/test_apparam_set_uint64",
+                                               test_apparam_set_uint64);
+       g_test_add_func("/gobex/test_apparam_set_string",
+                                               test_apparam_set_string);
+       g_test_add_func("/gobex/test_apparam_set_bytes",
+                                               test_apparam_set_bytes);
+       g_test_add_func("/gobex/test_apparam_set_multi",
+                                               test_apparam_set_multi);
+
+       return g_test_run();
+}
diff --git a/unit/test-gobex-header.c b/unit/test-gobex-header.c
new file mode 100644 (file)
index 0000000..31c49a6
--- /dev/null
@@ -0,0 +1,573 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <string.h>
+
+#include <gobex/gobex-header.h>
+
+#include "util.h"
+
+static uint8_t hdr_connid[] = { G_OBEX_HDR_CONNECTION, 1, 2, 3, 4 };
+static uint8_t hdr_name_empty[] = { G_OBEX_HDR_NAME, 0x00, 0x03 };
+static uint8_t hdr_name_ascii[] = { G_OBEX_HDR_NAME, 0x00, 0x0b,
+                               0x00, 'f', 0x00, 'o', 0x00, 'o',
+                               0x00, 0x00 };
+static uint8_t hdr_name_umlaut[] = { G_OBEX_HDR_NAME, 0x00, 0x0b,
+                               0x00, 0xe5, 0x00, 0xe4, 0x00, 0xf6,
+                               0x00, 0x00 };
+static uint8_t hdr_body[] = { G_OBEX_HDR_BODY, 0x00, 0x07, 1, 2, 3, 4 };
+static uint8_t hdr_actionid[] = { G_OBEX_HDR_ACTION, 0xab };
+
+static uint8_t hdr_uint32_nval[] = { G_OBEX_HDR_CONNECTION, 1, 2 };
+static uint8_t hdr_unicode_nval_short[] = { G_OBEX_HDR_NAME, 0x12, 0x34,
+                                               0x00, 'a', 0x00, 'b',
+                                               0x00, 0x00 };
+static uint8_t hdr_unicode_nval_data[] = { G_OBEX_HDR_NAME, 0x00, 0x01,
+                                               0x00, 'a', 0x00, 'b' };
+static uint8_t hdr_bytes_nval_short[] = { G_OBEX_HDR_BODY, 0xab, 0xcd,
+                                               0x01, 0x02, 0x03 };
+static uint8_t hdr_bytes_nval_data[] = { G_OBEX_HDR_BODY, 0xab };
+static uint8_t hdr_bytes_nval_len[] = { G_OBEX_HDR_BODY, 0x00, 0x00 };
+static uint8_t hdr_apparam[] = { G_OBEX_HDR_APPARAM, 0x00, 0x09, 0x00, 0x04,
+                                               0x01, 0x02, 0x03, 0x04 };
+
+static void test_header_name_empty(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024];
+       size_t len;
+
+       header = g_obex_header_new_unicode(G_OBEX_HDR_NAME, "");
+
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_name_empty, sizeof(hdr_name_empty), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_name_ascii(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024];
+       size_t len;
+
+       header = g_obex_header_new_unicode(G_OBEX_HDR_NAME, "foo");
+
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_name_ascii, sizeof(hdr_name_ascii), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_name_umlaut(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024];
+       size_t len;
+
+       header = g_obex_header_new_unicode(G_OBEX_HDR_NAME, "åäö");
+
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_name_umlaut, sizeof(hdr_name_umlaut), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_bytes(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024], data[] = { 1, 2, 3, 4 };
+       size_t len;
+
+       header = g_obex_header_new_bytes(G_OBEX_HDR_BODY, data, sizeof(data));
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_body, sizeof(hdr_body), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_apparam(void)
+{
+       GObexHeader *header;
+       GObexApparam *apparam;
+       uint8_t buf[1024];
+       size_t len;
+
+       apparam = g_obex_apparam_set_uint32(NULL, 0, 0x01020304);
+       g_assert(apparam != NULL);
+
+       header = g_obex_header_new_apparam(apparam);
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_apparam, sizeof(hdr_apparam), buf, len);
+
+       g_obex_apparam_free(apparam);
+       g_obex_header_free(header);
+}
+
+static void test_header_uint8(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024];
+       size_t len;
+
+       header = g_obex_header_new_uint8(G_OBEX_HDR_ACTION, 0xab);
+
+       g_assert(header != NULL);
+
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_actionid, sizeof(hdr_actionid), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_uint32(void)
+{
+       GObexHeader *header;
+       uint8_t buf[1024];
+       size_t len;
+
+       header = g_obex_header_new_uint32(G_OBEX_HDR_CONNECTION, 0x01020304);
+       len = g_obex_header_encode(header, buf, sizeof(buf));
+
+       assert_memequal(hdr_connid, sizeof(hdr_connid), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static GObexHeader *parse_and_encode(uint8_t *buf, size_t buf_len)
+{
+       GObexHeader *header;
+       uint8_t encoded[1024];
+       size_t len;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(buf, buf_len, G_OBEX_DATA_REF, &len,
+                                                                       &err);
+       g_assert_no_error(err);
+       g_assert_cmpuint(len, ==, buf_len);
+
+       len = g_obex_header_encode(header, encoded, sizeof(encoded));
+
+       assert_memequal(buf, buf_len, encoded, len);
+
+       return header;
+}
+
+static void test_header_encode_connid(void)
+{
+       GObexHeader *header;
+       gboolean ret;
+       guint32 val;
+
+       header = parse_and_encode(hdr_connid, sizeof(hdr_connid));
+
+       ret = g_obex_header_get_uint32(header, &val);
+
+       g_assert(ret == TRUE);
+       g_assert(val == 0x01020304);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_name_ascii(void)
+{
+       GObexHeader *header;
+       const char *str;
+       gboolean ret;
+
+       header = parse_and_encode(hdr_name_ascii, sizeof(hdr_name_ascii));
+
+       ret = g_obex_header_get_unicode(header, &str);
+
+       g_assert(ret == TRUE);
+       g_assert_cmpstr(str, ==, "foo");
+
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_name_umlaut(void)
+{
+       GObexHeader *header;
+       const char *str;
+       gboolean ret;
+
+       header = parse_and_encode(hdr_name_umlaut, sizeof(hdr_name_umlaut));
+
+       ret = g_obex_header_get_unicode(header, &str);
+
+       g_assert(ret == TRUE);
+       g_assert_cmpstr(str, ==, "åäö");
+
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_name_empty(void)
+{
+       GObexHeader *header;
+       const char *str;
+       gboolean ret;
+
+       header = parse_and_encode(hdr_name_empty, sizeof(hdr_name_empty));
+
+       ret = g_obex_header_get_unicode(header, &str);
+
+       g_assert(ret == TRUE);
+       g_assert_cmpstr(str, ==, "");
+
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_body(void)
+{
+       GObexHeader *header;
+       guint8 expected[] = { 1, 2, 3, 4};
+       const guint8 *buf;
+       size_t len;
+       gboolean ret;
+
+       header = parse_and_encode(hdr_body, sizeof(hdr_body));
+
+       ret = g_obex_header_get_bytes(header, &buf, &len);
+
+       g_assert(ret == TRUE);
+       assert_memequal(expected, sizeof(expected), buf, len);
+
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_apparam(void)
+{
+       GObexHeader *header;
+       GObexApparam *apparam;
+       gboolean ret;
+       guint32 data;
+
+       header = parse_and_encode(hdr_apparam, sizeof(hdr_apparam));
+
+       apparam = g_obex_header_get_apparam(header);
+       g_assert(apparam != NULL);
+
+       ret = g_obex_apparam_get_uint32(apparam, 0x00, &data);
+       g_assert(ret == TRUE);
+       g_assert(data == 0x01020304);
+
+       g_obex_apparam_free(apparam);
+       g_obex_header_free(header);
+}
+
+static void test_header_encode_actionid(void)
+{
+       GObexHeader *header;
+       gboolean ret;
+       guint8 val;
+
+       header = parse_and_encode(hdr_actionid, sizeof(hdr_actionid));
+
+       ret = g_obex_header_get_uint8(header, &val);
+
+       g_assert(ret == TRUE);
+       g_assert_cmpuint(val, ==, 0xab);
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_connid(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_connid, sizeof(hdr_connid),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_connid));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_name_ascii(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_name_ascii, sizeof(hdr_name_ascii),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_name_empty(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_name_empty, sizeof(hdr_name_empty),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_name_empty));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_name_umlaut(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_name_umlaut, sizeof(hdr_name_umlaut),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_name_umlaut));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_body(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_body, sizeof(hdr_body),
+                                       G_OBEX_DATA_COPY, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_body_extdata(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_body, sizeof(hdr_body),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
+
+       g_obex_header_free(header);
+}
+
+static void test_decode_header_actionid(void)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(hdr_actionid, sizeof(hdr_actionid),
+                                       G_OBEX_DATA_REF, &parsed, &err);
+       g_assert_no_error(err);
+
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid));
+
+       g_obex_header_free(header);
+}
+
+static void decode_header_nval(uint8_t *buf, size_t len)
+{
+       GObexHeader *header;
+       size_t parsed;
+       GError *err = NULL;
+
+       header = g_obex_header_decode(buf, len, G_OBEX_DATA_REF, &parsed,
+                                                                       &err);
+       g_assert_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR);
+       g_assert(header == NULL);
+       g_error_free(err);
+}
+
+static void test_decode_header_uint32_nval(void)
+{
+       decode_header_nval(hdr_uint32_nval, sizeof(hdr_uint32_nval));
+}
+
+static void test_decode_header_unicode_nval_short(void)
+{
+       decode_header_nval(hdr_unicode_nval_short,
+                                       sizeof(hdr_unicode_nval_short));
+}
+
+static void test_decode_header_unicode_nval_data(void)
+{
+       decode_header_nval(hdr_unicode_nval_data,
+                                       sizeof(hdr_unicode_nval_data));
+}
+
+static void test_decode_header_bytes_nval_short(void)
+{
+       decode_header_nval(hdr_bytes_nval_short, sizeof(hdr_bytes_nval_short));
+}
+
+static void test_decode_header_bytes_nval_data(void)
+{
+       decode_header_nval(hdr_bytes_nval_data, sizeof(hdr_bytes_nval_data));
+}
+
+static void test_decode_header_bytes_nval_len(void)
+{
+       decode_header_nval(hdr_bytes_nval_len, sizeof(hdr_bytes_nval_len));
+}
+
+static void test_decode_header_multi(void)
+{
+       GObexHeader *header;
+       GByteArray *buf;
+       size_t parsed;
+       GError *err = NULL;
+
+       buf = g_byte_array_sized_new(sizeof(hdr_connid) +
+                                       sizeof(hdr_name_ascii) +
+                                       sizeof(hdr_actionid) +
+                                       sizeof(hdr_body));
+
+       g_byte_array_append(buf, hdr_connid, sizeof(hdr_connid));
+       g_byte_array_append(buf, hdr_name_ascii, sizeof(hdr_name_ascii));
+       g_byte_array_append(buf, hdr_actionid, sizeof(hdr_actionid));
+       g_byte_array_append(buf, hdr_body, sizeof(hdr_body));
+
+       header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
+                                                               &parsed, &err);
+       g_assert_no_error(err);
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_connid));
+       g_byte_array_remove_range(buf, 0, parsed);
+       g_obex_header_free(header);
+
+       header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
+                                                               &parsed, &err);
+       g_assert_no_error(err);
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_name_ascii));
+       g_byte_array_remove_range(buf, 0, parsed);
+       g_obex_header_free(header);
+
+       header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
+                                                               &parsed, &err);
+       g_assert_no_error(err);
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_actionid));
+       g_byte_array_remove_range(buf, 0, parsed);
+       g_obex_header_free(header);
+
+       header = g_obex_header_decode(buf->data, buf->len, G_OBEX_DATA_REF,
+                                                               &parsed, &err);
+       g_assert_no_error(err);
+       g_assert_cmpuint(parsed, ==, sizeof(hdr_body));
+       g_byte_array_remove_range(buf, 0, parsed);
+       g_obex_header_free(header);
+
+       g_byte_array_unref(buf);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/test_decode_header_connid",
+                                               test_decode_header_connid);
+       g_test_add_func("/gobex/test_decode_header_name_empty",
+                                       test_decode_header_name_empty);
+       g_test_add_func("/gobex/test_decode_header_name_ascii",
+                                       test_decode_header_name_ascii);
+       g_test_add_func("/gobex/test_decode_header_name_umlaut",
+                                       test_decode_header_name_umlaut);
+       g_test_add_func("/gobex/test_decode_header_body",
+                                               test_decode_header_body);
+       g_test_add_func("/gobex/test_decode_header_body_extdata",
+                                       test_decode_header_body_extdata);
+       g_test_add_func("/gobex/test_decode_header_actionid",
+                                               test_decode_header_actionid);
+       g_test_add_func("/gobex/test_decode_header_multi",
+                                               test_decode_header_multi);
+
+       g_test_add_func("/gobex/test_decode_header_uint32_nval",
+                                       test_decode_header_uint32_nval);
+       g_test_add_func("/gobex/test_decode_header_unicode_nval_short",
+                                       test_decode_header_unicode_nval_short);
+       g_test_add_func("/gobex/test_decode_header_unicode_nval_data",
+                                       test_decode_header_unicode_nval_data);
+       g_test_add_func("/gobex/test_decode_header_bytes_nval_short",
+                                       test_decode_header_bytes_nval_short);
+       g_test_add_func("/gobex/test_decode_header_bytes_nval_data",
+                                       test_decode_header_bytes_nval_data);
+       g_test_add_func("/gobex/test_decode_header_bytes_nval_len",
+                                       test_decode_header_bytes_nval_len);
+
+       g_test_add_func("/gobex/test_header_encode_connid",
+                                               test_header_encode_connid);
+       g_test_add_func("/gobex/test_header_encode_name_empty",
+                                       test_header_encode_name_empty);
+       g_test_add_func("/gobex/test_header_encode_name_ascii",
+                                       test_header_encode_name_ascii);
+       g_test_add_func("/gobex/test_header_encode_name_umlaut",
+                                       test_header_encode_name_umlaut);
+       g_test_add_func("/gobex/test_header_encode_body",
+                                               test_header_encode_body);
+       g_test_add_func("/gobex/test_header_encode_connid",
+                                               test_header_encode_actionid);
+       g_test_add_func("/gobex/test_header_encode_apparam",
+                                               test_header_encode_apparam);
+
+       g_test_add_func("/gobex/test_header_name_empty",
+                                               test_header_name_empty);
+       g_test_add_func("/gobex/test_header_name_ascii",
+                                               test_header_name_ascii);
+       g_test_add_func("/gobex/test_header_name_umlaut",
+                                               test_header_name_umlaut);
+       g_test_add_func("/gobex/test_header_bytes", test_header_bytes);
+       g_test_add_func("/gobex/test_header_uint8", test_header_uint8);
+       g_test_add_func("/gobex/test_header_uint32", test_header_uint32);
+       g_test_add_func("/gobex/test_header_apparam", test_header_apparam);
+
+       return g_test_run();
+}
diff --git a/unit/test-gobex-packet.c b/unit/test-gobex-packet.c
new file mode 100644 (file)
index 0000000..bf2035b
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <gobex/gobex-packet.h>
+
+#include "util.h"
+
+static uint8_t pkt_connect[] = { G_OBEX_OP_CONNECT, 0x00, 0x0c,
+                                       0x10, 0x00, 0x10, 0x00,
+                                       G_OBEX_HDR_TARGET,
+                                               0x00, 0x05, 0xab, 0xcd };
+static uint8_t pkt_put_action[] = { G_OBEX_OP_PUT, 0x00, 0x05,
+                                       G_OBEX_HDR_ACTION, 0xab };
+static uint8_t pkt_put_body[] = { G_OBEX_OP_PUT, 0x00, 0x0a,
+                                       G_OBEX_HDR_BODY, 0x00, 0x07,
+                                       1, 2, 3, 4 };
+static uint8_t pkt_put[] = { G_OBEX_OP_PUT, 0x00, 0x03 };
+
+static uint8_t pkt_nval_len[] = { G_OBEX_OP_PUT, 0xab, 0xcd, 0x12 };
+
+static guint8 pkt_put_long[] = { G_OBEX_OP_PUT, 0x00, 0x32,
+       G_OBEX_HDR_CONNECTION, 0x01, 0x02, 0x03, 0x04,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_ACTION, 0xab,
+       G_OBEX_HDR_BODY, 0x00, 0x08,
+       0, 1, 2, 3, 4 };
+
+static void test_pkt(void)
+{
+       GObexPacket *pkt;
+
+       pkt = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_INVALID);
+
+       g_assert(pkt != NULL);
+
+       g_obex_packet_free(pkt);
+}
+
+static void test_decode_pkt(void)
+{
+       GObexPacket *pkt;
+       GError *err = NULL;
+
+       pkt = g_obex_packet_decode(pkt_put, sizeof(pkt_put), 0,
+                                               G_OBEX_DATA_REF, &err);
+       g_assert_no_error(err);
+
+       g_obex_packet_free(pkt);
+}
+
+static void test_decode_pkt_header(void)
+{
+       GObexPacket *pkt;
+       GObexHeader *header;
+       GError *err = NULL;
+       gboolean ret;
+       guint8 val;
+
+       pkt = g_obex_packet_decode(pkt_put_action, sizeof(pkt_put_action),
+                                               0, G_OBEX_DATA_REF, &err);
+       g_assert_no_error(err);
+
+       header = g_obex_packet_get_header(pkt, G_OBEX_HDR_ACTION);
+       g_assert(header != NULL);
+
+       ret = g_obex_header_get_uint8(header, &val);
+       g_assert(ret == TRUE);
+       g_assert(val == 0xab);
+
+       g_obex_packet_free(pkt);
+}
+
+static void test_decode_connect(void)
+{
+       GObexPacket *pkt;
+       GObexHeader *header;
+       GError *err = NULL;
+       gboolean ret;
+       const guint8 *buf;
+       guint8 target[] = { 0xab, 0xcd };
+       gsize len;
+
+       pkt = g_obex_packet_decode(pkt_connect, sizeof(pkt_connect),
+                                               4, G_OBEX_DATA_REF, &err);
+       g_assert_no_error(err);
+       g_assert(pkt != NULL);
+
+       header = g_obex_packet_get_header(pkt, G_OBEX_HDR_TARGET);
+       g_assert(header != NULL);
+
+       ret = g_obex_header_get_bytes(header, &buf, &len);
+       g_assert(ret == TRUE);
+       assert_memequal(target, sizeof(target), buf, len);
+
+       g_obex_packet_free(pkt);
+}
+
+static void test_decode_nval(void)
+{
+       GObexPacket *pkt;
+       GError *err = NULL;
+
+       pkt = g_obex_packet_decode(pkt_nval_len, sizeof(pkt_nval_len), 0,
+                                               G_OBEX_DATA_REF, &err);
+       g_assert_error(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR);
+       g_assert(pkt == NULL);
+
+       g_error_free(err);
+}
+
+static void test_decode_encode(void)
+{
+       GObexPacket *pkt;
+       GError *err = NULL;
+       uint8_t buf[255];
+       gssize len;
+
+       pkt = g_obex_packet_decode(pkt_put_action, sizeof(pkt_put_action),
+                                               0, G_OBEX_DATA_REF, &err);
+       g_assert_no_error(err);
+
+       len = g_obex_packet_encode(pkt, buf, sizeof(buf));
+       if (len < 0) {
+               g_printerr("Encoding failed: %s\n", g_strerror(-len));
+               g_assert_not_reached();
+       }
+
+       assert_memequal(pkt_put_action, sizeof(pkt_put_action), buf, len);
+
+       g_obex_packet_free(pkt);
+}
+
+static gssize get_body_data(void *buf, gsize len, gpointer user_data)
+{
+       uint8_t data[] = { 1, 2, 3, 4 };
+
+       memcpy(buf, data, sizeof(data));
+
+       return sizeof(data);
+}
+
+static void test_encode_on_demand(void)
+{
+       GObexPacket *pkt;
+       uint8_t buf[255];
+       gssize len;
+
+       pkt = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
+       g_obex_packet_add_body(pkt, get_body_data, NULL);
+
+       len = g_obex_packet_encode(pkt, buf, sizeof(buf));
+       if (len < 0) {
+               g_printerr("Encoding failed: %s\n", g_strerror(-len));
+               g_assert_not_reached();
+       }
+
+       assert_memequal(pkt_put_body, sizeof(pkt_put_body), buf, len);
+
+       g_obex_packet_free(pkt);
+}
+
+static gssize get_body_data_fail(void *buf, gsize len, gpointer user_data)
+{
+       return -EIO;
+}
+
+static void test_encode_on_demand_fail(void)
+{
+       GObexPacket *pkt;
+       uint8_t buf[255];
+       gssize len;
+
+       pkt = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
+       g_obex_packet_add_body(pkt, get_body_data_fail, NULL);
+
+       len = g_obex_packet_encode(pkt, buf, sizeof(buf));
+
+       g_assert_cmpint(len, ==, -EIO);
+
+       g_obex_packet_free(pkt);
+}
+
+static void test_create_args(void)
+{
+       GObexPacket *pkt;
+       guint8 buf[255], body[] = { 0x00, 0x01, 0x02, 0x03, 0x04 };
+       gssize len;
+
+       pkt = g_obex_packet_new(G_OBEX_OP_PUT, FALSE,
+                       G_OBEX_HDR_CONNECTION, 0x01020304,
+                       G_OBEX_HDR_TYPE, "foo/bar", strlen("foo/bar") + 1,
+                       G_OBEX_HDR_NAME, "file.txt",
+                       G_OBEX_HDR_ACTION, 0xab,
+                       G_OBEX_HDR_BODY, body, sizeof(body),
+                       G_OBEX_HDR_INVALID);
+
+       g_assert(pkt != NULL);
+
+       len = g_obex_packet_encode(pkt, buf, sizeof(buf));
+       g_assert(len > 0);
+
+       assert_memequal(pkt_put_long, sizeof(pkt_put_long), buf, len);
+
+       g_obex_packet_free(pkt);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/test_pkt", test_pkt);
+       g_test_add_func("/gobex/test_decode_pkt", test_decode_pkt);
+       g_test_add_func("/gobex/test_decode_pkt_header",
+                                               test_decode_pkt_header);
+       g_test_add_func("/gobex/test_decode_connect",
+                                               test_decode_connect);
+
+       g_test_add_func("/gobex/test_decode_nval", test_decode_nval);
+
+       g_test_add_func("/gobex/test_encode_pkt", test_decode_encode);
+
+       g_test_add_func("/gobex/test_encode_on_demand", test_encode_on_demand);
+       g_test_add_func("/gobex/test_encode_on_demand_fail",
+                                               test_encode_on_demand_fail);
+
+       g_test_add_func("/gobex/test_create_args", test_create_args);
+
+       return g_test_run();
+}
diff --git a/unit/test-gobex-transfer.c b/unit/test-gobex-transfer.c
new file mode 100644 (file)
index 0000000..ef05047
--- /dev/null
@@ -0,0 +1,2260 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <sys/stat.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+#include <fcntl.h>
+
+#include <gobex/gobex.h>
+
+#include "util.h"
+
+#define FINAL_BIT 0x80
+#define RANDOM_PACKETS 4
+
+static guint8 put_req_first[] = { G_OBEX_OP_PUT, 0x00, 0x30,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_BODY, 0x00, 0x0d,
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 put_req_first_srm[] = { G_OBEX_OP_PUT, 0x00, 0x32,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_SRM, G_OBEX_SRM_ENABLE,
+       G_OBEX_HDR_BODY, 0x00, 0x0d,
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 put_req_zero[255] = { G_OBEX_OP_PUT, 0x00, 0xff,
+       G_OBEX_HDR_BODY, 0x00, 0xfc };
+
+static guint8 put_req_last[] = { G_OBEX_OP_PUT | FINAL_BIT, 0x00, 0x06,
+                                       G_OBEX_HDR_BODY_END, 0x00, 0x03 };
+
+static guint8 abort_req[] = { G_OBEX_OP_ABORT | FINAL_BIT, 0x00, 0x03 };
+
+static guint8 put_rsp_first[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+                                                               0x00, 0x03 };
+static guint8 put_rsp_first_srm[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+                                                       0x00, 0x05,
+                                                       G_OBEX_HDR_SRM, 0x01 };
+static guint8 put_rsp_first_srm_wait[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+                                                       0x00, 0x07,
+                                                       G_OBEX_HDR_SRM, 0x01,
+                                                       G_OBEX_HDR_SRMP, 0x01 };
+static guint8 put_rsp_last[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x03 };
+
+static guint8 get_req_first[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x23,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 get_req_first_app[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x2a,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_APPARAM, 0x00, 0x07,
+       0, 1, 2, 3  };
+
+static guint8 get_req_first_srm[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x25,
+       G_OBEX_HDR_SRM, 0x01,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 get_req_first_srm_wait[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x27,
+       G_OBEX_HDR_SRM, 0x01,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_SRMP, 0x01 };
+
+static guint8 get_req_last[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x03, };
+
+static guint8 get_rsp_first_app[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x0A,
+                                       G_OBEX_HDR_APPARAM, 0x00, 0x07,
+                                       0, 1, 2, 3 };
+static guint8 get_rsp_first[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x10,
+                                       G_OBEX_HDR_BODY, 0x00, 0x0d,
+                                       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_first_srm[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0x12,
+                                       G_OBEX_HDR_SRM, 0x01,
+                                       G_OBEX_HDR_BODY, 0x00, 0x0d,
+                                       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_first_srm_wait_next[] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+                                       0x00, 0x14,
+                                       G_OBEX_HDR_SRM, 0x01,
+                                       G_OBEX_HDR_SRMP, 0x02,
+                                       G_OBEX_HDR_BODY, 0x00, 0x0d,
+                                       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+static guint8 get_rsp_zero[255] = { G_OBEX_RSP_CONTINUE | FINAL_BIT, 0x00, 0xff,
+                                       G_OBEX_HDR_BODY, 0x00, 0xfc };
+static guint8 get_rsp_zero_wait_next[255] = { G_OBEX_RSP_CONTINUE | FINAL_BIT,
+                                       0x00, 0xff,
+                                       G_OBEX_HDR_SRMP, 0x02,
+                                       G_OBEX_HDR_BODY, 0x00, 0xfa };
+static guint8 get_rsp_last[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x06,
+                                       G_OBEX_HDR_BODY_END, 0x00, 0x03 };
+
+static guint8 conn_req[] = { G_OBEX_OP_CONNECT | FINAL_BIT, 0x00, 0x07,
+                                       0x10, 0x00, 0x10, 0x00 };
+static guint8 conn_rsp[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x0c,
+                                       0x10, 0x00, 0x10, 0x00,
+                                       G_OBEX_HDR_CONNECTION, 0x00, 0x00,
+                                       0x00, 0x01 };
+
+static guint8 conn_req_srm[] = { G_OBEX_OP_CONNECT | FINAL_BIT, 0x00, 0x09,
+                                       0x10, 0x00, 0x10, 0x00,
+                                       G_OBEX_HDR_SRM, 0x02 };
+static guint8 conn_rsp_srm[] = { G_OBEX_RSP_SUCCESS | FINAL_BIT, 0x00, 0x0e,
+                                       0x10, 0x00, 0x10, 0x00,
+                                       G_OBEX_HDR_CONNECTION, 0x00, 0x00,
+                                       0x00, 0x01,
+                                       G_OBEX_HDR_SRM, 0x01 };
+
+static guint8 unavailable_rsp[] = { G_OBEX_RSP_SERVICE_UNAVAILABLE | FINAL_BIT,
+                                       0x00, 0x03 };
+
+static guint8 conn_get_req_first[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x28,
+       G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0x01,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 conn_get_req_wrg[] = { G_OBEX_OP_GET | FINAL_BIT, 0x00, 0x28,
+       G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0xFF,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static guint8 conn_put_req_first[] = { G_OBEX_OP_PUT, 0x00, 0x35,
+       G_OBEX_HDR_CONNECTION, 0x00, 0x00, 0x00, 0x01,
+       G_OBEX_HDR_TYPE, 0x00, 0x0b,
+       'f', 'o', 'o', '/', 'b', 'a', 'r', '\0',
+       G_OBEX_HDR_NAME, 0x00, 0x15,
+       0, 'f', 0, 'i', 0, 'l', 0, 'e', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0,
+       G_OBEX_HDR_BODY, 0x00, 0x0d,
+       0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static guint8 hdr_type[] = "foo/bar";
+static guint8 hdr_app[] = { 0, 1, 2, 3 };
+static guint8 body_data[] = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 };
+
+static void transfer_complete(GObex *obex, GError *err, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL)
+               d->err = g_error_copy(err);
+
+       g_main_loop_quit(d->mainloop);
+}
+
+static gboolean resume_obex(gpointer user_data)
+{
+       g_obex_resume(user_data);
+       return FALSE;
+}
+
+static gssize provide_seq(void *buf, gsize len, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       int fd;
+       gssize ret;
+
+       if (d->count == RANDOM_PACKETS - 1)
+               return 0;
+
+       fd = open("/dev/urandom", O_RDONLY | O_NOCTTY, 0);
+       if (fd < 0) {
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "open(/dev/urandom): %s", strerror(errno));
+               g_main_loop_quit(d->mainloop);
+               return -1;
+       }
+
+       ret = read(fd, buf, len);
+       close(fd);
+       return ret;
+}
+
+static gssize provide_eagain(void *buf, gsize len, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (d->count > 0)
+               return 0;
+
+       if (len < sizeof(body_data)) {
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Got data request for only %zu bytes", len);
+               g_main_loop_quit(d->mainloop);
+               return -1;
+       }
+
+       if (d->provide_delay > 0) {
+               g_timeout_add(d->provide_delay, resume_obex, d->obex);
+               d->provide_delay = 0;
+               return -EAGAIN;
+       }
+
+       memcpy(buf, body_data, sizeof(body_data));
+
+       return sizeof(body_data);
+}
+
+static gssize provide_data(void *buf, gsize len, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (d->total > 0)
+               return 0;
+
+       if (len < sizeof(body_data)) {
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Got data request for only %zu bytes", len);
+               g_main_loop_quit(d->mainloop);
+               return -1;
+       }
+
+       memcpy(buf, body_data, sizeof(body_data));
+
+       if (d->provide_delay > 0) {
+               g_obex_suspend(d->obex);
+               g_timeout_add(d->provide_delay, resume_obex, d->obex);
+       }
+
+       d->total += sizeof(body_data);
+
+       return sizeof(body_data);
+}
+
+static void test_put_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_req_first, sizeof(put_req_first) },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_data, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static gboolean rcv_data(const void *buf, gsize len, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (len != sizeof(body_data))
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected byte count %zu", len);
+
+       if (memcmp(buf, body_data, sizeof(body_data)) != 0) {
+               dump_bufs(body_data, sizeof(body_data), buf, len);
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected byte count %zu", len);
+       }
+
+       return TRUE;
+}
+
+static void handle_put(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_PUT) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_put_rsp(obex, req, rcv_data, transfer_complete, d, &d->err,
+                                                       G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_put_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } }, {
+                               { put_req_last, sizeof(put_req_last) },
+                               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put, &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first,
+                                       sizeof(put_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static gboolean rcv_seq(const void *buf, gsize len, gpointer user_data)
+{
+       return TRUE;
+}
+
+static void handle_put_seq(GObex *obex, GObexPacket *req,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_PUT) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_put_rsp(obex, req, rcv_seq, transfer_complete, d,
+                                               &d->err, G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_put_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } }, {
+                               { put_req_zero, sizeof(put_req_zero) },
+                               { put_req_zero, sizeof(put_req_zero) },
+                               { put_req_last, sizeof(put_req_last) },
+                               { NULL, -1 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq,
+                                                                       &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first,
+                                       sizeof(put_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static gboolean cancel_transfer(gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (d->id > 0)
+               g_obex_cancel_transfer(d->id, transfer_complete, user_data);
+
+       return FALSE;
+}
+
+static gssize abort_data(void *buf, gsize len, gpointer user_data)
+{
+       g_idle_add_full(G_PRIORITY_HIGH, cancel_transfer, user_data, NULL);
+       return provide_data(buf, len, user_data);
+}
+
+static void test_stream_put_req_abort(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_req_first, sizeof(put_req_first) },
+                               { abort_req, sizeof(abort_req) } }, {
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       d.id = g_obex_put_req(obex, abort_data, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_error(d.err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED);
+}
+
+static void test_stream_put_rsp_abort(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } }, {
+                               { put_req_zero, sizeof(put_req_zero) },
+                               { abort_req, sizeof(abort_req) },
+                               { NULL, -1 },
+                               { NULL, -1 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq, &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first,
+                                       sizeof(put_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_error(d.err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED);
+}
+
+static void handle_put_seq_wait(GObex *obex, GObexPacket *req,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_PUT) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_put_rsp(obex, req, rcv_seq, transfer_complete, d,
+                                       &d->err,
+                                       G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+                                       G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_packet_put_rsp_wait(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+               { put_rsp_first_srm_wait, sizeof(put_rsp_first_srm_wait) },
+               { put_rsp_first, sizeof(put_rsp_first) },
+               { NULL, -1 },
+               { put_rsp_last, sizeof(put_rsp_last) } }, {
+               { put_req_zero, sizeof(put_req_zero) },
+               { put_req_zero, sizeof(put_req_zero) },
+               { put_req_last, sizeof(put_req_last) },
+               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT,
+                                               handle_put_seq_wait, &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first_srm,
+                                       sizeof(put_req_first_srm), NULL,
+                                       &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_put_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { put_rsp_first_srm, sizeof(put_rsp_first_srm) },
+                       { NULL, -1 },
+                       { NULL, -1 },
+                       { put_rsp_last, sizeof(put_rsp_last) } }, {
+                       { put_req_zero, sizeof(put_req_zero) },
+                       { put_req_zero, sizeof(put_req_zero) },
+                       { put_req_last, sizeof(put_req_last) },
+                       { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_seq, &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first_srm,
+                                       sizeof(put_req_first_srm), NULL,
+                                       &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_req_first, sizeof(get_req_first) },
+                               { get_req_last, sizeof(get_req_last) } }, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_data, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_stream_get_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_req_first, sizeof(get_req_first) },
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { get_req_last, sizeof(get_req_last) } }, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_zero, sizeof(get_rsp_zero) },
+                               { get_rsp_zero, sizeof(get_rsp_zero) },
+                               { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { get_req_first_srm, sizeof(get_req_first_srm) },
+                       { NULL, -1 },
+                       { NULL, -1 },
+                       { get_req_last, sizeof(get_req_last) } }, {
+                       { get_rsp_first_srm, sizeof(get_rsp_first_srm) },
+                       { get_rsp_zero, sizeof(get_rsp_zero) },
+                       { get_rsp_zero, sizeof(get_rsp_zero) },
+                       { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req_wait(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+               { get_req_first_srm_wait, sizeof(get_req_first_srm_wait) },
+               { get_req_last, sizeof(get_req_last) },
+               { NULL, -1 },
+               { get_req_last, sizeof(get_req_last) } }, {
+               { get_rsp_first_srm, sizeof(get_rsp_first_srm) },
+               { get_rsp_zero, sizeof(get_rsp_zero) },
+               { get_rsp_zero, sizeof(get_rsp_zero) },
+               { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_get_req_wait_next(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+               { get_req_first_srm, sizeof(get_req_first_srm) },
+               { get_req_last, sizeof(get_req_last) },
+               { get_req_last, sizeof(get_req_last) },
+               { get_req_last, sizeof(get_req_last) } }, {
+               { get_rsp_first_srm_wait_next,
+               sizeof(get_rsp_first_srm_wait_next) },
+               { get_rsp_zero_wait_next, sizeof(get_rsp_zero_wait_next) },
+               { get_rsp_zero_wait_next, sizeof(get_rsp_zero_wait_next) },
+               { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_seq, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_req_app(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { get_req_first_app, sizeof(get_req_first_app) },
+                       { get_req_last, sizeof(get_req_last) },
+                       { get_req_last, sizeof(get_req_last) } }, {
+                       { get_rsp_first_app, sizeof(get_rsp_first_app) },
+                       { get_rsp_first, sizeof(get_rsp_first) },
+                       { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_data, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_APPARAM, hdr_app, sizeof(hdr_app),
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 3);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void handle_get_eagain(GObex *obex, GObexPacket *req,
+                                               gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_GET) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_get_rsp(obex, provide_eagain, transfer_complete, d,
+                                               &d->err, G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void handle_get(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_GET) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_get_rsp(obex, provide_data, transfer_complete, d, &d->err,
+                                                       G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_put_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "random.bin",
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_put_req_wait(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+               { NULL, 0 },
+               { NULL, 0 },
+               { NULL, 0 },
+               { put_req_last, sizeof(put_req_last) } }, {
+               { put_rsp_first_srm_wait, sizeof(put_rsp_first_srm_wait) },
+               { put_rsp_first, sizeof(put_rsp_first) },
+               { NULL, 0 },
+               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "random.bin",
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_put_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { NULL, 0 },
+                       { NULL, 0 },
+                       { NULL, 0 },
+                       { put_req_last, sizeof(put_req_last) } }, {
+                       { put_rsp_first_srm, sizeof(put_rsp_first_srm) },
+                       { NULL, 0 },
+                       { NULL, 0 },
+                       { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_seq, transfer_complete, &d, &d.err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "random.bin",
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_put_req_eagain(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_req_first, sizeof(put_req_first) },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_eagain, transfer_complete, &d, &d.err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "file.txt",
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { get_req_last, sizeof(get_req_last) },
+                               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first,
+                                       sizeof(get_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void handle_get_seq(GObex *obex, GObexPacket *req,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_GET) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_get_rsp(obex, provide_seq, transfer_complete, d,
+                                               &d->err, G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_stream_get_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { get_req_last, sizeof(get_req_last) },
+                               { get_req_last, sizeof(get_req_last) },
+                               { get_req_last, sizeof(get_req_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_seq, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first,
+                                       sizeof(get_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_packet_get_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { get_req_last, sizeof(get_req_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_seq, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first_srm,
+                                       sizeof(get_req_first_srm), NULL,
+                                       &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void handle_get_seq_srm_wait(GObex *obex, GObexPacket *req,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_GET) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_get_rsp(obex, provide_seq, transfer_complete, d,
+                                       &d->err,
+                                       G_OBEX_HDR_SRMP, G_OBEX_SRMP_WAIT,
+                                       G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_packet_get_rsp_wait(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { get_req_last, sizeof(get_req_last) },
+                               { NULL, 0 },
+                               { get_req_last, sizeof(get_req_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET,
+                                       handle_get_seq_srm_wait, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first_srm,
+                                       sizeof(get_req_first_srm), NULL,
+                                       &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS - 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void handle_get_app(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       GObexPacket *rsp;
+
+       if (op != G_OBEX_OP_GET) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       g_obex_add_request_function(d->obex, G_OBEX_OP_GET, handle_get, d);
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE,
+                               G_OBEX_HDR_APPARAM, hdr_app, sizeof(hdr_app),
+                               G_OBEX_HDR_INVALID);
+
+       if (g_obex_send(d->obex, rsp, NULL) == FALSE)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_get_rsp_app(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { get_rsp_first_app, sizeof(get_rsp_first_app) },
+                       { get_rsp_first, sizeof(get_rsp_first) },
+                       { get_rsp_last, sizeof(get_rsp_last) } }, {
+                       { get_req_first, sizeof(get_req_first) },
+                       { get_req_last, sizeof(get_req_last) },
+                       { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_app, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first_app,
+                                       sizeof(get_req_first_app), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_put_req_delay(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_req_first, sizeof(put_req_first) },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_put_req(obex, provide_data, transfer_complete, &d, &d.err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "file.txt",
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_rsp_delay(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { get_req_last, sizeof(get_req_last) },
+                               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get, &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first,
+                                       sizeof(get_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static gboolean rcv_data_delay(const void *buf, gsize len, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (len != sizeof(body_data))
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected byte count %zu", len);
+
+       if (memcmp(buf, body_data, sizeof(body_data)) != 0) {
+               dump_bufs(body_data, sizeof(body_data), buf, len);
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected byte count %zu", len);
+       }
+
+       if (d->provide_delay > 0) {
+               g_obex_suspend(d->obex);
+               g_timeout_add(d->provide_delay, resume_obex, d->obex);
+       }
+
+       return TRUE;
+}
+
+static void handle_put_delay(GObex *obex, GObexPacket *req, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       guint id;
+
+       if (op != G_OBEX_OP_PUT) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       id = g_obex_put_rsp(obex, req, rcv_data_delay, transfer_complete, d,
+                                               &d->err, G_OBEX_HDR_INVALID);
+       if (id == 0)
+               g_main_loop_quit(d->mainloop);
+}
+
+static void test_put_rsp_delay(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } }, {
+                               { put_req_last, sizeof(put_req_last) },
+                               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT, handle_put_delay, &d);
+
+       g_io_channel_write_chars(io, (char *) put_req_first,
+                                       sizeof(put_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_req_delay(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_req_first, sizeof(get_req_first) },
+                               { get_req_last, sizeof(get_req_last) } }, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_get_req(obex, rcv_data_delay, transfer_complete, &d, &d.err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_get_rsp_eagain(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { get_rsp_first, sizeof(get_rsp_first) },
+                               { get_rsp_last, sizeof(get_rsp_last) } }, {
+                               { get_req_last, sizeof(get_req_last) },
+                               { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+       d.provide_delay = 200;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET, handle_get_eagain,
+                                                                       &d);
+
+       g_io_channel_write_chars(io, (char *) get_req_first,
+                                       sizeof(get_req_first), NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void conn_complete(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL)
+               d->err = g_error_copy(err);
+
+       g_main_loop_quit(d->mainloop);
+}
+
+static void test_conn_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { conn_req, sizeof(conn_req) } }, {
+                               { conn_rsp, sizeof(conn_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, conn_complete, &d, &d.err, G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void handle_conn_rsp(GObex *obex, GObexPacket *req,
+                                               gpointer user_data)
+{
+       struct test_data *d = user_data;
+       guint8 op = g_obex_packet_get_operation(req, NULL);
+       GObexPacket *rsp;
+
+       if (op != G_OBEX_OP_CONNECT) {
+               d->err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Unexpected opcode 0x%02x", op);
+               g_main_loop_quit(d->mainloop);
+               return;
+       }
+
+       rsp = g_obex_packet_new(G_OBEX_RSP_SUCCESS, TRUE,
+                                               G_OBEX_HDR_CONNECTION, 1,
+                                               G_OBEX_HDR_INVALID);
+       g_obex_send(obex, rsp, &d->err);
+}
+
+static void test_conn_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_rsp, sizeof(conn_rsp) } }, {
+                       { NULL, -1 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+                                               handle_conn_rsp, &d);
+
+       g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+                                                               NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void conn_complete_get_req(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL) {
+               d->err = g_error_copy(err);
+               g_main_loop_quit(d->mainloop);
+       }
+
+       g_obex_get_req(obex, rcv_data, transfer_complete, d, &d->err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_get_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_req, sizeof(conn_req) },
+                       { conn_get_req_first, sizeof(conn_get_req_first) },
+                       { get_req_last, sizeof(get_req_last) }}, {
+                       { conn_rsp, sizeof(conn_rsp) } ,
+                       { get_rsp_first, sizeof(get_rsp_first) },
+                       { get_rsp_last, sizeof(get_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, conn_complete_get_req, &d, &d.err,
+                                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 3);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_conn_get_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_rsp, sizeof(conn_rsp) },
+                       { get_rsp_first, sizeof(get_rsp_first) },
+                       { get_rsp_last, sizeof(get_rsp_last) } }, {
+                       { conn_get_req_first, sizeof(conn_get_req_first) },
+                       { get_req_last, sizeof(get_req_last) },
+                       { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+                                               handle_conn_rsp, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_GET,
+                                               handle_get, &d);
+
+       g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+                                                               NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL) {
+               d->err = g_error_copy(err);
+               g_main_loop_quit(d->mainloop);
+       }
+
+       g_obex_put_req(obex, provide_data, transfer_complete, d, &d->err,
+                               G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                               G_OBEX_HDR_NAME, "file.txt",
+                               G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_req, sizeof(conn_req) },
+                       { conn_put_req_first, sizeof(conn_put_req_first) },
+                       { put_req_last, sizeof(put_req_last) }}, {
+                       { conn_rsp, sizeof(conn_rsp) } ,
+                       { put_rsp_first, sizeof(put_rsp_first) },
+                       { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, conn_complete_put_req, &d, &d.err,
+                                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 3);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_conn_put_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_rsp, sizeof(conn_rsp) },
+                       { put_rsp_first, sizeof(put_rsp_first) },
+                       { put_rsp_last, sizeof(put_rsp_last) } }, {
+                       { conn_put_req_first, sizeof(conn_put_req_first) },
+                       { put_req_last, sizeof(put_req_last) },
+                       { NULL, 0 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+                                               handle_conn_rsp, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_PUT,
+                                               handle_put, &d);
+
+       g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+                                                               NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_conn_get_wrg_rsp(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { conn_rsp, sizeof(conn_rsp) },
+                       { unavailable_rsp, sizeof(unavailable_rsp) } }, {
+                       { conn_get_req_wrg, sizeof(conn_get_req_wrg) },
+                       { NULL, -1 } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+                                               handle_conn_rsp, &d);
+
+       g_io_channel_write_chars(io, (char *) conn_req, sizeof(conn_req),
+                                                               NULL, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 2);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req_seq(GObex *obex, GError *err,
+                                       GObexPacket *rsp, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL) {
+               d->err = g_error_copy(err);
+               g_main_loop_quit(d->mainloop);
+       }
+
+       g_obex_put_req(obex, provide_seq, transfer_complete, d, &d->err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "random.bin",
+                                       G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req_seq(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { conn_req, sizeof(conn_req) } ,
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { conn_rsp, sizeof(conn_rsp) } ,
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_first, sizeof(put_rsp_first) },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, conn_complete_put_req_seq, &d, &d.err,
+                                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void conn_complete_put_req_seq_srm(GObex *obex, GError *err,
+                                       GObexPacket *rsp, gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL) {
+               d->err = g_error_copy(err);
+               g_main_loop_quit(d->mainloop);
+       }
+
+       g_obex_put_req(obex, provide_seq, transfer_complete, d, &d->err,
+                                       G_OBEX_HDR_TYPE, hdr_type, sizeof(hdr_type),
+                                       G_OBEX_HDR_NAME, "random.bin",
+                                       G_OBEX_HDR_INVALID);
+}
+
+static void test_conn_put_req_seq_srm(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { conn_req_srm, sizeof(conn_req_srm) } ,
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { put_req_last, sizeof(put_req_last) } }, {
+                               { conn_rsp_srm, sizeof(conn_rsp_srm) } ,
+                               { NULL, 0 },
+                               { NULL, 0 },
+                               { put_rsp_last, sizeof(put_rsp_last) } } };
+
+       create_endpoints(&obex, &io, SOCK_SEQPACKET);
+       d.obex = obex;
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, conn_complete_put_req_seq_srm, &d, &d.err,
+                                       G_OBEX_HDR_SRM, G_OBEX_SRM_INDICATE,
+                                       G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, RANDOM_PACKETS);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/test_conn_req", test_conn_req);
+       g_test_add_func("/gobex/test_conn_rsp", test_conn_rsp);
+
+       g_test_add_func("/gobex/test_put_req", test_put_req);
+       g_test_add_func("/gobex/test_put_rsp", test_put_rsp);
+
+       g_test_add_func("/gobex/test_get_req", test_get_req);
+       g_test_add_func("/gobex/test_get_rsp", test_get_rsp);
+
+       g_test_add_func("/gobex/test_get_req_app", test_get_req_app);
+       g_test_add_func("/gobex/test_get_rsp_app", test_get_rsp_app);
+
+       g_test_add_func("/gobex/test_put_req_delay", test_put_req_delay);
+       g_test_add_func("/gobex/test_put_rsp_delay", test_put_rsp_delay);
+
+       g_test_add_func("/gobex/test_get_req_delay", test_get_req_delay);
+       g_test_add_func("/gobex/test_get_rsp_delay", test_get_rsp_delay);
+
+       g_test_add_func("/gobex/test_put_req_eagain", test_put_req_eagain);
+       g_test_add_func("/gobex/test_get_req_eagain", test_get_rsp_eagain);
+
+       g_test_add_func("/gobex/test_stream_put_req", test_stream_put_req);
+       g_test_add_func("/gobex/test_stream_put_rsp", test_stream_put_rsp);
+
+       g_test_add_func("/gobex/test_stream_put_req_abort",
+                                               test_stream_put_req_abort);
+       g_test_add_func("/gobex/test_stream_put_rsp_abort",
+                                               test_stream_put_rsp_abort);
+
+       g_test_add_func("/gobex/test_stream_get_req", test_stream_get_req);
+       g_test_add_func("/gobex/test_stream_get_rsp", test_stream_get_rsp);
+
+       g_test_add_func("/gobex/test_conn_get_req", test_conn_get_req);
+       g_test_add_func("/gobex/test_conn_get_rsp", test_conn_get_rsp);
+
+       g_test_add_func("/gobex/test_conn_put_req", test_conn_put_req);
+       g_test_add_func("/gobex/test_conn_put_rsp", test_conn_put_rsp);
+
+       g_test_add_func("/gobex/test_conn_get_wrg_rsp", test_conn_get_wrg_rsp);
+
+       g_test_add_func("/gobex/test_conn_put_req_seq",
+                                               test_conn_put_req_seq);
+
+       g_test_add_func("/gobex/test_packet_put_req", test_packet_put_req);
+       g_test_add_func("/gobex/test_packet_put_req_wait",
+                                               test_packet_put_req_wait);
+
+       g_test_add_func("/gobex/test_packet_put_rsp", test_packet_put_rsp);
+       g_test_add_func("/gobex/test_packet_put_rsp_wait",
+                                               test_packet_put_rsp_wait);
+
+       g_test_add_func("/gobex/test_packet_get_rsp", test_packet_get_rsp);
+       g_test_add_func("/gobex/test_packet_get_rsp_wait",
+                                               test_packet_get_rsp_wait);
+
+       g_test_add_func("/gobex/test_packet_get_req", test_packet_get_req);
+       g_test_add_func("/gobex/test_packet_get_req_wait",
+                                               test_packet_get_req_wait);
+
+       g_test_add_func("/gobex/test_packet_get_req_wait_next",
+                                               test_packet_get_req_wait_next);
+
+       g_test_add_func("/gobex/test_conn_put_req_seq_srm",
+                                               test_conn_put_req_seq_srm);
+
+       return g_test_run();
+}
diff --git a/unit/test-gobex.c b/unit/test-gobex.c
new file mode 100644 (file)
index 0000000..66307c2
--- /dev/null
@@ -0,0 +1,1201 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include <stdlib.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <errno.h>
+#include <unistd.h>
+#include <string.h>
+#include <stdint.h>
+
+#include <gobex/gobex.h>
+
+#include "util.h"
+
+#define FINAL_BIT 0x80
+
+static GMainLoop *mainloop = NULL;
+
+static uint8_t pkt_connect_req[] = { G_OBEX_OP_CONNECT | FINAL_BIT,
+                                       0x00, 0x07, 0x10, 0x00, 0x10, 0x00 };
+static uint8_t pkt_connect_rsp[] = { 0x20 | FINAL_BIT, 0x00, 0x07,
+                                       0x10, 0x00, 0x10, 0x00 };
+
+static uint8_t pkt_setpath_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT, 0x00, 0x10,
+                                       0x02, 0x00,
+                                       G_OBEX_HDR_NAME, 0x00, 0x0b,
+                                       0, 'd', 0, 'i', 0, 'r', 0, 0 };
+static uint8_t pkt_setpath_up_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT,
+                                       0x00, 0x05, 0x03, 0x00 };
+static uint8_t pkt_setpath_up_down_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT,
+                                       0x00, 0x10, 0x03, 0x00,
+                                       G_OBEX_HDR_NAME, 0x00, 0x0b,
+                                       0, 'd', 0, 'i', 0, 'r', 0, 0 };
+static uint8_t pkt_success_rsp[] = { 0x20 | FINAL_BIT, 0x00, 0x03 };
+
+static uint8_t pkt_mkdir_req[] = { G_OBEX_OP_SETPATH | FINAL_BIT, 0x00, 0x10,
+                                       0x00, 0x00,
+                                       G_OBEX_HDR_NAME, 0x00, 0x0b,
+                                       0, 'd', 0, 'i', 0, 'r', 0, 0 };
+
+static uint8_t pkt_delete_req[] = { G_OBEX_OP_PUT | FINAL_BIT, 0x00, 0x16,
+               G_OBEX_HDR_NAME, 0x00, 0x13,
+               0, 'f', 0, 'o', 0, 'o', 0, '.', 0, 't', 0, 'x', 0, 't', 0, 0 };
+
+static uint8_t pkt_copy_req[] = { G_OBEX_OP_ACTION | FINAL_BIT, 0x00, 0x1b,
+                                       G_OBEX_HDR_ACTION, 0x00,
+                                       G_OBEX_HDR_NAME, 0x00, 0x0b,
+                                       0, 'f', 0, 'o', 0, 'o', 0, 0,
+                                       G_OBEX_HDR_DESTNAME, 0x00, 0x0b,
+                                       0, 'b', 0, 'a', 0, 'r', 0, 0 };
+static uint8_t pkt_move_req[] = { G_OBEX_OP_ACTION | FINAL_BIT, 0x00, 0x1b,
+                                       G_OBEX_HDR_ACTION, 0x01,
+                                       G_OBEX_HDR_NAME, 0x00, 0x0b,
+                                       0, 'f', 0, 'o', 0, 'o', 0, 0,
+                                       G_OBEX_HDR_DESTNAME, 0x00, 0x0b,
+                                       0, 'b', 0, 'a', 0, 'r', 0, 0 };
+
+static uint8_t pkt_nval_connect_rsp[] = { 0x10 | FINAL_BIT, 0x00, 0x05,
+                                       0x10, 0x00, };
+static uint8_t pkt_abort_rsp[] = { 0x90, 0x00, 0x03 };
+static uint8_t pkt_nval_short_rsp[] = { 0x10 | FINAL_BIT, 0x12 };
+static uint8_t pkt_put_body[] = { G_OBEX_OP_PUT, 0x00, 0x0a,
+                                       G_OBEX_HDR_BODY, 0x00, 0x07,
+                                       1, 2, 3, 4 };
+
+static gboolean timeout(gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!g_main_loop_is_running(mainloop))
+               return FALSE;
+
+       g_set_error(err, TEST_ERROR, TEST_ERROR_TIMEOUT, "Timed out");
+
+       g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static void connect_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       guint8 rsp_code;
+       gboolean final;
+       GError **test_err = user_data;
+
+       if (err != NULL) {
+               g_assert(*test_err == NULL);
+               *test_err = g_error_copy(err);
+               goto done;
+       }
+
+       rsp_code = g_obex_packet_get_operation(rsp, &final);
+       if (rsp_code != 0x20) {
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Unexpected response 0x%02x", rsp_code);
+               goto done;
+       }
+
+       if (!final) {
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Connect response didn't have final bit");
+               goto done;
+       }
+
+done:
+       g_main_loop_quit(mainloop);
+}
+
+static void nval_connect_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR))
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Did not get expected parse error");
+
+       g_main_loop_quit(mainloop);
+}
+
+static void timeout_rsp(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_TIMEOUT))
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Did not get expected timeout error");
+
+       g_main_loop_quit(mainloop);
+}
+
+static gboolean recv_and_send(GIOChannel *io, void *data, gsize len,
+                                                               GError **err)
+{
+       gsize bytes_written, rbytes;
+       char buf[255];
+       GIOStatus status;
+
+       status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+       if (status != G_IO_STATUS_NORMAL) {
+               g_set_error(err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "read failed with status %d", status);
+               return FALSE;
+       }
+
+       if (data == NULL)
+               return TRUE;
+
+       g_io_channel_write_chars(io, data, len, &bytes_written, NULL);
+       if (bytes_written != len) {
+               g_set_error(err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                               "Unable to write to socket");
+               return FALSE;
+       }
+
+       return TRUE;
+}
+
+static gboolean send_connect_rsp(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!recv_and_send(io, pkt_connect_rsp, sizeof(pkt_connect_rsp), err))
+               g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static gboolean send_nval_connect_rsp(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!recv_and_send(io, pkt_nval_connect_rsp,
+                                       sizeof(pkt_nval_connect_rsp), err))
+               g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static gboolean send_nval_short_rsp(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!recv_and_send(io, pkt_nval_short_rsp,
+                                       sizeof(pkt_nval_short_rsp), err))
+               g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static gboolean send_nothing(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       GError **err = user_data;
+
+       if (!recv_and_send(io, NULL, 0, err))
+               g_main_loop_quit(mainloop);
+
+       return FALSE;
+}
+
+static void send_req(GObexPacket *req, GObexResponseFunc rsp_func,
+                               GIOFunc send_rsp_func, int req_timeout,
+                               int transport_type)
+{
+       GError *gerr = NULL;
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id, test_time;
+       GObex *obex;
+
+       create_endpoints(&obex, &io, transport_type);
+
+       g_obex_send_req(obex, req, req_timeout, rsp_func, &gerr, &gerr);
+       g_assert_no_error(gerr);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, send_rsp_func, &gerr);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       if (req_timeout > 0)
+               test_time = req_timeout + 1;
+       else
+               test_time = 1;
+
+       timer_id = g_timeout_add_seconds(test_time, timeout, &gerr);
+
+       g_main_loop_run(mainloop);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(gerr);
+}
+
+static void send_connect(GObexResponseFunc rsp_func, GIOFunc send_rsp_func,
+                                       int req_timeout, int transport_type)
+{
+       GObexPacket *req;
+       guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 };
+
+       req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE, G_OBEX_HDR_INVALID);
+       g_assert(req != NULL);
+
+       g_obex_packet_set_data(req, connect_data, sizeof(connect_data),
+                                                       G_OBEX_DATA_REF);
+
+       send_req(req, rsp_func, send_rsp_func, req_timeout, transport_type);
+}
+
+static void test_send_connect_req_stream(void)
+{
+       send_connect(connect_rsp, send_connect_rsp, -1, SOCK_STREAM);
+}
+
+static void test_send_connect_req_pkt(void)
+{
+       send_connect(connect_rsp, send_connect_rsp, -1, SOCK_SEQPACKET);
+}
+
+static void test_send_nval_connect_req_stream(void)
+{
+       send_connect(nval_connect_rsp, send_nval_connect_rsp, -1, SOCK_STREAM);
+}
+
+static void test_send_nval_connect_req_pkt(void)
+{
+       send_connect(nval_connect_rsp, send_nval_connect_rsp, -1,
+                                                       SOCK_SEQPACKET);
+}
+
+static void test_send_nval_connect_req_short_pkt(void)
+{
+       send_connect(nval_connect_rsp, send_nval_short_rsp, -1,
+                                                       SOCK_SEQPACKET);
+}
+
+static void test_send_connect_req_timeout_stream(void)
+{
+       send_connect(timeout_rsp, send_nothing, 0, SOCK_STREAM);
+}
+
+static void test_send_connect_req_timeout_pkt(void)
+{
+       send_connect(timeout_rsp, send_nothing, 0, SOCK_SEQPACKET);
+}
+
+struct req_info {
+       GObex *obex;
+       guint id;
+       GError *err;
+};
+
+static void req_done(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct req_info *r = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_CANCELLED))
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Did not get expected cancelled error");
+
+       g_main_loop_quit(mainloop);
+}
+
+static void test_cancel_req_immediate(void)
+{
+       GObexPacket *req;
+       struct req_info r;
+       gboolean ret;
+
+       create_endpoints(&r.obex, NULL, SOCK_STREAM);
+
+       r.err = NULL;
+
+       req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_INVALID);
+       r.id = g_obex_send_req(r.obex, req, -1, req_done, &r, &r.err);
+       g_assert_no_error(r.err);
+       g_assert(r.id != 0);
+
+       ret = g_obex_cancel_req(r.obex, r.id, FALSE);
+       g_assert(ret == TRUE);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       g_main_loop_run(mainloop);
+
+       g_assert_no_error(r.err);
+
+       g_obex_unref(r.obex);
+       g_main_loop_unref(mainloop);
+}
+
+static gboolean cancel_server(GIOChannel *io, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct req_info *r = user_data;
+       GIOStatus status;
+       gsize bytes_written, rbytes;
+       char buf[255];
+
+       status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+       if (status != G_IO_STATUS_NORMAL) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Reading data failed with status %d", status);
+               goto failed;
+       }
+
+       if (rbytes < 3) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Not enough data from socket");
+               goto failed;
+       }
+
+       if ((uint8_t) buf[0] == (G_OBEX_OP_PUT | FINAL_BIT)) {
+               if (!g_obex_cancel_req(r->obex, r->id, FALSE)) {
+                       g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Cancelling request failed");
+                       goto failed;
+               }
+               return TRUE;
+       }
+
+       if ((uint8_t) buf[0] != (G_OBEX_OP_ABORT | FINAL_BIT)) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Neither Put nor Abort packet received");
+               goto failed;
+       }
+
+       g_io_channel_write_chars(io, (char *) pkt_abort_rsp,
+                               sizeof(pkt_abort_rsp), &bytes_written, NULL);
+       if (bytes_written != sizeof(pkt_abort_rsp)) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                               "Unable to write to socket");
+               goto failed;
+       }
+
+       return TRUE;
+
+failed:
+       g_main_loop_quit(mainloop);
+       return FALSE;
+}
+
+static void test_cancel_req_delay(int transport_type)
+{
+       GIOChannel *io;
+       guint io_id, timer_id;
+       struct req_info r;
+       GObexPacket *req;
+       GIOCondition cond;
+
+       create_endpoints(&r.obex, &io, transport_type);
+
+       r.err = NULL;
+
+       req = g_obex_packet_new(G_OBEX_OP_PUT, TRUE, G_OBEX_HDR_INVALID);
+       r.id = g_obex_send_req(r.obex, req, -1, req_done, &r, &r.err);
+       g_assert_no_error(r.err);
+       g_assert(r.id != 0);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, cancel_server, &r);
+
+       timer_id = g_timeout_add_seconds(2, timeout, &r.err);
+
+       g_main_loop_run(mainloop);
+
+       g_assert_no_error(r.err);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(r.obex);
+       g_main_loop_unref(mainloop);
+}
+
+static void test_cancel_req_delay_stream(void)
+{
+       test_cancel_req_delay(SOCK_STREAM);
+}
+
+static void test_cancel_req_delay_pkt(void)
+{
+       test_cancel_req_delay(SOCK_SEQPACKET);
+}
+
+struct rcv_buf_info {
+       GError *err;
+       const guint8 *buf;
+       gsize len;
+};
+
+static gboolean rcv_data(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+       struct rcv_buf_info *r = user_data;
+       GIOStatus status;
+       gsize rbytes;
+       char buf[255];
+
+       if (cond & (G_IO_HUP | G_IO_ERR | G_IO_NVAL)) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Unexpected condition %d on socket", cond);
+               goto done;
+       }
+
+       status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+       if (status != G_IO_STATUS_NORMAL) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Reading data failed with status %d", status);
+               goto done;
+       }
+
+       if (rbytes != r->len) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Got %zu bytes instead of %zu",
+                               rbytes, sizeof(pkt_connect_req));
+               dump_bufs(r->buf, r->len, buf, rbytes);
+               goto done;
+       }
+
+       if (memcmp(buf, r->buf, rbytes) != 0) {
+               g_set_error(&r->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Mismatch with received data");
+               dump_bufs(r->buf, r->len, buf, rbytes);
+               goto done;
+       }
+
+done:
+       g_main_loop_quit(mainloop);
+       return FALSE;
+}
+
+static void test_send_connect(int transport_type)
+{
+       guint8 connect_data[] = { 0x10, 0x00, 0x10, 0x00 };
+       struct rcv_buf_info r;
+       GIOChannel *io;
+       GIOCondition cond;
+       GObexPacket *req;
+       guint io_id, timer_id;
+       GObex *obex;
+
+       create_endpoints(&obex, &io, transport_type);
+
+       memset(&r, 0, sizeof(r));
+       r.buf = pkt_connect_req;
+       r.len = sizeof(pkt_connect_req);
+
+       req = g_obex_packet_new(G_OBEX_OP_CONNECT, TRUE, G_OBEX_HDR_INVALID);
+       g_assert(req != NULL);
+
+       g_obex_packet_set_data(req, connect_data, sizeof(connect_data),
+                                                       G_OBEX_DATA_REF);
+       g_obex_send(obex, req, &r.err);
+       g_assert_no_error(r.err);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, rcv_data, &r);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, timeout, &r.err);
+
+       g_main_loop_run(mainloop);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(r.err);
+}
+
+static void test_send_connect_stream(void)
+{
+       test_send_connect(SOCK_STREAM);
+}
+
+static void test_send_connect_pkt(void)
+{
+       test_send_connect(SOCK_SEQPACKET);
+}
+
+static void unexpected_disconn(GObex *obex, GError *err, gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_PARSE_ERROR))
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Didn't get parse error as expected");
+
+       g_main_loop_quit(mainloop);
+}
+
+static void test_recv_unexpected(void)
+{
+       GError *err = NULL;
+       GObexPacket *req;
+       GIOChannel *io;
+       guint timer_id;
+       GObex *obex;
+       guint8 buf[255];
+       gssize len;
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       g_obex_set_disconnect_function(obex, unexpected_disconn, &err);
+
+       req = g_obex_packet_new(G_OBEX_RSP_CONTINUE, TRUE, G_OBEX_HDR_INVALID);
+       len = g_obex_packet_encode(req, buf, sizeof(buf));
+       g_obex_packet_free(req);
+       g_assert_cmpint(len, >=, 0);
+
+       g_io_channel_write_chars(io, (char *) buf, len, NULL, &err);
+       g_assert_no_error(err);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, timeout, &err);
+
+       g_main_loop_run(mainloop);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_obex_unref(obex);
+
+       g_assert_no_error(err);
+}
+
+static gssize get_body_data(void *buf, gsize len, gpointer user_data)
+{
+       uint8_t data[] = { 1, 2, 3, 4 };
+
+       memcpy(buf, data, sizeof(data));
+
+       return sizeof(data);
+}
+
+static gssize get_body_data_fail(void *buf, gsize len, gpointer user_data)
+{
+       g_main_loop_quit(mainloop);
+       return -1;
+}
+
+static void test_send_on_demand(int transport_type, GObexDataProducer func)
+{
+       struct rcv_buf_info r;
+       GIOChannel *io;
+       GIOCondition cond;
+       GObexPacket *req;
+       guint io_id, timer_id;
+       GObex *obex;
+
+       create_endpoints(&obex, &io, transport_type);
+
+       memset(&r, 0, sizeof(r));
+       r.buf = pkt_put_body;
+       r.len = sizeof(pkt_put_body);
+
+       req = g_obex_packet_new(G_OBEX_OP_PUT, FALSE, G_OBEX_HDR_INVALID);
+       g_obex_packet_add_body(req, func, &r);
+
+       g_obex_send(obex, req, &r.err);
+       g_assert_no_error(r.err);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, rcv_data, &r);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, timeout, &r.err);
+
+       g_main_loop_run(mainloop);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(r.err);
+}
+
+static void test_send_on_demand_stream(void)
+{
+       test_send_on_demand(SOCK_STREAM, get_body_data);
+}
+
+static void test_send_on_demand_pkt(void)
+{
+       test_send_on_demand(SOCK_SEQPACKET, get_body_data);
+}
+
+static void test_send_on_demand_fail_stream(void)
+{
+       test_send_on_demand(SOCK_STREAM, get_body_data_fail);
+}
+
+static void test_send_on_demand_fail_pkt(void)
+{
+       test_send_on_demand(SOCK_SEQPACKET, get_body_data_fail);
+}
+
+static void handle_connect_req(GObex *obex, GObexPacket *req,
+                                                       gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (g_obex_packet_get_operation(req, NULL) != G_OBEX_OP_CONNECT)
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                               "Unexpected operation");
+       g_main_loop_quit(mainloop);
+
+}
+
+static void handle_connect_err(GObex *obex, GError *err, gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       g_main_loop_quit(mainloop);
+
+       if (err != NULL)
+               *test_err = g_error_copy(err);
+       else
+               *test_err = g_error_new(TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Disconnected");
+}
+
+static void recv_connect(int transport_type)
+{
+       GError *gerr = NULL;
+       guint timer_id;
+       GObex *obex;
+       GIOChannel *io;
+       GIOStatus status;
+       gsize bytes_written;
+
+       create_endpoints(&obex, &io, transport_type);
+
+       g_obex_add_request_function(obex, G_OBEX_OP_CONNECT,
+                                               handle_connect_req, &gerr);
+       g_obex_set_disconnect_function(obex, handle_connect_err, &gerr);
+
+       status = g_io_channel_write_chars(io, (char *) pkt_connect_req,
+                                               sizeof(pkt_connect_req),
+                                               &bytes_written, NULL);
+       g_assert_cmpint(status, ==, G_IO_STATUS_NORMAL);
+       g_assert_cmpuint(bytes_written, ==, sizeof(pkt_connect_req));
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, timeout, &gerr);
+
+       g_main_loop_run(mainloop);
+
+       g_source_remove(timer_id);
+       g_obex_unref(obex);
+       g_io_channel_unref(io);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+
+       g_assert_no_error(gerr);
+}
+
+static void test_recv_connect_stream(void)
+{
+       recv_connect(SOCK_STREAM);
+}
+
+static void test_recv_connect_pkt(void)
+{
+       recv_connect(SOCK_SEQPACKET);
+}
+
+static void disconn_ev(GObex *obex, GError *err, gpointer user_data)
+{
+       GError **test_err = user_data;
+
+       if (!g_error_matches(err, G_OBEX_ERROR, G_OBEX_ERROR_DISCONNECTED))
+               g_set_error(test_err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Did not get expected disconnect error");
+
+       g_main_loop_quit(mainloop);
+}
+
+static void test_disconnect(void)
+{
+       GError *gerr = NULL;
+       guint timer_id;
+       GObex *obex;
+       GIOChannel *io;
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       g_obex_set_disconnect_function(obex, disconn_ev, &gerr);
+
+       timer_id = g_timeout_add_seconds(1, timeout, &gerr);
+
+       mainloop = g_main_loop_new(NULL, FALSE);
+
+       g_io_channel_shutdown(io, FALSE, NULL);
+
+       g_main_loop_run(mainloop);
+
+       g_assert_no_error(gerr);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_obex_unref(obex);
+
+       g_main_loop_unref(mainloop);
+       mainloop = NULL;
+}
+
+static void test_ref_unref(void)
+{
+       GObex *obex;
+
+       obex = create_gobex(STDIN_FILENO, G_OBEX_TRANSPORT_STREAM, FALSE);
+
+       g_assert(obex != NULL);
+
+       obex = g_obex_ref(obex);
+
+       g_obex_unref(obex);
+       g_obex_unref(obex);
+}
+
+static void test_basic(void)
+{
+       GObex *obex;
+
+       obex = create_gobex(STDIN_FILENO, G_OBEX_TRANSPORT_STREAM, FALSE);
+
+       g_assert(obex != NULL);
+
+       g_obex_unref(obex);
+}
+
+static void test_null_io(void)
+{
+       GObex *obex;
+
+       obex = g_obex_new(NULL, 0, -1, -1);
+
+       g_assert(obex == NULL);
+}
+
+static void req_complete(GObex *obex, GError *err, GObexPacket *rsp,
+                                                       gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (err != NULL)
+               d->err = g_error_copy(err);
+
+       g_main_loop_quit(d->mainloop);
+}
+
+static void test_connect(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                               { pkt_connect_req, sizeof(pkt_connect_req) } }, {
+                               { pkt_connect_rsp, sizeof(pkt_connect_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_connect(obex, req_complete, &d, &d.err, G_OBEX_HDR_INVALID);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_setpath(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_setpath_req, sizeof(pkt_setpath_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_setpath(obex, "dir", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_setpath_up(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_setpath_up_req, sizeof(pkt_setpath_up_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_setpath(obex, "..", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_setpath_up_down(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_setpath_up_down_req,
+                                       sizeof(pkt_setpath_up_down_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_setpath(obex, "../dir", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_mkdir(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_mkdir_req, sizeof(pkt_mkdir_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_mkdir(obex, "dir", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_delete(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_delete_req, sizeof(pkt_delete_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_delete(obex, "foo.txt", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_copy(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_copy_req, sizeof(pkt_copy_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_copy(obex, "foo", "bar", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+static void test_move(void)
+{
+       GIOChannel *io;
+       GIOCondition cond;
+       guint io_id, timer_id;
+       GObex *obex;
+       struct test_data d = { 0, NULL, {
+                       { pkt_move_req, sizeof(pkt_move_req) } }, {
+                       { pkt_success_rsp, sizeof(pkt_success_rsp) } } };
+
+       create_endpoints(&obex, &io, SOCK_STREAM);
+
+       cond = G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL;
+       io_id = g_io_add_watch(io, cond, test_io_cb, &d);
+
+       d.mainloop = g_main_loop_new(NULL, FALSE);
+
+       timer_id = g_timeout_add_seconds(1, test_timeout, &d);
+
+       g_obex_move(obex, "foo", "bar", req_complete, &d, &d.err);
+       g_assert_no_error(d.err);
+
+       g_main_loop_run(d.mainloop);
+
+       g_assert_cmpuint(d.count, ==, 1);
+
+       g_main_loop_unref(d.mainloop);
+
+       g_source_remove(timer_id);
+       g_io_channel_unref(io);
+       g_source_remove(io_id);
+       g_obex_unref(obex);
+
+       g_assert_no_error(d.err);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/gobex/null_io", test_null_io);
+       g_test_add_func("/gobex/basic", test_basic);
+       g_test_add_func("/gobex/ref_unref", test_ref_unref);
+
+       g_test_add_func("/gobex/test_disconnect", test_disconnect);
+
+       g_test_add_func("/gobex/test_recv_connect_stream",
+                                               test_recv_connect_stream);
+       g_test_add_func("/gobex/test_recv_connect_pkt",
+                                               test_recv_connect_pkt);
+       g_test_add_func("/gobex/test_send_connect_stream",
+                                               test_send_connect_stream);
+       g_test_add_func("/gobex/test_send_connect_pkt",
+                                               test_send_connect_pkt);
+       g_test_add_func("/gobex/test_recv_unexpected",
+                                               test_recv_unexpected);
+       g_test_add_func("/gobex/test_send_on_demand_stream",
+                                               test_send_on_demand_stream);
+       g_test_add_func("/gobex/test_send_on_demand_pkt",
+                                               test_send_on_demand_pkt);
+       g_test_add_func("/gobex/test_send_on_demand_fail_stream",
+                                       test_send_on_demand_fail_stream);
+       g_test_add_func("/gobex/test_send_on_demand_fail_pkt",
+                                       test_send_on_demand_fail_pkt);
+       g_test_add_func("/gobex/test_send_connect_req_stream",
+                                       test_send_connect_req_stream);
+       g_test_add_func("/gobex/test_send_connect_req_pkt",
+                                       test_send_connect_req_pkt);
+       g_test_add_func("/gobex/test_send_nval_connect_req_stream",
+                                       test_send_nval_connect_req_stream);
+       g_test_add_func("/gobex/test_send_nval_connect_req_pkt",
+                                       test_send_nval_connect_req_pkt);
+       g_test_add_func("/gobex/test_send_nval_connect_req_short_pkt",
+                                       test_send_nval_connect_req_short_pkt);
+       g_test_add_func("/gobex/test_send_connect_req_timeout_stream",
+                                       test_send_connect_req_timeout_stream);
+       g_test_add_func("/gobex/test_send_connect_req_timeout_pkt",
+                                       test_send_connect_req_timeout_pkt);
+
+
+       g_test_add_func("/gobex/test_cancel_req_immediate",
+                                       test_cancel_req_immediate);
+       g_test_add_func("/gobex/test_cancel_req_delay_stream",
+                                       test_cancel_req_delay_stream);
+       g_test_add_func("/gobex/test_cancel_req_delay_pkt",
+                                       test_cancel_req_delay_pkt);
+
+       g_test_add_func("/gobex/test_connect", test_connect);
+
+       g_test_add_func("/gobex/test_setpath", test_setpath);
+       g_test_add_func("/gobex/test_setpath_up", test_setpath_up);
+       g_test_add_func("/gobex/test_setpath_up_down", test_setpath_up_down);
+
+       g_test_add_func("/gobex/test_mkdir", test_mkdir);
+
+       g_test_add_func("/gobex/test_delete", test_delete);
+
+       g_test_add_func("/gobex/test_copy", test_copy);
+       g_test_add_func("/gobex/test_move", test_move);
+
+       return g_test_run();
+}
diff --git a/unit/test-lib.c b/unit/test-lib.c
new file mode 100644 (file)
index 0000000..def133a
--- /dev/null
@@ -0,0 +1,471 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2013  Intel Corporation. All rights reserved.
+ *  Copyright (C) 2013  Instituto Nokia de Tecnologia - INdT
+ *
+ *
+ *  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 <stdlib.h>
+#include <errno.h>
+
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
+static void test_sdp_get_access_protos_valid(void)
+{
+       sdp_record_t *rec;
+       sdp_list_t *aproto, *apseq, *proto[2];
+       const uint8_t u8 = 1;
+       uuid_t l2cap, rfcomm;
+       sdp_data_t *channel;
+       int err;
+
+       rec = sdp_record_alloc();
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto[0] = sdp_list_append(NULL, &l2cap);
+       apseq = sdp_list_append(NULL, proto[0]);
+
+       sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+       proto[1] = sdp_list_append(NULL, &rfcomm);
+       channel = sdp_data_alloc(SDP_UINT8, &u8);
+       proto[1] = sdp_list_append(proto[1], channel);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       aproto = sdp_list_append(NULL, apseq);
+       sdp_set_access_protos(rec, aproto);
+       sdp_set_add_access_protos(rec, aproto);
+       sdp_data_free(channel);
+       sdp_list_free(proto[0], NULL);
+       sdp_list_free(proto[1], NULL);
+       sdp_list_free(apseq, NULL);
+       sdp_list_free(aproto, NULL);
+
+       err = sdp_get_access_protos(rec, &aproto);
+       g_assert(err == 0);
+       sdp_list_foreach(aproto, (sdp_list_func_t) sdp_list_free, NULL);
+       sdp_list_free(aproto, NULL);
+
+       err = sdp_get_add_access_protos(rec, &aproto);
+       g_assert(err == 0);
+       sdp_list_foreach(aproto, (sdp_list_func_t) sdp_list_free, NULL);
+       sdp_list_free(aproto, NULL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_access_protos_nodata(void)
+{
+       sdp_record_t *rec;
+       sdp_list_t *aproto;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       err = sdp_get_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == ENODATA);
+
+       err = sdp_get_add_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == ENODATA);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_access_protos_invalid_dtd1(void)
+{
+       const uint32_t u32 = 0xdeadbeeb;
+       sdp_record_t *rec;
+       sdp_list_t *aproto;
+       sdp_data_t *data;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       data = sdp_data_alloc(SDP_UINT32, &u32);
+       g_assert(data != NULL);
+       sdp_attr_replace(rec, SDP_ATTR_PROTO_DESC_LIST, data);
+
+       err = sdp_get_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == EINVAL);
+
+       data = sdp_data_alloc(SDP_UINT32, &u32);
+       g_assert(data != NULL);
+       sdp_attr_replace(rec, SDP_ATTR_ADD_PROTO_DESC_LIST, data);
+
+       err = sdp_get_add_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_access_protos_invalid_dtd2(void)
+{
+       uint8_t dtd = SDP_UINT8, u8 = 0xff;
+       void *dtds = &dtd, *values = &u8;
+       sdp_record_t *rec;
+       sdp_list_t *aproto;
+       sdp_data_t *data;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       data = sdp_seq_alloc(&dtds, &values, 1);
+       g_assert(data != NULL);
+       sdp_attr_replace(rec, SDP_ATTR_PROTO_DESC_LIST, data);
+
+       err = sdp_get_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == EINVAL);
+
+       data = sdp_seq_alloc(&dtds, &values, 1);
+       g_assert(data != NULL);
+       sdp_attr_replace(rec, SDP_ATTR_ADD_PROTO_DESC_LIST, data);
+
+       err = sdp_get_add_access_protos(rec, &aproto);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_lang_attr_valid(void)
+{
+       sdp_record_t *rec;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+       sdp_add_lang_attr(rec);
+
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == 0);
+
+       sdp_list_free(list, free);
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_lang_attr_nodata(void)
+{
+       sdp_record_t *rec;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == ENODATA);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_lang_attr_invalid_dtd(void)
+{
+       uint8_t dtd1 = SDP_UINT16, dtd2 = SDP_UINT32;
+       uint32_t u32 = 0xdeadbeeb;
+       uint16_t u16 = 0x1234;
+       void *dtds1[] = { &dtd1, &dtd2, &dtd2 };
+       void *values1[] = { &u16, &u32, &u32 };
+       void *dtds2[] = { &dtd1, &dtd1, &dtd2 };
+       void *values2[] = { &u16, &u16, &u32 };
+       sdp_record_t *rec;
+       sdp_data_t *data;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       /* UINT32 */
+       data = sdp_data_alloc(SDP_UINT32, &u32);
+       g_assert(data != NULL);
+       sdp_attr_add(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, data);
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(UINT32) */
+       data = sdp_seq_alloc(&dtds1[1], &values1[1], 1);
+       sdp_attr_replace(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, data);
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(UINT16, UINT16) */
+       data = sdp_seq_alloc(dtds2, values2, 2);
+       sdp_attr_replace(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, data);
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(UINT16, UINT32, UINT32) */
+       data = sdp_seq_alloc(dtds1, values1, 3);
+       sdp_attr_replace(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, data);
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(UINT16, UINT16, UINT32) */
+       data = sdp_seq_alloc(dtds2, values2, 3);
+       sdp_attr_replace(rec, SDP_ATTR_LANG_BASE_ATTR_ID_LIST, data);
+       err = sdp_get_lang_attr(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_profile_descs_valid(void)
+{
+       sdp_profile_desc_t profile;
+       sdp_record_t *rec;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       sdp_uuid16_create(&profile.uuid, NAP_PROFILE_ID);
+       profile.version = 0x0100;
+       list = sdp_list_append(NULL, &profile);
+       err = sdp_set_profile_descs(rec, list);
+       sdp_list_free(list, NULL);
+       g_assert(err == 0);
+
+       list = NULL;
+       err = sdp_get_profile_descs(rec, &list);
+       sdp_list_free(list, free);
+       g_assert(err == 0 && list != NULL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_profile_descs_nodata(void)
+{
+       sdp_record_t *rec;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == ENODATA);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_profile_descs_invalid_dtd(void)
+{
+       uint8_t dtd1 = SDP_UUID16, dtd2 = SDP_UINT32;
+       uint32_t u32 = 0xdeadbeeb;
+       uint16_t u16 = 0x1234;
+       void *dtds[1], *values[1];
+       void *dtds2[] = { &dtd1, &dtd2 };
+       void *values2[] = { &u16, &u32 };
+       sdp_record_t *rec;
+       sdp_data_t *data;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       /* UINT32 */
+       data = sdp_data_alloc(SDP_UINT32, &u32);
+       g_assert(data != NULL);
+       sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8() */
+       data = sdp_seq_alloc(NULL, NULL, 0);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(UINT32) */
+       data = sdp_seq_alloc(&dtds2[1], &values2[1], 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(SEQ8()) */
+       data = sdp_seq_alloc(NULL, NULL, 0);
+       dtds[0] = &data->dtd;
+       values[0] = data;
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(SEQ8(UINT32)) */
+       data = sdp_seq_alloc(&dtds2[1], &values2[1], 1);
+       dtds[0] = &data->dtd;
+       values[0] = data;
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(SEQ8(UUID16)) */
+       data = sdp_seq_alloc(dtds2, values2, 1);
+       dtds[0] = &data->dtd;
+       values[0] = data;
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* SEQ8(SEQ8(UUID16, UINT32)) */
+       data = sdp_seq_alloc(dtds2, values2, 2);
+       dtds[0] = &data->dtd;
+       values[0] = data;
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_profile_descs_workaround(void)
+{
+       uint8_t dtd1 = SDP_UUID16, dtd2 = SDP_UINT16, dtd3 = SDP_UINT32;
+       uint16_t u16 = 0x1234;
+       uint32_t u32 = 0xdeadbeeb;
+       void *dtds[] = { &dtd1, &dtd2 };
+       void *values[] = { &u16, &u16 };
+       void *dtds2[] = { &dtd1, &dtd3 };
+       void *values2[] = { &u16, &u32 };
+       sdp_record_t *rec;
+       sdp_data_t *data;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       /* SEQ8(UUID16) */
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_add(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       list = NULL;
+       err = sdp_get_profile_descs(rec, &list);
+       sdp_list_free(list, free);
+       g_assert(err == 0 && list != NULL);
+
+       /* SEQ8(UUID16, UINT16) */
+       data = sdp_seq_alloc(dtds, values, 2);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       list = NULL;
+       err = sdp_get_profile_descs(rec, &list);
+       sdp_list_free(list, free);
+       g_assert(err == 0 && list != NULL);
+
+       /* SEQ8(UUID16) */
+       data = sdp_seq_alloc(dtds, values, 1);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       list = NULL;
+       err = sdp_get_profile_descs(rec, &list);
+       sdp_list_free(list, free);
+       g_assert(err == 0 && list != NULL);
+
+       /* SEQ8(UUID16, UINT32) */
+       data = sdp_seq_alloc(dtds2, values2, 2);
+       sdp_attr_replace(rec, SDP_ATTR_PFILE_DESC_LIST, data);
+       list = NULL;
+       err = sdp_get_profile_descs(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+static void test_sdp_get_server_ver(void)
+{
+       uint16_t u16 = 0x1234;
+       uint32_t u32 = 0xdeadbeeb;
+       uint8_t dtd1 = SDP_UINT16, dtd2 = SDP_UINT32;
+       void *dtds1[] = { &dtd1 };
+       void *values1[] = { &u16 };
+       void *dtds2[] = { &dtd2 };
+       void *values2[] = { &u32 };
+       sdp_record_t *rec;
+       sdp_data_t *data;
+       sdp_list_t *list;
+       int err;
+
+       rec = sdp_record_alloc();
+
+       err = sdp_get_server_ver(rec, &list);
+       g_assert(err == -1 && errno == ENODATA);
+
+       /* Valid DTD */
+       data = sdp_seq_alloc(dtds1, values1, 1);
+       sdp_attr_add(rec, SDP_ATTR_VERSION_NUM_LIST, data);
+       err = sdp_get_server_ver(rec, &list);
+       g_assert(err == 0 && list != NULL);
+       sdp_list_free(list, NULL);
+
+       /* Invalid: UINT32 */
+       data = sdp_data_alloc(SDP_UINT32, &u32);
+       sdp_attr_replace(rec, SDP_ATTR_VERSION_NUM_LIST, data);
+       err = sdp_get_server_ver(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* Invalid: SEQ8() */
+       data = sdp_seq_alloc(NULL, NULL, 0);
+       sdp_attr_replace(rec, SDP_ATTR_VERSION_NUM_LIST, data);
+       err = sdp_get_server_ver(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       /* Invalid: SEQ8(UINT32) */
+       data = sdp_seq_alloc(dtds2, values2, 1);
+       sdp_attr_replace(rec, SDP_ATTR_VERSION_NUM_LIST, data);
+       err = sdp_get_server_ver(rec, &list);
+       g_assert(err == -1 && errno == EINVAL);
+
+       sdp_record_free(rec);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/lib/sdp_get_access_protos/valid",
+                                       test_sdp_get_access_protos_valid);
+       g_test_add_func("/lib/sdp_get_access_protos/nodata",
+                                       test_sdp_get_access_protos_nodata);
+       g_test_add_func("/lib/sdp_get_access_protos/invalid_dtd1",
+                               test_sdp_get_access_protos_invalid_dtd1);
+       g_test_add_func("/lib/sdp_get_access_protos/invalid_dtd2",
+                               test_sdp_get_access_protos_invalid_dtd2);
+
+       g_test_add_func("/lib/sdp_get_lang_attr/valid",
+                                               test_sdp_get_lang_attr_valid);
+       g_test_add_func("/lib/sdp_get_lang_attr/nodata",
+                                               test_sdp_get_lang_attr_nodata);
+       g_test_add_func("/lib/sdp_get_lang_attr/invalid_dtd",
+                                       test_sdp_get_lang_attr_invalid_dtd);
+
+       g_test_add_func("/lib/sdp_get_profile_descs/valid",
+                                       test_sdp_get_profile_descs_valid);
+       g_test_add_func("/lib/sdp_get_profile_descs/nodata",
+                                       test_sdp_get_profile_descs_nodata);
+       g_test_add_func("/lib/sdp_get_profile_descs/invalid_dtd",
+                                       test_sdp_get_profile_descs_invalid_dtd);
+       /* Test for workaround commented on sdp_get_profile_descs() */
+       g_test_add_func("/lib/sdp_get_profile_descs/workaround",
+                                       test_sdp_get_profile_descs_workaround);
+
+       g_test_add_func("/lib/sdp_get_server_ver", test_sdp_get_server_ver);
+
+       return g_test_run();
+}
diff --git a/unit/test-mgmt.c b/unit/test-mgmt.c
new file mode 100644 (file)
index 0000000..f9dcb00
--- /dev/null
@@ -0,0 +1,243 @@
+/*
+ *
+ *  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 <stdbool.h>
+#include <unistd.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/mgmt.h"
+
+#include "src/shared/mgmt.h"
+
+struct context {
+       GMainLoop *main_loop;
+       struct mgmt *mgmt_client;
+       guint server_source;
+       GList *handler_list;
+};
+
+enum action {
+       ACTION_PASSED,
+       ACTION_IGNORE,
+};
+
+struct handler {
+       const void *cmd_data;
+       uint16_t cmd_size;
+       bool match_prefix;
+       enum action action;
+};
+
+static void mgmt_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       g_print("%s%s\n", prefix, str);
+}
+
+static void context_quit(struct context *context)
+{
+       g_main_loop_quit(context->main_loop);
+}
+
+static void check_actions(struct context *context,
+                                       const void *data, uint16_t size)
+{
+       GList *list;
+
+       for (list = g_list_first(context->handler_list); list;
+                                               list = g_list_next(list)) {
+               struct handler *handler = list->data;
+
+               if (handler->match_prefix) {
+                       if (size < handler->cmd_size)
+                               continue;
+               } else {
+                       if (size != handler->cmd_size)
+                               continue;
+               }
+
+               if (memcmp(data, handler->cmd_data, handler->cmd_size))
+                       continue;
+
+               switch (handler->action) {
+               case ACTION_PASSED:
+                       context_quit(context);
+                       return;
+               case ACTION_IGNORE:
+                       return;
+               }
+       }
+
+       g_test_message("Command not handled\n");
+       g_assert_not_reached();
+}
+
+static gboolean server_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct context *context = user_data;
+       unsigned char buf[512];
+       ssize_t result;
+       int fd;
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       result = read(fd, buf, sizeof(buf));
+       if (result < 0)
+               return FALSE;
+
+       check_actions(context, buf, result);
+
+       return TRUE;
+}
+
+static struct context *create_context(void)
+{
+       struct context *context = g_new0(struct context, 1);
+       GIOChannel *channel;
+       int err, sv[2];
+
+       context->main_loop = g_main_loop_new(NULL, FALSE);
+       g_assert(context->main_loop);
+
+       err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+       g_assert(err == 0);
+
+       channel = g_io_channel_unix_new(sv[0]);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       context->server_source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               server_handler, context);
+       g_assert(context->server_source > 0);
+
+       g_io_channel_unref(channel);
+
+       context->mgmt_client = mgmt_new(sv[1]);
+       g_assert(context->mgmt_client);
+
+       if (g_test_verbose() == TRUE)
+               mgmt_set_debug(context->mgmt_client,
+                                       mgmt_debug, "mgmt: ", NULL);
+
+       mgmt_set_close_on_unref(context->mgmt_client, true);
+
+       return context;
+}
+
+static void execute_context(struct context *context)
+{
+       g_main_loop_run(context->main_loop);
+
+       g_list_free_full(context->handler_list, g_free);
+
+       g_source_remove(context->server_source);
+
+       mgmt_unref(context->mgmt_client);
+
+       g_main_loop_unref(context->main_loop);
+
+       g_free(context);
+}
+
+static void add_action(struct context *context,
+                               const void *cmd_data, uint16_t cmd_size,
+                               bool match_prefix, enum action action)
+{
+       struct handler *handler = g_new0(struct handler, 1);
+
+       handler->cmd_data = cmd_data;
+       handler->cmd_size = cmd_size;
+       handler->match_prefix = match_prefix;
+       handler->action = action;
+
+       context->handler_list = g_list_append(context->handler_list, handler);
+}
+
+struct command_test_data {
+       uint16_t opcode;
+       uint16_t index;
+       uint16_t length;
+       const void *param;
+       const void *cmd_data;
+       uint16_t cmd_size;
+};
+
+static const unsigned char read_version_command[] =
+                               { 0x01, 0x00, 0xff, 0xff, 0x00, 0x00 };
+
+static const struct command_test_data command_test_1 = {
+       .opcode = MGMT_OP_READ_VERSION,
+       .index = MGMT_INDEX_NONE,
+       .cmd_data = read_version_command,
+       .cmd_size = sizeof(read_version_command),
+};
+
+static const unsigned char read_info_command[] =
+                               { 0x04, 0x00, 0x00, 0x02, 0x00, 0x00 };
+
+static const struct command_test_data command_test_2 = {
+       .opcode = MGMT_OP_READ_INFO,
+       .index = 512,
+       .cmd_data = read_info_command,
+       .cmd_size = sizeof(read_info_command),
+};
+
+static void test_command(gconstpointer data)
+{
+       const struct command_test_data *test = data;
+       struct context *context = create_context();
+
+       add_action(context, test->cmd_data, test->cmd_size,
+                                               false, ACTION_PASSED);
+
+       mgmt_send(context->mgmt_client, test->opcode, test->index,
+                                       test->length, test->param,
+                                               NULL ,NULL, NULL);
+
+       execute_context(context);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_data_func("/mgmt/command/1", &command_test_1, test_command);
+       g_test_add_data_func("/mgmt/command/2", &command_test_2, test_command);
+
+       return g_test_run();
+}
diff --git a/unit/test-sdp.c b/unit/test-sdp.c
new file mode 100644 (file)
index 0000000..6d699e2
--- /dev/null
@@ -0,0 +1,2828 @@
+/*
+ *
+ *  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 <unistd.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <sys/socket.h>
+
+#include <glib.h>
+
+#include "lib/bluetooth.h"
+#include "lib/sdp.h"
+#include "lib/sdp_lib.h"
+
+#include "src/shared/util.h"
+#include "src/sdpd.h"
+
+struct sdp_pdu {
+       bool valid;
+       const void *raw_data;
+       size_t raw_size;
+       uint8_t cont_len;
+};
+
+struct test_data {
+       int mtu;
+       struct sdp_pdu *pdu_list;
+};
+
+#define raw_data(args...) ((const unsigned char[]) { args })
+#define build_u128(args...) ((const uint128_t) { .data = { args } })
+
+#define raw_pdu(args...) \
+       {                                                       \
+               .valid = true,                                  \
+               .raw_data = raw_data(args),                     \
+               .raw_size = sizeof(raw_data(args)),             \
+       }
+
+#define raw_pdu_cont(cont, args...) \
+       {                                                       \
+               .valid = true,                                  \
+               .raw_data = raw_data(args),                     \
+               .raw_size = sizeof(raw_data(args)),             \
+               .cont_len = cont,                               \
+       }
+
+#define define_test(name, _mtu, args...) \
+       do {                                                            \
+               const struct sdp_pdu pdus[] = {                         \
+                       args, { }, { }                                  \
+               };                                                      \
+               static struct test_data data;                           \
+               data.mtu = _mtu;                                        \
+               data.pdu_list = g_malloc(sizeof(pdus));                 \
+               memcpy(data.pdu_list, pdus, sizeof(pdus));              \
+               g_test_add_data_func(name, &data, test_sdp);            \
+       } while (0)
+
+#define define_ss(name, args...) define_test("/TP/SERVER/SS/" name, 48, args)
+#define define_sa(name, args...) define_test("/TP/SERVER/SA/" name, 48, args)
+#define define_ssa(name, args...) define_test("/TP/SERVER/SSA/" name, 48, args)
+#define define_brw(name, args...) define_test("/TP/SERVER/BRW/" name, 672, args)
+
+/* SDP Data Element (DE) tests */
+struct test_data_de {
+       const void *input_data;
+       size_t input_size;
+       sdp_data_t expected;
+};
+
+#define exp_data(_dtd, val_type, val_data) \
+       ((const sdp_data_t) {                   \
+               .dtd = _dtd,                    \
+               .val.val_type = val_data,       \
+       })
+
+#define define_test_de_attr(name, input, exp) \
+       do {                                                            \
+               static struct test_data_de data;                        \
+               data.input_data = input;                                \
+               data.input_size = sizeof(input);                        \
+               data.expected = exp;                                    \
+               g_test_add_data_func("/sdp/DE/ATTR/" name, &data,       \
+                                               test_sdp_de_attr);      \
+       } while (0)
+
+struct context {
+       GMainLoop *main_loop;
+       guint server_source;
+       guint client_source;
+       int fd;
+       int mtu;
+       uint8_t cont_data[16];
+       uint8_t cont_size;
+       unsigned int pdu_offset;
+       const struct sdp_pdu *pdu_list;
+};
+
+static void sdp_debug(const char *str, void *user_data)
+{
+       const char *prefix = user_data;
+
+       g_print("%s%s\n", prefix, str);
+}
+
+void btd_debug(const char *format, ...);
+
+void btd_debug(const char *format, ...)
+{
+}
+
+static void context_quit(struct context *context)
+{
+       g_main_loop_quit(context->main_loop);
+}
+
+static gboolean server_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct context *context = user_data;
+       sdp_pdu_hdr_t hdr;
+       void *buf;
+       size_t size;
+       ssize_t len;
+       int fd;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP)) {
+               sdp_svcdb_collect_all(fd);
+               return FALSE;
+       }
+
+       len = recv(fd, &hdr, sizeof(sdp_pdu_hdr_t), MSG_PEEK);
+       if (len != sizeof(sdp_pdu_hdr_t)) {
+               sdp_svcdb_collect_all(fd);
+               return FALSE;
+       }
+
+       size = sizeof(sdp_pdu_hdr_t) + ntohs(hdr.plen);
+
+       buf = malloc(size);
+       if (!buf)
+               return TRUE;
+
+       len = recv(fd, buf, size, 0);
+       if (len <= 0) {
+               sdp_svcdb_collect_all(fd);
+               free(buf);
+               return FALSE;
+       }
+
+       if (g_test_verbose() == TRUE)
+               util_hexdump('<', buf, len, sdp_debug, "SDP: ");
+
+       handle_internal_request(fd, context->mtu, buf, len);
+
+       return TRUE;
+}
+
+static gboolean send_pdu(gpointer user_data)
+{
+       struct context *context = user_data;
+       const struct sdp_pdu *req_pdu;
+       uint16_t pdu_len;
+       unsigned char *buf;
+       ssize_t len;
+
+       req_pdu = &context->pdu_list[context->pdu_offset];
+
+       pdu_len = req_pdu->raw_size + context->cont_size;
+
+       buf = g_malloc0(pdu_len);
+
+       memcpy(buf, req_pdu->raw_data, req_pdu->raw_size);
+
+       if (context->cont_size > 0)
+               memcpy(buf + req_pdu->raw_size, context->cont_data,
+                                                       context->cont_size);
+
+       len = write(context->fd, buf, pdu_len);
+
+       g_free(buf);
+
+       g_assert(len == pdu_len);
+
+       return FALSE;
+}
+
+static void context_increment(struct context *context)
+{
+       context->pdu_offset += 2;
+
+       if (!context->pdu_list[context->pdu_offset].valid) {
+               context_quit(context);
+               return;
+       }
+
+       g_idle_add(send_pdu, context);
+}
+
+static gboolean client_handler(GIOChannel *channel, GIOCondition cond,
+                                                       gpointer user_data)
+{
+       struct context *context = user_data;
+       const struct sdp_pdu *rsp_pdu;
+       unsigned char buf[512];
+       ssize_t len;
+       int fd;
+
+       rsp_pdu = &context->pdu_list[context->pdu_offset + 1];
+
+       if (cond & (G_IO_NVAL | G_IO_ERR | G_IO_HUP))
+               return FALSE;
+
+       fd = g_io_channel_unix_get_fd(channel);
+
+       len = read(fd, buf, sizeof(buf));
+       if (len < 0)
+               return FALSE;
+
+       if (g_test_verbose() == TRUE)
+               util_hexdump('>', buf, len, sdp_debug, "SDP: ");
+
+       g_assert(len > 0);
+       g_assert((size_t) len == rsp_pdu->raw_size + rsp_pdu->cont_len);
+
+       g_assert(memcmp(buf, rsp_pdu->raw_data, rsp_pdu->raw_size) == 0);
+
+       if (rsp_pdu->cont_len > 0)
+               memcpy(context->cont_data, buf + rsp_pdu->raw_size,
+                                                       rsp_pdu->cont_len);
+
+       context->cont_size = rsp_pdu->cont_len;
+
+       context_increment(context);
+
+       return TRUE;
+}
+
+static void update_db_timestamp(void)
+{
+}
+
+static void register_serial_port(void)
+{
+       sdp_list_t *svclass_id, *apseq, *proto[2], *profiles, *root, *aproto;
+       uuid_t root_uuid, sp_uuid, l2cap, rfcomm;
+       sdp_profile_desc_t profile;
+       uint8_t u8 = 1;
+       sdp_data_t *sdp_data, *channel;
+       sdp_record_t *record = sdp_record_alloc();
+
+       record->handle = sdp_next_handle();
+
+       sdp_record_add(BDADDR_ANY, record);
+       sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+       sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+       sdp_list_free(root, 0);
+
+       sdp_uuid16_create(&sp_uuid, SERIAL_PORT_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &sp_uuid);
+       sdp_set_service_classes(record, svclass_id);
+       sdp_list_free(svclass_id, 0);
+
+       sdp_uuid16_create(&profile.uuid, SERIAL_PORT_PROFILE_ID);
+       profile.version = 0x0100;
+       profiles = sdp_list_append(0, &profile);
+       sdp_set_profile_descs(record, profiles);
+       sdp_list_free(profiles, 0);
+
+       sdp_uuid16_create(&l2cap, L2CAP_UUID);
+       proto[0] = sdp_list_append(0, &l2cap);
+       apseq = sdp_list_append(0, proto[0]);
+
+       sdp_uuid16_create(&rfcomm, RFCOMM_UUID);
+       proto[1] = sdp_list_append(0, &rfcomm);
+       channel = sdp_data_alloc(SDP_UINT8, &u8);
+       proto[1] = sdp_list_append(proto[1], channel);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       sdp_add_lang_attr(record);
+
+       sdp_set_info_attr(record, "Serial Port", "BlueZ", "COM Port");
+
+       sdp_set_url_attr(record, "http://www.bluez.org/",
+                       "http://www.bluez.org/", "http://www.bluez.org/");
+
+       sdp_set_service_id(record, sp_uuid);
+       sdp_set_service_ttl(record, 0xffff);
+       sdp_set_service_avail(record, 0xff);
+       sdp_set_record_state(record, 0x00001234);
+
+       sdp_data_free(channel);
+       sdp_list_free(proto[0], 0);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto, 0);
+
+       update_db_timestamp();
+}
+
+static void register_object_push(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+       uuid_t root_uuid, opush_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto, *proto[3];
+       uint8_t chan = 9;
+       sdp_data_t *channel;
+       uint8_t formats[] = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0xff };
+       void *dtds[sizeof(formats)], *values[sizeof(formats)];
+       unsigned int i;
+       uint8_t dtd = SDP_UINT8;
+       sdp_data_t *sdp_data, *sflist;
+       sdp_record_t *record = sdp_record_alloc();
+
+       record->handle = sdp_next_handle();
+
+       sdp_record_add(BDADDR_ANY, record);
+       sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+       sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       sdp_uuid16_create(&opush_uuid, OBEX_OBJPUSH_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &opush_uuid);
+       sdp_set_service_classes(record, svclass_id);
+
+       sdp_uuid16_create(&profile[0].uuid, OBEX_OBJPUSH_PROFILE_ID);
+       profile[0].version = 0x0100;
+       pfseq = sdp_list_append(0, profile);
+       sdp_set_profile_descs(record, pfseq);
+
+       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+       proto[0] = sdp_list_append(0, &l2cap_uuid);
+       apseq = sdp_list_append(0, proto[0]);
+
+       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+       proto[1] = sdp_list_append(0, &rfcomm_uuid);
+       channel = sdp_data_alloc(SDP_UINT8, &chan);
+       proto[1] = sdp_list_append(proto[1], channel);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+       proto[2] = sdp_list_append(0, &obex_uuid);
+       apseq = sdp_list_append(apseq, proto[2]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       for (i = 0; i < sizeof(formats); i++) {
+               dtds[i] = &dtd;
+               values[i] = &formats[i];
+       }
+       sflist = sdp_seq_alloc(dtds, values, sizeof(formats));
+       sdp_attr_add(record, SDP_ATTR_SUPPORTED_FORMATS_LIST, sflist);
+
+       sdp_set_info_attr(record, "OBEX Object Push", 0, 0);
+
+       sdp_data_free(channel);
+       sdp_list_free(root, 0);
+       sdp_list_free(svclass_id, 0);
+       sdp_list_free(pfseq, 0);
+       sdp_list_free(proto[0], 0);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(proto[2], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto, 0);
+
+       update_db_timestamp();
+}
+
+static void register_hid_keyboard(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+       uuid_t root_uuid, hidkb_uuid, l2cap_uuid, hidp_uuid;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto, *proto[3];
+       sdp_data_t *psm, *lang_lst, *lang_lst2, *hid_spec_lst, *hid_spec_lst2;
+       unsigned int i;
+       uint8_t dtd = SDP_UINT16;
+       uint8_t dtd2 = SDP_UINT8;
+       uint8_t dtd_data = SDP_TEXT_STR8;
+       void *dtds[2];
+       void *values[2];
+       void *dtds2[2];
+       void *values2[2];
+       int leng[2];
+       uint8_t hid_spec_type = 0x22;
+       uint16_t hid_attr_lang[] = { 0x409, 0x100 };
+       static const uint16_t ctrl = 0x11;
+       static const uint16_t intr = 0x13;
+       static const uint16_t hid_attr[] = { 0x100, 0x111, 0x40, 0x0d,
+                                                               0x01, 0x01 };
+       static const uint16_t hid_attr2[] = { 0x0, 0x01, 0x100, 0x1f40,
+                                                               0x01, 0x01 };
+       const uint8_t hid_spec[] = {
+               0x05, 0x01, // usage page
+               0x09, 0x06, // keyboard
+               0xa1, 0x01, // key codes
+               0x85, 0x01, // minimum
+               0x05, 0x07, // max
+               0x19, 0xe0, // logical min
+               0x29, 0xe7, // logical max
+               0x15, 0x00, // report size
+               0x25, 0x01, // report count
+               0x75, 0x01, // input data variable absolute
+               0x95, 0x08, // report count
+               0x81, 0x02, // report size
+               0x75, 0x08,
+               0x95, 0x01,
+               0x81, 0x01,
+               0x75, 0x01,
+               0x95, 0x05,
+               0x05, 0x08,
+               0x19, 0x01,
+               0x29, 0x05,
+               0x91, 0x02,
+               0x75, 0x03,
+               0x95, 0x01,
+               0x91, 0x01,
+               0x75, 0x08,
+               0x95, 0x06,
+               0x15, 0x00,
+               0x26, 0xff,
+               0x00, 0x05,
+               0x07, 0x19,
+               0x00, 0x2a,
+               0xff, 0x00,
+               0x81, 0x00,
+               0x75, 0x01,
+               0x95, 0x01,
+               0x15, 0x00,
+               0x25, 0x01,
+               0x05, 0x0c,
+               0x09, 0xb8,
+               0x81, 0x06,
+               0x09, 0xe2,
+               0x81, 0x06,
+               0x09, 0xe9,
+               0x81, 0x02,
+               0x09, 0xea,
+               0x81, 0x02,
+               0x75, 0x01,
+               0x95, 0x04,
+               0x81, 0x01,
+               0xc0         // end tag
+       };
+       sdp_data_t *sdp_data;
+       sdp_record_t *record = sdp_record_alloc();
+
+       record->handle = sdp_next_handle();
+
+       sdp_record_add(BDADDR_ANY, record);
+       sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+       sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+       sdp_list_free(root, 0);
+
+       sdp_add_lang_attr(record);
+
+       sdp_uuid16_create(&hidkb_uuid, HID_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &hidkb_uuid);
+       sdp_set_service_classes(record, svclass_id);
+       sdp_list_free(svclass_id, 0);
+
+       sdp_uuid16_create(&profile[0].uuid, HID_PROFILE_ID);
+       profile[0].version = 0x0100;
+       pfseq = sdp_list_append(0, profile);
+       sdp_set_profile_descs(record, pfseq);
+       sdp_list_free(pfseq, 0);
+
+       /* protocols */
+       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+       proto[1] = sdp_list_append(0, &l2cap_uuid);
+       psm = sdp_data_alloc(SDP_UINT16, &ctrl);
+       proto[1] = sdp_list_append(proto[1], psm);
+       apseq = sdp_list_append(0, proto[1]);
+
+       sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+       proto[2] = sdp_list_append(0, &hidp_uuid);
+       apseq = sdp_list_append(apseq, proto[2]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       sdp_data_free(psm);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(proto[2], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto, 0);
+
+       /* additional protocols */
+       proto[1] = sdp_list_append(0, &l2cap_uuid);
+       psm = sdp_data_alloc(SDP_UINT16, &intr);
+       proto[1] = sdp_list_append(proto[1], psm);
+       apseq = sdp_list_append(0, proto[1]);
+
+       sdp_uuid16_create(&hidp_uuid, HIDP_UUID);
+       proto[2] = sdp_list_append(0, &hidp_uuid);
+       apseq = sdp_list_append(apseq, proto[2]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_add_access_protos(record, aproto);
+
+       sdp_data_free(psm);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(proto[2], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto, 0);
+
+       sdp_set_info_attr(record, "HID Keyboard", NULL, NULL);
+
+       for (i = 0; i < sizeof(hid_attr) / 2; i++)
+               sdp_attr_add_new(record,
+                               SDP_ATTR_HID_DEVICE_RELEASE_NUMBER + i,
+                               SDP_UINT16, &hid_attr[i]);
+
+       dtds[0] = &dtd2;
+       values[0] = &hid_spec_type;
+       dtds[1] = &dtd_data;
+       values[1] = (uint8_t *) hid_spec;
+       leng[0] = 0;
+       leng[1] = sizeof(hid_spec);
+       hid_spec_lst = sdp_seq_alloc_with_length(dtds, values, leng, 2);
+       hid_spec_lst2 = sdp_data_alloc(SDP_SEQ8, hid_spec_lst);
+       sdp_attr_add(record, SDP_ATTR_HID_DESCRIPTOR_LIST, hid_spec_lst2);
+
+       for (i = 0; i < sizeof(hid_attr_lang) / 2; i++) {
+               dtds2[i] = &dtd;
+               values2[i] = &hid_attr_lang[i];
+       }
+
+       lang_lst = sdp_seq_alloc(dtds2, values2, sizeof(hid_attr_lang) / 2);
+       lang_lst2 = sdp_data_alloc(SDP_SEQ8, lang_lst);
+       sdp_attr_add(record, SDP_ATTR_HID_LANG_ID_BASE_LIST, lang_lst2);
+
+       sdp_attr_add_new(record, SDP_ATTR_HID_SDP_DISABLE,
+                                               SDP_UINT16, &hid_attr2[0]);
+
+       for (i = 0; i < sizeof(hid_attr2) / 2 - 1; i++)
+               sdp_attr_add_new(record, SDP_ATTR_HID_REMOTE_WAKEUP + i,
+                                               SDP_UINT16, &hid_attr2[i + 1]);
+
+       update_db_timestamp();
+}
+
+static void register_file_transfer(void)
+{
+       sdp_list_t *svclass_id, *pfseq, *apseq, *root;
+       uuid_t root_uuid, ftrn_uuid, l2cap_uuid, rfcomm_uuid, obex_uuid;
+       sdp_profile_desc_t profile[1];
+       sdp_list_t *aproto, *proto[3];
+       uint8_t u8 = 10;
+       sdp_data_t *sdp_data, *channel;
+       sdp_record_t *record = sdp_record_alloc();
+
+       record->handle = sdp_next_handle();
+
+       sdp_record_add(BDADDR_ANY, record);
+       sdp_data = sdp_data_alloc(SDP_UINT32, &record->handle);
+       sdp_attr_add(record, SDP_ATTR_RECORD_HANDLE, sdp_data);
+
+       sdp_uuid16_create(&root_uuid, PUBLIC_BROWSE_GROUP);
+       root = sdp_list_append(0, &root_uuid);
+       sdp_set_browse_groups(record, root);
+
+       sdp_uuid16_create(&ftrn_uuid, OBEX_FILETRANS_SVCLASS_ID);
+       svclass_id = sdp_list_append(0, &ftrn_uuid);
+       sdp_set_service_classes(record, svclass_id);
+
+       sdp_uuid16_create(&profile[0].uuid, OBEX_FILETRANS_PROFILE_ID);
+       profile[0].version = 0x0100;
+       pfseq = sdp_list_append(0, &profile[0]);
+       sdp_set_profile_descs(record, pfseq);
+
+       sdp_uuid16_create(&l2cap_uuid, L2CAP_UUID);
+       proto[0] = sdp_list_append(0, &l2cap_uuid);
+       apseq = sdp_list_append(0, proto[0]);
+
+       sdp_uuid16_create(&rfcomm_uuid, RFCOMM_UUID);
+       proto[1] = sdp_list_append(0, &rfcomm_uuid);
+       channel = sdp_data_alloc(SDP_UINT8, &u8);
+       proto[1] = sdp_list_append(proto[1], channel);
+       apseq = sdp_list_append(apseq, proto[1]);
+
+       sdp_uuid16_create(&obex_uuid, OBEX_UUID);
+       proto[2] = sdp_list_append(0, &obex_uuid);
+       apseq = sdp_list_append(apseq, proto[2]);
+
+       aproto = sdp_list_append(0, apseq);
+       sdp_set_access_protos(record, aproto);
+
+       sdp_set_info_attr(record, "OBEX File Transfer", 0, 0);
+
+       sdp_data_free(channel);
+       sdp_list_free(root, 0);
+       sdp_list_free(svclass_id, 0);
+       sdp_list_free(pfseq, 0);
+       sdp_list_free(proto[0], 0);
+       sdp_list_free(proto[1], 0);
+       sdp_list_free(proto[2], 0);
+       sdp_list_free(apseq, 0);
+       sdp_list_free(aproto, 0);
+
+       update_db_timestamp();
+}
+
+static struct context *create_context(void)
+{
+       struct context *context = g_new0(struct context, 1);
+       GIOChannel *channel;
+       int err, sv[2];
+
+       context->main_loop = g_main_loop_new(NULL, FALSE);
+       g_assert(context->main_loop);
+
+       err = socketpair(AF_UNIX, SOCK_SEQPACKET | SOCK_CLOEXEC, 0, sv);
+       g_assert(err == 0);
+
+       channel = g_io_channel_unix_new(sv[0]);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       context->server_source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               server_handler, context);
+       g_assert(context->server_source > 0);
+
+       g_io_channel_unref(channel);
+
+       channel = g_io_channel_unix_new(sv[1]);
+
+       g_io_channel_set_close_on_unref(channel, TRUE);
+       g_io_channel_set_encoding(channel, NULL, NULL);
+       g_io_channel_set_buffered(channel, FALSE);
+
+       context->client_source = g_io_add_watch(channel,
+                               G_IO_IN | G_IO_HUP | G_IO_ERR | G_IO_NVAL,
+                               client_handler, context);
+       g_assert(context->client_source > 0);
+
+       g_io_channel_unref(channel);
+
+       context->fd = sv[1];
+
+       set_fixed_db_timestamp(0x496f0654);
+
+       register_public_browse_group();
+       register_server_service();
+
+       register_serial_port();
+       register_object_push();
+       register_hid_keyboard();
+       register_file_transfer();
+       register_file_transfer();
+       register_file_transfer();
+       register_file_transfer();
+       register_file_transfer();
+
+       return context;
+}
+
+static void execute_context(struct context *context)
+{
+       g_main_loop_run(context->main_loop);
+
+       sdp_svcdb_collect_all(context->fd);
+       sdp_svcdb_reset();
+
+       g_source_remove(context->server_source);
+       g_source_remove(context->client_source);
+
+       g_main_loop_unref(context->main_loop);
+
+       g_free(context);
+}
+
+static void test_sdp(gconstpointer data)
+{
+       const struct test_data *test = data;
+       struct context *context = create_context();
+
+       context->mtu = test->mtu;
+       context->pdu_list = test->pdu_list;
+
+       g_idle_add(send_pdu, context);
+
+       execute_context(context);
+
+       g_free(test->pdu_list);
+}
+
+static void test_sdp_de_attr(gconstpointer data)
+{
+       const struct test_data_de *test = data;
+       uint128_t u128;
+       sdp_data_t *d;
+       int size = 0;
+
+       d = sdp_extract_attr(test->input_data, test->input_size, &size, NULL);
+       g_assert(d != NULL);
+       g_assert_cmpuint(test->input_size, ==, size);
+       g_assert_cmpuint(test->expected.dtd, ==, d->dtd);
+
+       if (g_test_verbose() == TRUE)
+               g_print("DTD=0x%02x\n", d->dtd);
+
+       switch (d->dtd) {
+       case SDP_TEXT_STR8:
+       case SDP_TEXT_STR16:
+       case SDP_URL_STR8:
+       case SDP_URL_STR16:
+               g_assert_cmpstr(test->expected.val.str, ==, d->val.str);
+               break;
+       case SDP_DATA_NIL:
+       case SDP_UINT8:
+               g_assert_cmpuint(test->expected.val.uint8, ==, d->val.uint8);
+               break;
+       case SDP_UINT16:
+               g_assert_cmpuint(test->expected.val.uint16, ==, d->val.uint16);
+               break;
+       case SDP_UINT32:
+               g_assert_cmpuint(test->expected.val.uint32, ==, d->val.uint32);
+               break;
+       case SDP_UINT64:
+               g_assert_cmpuint(test->expected.val.uint64, ==, d->val.uint64);
+               break;
+       case SDP_BOOL:
+       case SDP_INT8:
+               g_assert_cmpuint(test->expected.val.int8, ==, d->val.int8);
+               break;
+       case SDP_INT16:
+               g_assert_cmpuint(test->expected.val.int16, ==, d->val.int16);
+               break;
+       case SDP_INT32:
+               g_assert_cmpuint(test->expected.val.int32, ==, d->val.int32);
+               break;
+       case SDP_INT64:
+               g_assert_cmpuint(test->expected.val.int64, ==, d->val.int64);
+               break;
+       case SDP_UINT128:
+       case SDP_INT128:
+               /* Expected bytes are in network order */
+               hton128(&d->val.uint128, &u128);
+               g_assert(memcmp(&test->expected.val.uint128, &u128,
+                                               sizeof(uint128_t)) == 0);
+               break;
+       default:
+               g_assert_not_reached();
+       }
+
+       sdp_data_free(d);
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       /*
+        * Service Search Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing service(s).
+        */
+       define_ss("BV-01-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00));
+       define_ss("BV-01-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x00, 0x03, 0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00));
+       define_ss("BV-01-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00));
+
+       /*
+        * Service Search Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing service(s), using continuation state.
+        */
+       define_ss("BV-03-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0x01, 0x00, 0xff, 0xff, 0x00),
+               raw_pdu_cont(8, 0x03, 0x00, 0x01, 0x00, 0x29, 0x00, 0x08, 0x00,
+                               0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                               0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                               0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                               0x05, 0x00, 0x01, 0x00, 0x06, 0x08),
+               raw_pdu_cont(8, 0x02, 0x00, 0x02, 0x00, 0x10, 0x35, 0x03, 0x19,
+                               0x01, 0x00, 0xff, 0xff, 0x08),
+               raw_pdu(0x03, 0x00, 0x02, 0x00, 0x09, 0x00, 0x08, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x07, 0x00));
+       define_ss("BV-03-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x00),
+               raw_pdu_cont(8, 0x03, 0x00, 0x01, 0x00, 0x29, 0x00, 0x08, 0x00,
+                               0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                               0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                               0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                               0x05, 0x00, 0x01, 0x00, 0x06, 0x08),
+               raw_pdu_cont(8, 0x02, 0x00, 0x02, 0x00, 0x12, 0x35, 0x05, 0x1a,
+                               0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x08),
+               raw_pdu(0x03, 0x00, 0x02, 0x00, 0x09, 0x00, 0x08, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x07, 0x00));
+       define_ss("BV-03-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x00),
+               raw_pdu_cont(8, 0x03, 0x00, 0x01, 0x00, 0x29, 0x00, 0x08, 0x00,
+                               0x07, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                               0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                               0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                               0x05, 0x00, 0x01, 0x00, 0x06, 0x08),
+               raw_pdu_cont(8, 0x02, 0x00, 0x02, 0x00, 0x1e, 0x35, 0x11, 0x1c,
+                               0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                               0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                               0xff, 0xff, 0x08),
+               raw_pdu(0x03, 0x00, 0x02, 0x00, 0x09, 0x00, 0x08, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x07, 0x00));
+
+       /*
+        * Service Search Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * no existing service(s).
+        */
+       define_ss("BV-04-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0xff, 0xff, 0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x00, 0x00));
+       define_ss("BV-04-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x00, 0x00));
+       define_ss("BV-04-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0xff, 0xff, 0xff, 0xff, 0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x05, 0x00, 0x00, 0x00,
+                       0x00, 0x00));
+
+       /*
+        * Service Search Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing service(s), using invalid PDU size.
+        */
+       define_ss("BI-01-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x01, 0x00, 0x00, 0x05, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+       define_ss("BI-01-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x05, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+       define_ss("BI-01-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x05, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+
+       /*
+        * Service Search Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing service(s), using invalid request syntax.
+        */
+       define_ss("BI-02-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x06, 0x35, 0x03, 0x19,
+                       0x01, 0x00, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+       define_ss("BI-02-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x01, 0x00, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+       define_ss("BI-02-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x14, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with attribute(s).
+        */
+       define_sa("BV-01-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x0a, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the existing
+        * Attribute(s) using ContinuationState.
+        */
+       define_sa("BV-03-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu_cont(8, 0x05, 0x00, 0x01, 0x00, 0x12, 0x00, 0x07, 0x35,
+                               0x10, 0x09, 0x00, 0x00, 0x0a, 0x00, 0x08),
+               raw_pdu_cont(8, 0x04, 0x00, 0x02, 0x00, 0x17, 0x00, 0x01, 0x00,
+                               0x00, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00,
+                               0x09, 0x00, 0x01, 0x08),
+               raw_pdu_cont(8, 0x05, 0x00, 0x02, 0x00, 0x12, 0x00, 0x07, 0x01,
+                               0x00, 0x00, 0x09, 0x00, 0x01, 0x35, 0x08),
+               raw_pdu_cont(8, 0x04, 0x00, 0x03, 0x00, 0x17, 0x00, 0x01, 0x00,
+                               0x00, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00,
+                               0x09, 0x00, 0x01, 0x08),
+               raw_pdu(0x05, 0x00, 0x03, 0x00, 0x07, 0x00, 0x04, 0x03,
+                       0x19, 0x11, 0x01, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ServiceID attribute.
+        */
+       define_sa("BV-04-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x19, 0x35, 0x03, 0x09, 0x00, 0x03,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0b, 0x00, 0x08, 0x35,
+                       0x06, 0x09, 0x00, 0x03, 0x19, 0x11, 0x01, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ProtocolDescriptorList attribute.
+        */
+       define_sa("BV-05-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x04,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x1b, 0x00, 0x18, 0x35,
+                       0x16, 0x09, 0x00, 0x04, 0x35, 0x11, 0x35, 0x03,
+                       0x19, 0x01, 0x00, 0x35, 0x05, 0x19, 0x00, 0x03,
+                       0x08, 0x09, 0x35, 0x03, 0x19, 0x00, 0x08, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * ServiceRecordState attribute.
+        */
+       define_sa("BV-06-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x0d, 0x35, 0x03, 0x09, 0x00, 0x02,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x02, 0x0a, 0x00, 0x00, 0x12,
+                       0x34, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * ServiceInfoTime attribute.
+        */
+       define_sa("BV-07-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x0d, 0x35, 0x03, 0x09, 0x00, 0x07,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x07, 0x0a, 0x00, 0x00, 0xff,
+                       0xff, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * BrowseGroupList attribute.
+        */
+       define_sa("BV-08-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x0a, 0x35, 0x03, 0x09, 0x00, 0x05,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x05, 0x35, 0x03, 0x19, 0x10,
+                       0x02, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * LanguageBaseAttributeIdList attribute.
+        */
+       define_sa("BV-09-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x13, 0x35, 0x03, 0x09, 0x00, 0x06,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x13, 0x00, 0x10, 0x35,
+                       0x0e, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65,
+                       0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ServiceAvailability attribute.
+        */
+       define_sa("BV-10-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x0a, 0x35, 0x03, 0x09, 0x00, 0x08,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0a, 0x00, 0x07, 0x35,
+                       0x05, 0x09, 0x00, 0x08, 0x08, 0xff, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * IconURL attribute.
+        */
+       define_sa("BV-11-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x1f, 0x35, 0x03, 0x09, 0x00, 0x0c,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1c, 0x35,
+                       0x1a, 0x09, 0x00, 0x0c, 0x45, 0x15, 0x68, 0x74,
+                       0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+                       0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a, 0x2e, 0x6f,
+                       0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ServiceName attribute.
+        */
+       define_sa("BV-12-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x16, 0x35, 0x03, 0x09, 0x00, 0x06,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x13, 0x00, 0x10, 0x35,
+                       0x0e, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65,
+                       0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x15, 0x35, 0x03, 0x09, 0x01, 0x00,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x09, 0x01, 0x00, 0x25, 0x0b, 0x53, 0x65,
+                       0x72, 0x69, 0x61, 0x6c, 0x20, 0x50, 0x6f, 0x72,
+                       0x74, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ServiceDescription attribute.
+        */
+       define_sa("BV-13-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x16, 0x35, 0x03, 0x09, 0x00, 0x06,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x13, 0x00, 0x10, 0x35,
+                       0x0e, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65,
+                       0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x12, 0x35, 0x03, 0x09, 0x01, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x12, 0x00, 0x0f, 0x35,
+                       0x0d, 0x09, 0x01, 0x01, 0x25, 0x08, 0x43, 0x4f,
+                       0x4d, 0x20, 0x50, 0x6f, 0x72, 0x74, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * ProviderName attribute.
+        */
+       define_sa("BV-14-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x16, 0x35, 0x03, 0x09, 0x00, 0x06,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x13, 0x00, 0x10, 0x35,
+                       0x0e, 0x09, 0x00, 0x06, 0x35, 0x09, 0x09, 0x65,
+                       0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x0f, 0x35, 0x03, 0x09, 0x01, 0x02,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x09, 0x01, 0x02, 0x25, 0x05, 0x42, 0x6c,
+                       0x75, 0x65, 0x5a, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * VersionNumberList attribute.
+        */
+       define_sa("BV-15-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x0d, 0x35, 0x03, 0x09, 0x02, 0x00,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x02, 0x00, 0x35, 0x03, 0x09, 0x01,
+                       0x00, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * ServiceDatabaseState attribute.
+        */
+       define_sa("BV-16-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x00, 0x00,
+                       0x00, 0x00, 0x0d, 0x35, 0x03, 0x09, 0x02, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x02, 0x01, 0x0a, 0x49, 0x6f, 0x06,
+                       0x54, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * BluetoothProfileDescriptorList attribute.
+        */
+       define_sa("BV-17-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x0f, 0x35, 0x03, 0x09, 0x00, 0x09,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x12, 0x00, 0x0f, 0x35,
+                       0x0d, 0x09, 0x00, 0x09, 0x35, 0x08, 0x35, 0x06,
+                       0x19, 0x11, 0x05, 0x09, 0x01, 0x00, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * DocumentationURL attribute.
+        */
+       define_sa("BV-18-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x1f, 0x35, 0x03, 0x09, 0x00, 0x0a,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1c, 0x35,
+                       0x1a, 0x09, 0x00, 0x0a, 0x45, 0x15, 0x68, 0x74,
+                       0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+                       0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a, 0x2e, 0x6f,
+                       0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with the
+        * ClientExecutableURL attribute.
+        */
+       define_sa("BV-19-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x1f, 0x35, 0x03, 0x09, 0x00, 0x0b,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x1f, 0x00, 0x1c, 0x35,
+                       0x1a, 0x09, 0x00, 0x0b, 0x45, 0x15, 0x68, 0x74,
+                       0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77,
+                       0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a, 0x2e, 0x6f,
+                       0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for non-existing Attribute.
+        */
+       define_sa("BV-20-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x07, 0x35, 0x03, 0x09, 0xff, 0xff,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify that the IUT is able to respond with an
+        * AdditionalProtocolDescriptorList attribute.
+        */
+       define_sa("BV-21-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x24, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00),
+               raw_pdu(0x04, 0x00, 0x02, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x0d,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x02, 0x00, 0x19, 0x00, 0x16, 0x35,
+                       0x14, 0x09, 0x00, 0x0d, 0x35, 0x0f, 0x35, 0x0d,
+                       0x35, 0x06, 0x19, 0x01, 0x00, 0x09, 0x00, 0x13,
+                       0x35, 0x03, 0x19, 0x00, 0x11, 0x00));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attribute, using invalid ServiceRecordHandle.
+        */
+       define_sa("BI-01-C",
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0xff, 0xff, 0xff,
+                       0xff, 0x00, 0x07, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x02));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attribute, using invalid request syntax.
+        */
+       define_sa("BI-02-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0a, 0x00, 0x01, 0x00,
+                       0x00, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+
+       /*
+        * Service Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attribute, using invalid PDU-Size.
+        */
+       define_sa("BI-03-C",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x01, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x00, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x11, 0x00, 0x01, 0x00,
+                       0x00, 0x00, 0x07, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for non-existing Service, existing Attribute using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-01-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0xff, 0xff, 0x00, 0x0a, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-01-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x35, 0x03,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-01-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0x00, 0x0a, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service, non-existing Attribute using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-02-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0x00, 0x0a, 0x35, 0x03, 0x09, 0xff,
+                       0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-02-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x0a, 0x35, 0x03,
+                       0x09, 0xff, 0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-02-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x0a, 0x35, 0x03, 0x09, 0xff, 0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for non-existing Service, non-existing Attribute using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-03-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0xff, 0xff, 0x00, 0x0a, 0x35, 0x03, 0x09, 0xff,
+                       0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-03-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0xff, 0xff, 0xff, 0xff, 0x00, 0x0a, 0x35, 0x03,
+                       0x09, 0xff, 0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+       define_ssa("BV-03-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                       0x00, 0x0a, 0x35, 0x03, 0x09, 0xff, 0xff, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x05, 0x00, 0x02, 0x35,
+                       0x00, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute(s) using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-04-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0x00, 0x11, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x05, 0x00));
+       define_ssa("BV-04-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x11, 0x35, 0x03,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x05, 0x00));
+       define_ssa("BV-04-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x11, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x05, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attributes, using Continuation State and
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-06-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x10, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00,
+                       0x00, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu_cont(8, 0x07, 0x00, 0x01, 0x00, 0x12, 0x00, 0x07, 0x35,
+                               0x12, 0x35, 0x10, 0x09, 0x00, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x02, 0x00, 0x18, 0x35, 0x03, 0x19,
+                               0x11, 0x05, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00,
+                               0x00, 0x09, 0x00, 0x01, 0x08),
+               raw_pdu_cont(8, 0x07, 0x00, 0x02, 0x00, 0x12, 0x00, 0x07, 0x0a,
+                               0x00, 0x01, 0x00, 0x01, 0x09, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x03, 0x00, 0x18, 0x35, 0x03, 0x19,
+                               0x11, 0x05, 0x00, 0x07, 0x35, 0x06, 0x09, 0x00,
+                               0x00, 0x09, 0x00, 0x01, 0x08),
+               raw_pdu(0x07, 0x00, 0x03, 0x00, 0x09, 0x00, 0x06, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x00));
+       define_ssa("BV-06-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x12, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x07, 0x35, 0x06,
+                       0x09, 0x00, 0x00, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu_cont(8, 0x07, 0x00, 0x01, 0x00, 0x12, 0x00, 0x07, 0x35,
+                               0x12, 0x35, 0x10, 0x09, 0x00, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x02, 0x00, 0x1a, 0x35, 0x05, 0x1a,
+                               0x00, 0x00, 0x11, 0x05, 0x00, 0x07, 0x35, 0x06,
+                               0x09, 0x00, 0x00, 0x09, 0x00, 0x01, 0x08),
+               raw_pdu_cont(8, 0x07, 0x00, 0x02, 0x00, 0x12, 0x00, 0x07, 0x0a,
+                               0x00, 0x01, 0x00, 0x01, 0x09, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x03, 0x00, 0x1a, 0x35, 0x05, 0x1a,
+                               0x00, 0x00, 0x11, 0x05, 0x00, 0x07, 0x35, 0x06,
+                               0x09, 0x00, 0x00, 0x09, 0x00, 0x01, 0x08),
+               raw_pdu(0x07, 0x00, 0x03, 0x00, 0x09, 0x00, 0x06, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x00));
+       define_ssa("BV-06-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1e, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00, 0x09,
+                       0x00, 0x01, 0x00),
+               raw_pdu_cont(8, 0x07, 0x00, 0x01, 0x00, 0x12, 0x00, 0x07, 0x35,
+                               0x12, 0x35, 0x10, 0x09, 0x00, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x02, 0x00, 0x26, 0x35, 0x11, 0x1c,
+                               0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                               0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                               0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00, 0x09,
+                               0x00, 0x01, 0x08),
+               raw_pdu_cont(8, 0x07, 0x00, 0x02, 0x00, 0x12, 0x00, 0x07, 0x0a,
+                               0x00, 0x01, 0x00, 0x01, 0x09, 0x00, 0x08),
+               raw_pdu_cont(8, 0x06, 0x00, 0x03, 0x00, 0x26, 0x35, 0x11, 0x1c,
+                               0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                               0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                               0x00, 0x07, 0x35, 0x06, 0x09, 0x00, 0x00, 0x09,
+                               0x00, 0x01, 0x08),
+               raw_pdu(0x07, 0x00, 0x03, 0x00, 0x09, 0x00, 0x06, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceRecordState
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-07-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x13, 0x35, 0x03, 0x09, 0x00,
+                       0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x02, 0x0a, 0x00,
+                       0x00, 0x12, 0x34, 0x00));
+       define_ssa("BV-07-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x13, 0x35, 0x03,
+                       0x09, 0x00, 0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x02, 0x0a, 0x00,
+                       0x00, 0x12, 0x34, 0x00));
+       define_ssa("BV-07-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x13, 0x35, 0x03, 0x09, 0x00, 0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x02, 0x0a, 0x00,
+                       0x00, 0x12, 0x34, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceDataBaseState
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-08-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x10, 0x00, 0x00, 0x13, 0x35, 0x03, 0x09, 0x02,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x01, 0x0a, 0x49,
+                       0x6f, 0x06, 0x54, 0x00));
+       define_ssa("BV-08-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x13, 0x35, 0x03,
+                       0x09, 0x02, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x01, 0x0a, 0x49,
+                       0x6f, 0x06, 0x54, 0x00));
+       define_ssa("BV-08-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x13, 0x35, 0x03, 0x09, 0x02, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x01, 0x0a, 0x49,
+                       0x6f, 0x06, 0x54, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceInfoTimeToLive
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-09-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x13, 0x35, 0x03, 0x09, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x07, 0x0a, 0x00,
+                       0x00, 0xff, 0xff, 0x00));
+       define_ssa("BV-09-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x13, 0x35, 0x03,
+                       0x09, 0x00, 0x07, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x07, 0x0a, 0x00,
+                       0x00, 0xff, 0xff, 0x00));
+       define_ssa("BV-09-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x13, 0x35, 0x03, 0x09, 0x00, 0x07, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x07, 0x0a, 0x00,
+                       0x00, 0xff, 0xff, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceID using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-10-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1e, 0x35, 0x03, 0x09, 0x00,
+                       0x03, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x00, 0x03, 0x19, 0x11,
+                       0x01, 0x00));
+       define_ssa("BV-10-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1e, 0x35, 0x03,
+                       0x09, 0x00, 0x03, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x00, 0x03, 0x19, 0x11,
+                       0x01, 0x00));
+       define_ssa("BV-10-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1e, 0x35, 0x03, 0x09, 0x00, 0x03, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x00, 0x03, 0x19, 0x11,
+                       0x01, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ProtocolDescriptorList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-11-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x04, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x1a, 0x35,
+                       0x18, 0x35, 0x16, 0x09, 0x00, 0x04, 0x35, 0x11,
+                       0x35, 0x03, 0x19, 0x01, 0x00, 0x35, 0x05, 0x19,
+                       0x00, 0x03, 0x08, 0x09, 0x35, 0x03, 0x19, 0x00,
+                       0x08, 0x00));
+       define_ssa("BV-11-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x04, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x1a, 0x35,
+                       0x18, 0x35, 0x16, 0x09, 0x00, 0x04, 0x35, 0x11,
+                       0x35, 0x03, 0x19, 0x01, 0x00, 0x35, 0x05, 0x19,
+                       0x00, 0x03, 0x08, 0x09, 0x35, 0x03, 0x19, 0x00,
+                       0x08, 0x00));
+       define_ssa("BV-11-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x04, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1d, 0x00, 0x1a, 0x35,
+                       0x18, 0x35, 0x16, 0x09, 0x00, 0x04, 0x35, 0x11,
+                       0x35, 0x03, 0x19, 0x01, 0x00, 0x35, 0x05, 0x19,
+                       0x00, 0x03, 0x08, 0x09, 0x35, 0x03, 0x19, 0x00,
+                       0x08, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute BrowseGroupList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-12-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x05, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x05, 0x35, 0x03,
+                       0x19, 0x10, 0x02, 0x00));
+       define_ssa("BV-12-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x05, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x05, 0x35, 0x03,
+                       0x19, 0x10, 0x02, 0x00));
+       define_ssa("BV-12-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x05, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x00, 0x05, 0x35, 0x03,
+                       0x19, 0x10, 0x02, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute LanguageBaseAttributeIdList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-13-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x18, 0x35, 0x03, 0x09, 0x00,
+                       0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00));
+       define_ssa("BV-13-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x18, 0x35, 0x03,
+                       0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00));
+       define_ssa("BV-13-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x18, 0x35, 0x03, 0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceAvailability
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-14-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x0f, 0x35, 0x03, 0x09, 0x00,
+                       0x08, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x09, 0x35,
+                       0x07, 0x35, 0x05, 0x09, 0x00, 0x08, 0x08, 0xff,
+                       0x00));
+       define_ssa("BV-14-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x0f, 0x35, 0x03,
+                       0x09, 0x00, 0x08, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x09, 0x35,
+                       0x07, 0x35, 0x05, 0x09, 0x00, 0x08, 0x08, 0xff,
+                       0x00));
+       define_ssa("BV-14-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x0f, 0x35, 0x03, 0x09, 0x00, 0x08, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x09, 0x35,
+                       0x07, 0x35, 0x05, 0x09, 0x00, 0x08, 0x08, 0xff,
+                       0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute IconURL using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-15-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x24, 0x35, 0x03, 0x09, 0x00,
+                       0x0c, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0c, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-15-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x24, 0x35, 0x03,
+                       0x09, 0x00, 0x0c, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0c, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-15-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x24, 0x35, 0x03, 0x09, 0x00, 0x0c, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0c, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceName using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-16-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1b, 0x35, 0x03, 0x09, 0x00,
+                       0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1d, 0x35, 0x03, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x17, 0x00, 0x14, 0x35,
+                       0x12, 0x35, 0x10, 0x09, 0x01, 0x00, 0x25, 0x0b,
+                       0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x50,
+                       0x6f, 0x72, 0x74, 0x00));
+       define_ssa("BV-16-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1b, 0x35, 0x03,
+                       0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1d, 0x35, 0x03,
+                       0x09, 0x01, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x17, 0x00, 0x14, 0x35,
+                       0x12, 0x35, 0x10, 0x09, 0x01, 0x00, 0x25, 0x0b,
+                       0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x50,
+                       0x6f, 0x72, 0x74, 0x00));
+       define_ssa("BV-16-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1b, 0x35, 0x03, 0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1d, 0x35, 0x03, 0x09, 0x01, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x17, 0x00, 0x14, 0x35,
+                       0x12, 0x35, 0x10, 0x09, 0x01, 0x00, 0x25, 0x0b,
+                       0x53, 0x65, 0x72, 0x69, 0x61, 0x6c, 0x20, 0x50,
+                       0x6f, 0x72, 0x74, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ServiceDescription
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-17-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1b, 0x35, 0x03, 0x09, 0x00,
+                       0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1a, 0x35, 0x03, 0x09, 0x01,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x01, 0x01, 0x25, 0x08,
+                       0x43, 0x4f, 0x4d, 0x20, 0x50, 0x6f, 0x72, 0x74,
+                       0x00));
+       define_ssa("BV-17-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1b, 0x35, 0x03,
+                       0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1a, 0x35, 0x03,
+                       0x09, 0x01, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x01, 0x01, 0x25, 0x08,
+                       0x43, 0x4f, 0x4d, 0x20, 0x50, 0x6f, 0x72, 0x74,
+                       0x00));
+       define_ssa("BV-17-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1b, 0x35, 0x03, 0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1a, 0x35, 0x03, 0x09, 0x01, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x01, 0x01, 0x25, 0x08,
+                       0x43, 0x4f, 0x4d, 0x20, 0x50, 0x6f, 0x72, 0x74,
+                       0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ProviderName using
+        * ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-18-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x1b, 0x35, 0x03, 0x09, 0x00,
+                       0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x17, 0x35, 0x03, 0x09, 0x01,
+                       0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x11, 0x00, 0x0e, 0x35,
+                       0x0c, 0x35, 0x0a, 0x09, 0x01, 0x02, 0x25, 0x05,
+                       0x42, 0x6c, 0x75, 0x65, 0x5a, 0x00));
+       define_ssa("BV-18-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x1b, 0x35, 0x03,
+                       0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x17, 0x35, 0x03,
+                       0x09, 0x01, 0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x11, 0x00, 0x0e, 0x35,
+                       0x0c, 0x35, 0x0a, 0x09, 0x01, 0x02, 0x25, 0x05,
+                       0x42, 0x6c, 0x75, 0x65, 0x5a, 0x00));
+       define_ssa("BV-18-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x1b, 0x35, 0x03, 0x09, 0x00, 0x06, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x15, 0x00, 0x12, 0x35,
+                       0x10, 0x35, 0x0e, 0x09, 0x00, 0x06, 0x35, 0x09,
+                       0x09, 0x65, 0x6e, 0x09, 0x00, 0x6a, 0x09, 0x01,
+                       0x00, 0x00),
+               raw_pdu(0x06, 0x00, 0x02, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x17, 0x35, 0x03, 0x09, 0x01, 0x02, 0x00),
+               raw_pdu(0x07, 0x00, 0x02, 0x00, 0x11, 0x00, 0x0e, 0x35,
+                       0x0c, 0x35, 0x0a, 0x09, 0x01, 0x02, 0x25, 0x05,
+                       0x42, 0x6c, 0x75, 0x65, 0x5a, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute VersionNumberList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-19-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x10, 0x00, 0x00, 0x12, 0x35, 0x03, 0x09, 0x02,
+                       0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x00, 0x35, 0x03,
+                       0x09, 0x01, 0x00, 0x00));
+       define_ssa("BV-19-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x12, 0x35, 0x03,
+                       0x09, 0x02, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x00, 0x35, 0x03,
+                       0x09, 0x01, 0x00, 0x00));
+       define_ssa("BV-19-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x12, 0x35, 0x03, 0x09, 0x02, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0f, 0x00, 0x0c, 0x35,
+                       0x0a, 0x35, 0x08, 0x09, 0x02, 0x00, 0x35, 0x03,
+                       0x09, 0x01, 0x00, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing Service(s) and Attribute BluetoothProfileDescriptorList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-20-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x09, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x00, 0x09, 0x35, 0x08,
+                       0x35, 0x06, 0x19, 0x11, 0x05, 0x09, 0x01, 0x00,
+                       0x00));
+       define_ssa("BV-20-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x05, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x09, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x00, 0x09, 0x35, 0x08,
+                       0x35, 0x06, 0x19, 0x11, 0x05, 0x09, 0x01, 0x00,
+                       0x00));
+       define_ssa("BV-20-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x05, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x09, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x14, 0x00, 0x11, 0x35,
+                       0x0f, 0x35, 0x0d, 0x09, 0x00, 0x09, 0x35, 0x08,
+                       0x35, 0x06, 0x19, 0x11, 0x05, 0x09, 0x01, 0x00,
+                       0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute DocumentationURL
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-21-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x24, 0x35, 0x03, 0x09, 0x00,
+                       0x0a, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0a, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-21-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x24, 0x35, 0x03,
+                       0x09, 0x00, 0x0a, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0a, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-21-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x24, 0x35, 0x03, 0x09, 0x00, 0x0a, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0a, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Service(s) and Attribute ClientExecutableURL
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-22-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x01, 0x00, 0x24, 0x35, 0x03, 0x09, 0x00,
+                       0x0b, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0b, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-22-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x24, 0x35, 0x03,
+                       0x09, 0x00, 0x0b, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0b, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+       define_ssa("BV-22-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x00, 0x24, 0x35, 0x03, 0x09, 0x00, 0x0b, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x21, 0x00, 0x1e, 0x35,
+                       0x1c, 0x35, 0x1a, 0x09, 0x00, 0x0b, 0x45, 0x15,
+                       0x68, 0x74, 0x74, 0x70, 0x3a, 0x2f, 0x2f, 0x77,
+                       0x77, 0x77, 0x2e, 0x62, 0x6c, 0x75, 0x65, 0x7a,
+                       0x2e, 0x6f, 0x72, 0x67, 0x2f, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching for
+        * existing Service(s) and Attribute AdditionalProtocolDescriptorList
+        * using ServiceSearchAttributeRequest.
+        */
+       define_ssa("BV-23-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x11, 0x24, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x0d, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x18, 0x35,
+                       0x16, 0x35, 0x14, 0x09, 0x00, 0x0d, 0x35, 0x0f,
+                       0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09,
+                       0x00, 0x13, 0x35, 0x03, 0x19, 0x00, 0x11, 0x00));
+       define_ssa("BV-23-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x11, 0x24, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x0d, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x18, 0x35,
+                       0x16, 0x35, 0x14, 0x09, 0x00, 0x0d, 0x35, 0x0f,
+                       0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09,
+                       0x00, 0x13, 0x35, 0x03, 0x19, 0x00, 0x11, 0x00));
+       define_ssa("BV-23-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x11, 0x24, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x0d, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x1b, 0x00, 0x18, 0x35,
+                       0x16, 0x35, 0x14, 0x09, 0x00, 0x0d, 0x35, 0x0f,
+                       0x35, 0x0d, 0x35, 0x06, 0x19, 0x01, 0x00, 0x09,
+                       0x00, 0x13, 0x35, 0x03, 0x19, 0x00, 0x11, 0x00));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attribute, using invalid request syntax,
+        * using the ServiceSearchAttributeRequest PDU.
+        */
+       define_ssa("BI-01-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0b, 0x35, 0x03, 0x19,
+                       0x01, 0x00, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+       define_ssa("BI-01-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x01, 0x00, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+       define_ssa("BI-01-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x19, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x03));
+
+       /*
+        * Service Search Attribute Request
+        *
+        * Verify the correct behaviour of the IUT when searching
+        * for existing Attribute, using invalid PDU-size, using the
+        * ServiceSearchAttributeRequest PDU.
+        */
+       define_ssa("BI-02-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x12, 0x35, 0x03, 0x19,
+                       0x01, 0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+       define_ssa("BI-02-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x14, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x01, 0x00, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+       define_ssa("BI-02-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x20, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x04));
+
+       /*
+        * Service Browse
+        *
+        * Verify that the IUT behave correct using SDP_ServiceSearchRequest
+        * and SDP_ServiceAttributeRequest for Service Browse.
+        */
+       define_brw("BV-01-C/UUID-16",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0x10, 0x02, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0x10, 0x01, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x02, 0x00,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x08, 0x35,
+                       0x06, 0x09, 0x02, 0x00, 0x19, 0x10, 0x02, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x08, 0x35, 0x03, 0x19,
+                       0x10, 0x02, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+       define_brw("BV-01-C/UUID-32",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x02, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x01, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x02, 0x00,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x08, 0x35,
+                       0x06, 0x09, 0x02, 0x00, 0x19, 0x10, 0x02, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x0a, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x02, 0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+       define_brw("BV-01-C/UUID-128",
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x09, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x00, 0x00, 0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x00, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x02, 0x00,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0b, 0x00, 0x08, 0x35,
+                       0x06, 0x09, 0x02, 0x00, 0x19, 0x10, 0x02, 0x00),
+               raw_pdu(0x02, 0x00, 0x01, 0x00, 0x16, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x00),
+               raw_pdu(0x03, 0x00, 0x01, 0x00, 0x25, 0x00, 0x08, 0x00,
+                       0x08, 0x00, 0x01, 0x00, 0x00, 0x00, 0x01, 0x00,
+                       0x01, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00,
+                       0x03, 0x00, 0x01, 0x00, 0x04, 0x00, 0x01, 0x00,
+                       0x05, 0x00, 0x01, 0x00, 0x06, 0x00, 0x01, 0x00,
+                       0x07, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x00, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x01, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x05, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x24, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x03, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x04, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x05, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x06, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x04, 0x00, 0x01, 0x00, 0x0c, 0x00, 0x01, 0x00,
+                       0x07, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01,
+                       0x00),
+               raw_pdu(0x05, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+
+       /*
+        * Service Browse
+        *
+        * Verify that the IUT behave correct using
+        * SDP_ServiceSearchAttributeRequest for Service Browse.
+        */
+       define_brw("BV-02-C/UUID-16",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x10, 0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x10, 0x01, 0xff, 0xff, 0x35, 0x03, 0x09, 0x02,
+                       0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x02, 0x00, 0x19, 0x10,
+                       0x02, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0d, 0x35, 0x03, 0x19,
+                       0x10, 0x02, 0xff, 0xff, 0x35, 0x03, 0x09, 0x00,
+                       0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+       define_brw("BV-02-C/UUID-32",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x02, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x01, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x02, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x02, 0x00, 0x19, 0x10,
+                       0x02, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x0f, 0x35, 0x05, 0x1a,
+                       0x00, 0x00, 0x10, 0x02, 0xff, 0xff, 0x35, 0x03,
+                       0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+       define_brw("BV-02-C/UUID-128",
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x01, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x02, 0x00, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x0d, 0x00, 0x0a, 0x35,
+                       0x08, 0x35, 0x06, 0x09, 0x02, 0x00, 0x19, 0x10,
+                       0x02, 0x00),
+               raw_pdu(0x06, 0x00, 0x01, 0x00, 0x1b, 0x35, 0x11, 0x1c,
+                       0x00, 0x00, 0x10, 0x02, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb,
+                       0xff, 0xff, 0x35, 0x03, 0x09, 0x00, 0x01, 0x00),
+               raw_pdu(0x07, 0x00, 0x01, 0x00, 0x55, 0x00, 0x52, 0x35,
+                       0x50, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x01, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x05, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x24, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x35, 0x08, 0x09, 0x00, 0x01, 0x35, 0x03,
+                       0x19, 0x11, 0x06, 0x35, 0x08, 0x09, 0x00, 0x01,
+                       0x35, 0x03, 0x19, 0x11, 0x06, 0x35, 0x08, 0x09,
+                       0x00, 0x01, 0x35, 0x03, 0x19, 0x11, 0x06, 0x35,
+                       0x08, 0x09, 0x00, 0x01, 0x35, 0x03, 0x19, 0x11,
+                       0x06, 0x00));
+
+       /*
+        * SDP Data Element (DE) tests
+        *
+        * Test extraction of valid DEs supported by sdp_extract_attr().
+        */
+       define_test_de_attr("TEXT_STR8/empty",
+                       raw_data(0x25, 0x00),
+                       exp_data(SDP_TEXT_STR8, str, ""));
+       define_test_de_attr("TEXT_STR8",
+                       raw_data(0x25, 0x04, 0x41, 0x42, 0x43, 0x44),
+                       exp_data(SDP_TEXT_STR8, str, "ABCD"));
+       define_test_de_attr("TEXT_STR16",
+                       raw_data(0x26, 0x00, 0x04, 0x41, 0x42, 0x43, 0x44),
+                       exp_data(SDP_TEXT_STR16, str, "ABCD"));
+       define_test_de_attr("URL_STR8",
+                       raw_data(0x45, 0x15, 0x68, 0x74, 0x74, 0x70, 0x3a,
+                               0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62, 0x6c,
+                               0x75, 0x65, 0x7a, 0x2e, 0x6f, 0x72, 0x67,
+                               0x2f),
+                       exp_data(SDP_URL_STR8, str, "http://www.bluez.org/"));
+       define_test_de_attr("URL_STR16",
+                       raw_data(0x46, 0x00, 0x15, 0x68, 0x74, 0x74, 0x70,
+                               0x3a, 0x2f, 0x2f, 0x77, 0x77, 0x77, 0x2e, 0x62,
+                               0x6c, 0x75, 0x65, 0x7a, 0x2e, 0x6f, 0x72, 0x67,
+                               0x2f),
+                       exp_data(SDP_URL_STR16, str, "http://www.bluez.org/"));
+       define_test_de_attr("NIL",
+                       raw_data(0x00),
+                       exp_data(SDP_DATA_NIL, uint8, 0));
+       define_test_de_attr("UINT8",
+                       raw_data(0x08, 0xff),
+                       exp_data(SDP_UINT8, uint8, UINT8_MAX));
+       define_test_de_attr("INT8",
+                       raw_data(0x10, 0x80),
+                       exp_data(SDP_INT8, int8, INT8_MIN));
+       define_test_de_attr("BOOL",
+                       raw_data(0x28, 0x01),
+                       exp_data(SDP_BOOL, int8, 1));
+       define_test_de_attr("UINT16",
+                       raw_data(0x09, 0xff, 0xff),
+                       exp_data(SDP_UINT16, uint16, UINT16_MAX));
+       define_test_de_attr("INT16",
+                       raw_data(0x11, 0x80, 0x00),
+                       exp_data(SDP_INT16, int16, INT16_MIN));
+       define_test_de_attr("UINT32",
+                       raw_data(0x0A, 0xff, 0xff, 0xff, 0xff),
+                       exp_data(SDP_UINT32, uint32, UINT32_MAX));
+       define_test_de_attr("INT32",
+                       raw_data(0x12, 0x80, 0x00, 0x00, 0x00),
+                       exp_data(SDP_INT32, int32, INT32_MIN));
+       define_test_de_attr("UINT64",
+                       raw_data(0x0B, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                                                       0xff),
+                       exp_data(SDP_UINT64, uint64, UINT64_MAX));
+       define_test_de_attr("INT64",
+                       raw_data(0x13, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                                                       0x00),
+                       exp_data(SDP_INT64, int64, INT64_MIN));
+       /* UINT128/INT128 are just byte arrays parsed as uint128_t */
+       define_test_de_attr("UINT128",
+                       raw_data(0x0C, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                       0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                       0xff, 0xff, 0xff),
+                       exp_data(SDP_UINT128, uint128,
+                               build_u128(0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+                                               0xff, 0xff, 0xff, 0xff, 0xff,
+                                               0xff, 0xff, 0xff, 0xff, 0xff)));
+       define_test_de_attr("INT128",
+                       raw_data(0x14, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                       0x00, 0x00, 0x00),
+                       exp_data(SDP_INT128, uint128,
+                               build_u128(0x80, 0x00, 0x00, 0x00, 0x00, 0x00,
+                                               0x00, 0x00, 0x00, 0x00, 0x00,
+                                               0x00, 0x00, 0x00, 0x00, 0x00)));
+
+       return g_test_run();
+}
diff --git a/unit/test-textfile.c b/unit/test-textfile.c
new file mode 100644 (file)
index 0000000..d873df4
--- /dev/null
@@ -0,0 +1,277 @@
+/*
+ *
+ *  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 <fcntl.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "src/textfile.h"
+
+static const char test_pathname[] = "/tmp/textfile";
+
+static void util_create_empty(void)
+{
+       int fd;
+
+       fd = creat(test_pathname, 0644);
+       if (fd < 0)
+               return;
+
+       if (ftruncate(fd, 0) < 0)
+               goto done;
+
+done:
+       close(fd);
+}
+
+static void util_create_pagesize(void)
+{
+       char value[512];
+       unsigned int i;
+       int fd, size;
+
+       size = getpagesize();
+       if (size < 0)
+               return;
+
+       fd = creat(test_pathname, 0644);
+       if (fd < 0)
+               return;
+
+       if (ftruncate(fd, 0) < 0)
+               goto done;
+
+       memset(value, 0, sizeof(value));
+       for (i = 0; i < (size / sizeof(value)); i++) {
+               if (write(fd, value, sizeof(value)) < 0)
+                       break;
+       }
+
+done:
+       close(fd);
+}
+
+static void test_pagesize(void)
+{
+       char key[18], *str;
+       int size;
+
+       size = getpagesize();
+       g_assert(size >= 4096);
+
+       if (g_test_verbose())
+               g_print("System uses a page size of %d bytes\n", size);
+
+       util_create_pagesize();
+
+       sprintf(key, "11:11:11:11:11:11");
+       str = textfile_get(test_pathname, key);
+
+       if (g_test_verbose())
+               g_print("%s\n", str);
+
+       g_assert(str == NULL);
+}
+
+static void test_delete(void)
+{
+       char key[18], value[512], *str;
+
+       util_create_empty();
+
+       sprintf(key, "00:00:00:00:00:00");
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       memset(value, 0, sizeof(value));
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       str = textfile_get(test_pathname, key);
+       g_assert(str != NULL);
+
+       if (g_test_verbose())
+               g_print("%s\n", str);
+
+       g_free(str);
+}
+
+static void test_overwrite(void)
+{
+       char key[18], value[512], *str;
+
+       util_create_empty();
+
+       sprintf(key, "00:00:00:00:00:00");
+       memset(value, 0, sizeof(value));
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       snprintf(value, sizeof(value), "Test");
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       str = textfile_get(test_pathname, key);
+
+       if (g_test_verbose())
+               g_print("%s\n", str);
+
+       g_assert(str == NULL);
+}
+
+static void check_entry(char *key, char *value, void *data)
+{
+       unsigned int max = GPOINTER_TO_UINT(data);
+       unsigned int len;
+
+       len = strtol(key + 16, NULL, 16);
+       if (len == 1)
+               len = max;
+
+       if (g_test_verbose())
+               g_print("%s %s\n", key, value);
+
+       g_assert(strlen(value) == len);
+}
+
+static void test_multiple(void)
+{
+       char key[18], value[512], *str;
+       unsigned int i, j, max = 10;
+
+       util_create_empty();
+
+       for (i = 1; i < max + 1; i++) {
+               sprintf(key, "00:00:00:00:00:%02X", i);
+
+               memset(value, 0, sizeof(value));
+               for (j = 0; j < i; j++)
+                       value[j] = 'x';
+
+               g_assert(textfile_put(test_pathname, key, value) == 0);
+
+               str = textfile_get(test_pathname, key);
+
+               if (g_test_verbose())
+                       g_print("%s %s\n", key, str);
+
+               g_assert(str != NULL);
+               g_assert(strcmp(str, value) == 0);
+
+               free(str);
+       }
+
+       sprintf(key, "00:00:00:00:00:%02X", max);
+
+       memset(value, 0, sizeof(value));
+       for (j = 0; j < max; j++)
+               value[j] = 'y';
+
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       str = textfile_get(test_pathname, key);
+
+       if (g_test_verbose())
+               g_print("%s %s\n", key, str);
+
+       g_assert(str != NULL);
+       g_assert(strcmp(str, value) == 0);
+
+       free(str);
+
+       sprintf(key, "00:00:00:00:00:%02X", 1);
+
+       memset(value, 0, sizeof(value));
+       for (j = 0; j < max; j++)
+               value[j] = 'z';
+
+       g_assert(textfile_put(test_pathname, key, value) == 0);
+
+       str = textfile_get(test_pathname, key);
+
+       if (g_test_verbose())
+               g_print("%s %s\n", key, str);
+
+       g_assert(str != NULL);
+       g_assert(strcmp(str, value) == 0);
+
+       free(str);
+
+       for (i = 1; i < max + 1; i++) {
+               sprintf(key, "00:00:00:00:00:%02X", i);
+               str = textfile_get(test_pathname, key);
+
+               if (g_test_verbose())
+                       g_print("%s %s\n", key, str);
+
+               g_assert(str != NULL);
+
+               if (i == 1)
+                       g_assert(strlen(str) == max);
+               else
+                       g_assert(strlen(str) == i);
+
+               g_free(str);
+       }
+
+       sprintf(key, "00:00:00:00:00:%02X", 2);
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       sprintf(key, "00:00:00:00:00:%02X", max - 3);
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       textfile_foreach(test_pathname, check_entry, GUINT_TO_POINTER(max));
+
+       sprintf(key, "00:00:00:00:00:%02X", 1);
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       sprintf(key, "00:00:00:00:00:%02X", max);
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       sprintf(key, "00:00:00:00:00:%02X", max + 1);
+       g_assert(textfile_del(test_pathname, key) == 0);
+
+       textfile_foreach(test_pathname, check_entry, GUINT_TO_POINTER(max));
+}
+
+int main(int argc, char *argv[])
+{
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_func("/textfile/pagesize", test_pagesize);
+       g_test_add_func("/textfile/delete", test_delete);
+       g_test_add_func("/textfile/overwrite", test_overwrite);
+       g_test_add_func("/textfile/multiple", test_multiple);
+
+       return g_test_run();
+}
diff --git a/unit/test-uuid.c b/unit/test-uuid.c
new file mode 100644 (file)
index 0000000..79ab3e6
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ *
+ *  BlueZ - Bluetooth protocol stack for Linux
+ *
+ *  Copyright (C) 2011  Intel Corporation
+ *
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License as published by
+ *  the Free Software Foundation; either version 2 of the License, or
+ *  (at your option) any later version.
+ *
+ *  This program is distributed in the hope that it will be useful,
+ *  but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *  GNU General Public License for more details.
+ *
+ *  You should have received a copy of the GNU General Public License
+ *  along with this program; if not, write to the Free Software
+ *  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifdef HAVE_CONFIG_H
+#include <config.h>
+#endif
+
+#include <glib.h>
+
+#include <bluetooth/bluetooth.h>
+
+#include "lib/uuid.h"
+
+struct uuid_test_data {
+       const char *str;
+       uint16_t val16;
+       uint32_t val32;
+       unsigned char *binary;
+       uint8_t type;
+       const char *str128;
+       unsigned char *binary128;
+};
+
+static unsigned char uuid_base_binary[] = {
+                       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb };
+
+static struct uuid_test_data uuid_base = {
+       .str = "00000000-0000-1000-8000-00805F9B34FB",
+       .binary = uuid_base_binary,
+       .type = BT_UUID128,
+       .str128 = "00000000-0000-1000-8000-00805F9B34FB",
+       .binary128 = uuid_base_binary,
+};
+
+static unsigned char uuid_sixteen_binary[] = {
+                       0x00, 0x00, 0x12, 0x34, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb };
+
+static struct uuid_test_data uuid_sixteen1 = {
+       .str = "0x1234",
+       .val16 = 0x1234,
+       .type = BT_UUID16,
+       .str128 = "00001234-0000-1000-8000-00805F9B34FB",
+       .binary128 = uuid_sixteen_binary,
+};
+
+static struct uuid_test_data uuid_sixteen2 = {
+       .str = "1234",
+       .val16 = 0x1234,
+       .type = BT_UUID16,
+       .str128 = "00001234-0000-1000-8000-00805F9B34FB",
+       .binary128 = uuid_sixteen_binary,
+};
+
+static unsigned char uuid_32_binary[] = {
+                       0x12, 0x34, 0x56, 0x78, 0x00, 0x00, 0x10, 0x00,
+                       0x80, 0x00, 0x00, 0x80, 0x5f, 0x9b, 0x34, 0xfb };
+
+static struct uuid_test_data uuid_32_1 = {
+       .str = "0x12345678",
+       .val32 = 0x12345678,
+       .type = BT_UUID32,
+        .str128 = "12345678-0000-1000-8000-00805F9B34FB",
+       .binary128 = uuid_32_binary,
+};
+
+static struct uuid_test_data uuid_32_2 = {
+       .str = "12345678",
+       .val32 = 0x12345678,
+       .type = BT_UUID32,
+       .str128 = "12345678-0000-1000-8000-00805F9B34FB",
+       .binary128 = uuid_32_binary,
+};
+
+static void test_uuid(gconstpointer data)
+{
+       const struct uuid_test_data *test_data = data;
+       bt_uuid_t uuid;
+       uint128_t n128, u128;
+
+       g_assert(bt_string_to_uuid(&uuid, test_data->str) == 0);
+       g_assert(uuid.type == test_data->type);
+
+       switch (uuid.type) {
+       case BT_UUID16:
+               g_assert(uuid.value.u16 == test_data->val16);
+               break;
+       case BT_UUID32:
+               g_assert(uuid.value.u32 == test_data->val32);
+               break;
+       case BT_UUID128:
+               memcpy(&n128, test_data->binary, 16);
+               ntoh128(&n128, &u128);
+               g_assert(memcmp(&uuid.value.u128, &u128, 16) == 0);
+               break;
+       default:
+               return;
+        }
+}
+
+static void test_str(gconstpointer data)
+{
+       const struct uuid_test_data *test_data = data;
+       const char *str;
+       char buf[128];
+       bt_uuid_t uuid;
+
+       if (g_str_has_prefix(test_data->str, "0x") == TRUE)
+               str = test_data->str + 2;
+       else
+               str = test_data->str;
+
+       g_assert(bt_string_to_uuid(&uuid, test_data->str) == 0);
+
+       bt_uuid_to_string(&uuid, buf, sizeof(buf));
+       g_assert(strcasecmp(buf, str) == 0);
+
+       switch (test_data->type) {
+       case BT_UUID16:
+               bt_uuid16_create(&uuid, test_data->val16);
+               break;
+       case BT_UUID32:
+               bt_uuid32_create(&uuid, test_data->val32);
+               break;
+       default:
+               return;
+       }
+
+       bt_uuid_to_string(&uuid, buf, sizeof(buf));
+       g_assert(strcasecmp(buf, str) == 0);
+}
+
+static void test_cmp(gconstpointer data)
+{
+       const struct uuid_test_data *test_data = data;
+       bt_uuid_t uuid1, uuid2;
+
+       g_assert(bt_string_to_uuid(&uuid1, test_data->str) == 0);
+       g_assert(bt_string_to_uuid(&uuid2, test_data->str128) == 0);
+
+       g_assert(bt_uuid_cmp(&uuid1, &uuid2) == 0);
+}
+
+static const char *malformed[] = {
+       "0",
+       "01",
+       "012",
+       "xxxx",
+       "xxxxx",
+       "0xxxxx",
+       "0123456",
+       "012g4567",
+       "012345678",
+       "0x234567u9",
+       "01234567890",
+       "00001234-0000-1000-8000-00805F9B34F",
+       "00001234-0000-1000-8000 00805F9B34FB",
+       "00001234-0000-1000-8000-00805F9B34FBC",
+       "00001234-0000-1000-800G-00805F9B34FB",
+       NULL,
+};
+
+static void test_malformed(gconstpointer data)
+{
+       const char *str = data;
+       bt_uuid_t uuid;
+
+       g_assert(bt_string_to_uuid(&uuid, str) != 0);
+}
+
+int main(int argc, char *argv[])
+{
+       int i;
+
+       g_test_init(&argc, &argv, NULL);
+
+       g_test_add_data_func("/uuid/base", &uuid_base, test_uuid);
+       g_test_add_data_func("/uuid/base/str", &uuid_base, test_str);
+       g_test_add_data_func("/uuid/base/cmp", &uuid_base, test_cmp);
+
+       g_test_add_data_func("/uuid/sixteen1", &uuid_sixteen1, test_uuid);
+       g_test_add_data_func("/uuid/sixteen1/str", &uuid_sixteen1, test_str);
+       g_test_add_data_func("/uuid/sixteen1/cmp", &uuid_sixteen1, test_cmp);
+
+       g_test_add_data_func("/uuid/sixteen2", &uuid_sixteen2, test_uuid);
+       g_test_add_data_func("/uuid/sixteen2/str", &uuid_sixteen2, test_str);
+       g_test_add_data_func("/uuid/sixteen2/cmp", &uuid_sixteen2, test_cmp);
+
+       g_test_add_data_func("/uuid/thirtytwo1", &uuid_32_1, test_uuid);
+       g_test_add_data_func("/uuid/thirtytwo1/str", &uuid_32_1, test_str);
+       g_test_add_data_func("/uuid/thirtytwo1/cmp", &uuid_32_1, test_cmp);
+
+       g_test_add_data_func("/uuid/thirtytwo2", &uuid_32_2, test_uuid);
+       g_test_add_data_func("/uuid/thritytwo2/str", &uuid_32_2, test_str);
+       g_test_add_data_func("/uuid/thirtytwo2/cmp", &uuid_32_2, test_cmp);
+
+       for (i = 0; malformed[i]; i++) {
+               char *testpath;
+
+               testpath = g_strdup_printf("/uuid/malformed/%s", malformed[i]);
+               g_test_add_data_func(testpath, malformed[i], test_malformed);
+               g_free(testpath);
+       }
+
+       return g_test_run();
+}
diff --git a/unit/util.c b/unit/util.c
new file mode 100644 (file)
index 0000000..c76acdf
--- /dev/null
@@ -0,0 +1,197 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 <sys/types.h>
+#include <sys/socket.h>
+#include <unistd.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <string.h>
+#include <errno.h>
+
+#include <glib.h>
+
+#include "util.h"
+
+GQuark test_error_quark(void)
+{
+       return g_quark_from_static_string("test-error-quark");
+}
+
+static void dump_bytes(const uint8_t *buf, size_t buf_len)
+{
+       size_t i;
+
+       for (i = 0; i < buf_len; i++)
+               g_printerr("%02x ", buf[i]);
+
+       g_printerr("\n");
+}
+
+void dump_bufs(const void *mem1, size_t len1, const void *mem2, size_t len2)
+{
+       g_printerr("\nExpected: ");
+       dump_bytes(mem1, len1);
+       g_printerr("Got:      ");
+       dump_bytes(mem2, len2);
+}
+
+void assert_memequal(const void *mem1, size_t len1,
+                                               const void *mem2, size_t len2)
+{
+       if (len1 == len2 && memcmp(mem1, mem2, len1) == 0)
+               return;
+
+       dump_bufs(mem1, len1, mem2, len2);
+
+       g_assert(0);
+}
+
+GObex *create_gobex(int fd, GObexTransportType transport_type,
+                                               gboolean close_on_unref)
+{
+       GIOChannel *io;
+       GObex *obex;
+
+       io = g_io_channel_unix_new(fd);
+       g_assert(io != NULL);
+
+       g_io_channel_set_close_on_unref(io, close_on_unref);
+
+       obex = g_obex_new(io, transport_type, -1, -1);
+       g_io_channel_unref(io);
+
+       return obex;
+}
+
+void create_endpoints(GObex **obex, GIOChannel **io, int sock_type)
+{
+       GObexTransportType transport_type;
+       int sv[2];
+
+       if (socketpair(AF_UNIX, sock_type | SOCK_NONBLOCK, 0, sv) < 0) {
+               g_printerr("socketpair: %s", strerror(errno));
+               abort();
+       }
+
+       if (sock_type == SOCK_STREAM)
+               transport_type = G_OBEX_TRANSPORT_STREAM;
+       else
+               transport_type = G_OBEX_TRANSPORT_PACKET;
+
+       *obex = create_gobex(sv[0], transport_type, TRUE);
+       g_assert(*obex != NULL);
+
+       if (io == NULL) {
+               close(sv[1]);
+               return;
+       }
+
+       *io = g_io_channel_unix_new(sv[1]);
+       g_assert(*io != NULL);
+
+       g_io_channel_set_encoding(*io, NULL, NULL);
+       g_io_channel_set_buffered(*io, FALSE);
+       g_io_channel_set_close_on_unref(*io, TRUE);
+}
+
+gboolean test_timeout(gpointer user_data)
+{
+       struct test_data *d = user_data;
+
+       if (!g_main_loop_is_running(d->mainloop))
+               return FALSE;
+
+       d->err = g_error_new(TEST_ERROR, TEST_ERROR_TIMEOUT, "Timed out");
+
+       g_main_loop_quit(d->mainloop);
+
+       return FALSE;
+}
+
+gboolean test_io_cb(GIOChannel *io, GIOCondition cond, gpointer user_data)
+{
+       struct test_data *d = user_data;
+       GIOStatus status;
+       gsize bytes_written, rbytes, send_buf_len, expect_len;
+       char buf[65535];
+       const char *send_buf, *expect;
+
+       expect = d->recv[d->count].data;
+       expect_len = d->recv[d->count].len;
+       send_buf = d->send[d->count].data;
+       send_buf_len = d->send[d->count].len;
+
+       d->count++;
+
+       if (!(cond & G_IO_IN))
+               goto send;
+
+       status = g_io_channel_read_chars(io, buf, sizeof(buf), &rbytes, NULL);
+       if (status != G_IO_STATUS_NORMAL) {
+               g_print("io_cb count %u\n", d->count);
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                               "Reading data failed with status %d", status);
+               goto failed;
+       }
+
+       if (rbytes < expect_len) {
+               g_print("io_cb count %u\n", d->count);
+               dump_bufs(expect, expect_len, buf, rbytes);
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Not enough data from socket");
+               goto failed;
+       }
+
+       if (memcmp(buf, expect, expect_len) != 0) {
+               g_print("io_cb count %u\n", d->count);
+               dump_bufs(expect, expect_len, buf, rbytes);
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                       "Received data is not correct");
+               goto failed;
+       }
+
+send:
+       if ((gssize) send_buf_len < 0)
+               goto failed;
+
+       g_io_channel_write_chars(io, send_buf, send_buf_len, &bytes_written,
+                                                                       NULL);
+       if (bytes_written != send_buf_len) {
+               g_print("io_cb count %u\n", d->count);
+               g_set_error(&d->err, TEST_ERROR, TEST_ERROR_UNEXPECTED,
+                                               "Unable to write to socket");
+               goto failed;
+       }
+
+       if (d->recv[d->count].len < 0 || (gssize) expect_len < 0)
+               return test_io_cb(io, G_IO_OUT, user_data);
+
+       return TRUE;
+
+failed:
+       g_main_loop_quit(d->mainloop);
+       return FALSE;
+}
diff --git a/unit/util.h b/unit/util.h
new file mode 100644 (file)
index 0000000..752ce61
--- /dev/null
@@ -0,0 +1,58 @@
+/*
+ *
+ *  OBEX library with GLib integration
+ *
+ *  Copyright (C) 2011  Intel Corporation. All rights reserved.
+ *
+ *  This program is free software; you can redistribute it and/or modify
+ *  it under the terms of the GNU General Public License version 2 as
+ *  published by the Free Software Foundation.
+ *
+ *  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 <gobex/gobex.h>
+
+enum {
+       TEST_ERROR_TIMEOUT,
+       TEST_ERROR_UNEXPECTED,
+};
+
+struct test_buf {
+       const void *data;
+       gssize len;
+};
+
+struct test_data {
+       guint count;
+       GError *err;
+       struct test_buf recv[4];
+       struct test_buf send[4];
+       guint provide_delay;
+       GObex *obex;
+       guint id;
+       gsize total;
+       GMainLoop *mainloop;
+};
+
+#define TEST_ERROR test_error_quark()
+GQuark test_error_quark(void);
+
+void dump_bufs(const void *mem1, size_t len1, const void *mem2, size_t len2);
+void assert_memequal(const void *mem1, size_t len1,
+                                               const void *mem2, size_t len2);
+
+GObex *create_gobex(int fd, GObexTransportType transport_type,
+                                               gboolean close_on_unref);
+void create_endpoints(GObex **obex, GIOChannel **io, int sock_type);
+
+gboolean test_io_cb(GIOChannel *io, GIOCondition cond, gpointer user_data);
+gboolean test_timeout(gpointer user_data);
diff --git a/ylwrap b/ylwrap
deleted file mode 100755 (executable)
index 9253635..0000000
--- a/ylwrap
+++ /dev/null
@@ -1,226 +0,0 @@
-#! /bin/sh
-# ylwrap - wrapper for lex/yacc invocations.
-
-scriptversion=2011-08-25.18; # UTC
-
-# Copyright (C) 1996, 1997, 1998, 1999, 2001, 2002, 2003, 2004, 2005,
-# 2007, 2009, 2010, 2011 Free Software Foundation, Inc.
-#
-# Written by Tom Tromey <tromey@cygnus.com>.
-#
-# This program is free software; you can redistribute it and/or modify
-# it under the terms of the GNU General Public License as published by
-# the Free Software Foundation; either version 2, 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, see <http://www.gnu.org/licenses/>.
-
-# As a special exception to the GNU General Public License, if you
-# distribute this file as part of a program that contains a
-# configuration script generated by Autoconf, you may include it under
-# the same distribution terms that you use for the rest of that program.
-
-# This file is maintained in Automake, please report
-# bugs to <bug-automake@gnu.org> or send patches to
-# <automake-patches@gnu.org>.
-
-case "$1" in
-  '')
-    echo "$0: No files given.  Try \`$0 --help' for more information." 1>&2
-    exit 1
-    ;;
-  --basedir)
-    basedir=$2
-    shift 2
-    ;;
-  -h|--h*)
-    cat <<\EOF
-Usage: ylwrap [--help|--version] INPUT [OUTPUT DESIRED]... -- PROGRAM [ARGS]...
-
-Wrapper for lex/yacc invocations, renaming files as desired.
-
-  INPUT is the input file
-  OUTPUT is one file PROG generates
-  DESIRED is the file we actually want instead of OUTPUT
-  PROGRAM is program to run
-  ARGS are passed to PROG
-
-Any number of OUTPUT,DESIRED pairs may be used.
-
-Report bugs to <bug-automake@gnu.org>.
-EOF
-    exit $?
-    ;;
-  -v|--v*)
-    echo "ylwrap $scriptversion"
-    exit $?
-    ;;
-esac
-
-
-# The input.
-input="$1"
-shift
-case "$input" in
-  [\\/]* | ?:[\\/]*)
-    # Absolute path; do nothing.
-    ;;
-  *)
-    # Relative path.  Make it absolute.
-    input="`pwd`/$input"
-    ;;
-esac
-
-pairlist=
-while test "$#" -ne 0; do
-  if test "$1" = "--"; then
-    shift
-    break
-  fi
-  pairlist="$pairlist $1"
-  shift
-done
-
-# The program to run.
-prog="$1"
-shift
-# Make any relative path in $prog absolute.
-case "$prog" in
-  [\\/]* | ?:[\\/]*) ;;
-  *[\\/]*) prog="`pwd`/$prog" ;;
-esac
-
-# FIXME: add hostname here for parallel makes that run commands on
-# other machines.  But that might take us over the 14-char limit.
-dirname=ylwrap$$
-do_exit="cd '`pwd`' && rm -rf $dirname > /dev/null 2>&1;"' (exit $ret); exit $ret'
-trap "ret=129; $do_exit" 1
-trap "ret=130; $do_exit" 2
-trap "ret=141; $do_exit" 13
-trap "ret=143; $do_exit" 15
-mkdir $dirname || exit 1
-
-cd $dirname
-
-case $# in
-  0) "$prog" "$input" ;;
-  *) "$prog" "$@" "$input" ;;
-esac
-ret=$?
-
-if test $ret -eq 0; then
-  set X $pairlist
-  shift
-  first=yes
-  # Since DOS filename conventions don't allow two dots,
-  # the DOS version of Bison writes out y_tab.c instead of y.tab.c
-  # and y_tab.h instead of y.tab.h. Test to see if this is the case.
-  y_tab_nodot="no"
-  if test -f y_tab.c || test -f y_tab.h; then
-    y_tab_nodot="yes"
-  fi
-
-  # The directory holding the input.
-  input_dir=`echo "$input" | sed -e 's,\([\\/]\)[^\\/]*$,\1,'`
-  # Quote $INPUT_DIR so we can use it in a regexp.
-  # FIXME: really we should care about more than `.' and `\'.
-  input_rx=`echo "$input_dir" | sed 's,\\\\,\\\\\\\\,g;s,\\.,\\\\.,g'`
-
-  while test "$#" -ne 0; do
-    from="$1"
-    # Handle y_tab.c and y_tab.h output by DOS
-    if test $y_tab_nodot = "yes"; then
-      if test $from = "y.tab.c"; then
-        from="y_tab.c"
-      else
-        if test $from = "y.tab.h"; then
-          from="y_tab.h"
-        fi
-      fi
-    fi
-    if test -f "$from"; then
-      # If $2 is an absolute path name, then just use that,
-      # otherwise prepend `../'.
-      case "$2" in
-        [\\/]* | ?:[\\/]*) target="$2";;
-        *) target="../$2";;
-      esac
-
-      # We do not want to overwrite a header file if it hasn't
-      # changed.  This avoid useless recompilations.  However the
-      # parser itself (the first file) should always be updated,
-      # because it is the destination of the .y.c rule in the
-      # Makefile.  Divert the output of all other files to a temporary
-      # file so we can compare them to existing versions.
-      if test $first = no; then
-        realtarget="$target"
-        target="tmp-`echo $target | sed s/.*[\\/]//g`"
-      fi
-      # Edit out `#line' or `#' directives.
-      #
-      # We don't want the resulting debug information to point at
-      # an absolute srcdir; it is better for it to just mention the
-      # .y file with no path.
-      #
-      # We want to use the real output file name, not yy.lex.c for
-      # instance.
-      #
-      # We want the include guards to be adjusted too.
-      FROM=`echo "$from" | sed \
-            -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
-            -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
-      TARGET=`echo "$2" | sed \
-            -e 'y/abcdefghijklmnopqrstuvwxyz/ABCDEFGHIJKLMNOPQRSTUVWXYZ/'\
-            -e 's/[^ABCDEFGHIJKLMNOPQRSTUVWXYZ]/_/g'`
-
-      sed -e "/^#/!b" -e "s,$input_rx,," -e "s,$from,$2," \
-          -e "s,$FROM,$TARGET," "$from" >"$target" || ret=$?
-
-      # Check whether header files must be updated.
-      if test $first = no; then
-        if test -f "$realtarget" && cmp -s "$realtarget" "$target"; then
-          echo "$2" is unchanged
-          rm -f "$target"
-        else
-          echo updating "$2"
-          mv -f "$target" "$realtarget"
-        fi
-      fi
-    else
-      # A missing file is only an error for the first file.  This
-      # is a blatant hack to let us support using "yacc -d".  If -d
-      # is not specified, we don't want an error when the header
-      # file is "missing".
-      if test $first = yes; then
-        ret=1
-      fi
-    fi
-    shift
-    shift
-    first=no
-  done
-else
-  ret=$?
-fi
-
-# Remove the directory.
-cd ..
-rm -rf $dirname
-
-exit $ret
-
-# Local Variables:
-# mode: shell-script
-# sh-indentation: 2
-# eval: (add-hook 'write-file-hooks 'time-stamp)
-# time-stamp-start: "scriptversion="
-# time-stamp-format: "%:y-%02m-%02d.%02H"
-# time-stamp-time-zone: "UTC"
-# time-stamp-end: "; # UTC"
-# End: